Restructure solver modules with classes and unittest suites
This commit is contained in:
86
puzzles/3.py
86
puzzles/3.py
@@ -1,40 +1,58 @@
|
||||
import re
|
||||
from functools import reduce
|
||||
from typing import Literal, override
|
||||
from unittest import TestCase
|
||||
|
||||
test_input_p1 = """
|
||||
xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))
|
||||
"""
|
||||
|
||||
test_input_p2 = """
|
||||
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))
|
||||
"""
|
||||
|
||||
test_solution_p1 = 161
|
||||
test_solution_p2 = 48
|
||||
|
||||
instruction_pattern = re.compile(r"mul\((\d+),(\d+)\)|(do(?:n't)?)\(\)")
|
||||
from puzzles._solver import Solver
|
||||
|
||||
|
||||
def solve_p1(puzzle_input: str) -> int:
|
||||
instructions = (
|
||||
tuple(map(int, match[:2]))
|
||||
for match in instruction_pattern.findall(puzzle_input)
|
||||
if match[0]
|
||||
)
|
||||
return sum(a * b for a, b in instructions)
|
||||
class DayThreeSolver(Solver):
|
||||
memory: tuple[int, int] | Literal["do", "don't"]
|
||||
|
||||
@override
|
||||
def __init__(self, puzzle_input: str):
|
||||
matches = re.findall(r"mul\((\d+),(\d+)\)|(do(?:n't)?)\(\)", puzzle_input)
|
||||
self.memory = tuple(
|
||||
(int(a), int(b)) if a else enable_flag for a, b, enable_flag in matches
|
||||
)
|
||||
|
||||
@override
|
||||
def solve_p1(self) -> int:
|
||||
total = 0
|
||||
|
||||
for match in self.memory:
|
||||
match match:
|
||||
case a, b:
|
||||
total += a * b
|
||||
|
||||
return total
|
||||
|
||||
@override
|
||||
def solve_p2(self) -> int:
|
||||
total = 0
|
||||
enabled = True
|
||||
|
||||
for match in self.memory:
|
||||
match match:
|
||||
case "do":
|
||||
enabled = True
|
||||
case "don't":
|
||||
enabled = False
|
||||
case a, b:
|
||||
if enabled:
|
||||
total += a * b
|
||||
|
||||
return total
|
||||
|
||||
|
||||
def solve_p2(puzzle_input: str) -> int:
|
||||
instructions = (
|
||||
match[2] or tuple(map(int, match[:2]))
|
||||
for match in instruction_pattern.findall(puzzle_input)
|
||||
)
|
||||
return reduce(
|
||||
lambda a, i: (
|
||||
(1 if i == "do" else 0, a[1])
|
||||
if isinstance(i, str)
|
||||
else (a[0], a[1] + a[0] * i[0] * i[1])
|
||||
),
|
||||
instructions,
|
||||
(1, 0),
|
||||
)[1]
|
||||
class TestDayThreeSolver(TestCase):
|
||||
def test_solve_p1(self):
|
||||
solver = DayThreeSolver(
|
||||
"xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))\n"
|
||||
)
|
||||
self.assertEqual(solver.solve_p1(), 161)
|
||||
|
||||
def test_solve_p2(self):
|
||||
solver = DayThreeSolver(
|
||||
"xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))\n"
|
||||
)
|
||||
self.assertEqual(solver.solve_p2(), 48)
|
||||
|
Reference in New Issue
Block a user