diff --git a/day3/day3.py b/day3/day3.py index e220a48..a961c83 100644 --- a/day3/day3.py +++ b/day3/day3.py @@ -1,17 +1,18 @@ -from typing import Tuple, List, Dict, Set +from typing import Tuple, List, Set from dataclasses import dataclass -from collections import defaultdict @dataclass(frozen=True) class Item: pos: Tuple[int, int] symbol: str + def browse_schema(schema): total_parts = 0 buf = [] max_row, max_col = len(schema), len(schema[0]) + symbols: List[Tuple[Item, Set[Item]]] = [] numbers: List[Item] = [] for y in range(max_row): @@ -20,11 +21,15 @@ def browse_schema(schema): if item.isnumeric(): # continue parsing full number buf.append(item) - elif buf: + else: + neighbors = get_neighbors_of((x, y), schema) + symbols.append((Item((x, y), item), set(neighbors))) + if buf and not item.isnumeric(): # end of a number, do the engine part check number = "".join(buf) neighbors = get_neighbors((x, y), len(buf), schema) start_pos = (x-len(number), y) + symbols.append((Item((x, y), number), get_neighbors_of((x, y), schema))) numbers.append(Item(start_pos, number)) if is_engine_part(neighbors): @@ -33,28 +38,27 @@ def browse_schema(schema): buf.clear() # reached end of a number, clear buffer print(f"Part 1, sum of the parts numbers = {total_parts}") + part2(symbols, numbers) - gears: Dict[Tuple[int, int], Set[Item]] = defaultdict(set) - for y in range(max_row): - for x in range(max_col): - item = schema[y][x] - if item == "*": - print(f"* ({x}, {y})") - neighbors = [n for n in get_neighbors_of((x, y), schema) if n.symbol.isdigit()] - if (x, y) == (5, 8): - breakpoint() +def part2(symbols, numbers): + total_gears = 0 + stars = [(s, neighbors) for s, neighbors in symbols if s.symbol == "*"] + for _, neighbors in stars: + corresponding_numbers = set() + digits = [n for n in neighbors if n.symbol.isdigit()] + for digit in digits: + # find full number (number.start_pos < digit.pos < number.end_pos) + for number in numbers: + if number.pos[1] - 1 <= digit.pos[1] <= number.pos[1] + 1 and number.pos[0] <= digit.pos[0] <= number.pos[0]+len(number.symbol): + corresponding_numbers.add(number.symbol) - for neighbor in neighbors: - neighboring_numbers = [n for n in numbers - if y-1 <= n.pos[1] == y+1 - and n.pos[0] <= neighbor.pos[0] <= n.pos[0] + len(n.symbol)] - gears[(x,y)] = gears[(x,y)].union(neighboring_numbers) - - # gears = { key: value for key, value in gears.items() if len(value) <= 2 } + if len(corresponding_numbers) == 2: + a, b = corresponding_numbers + total_gears += int(a) * int(b) + #print(f"star: {star.pos} {corresponding_numbers}") - - - print(f"Part 2, sum of the gear ratios = TODO") + print(f"Part 2, sum of gear ratios = {total_gears}") + def is_engine_part(neighbors: List[Item]) -> bool: