main.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import os, sys
  2. import numpy as np
  3. from functools import partial
  4. from scipy.ndimage.measurements import label
  5. task_dir = os.path.dirname(__file__)
  6. sys.path.append(f"{task_dir}/..")
  7. from get_tasks import get_input, generate_readme, check_example
  8. def parse_input(inputs: list[str]):
  9. return np.array([list(line.strip()) for line in inputs], dtype=int)
  10. def part1(cave: np.ndarray) -> np.ndarray:
  11. centers = np.array([0, 0], dtype=int)
  12. mins = np.array([], dtype=int)
  13. for i in range(cave.shape[0]):
  14. for j in range(cave.shape[1]):
  15. if (here := cave[i, j]) == (
  16. cave[max(0, i - 1) : i + 2, max(0, j - 1) : j + 2]
  17. ).min() and here != 9:
  18. mins = np.append(mins, here)
  19. centers = np.vstack([centers, [i, j]])
  20. centers = np.delete(centers, 0, 0)
  21. print("The answer of part1 is:", (mins + 1).sum())
  22. return centers
  23. def part2(cave: np.ndarray, centers_basins: np.ndarray, scipy=False, verbose=True):
  24. # solve with cheats!
  25. if scipy:
  26. labels, count = label(cave != 9)
  27. return (
  28. np.sort(np.unique(labels[np.where(labels > 0)], return_counts=1)[1])[
  29. -3:
  30. ].prod(),
  31. count,
  32. )
  33. # solve without cheats
  34. def get_dirs(center):
  35. i, j = center
  36. up = max(0, i - 1), j
  37. left = i, max(0, j - 1)
  38. down = min(i + 1, i_size), j
  39. right = i, min(j_size, j + 1)
  40. return up, left, down, right
  41. i_size, j_size = cave.shape
  42. i_size, j_size = i_size - 1, j_size - 1
  43. for idx, center in enumerate(centers_basins):
  44. queue = []
  45. i, j = center
  46. queue.append((i, j))
  47. cave[i, j] = idx + 11
  48. while queue:
  49. pos = queue.pop()
  50. for dir in get_dirs(pos):
  51. if cave[dir] < 9:
  52. cave[dir] = idx + 11
  53. queue.append(dir)
  54. basins = np.sort(np.unique(cave[np.where(cave > 10)], return_counts=1)[1])
  55. if verbose:
  56. print("The answer of part2 is:", basins[-3:].prod())
  57. return basins, cave, idx
  58. if __name__ == "__main__":
  59. input, example = get_input(task_dir, 9)
  60. example_cave = parse_input(example)
  61. real_cave = parse_input(input)
  62. check_example(example_cave, part1)
  63. example_basins = part1(example_cave)
  64. check_part2 = partial(part2, example_cave)
  65. check_example(example_basins, check_part2)
  66. centers_basisns = part1(real_cave)
  67. part2(real_cave, centers_basisns)
  68. generate_readme(task_dir, 9)