From: Pat Thoyts Date: Sun, 3 Dec 2023 09:52:05 +0000 (+0000) Subject: day3: completed part 2 X-Git-Url: http://privyetmir.co.uk/gitweb?a=commitdiff_plain;h=4f584776ee4351a1a51cb4196f3f4221d8600103;p=aoc2023.git day3: completed part 2 --- diff --git a/day3/data/test_input b/day3/data/test_input index 6537f8b..b20187f 100644 --- a/day3/data/test_input +++ b/day3/data/test_input @@ -8,4 +8,3 @@ ......755. ...$.*.... .664.598.. - diff --git a/day3/run.py b/day3/run.py index fb2d64e..e53b320 100755 --- a/day3/run.py +++ b/day3/run.py @@ -13,7 +13,17 @@ def main(args=None): with open(options.filename, 'r') as input: schematic = Schematic.fromstream(input) - print(f"part1: {sum(schematic.parts)}") + partnos = [p.number for p in schematic.parts] + print(f"part1: {sum(partnos)}") + + collection = [] + for gear in schematic.gears: + if len(schematic.gears[gear]) > 1: + collection.append([part.number for part in schematic.gears[gear]]) + + result = sum([(g[0] * g[1]) for g in collection]) + print(f"part2: {result}") + return 0 diff --git a/day3/schematic.py b/day3/schematic.py index ef060b6..143d885 100644 --- a/day3/schematic.py +++ b/day3/schematic.py @@ -1,11 +1,46 @@ +from dataclasses import dataclass from typing import List +@dataclass +class Position: + row: int = 0 + col: int = 0 + + +@dataclass +class Symbol: + symbol: str + pos: Position + + @property + def symid(self): + return self.pos.row * 1000 + self.pos.col + + +@dataclass +class Part: + number: int + symbols: List[Symbol] + + def __repr__(self) -> str: + return f"Part(number='{self.number}',symbols='{self.symbols}')" + + @property + def is_valid(self): + return bool(self.symbols) + + @property + def is_gear(self): + return [sym for sym in self.symbols if sym.symbol == '*'] + + class Schematic: def __init__(self, rows: List[str]): self.rows = rows self.span = len(rows[0]) self.parts = [] + self.gears = {} self.debug = True self.update() @@ -18,7 +53,7 @@ class Schematic: c = self.rows[row][col] if c.isdigit(): part['digits'].append(c) - part['symbols'].append(self.get_neighbours(row, col)) + part['symbols'] += self.get_neighbours(row, col) else: if part['digits']: self._complete_part(part) @@ -26,24 +61,31 @@ class Schematic: if part['digits']: self._complete_part(part) part = {'digits': [], 'symbols':[]} + # get gears + for part in self.parts: + if part.is_gear: + symid = part.is_gear[0].symid + self.gears.setdefault(symid, []) + self.gears[symid].append(part) + #print(self.gears) - def _complete_part(self, part:dict): - value = int(''.join(part['digits'])) - valid = bool(''.join(part['symbols'])) + def _complete_part(self, data:dict): + value = int(''.join(data['digits'])) + part = Part(value, data['symbols']) if self.debug: - print(value, valid, ''.join(part['symbols'])) - if valid: - self.parts.append(value) + print(part.number, part.is_valid, part.symbols) + if part.is_valid: + self.parts.append(part) - def get_neighbours(self, row: int, col: int) -> bool: - result = '' + def get_neighbours(self, row: int, col: int) -> List[Position]: + result = [] for r in [row - 1, row, row + 1]: if r >= 0 and r < len(self.rows): for c in [col - 1, col, col + 1]: if c >= 0 and c < self.span: t = self.rows[r][c] if not (t.isdigit() or t == '.'): - result = result + t + result.append(Symbol(t, Position(r, c))) return result @staticmethod diff --git a/day3/test_schematic.py b/day3/test_schematic.py index f07335f..17a320a 100644 --- a/day3/test_schematic.py +++ b/day3/test_schematic.py @@ -1,6 +1,4 @@ import unittest -import os -import sys from io import StringIO from schematic import Schematic @@ -9,17 +7,50 @@ class TestPart1(unittest.TestCase): def test_schematic_sum(self): with open('data/test_input') as input: schematic = Schematic.fromstream(input) + partnos = [p.number for p in schematic.parts] self.assertSequenceEqual( [467, 35, 633, 617, 592, 755, 664, 598], - schematic.parts) - self.assertEqual(4361, sum(schematic.parts)) + partnos) + self.assertEqual(4361, sum(partnos)) def test_schematic_from_file2(self): with open('data/test_input2') as input: schematic = Schematic.fromstream(input) self.assertSequenceEqual( [467, 35, 633, 617, 592, 755, 664, 598], - schematic.parts) + [p.number for p in schematic.parts]) + + +class TestPart2(unittest.TestCase): + def test_is_gear(self): + stream = StringIO("111...\n..*...\n..222.\n") + schematic = Schematic.fromstream(stream) + part = schematic.parts[0] + self.assertTrue(part.is_gear) + + def test_gears(self): + stream = StringIO("111...\n..*...\n..222.\n") + schematic = Schematic.fromstream(stream) + print(schematic.gears) + self.assertEqual(1, len(schematic.gears)) + self.assertEqual(2, len(schematic.gears[1002])) + self.assertEqual([111, 222], [part.number for part in schematic.gears[1002]]) + + def test_gear_ratio(self): + with open('data/test_input') as input: + schematic = Schematic.fromstream(input) + collection = [] + for gear in schematic.gears: + if len(schematic.gears[gear]) > 1: + collection.append([part.number for part in schematic.gears[gear]]) + + self.assertEqual( + [[467, 35], [755, 598]], + collection) + self.assertEqual( + 467835, + sum([(g[0] * g[1]) for g in collection])) + if __name__ == '__main__': unittest.main()