day3: completed part 1
authorPat Thoyts <pat.thoyts@gmail.com>
Sun, 3 Dec 2023 08:33:40 +0000 (08:33 +0000)
committerPat Thoyts <pat.thoyts@gmail.com>
Sun, 3 Dec 2023 08:33:40 +0000 (08:33 +0000)
day3/data/test_input2 [new file with mode: 0644]
day3/run.py [new file with mode: 0755]
day3/schematic.py [new file with mode: 0644]
day3/test_schematic.py [new file with mode: 0644]

diff --git a/day3/data/test_input2 b/day3/data/test_input2
new file mode 100644 (file)
index 0000000..395c419
--- /dev/null
@@ -0,0 +1,10 @@
+467....114
+...*......
+..35..633.
+......#...
+617*......
+.....+.58.
+..592.....
+......755.
+...$.*....
+.664.598..
diff --git a/day3/run.py b/day3/run.py
new file mode 100755 (executable)
index 0000000..fb2d64e
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/env python3
+
+import sys
+import argparse
+from schematic import Schematic
+
+
+def main(args=None):
+    parser = argparse.ArgumentParser(description="AoC 2023 day 2")
+    parser.add_argument('filename', type=str, help="input path")
+    parser.add_argument('-d', '--debug', action='store_true')
+    options = parser.parse_args(args)
+
+    with open(options.filename, 'r') as input:
+        schematic = Schematic.fromstream(input)
+        print(f"part1: {sum(schematic.parts)}")
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
diff --git a/day3/schematic.py b/day3/schematic.py
new file mode 100644 (file)
index 0000000..ef060b6
--- /dev/null
@@ -0,0 +1,51 @@
+from typing import List
+
+
+class Schematic:
+    def __init__(self, rows: List[str]):
+        self.rows = rows
+        self.span = len(rows[0])
+        self.parts = []
+        self.debug = True
+        self.update()
+
+    def update(self):
+        """Parse the input data and generate the list of parts"""
+        self.parts = []
+        for row in range(len(self.rows)):
+            part = {'digits': [], 'symbols':[]}
+            for col in range(self.span):
+                c = self.rows[row][col]
+                if c.isdigit():
+                    part['digits'].append(c)
+                    part['symbols'].append(self.get_neighbours(row, col))
+                else:
+                    if part['digits']:
+                        self._complete_part(part)
+                        part = {'digits': [], 'symbols':[]}
+            if part['digits']:
+                self._complete_part(part)
+                part = {'digits': [], 'symbols':[]}
+
+    def _complete_part(self, part:dict):
+        value = int(''.join(part['digits']))
+        valid = bool(''.join(part['symbols']))
+        if self.debug:
+            print(value, valid, ''.join(part['symbols']))
+        if valid:
+            self.parts.append(value)
+
+    def get_neighbours(self, row: int, col: int) -> bool:
+        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
+        return result
+
+    @staticmethod
+    def fromstream(stream) -> 'Schematic':
+        return Schematic([x.strip() for x in stream.readlines() if x.strip()])
diff --git a/day3/test_schematic.py b/day3/test_schematic.py
new file mode 100644 (file)
index 0000000..f07335f
--- /dev/null
@@ -0,0 +1,25 @@
+import unittest
+import os
+import sys
+from io import StringIO
+from schematic import Schematic
+
+
+class TestPart1(unittest.TestCase):
+    def test_schematic_sum(self):
+        with open('data/test_input') as input:
+            schematic = Schematic.fromstream(input)
+            self.assertSequenceEqual(
+                [467, 35, 633, 617, 592, 755, 664, 598],
+                schematic.parts)
+            self.assertEqual(4361, sum(schematic.parts))
+
+    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)
+
+if __name__ == '__main__':
+    unittest.main()