JonathanGupton

Advent of Code 2024 - Day 08 - Python

Dec 8th, 2024
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.02 KB | None | 0 0
  1. from collections import defaultdict
  2. from dataclasses import dataclass
  3. from itertools import permutations
  4.  
  5.  
  6. @dataclass
  7. class Bounds:
  8.     x_min: int
  9.     x_max: int
  10.     y_min: int
  11.     y_max: int
  12.  
  13.     def in_bounds(self, coordinate: complex) -> bool:
  14.         return (
  15.             self.x_min <= coordinate.real < self.x_max
  16.             and self.y_min <= coordinate.imag < self.y_max
  17.         )
  18.  
  19.  
  20. def parse_data(fp) -> tuple[dict[str, set[complex]], Bounds]:
  21.     data = defaultdict(set)
  22.     with open(fp, "r") as f:
  23.         rows = f.readlines()
  24.     for y, row in enumerate(rows):
  25.         for x, col in enumerate(row.strip()):
  26.             if col != ".":
  27.                 data[col].add(complex(x, y))
  28.     bounds = Bounds(0, len(rows[0].strip()), 0, len(rows))
  29.     return data, bounds
  30.  
  31.  
  32. def compute_distance(pos1: complex, pos2: complex) -> complex:
  33.     return complex(pos2.real - pos1.real, pos2.imag - pos1.imag)
  34.  
  35.  
  36. def compute_antinode_position(pair: tuple[complex, complex]) -> complex:
  37.     l, r = pair
  38.     dist = compute_distance(l, r)
  39.     new_position = r + dist
  40.     return new_position
  41.  
  42.  
  43. def compute_next_position(position: complex, distance: complex) -> complex:
  44.     return position + distance
  45.  
  46.  
  47. def get_antinode_positions(
  48.     node_map: dict[str, set[complex]], bounds: Bounds
  49. ) -> set[complex]:
  50.     antinode_positions: set[complex] = set()
  51.     for k, v in node_map.items():
  52.         for pair in permutations(v, 2):
  53.             new_antinode_position = compute_antinode_position(pair)
  54.             if bounds.in_bounds(new_antinode_position):
  55.                 antinode_positions.add(new_antinode_position)
  56.     return antinode_positions
  57.  
  58.  
  59. def get_resonant_antinode_positions(
  60.     node_map: dict[str, set[complex]], bounds: Bounds
  61. ) -> set[complex]:
  62.     antinode_positions: set[complex] = set()
  63.     for k, v in node_map.items():
  64.         for pair in permutations(v, 2):
  65.             antinode_positions.update(pair)
  66.             distance = compute_distance(*pair)
  67.             current_position = pair[1]
  68.             while True:
  69.                 current_position += distance
  70.                 if bounds.in_bounds(current_position):
  71.                     antinode_positions.add(current_position)
  72.                 else:
  73.                     break
  74.     return antinode_positions
  75.  
  76.  
  77. def part_a_example():
  78.     pair1 = (complex(0, 0), complex(0, 1))
  79.     antinode_position = compute_antinode_position(pair1)
  80.     assert antinode_position == complex(0, 2)
  81.  
  82.     pair2 = (complex(0, 1), complex(0, 0))
  83.     antinode_position = compute_antinode_position(pair2)
  84.     assert antinode_position == complex(0, -1)
  85.  
  86.     pair3 = (complex(0, 0), complex(2, 2))
  87.     antinode_position = compute_antinode_position(pair3)
  88.     assert antinode_position == complex(4, 4)
  89.  
  90.     fp = "./example/day08-example01.txt"
  91.     node_map, bounds = parse_data(fp)
  92.     antinode_positions = get_antinode_positions(node_map, bounds)
  93.     print(len(antinode_positions), "= 2")
  94.  
  95.     fp = "./example/day08-example02.txt"
  96.     node_map, bounds = parse_data(fp)
  97.     antinode_positions = get_antinode_positions(node_map, bounds)
  98.     print(len(antinode_positions), "= 14")
  99.  
  100.  
  101. def part_a():
  102.     fp = "./data/day08.txt"
  103.     node_map, bounds = parse_data(fp)
  104.     antinode_positions = get_antinode_positions(node_map, bounds)
  105.     print(len(antinode_positions))
  106.  
  107.  
  108. def part_b_example():
  109.     fp = "./example/day08-example02.txt"
  110.     node_map, bounds = parse_data(fp)
  111.     antinode_positions = get_resonant_antinode_positions(node_map, bounds)
  112.     print(len(antinode_positions), "= 34")
  113.  
  114.     fp = "./example/day08-example03.txt"
  115.     node_map, bounds = parse_data(fp)
  116.     antinode_positions = get_resonant_antinode_positions(node_map, bounds)
  117.     print(len(antinode_positions), "= 9")
  118.  
  119.  
  120. def part_b():
  121.     fp = "./data/day08.txt"
  122.     node_map, bounds = parse_data(fp)
  123.     antinode_positions = get_resonant_antinode_positions(node_map, bounds)
  124.     print(len(antinode_positions))
  125.  
  126.  
  127. if __name__ == "__main__":
  128.     part_a_example()
  129.     part_a()
  130.     part_b_example()
  131.     part_b()
  132.  
Advertisement
Add Comment
Please, Sign In to add comment