main.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import os, sys
  2. import numpy as np
  3. from queue import PriorityQueue
  4. from collections import defaultdict, deque
  5. task_dir = os.path.dirname(__file__)
  6. sys.path.append(f"{task_dir}/..")
  7. from get_tasks import get_input, check_example, generate_readme
  8. def get_dirs(center, i_size, j_size):
  9. i, j = center
  10. up = max(0, i - 1), j
  11. left = i, max(0, j - 1)
  12. down = min(i + 1, i_size), j
  13. right = i, min(j_size, j + 1)
  14. return up, left, down, right
  15. def dijkstra(G, start=(0, 0), end=False, pq=True, star=False):
  16. i_s, j_s = G.shape[0] - 1, G.shape[1] - 1
  17. end = (i_s, j_s) if not end else end
  18. parents = {}
  19. q = PriorityQueue() if pq else deque()
  20. nodeCosts = defaultdict(lambda: float("inf"))
  21. nodeCosts[start] = 0
  22. if pq:
  23. q.put((0, start))
  24. else:
  25. q.append((0, start))
  26. def get_path(node):
  27. path = []
  28. while node != start:
  29. path.append(node)
  30. node = parents[node]
  31. path.append(start)
  32. return path[::-1]
  33. def estimate(end, node):
  34. return abs(end[0] - node[0]) + abs(end[1] - node[1])
  35. acc = 0
  36. while (q.qsize() if pq else len(q)) != 0:
  37. acc += 1
  38. _, node = q.get() if pq else q.popleft()
  39. if pq and node == end:
  40. print("With early stop!", acc)
  41. return get_path(node), nodeCosts[node]
  42. for adjNode in get_dirs(node, i_s, j_s):
  43. newCost = nodeCosts[node] + G[adjNode]
  44. if nodeCosts[adjNode] > newCost:
  45. parents[adjNode] = node
  46. nodeCosts[adjNode] = newCost
  47. if star:
  48. newCost += estimate(end, adjNode)
  49. if pq:
  50. q.put((newCost, adjNode))
  51. else:
  52. q.append((newCost, adjNode))
  53. return get_path(end), nodeCosts[end]
  54. def part1(input: list[str], verbose=True):
  55. ceiling = np.array([list(line) for line in input], dtype=int)
  56. _, cost = dijkstra(ceiling)
  57. if verbose:
  58. print("The answer of part1 is:", cost)
  59. def part2(input: list[str], pq=True, star=False, verbose=True):
  60. ceiling = np.array([list(line) for line in input], dtype=int)
  61. full_ceiling = ceiling.copy()
  62. for step in range(1, 5):
  63. left_ceiling = ceiling + step
  64. left_ceiling[left_ceiling > 9] -= 9
  65. full_ceiling = np.hstack([full_ceiling, left_ceiling])
  66. line_ceiling = full_ceiling.copy()
  67. for step in range(1, 5):
  68. down_ceiling = line_ceiling + step
  69. down_ceiling[down_ceiling > 9] -= 9
  70. full_ceiling = np.vstack([full_ceiling, down_ceiling])
  71. _, cost = dijkstra(full_ceiling, pq=pq, star=star)
  72. if verbose:
  73. print("The answer of part2 is:", cost)
  74. if __name__ == "__main__":
  75. input, example = get_input(task_dir, 15)
  76. check_example(example, part1)
  77. check_example(example, part2)
  78. part1(input)
  79. part2(input)
  80. generate_readme(task_dir, 15)