Cleanup day 1 solution

This commit is contained in:
Nettika
2023-12-16 10:29:16 -08:00
parent 0b30503e72
commit dd52297b08
10 changed files with 169 additions and 1138 deletions

View File

@@ -2,3 +2,16 @@
__author__ = "Nettika <nettika@leaf.ninja>"
__version__ = "1.0.0"
from typing import Callable
from advent_of_code.trebuchet import (
recover_calibration_digits_and_words,
recover_calibration_digits_only,
)
Solver = Callable[[str], str]
solvers: dict[int, tuple[Solver, Solver]] = {
1: (recover_calibration_digits_only, recover_calibration_digits_and_words),
}

View File

@@ -3,10 +3,7 @@ from argparse import ArgumentParser
import requests
from advent_of_code import __version__
from advent_of_code.solver import Solver
solvers: dict[int, Solver] = {}
from advent_of_code import __version__, solvers
def main():
@@ -57,10 +54,10 @@ def main():
# Execute solvers
print(f"Solving day {args.day}'s puzzle")
start = time.time()
print("Part 1 -", solver.solve_part_1(input))
print("Part 2 -", solver.solve_part_2(input))
print("Part 1 -", solver[0](input))
print("Part 2 -", solver[1](input))
end = time.time()
print(f"Solved in {end-start:,} seconds.")
print(f"Solved in {end-start:,.4f} seconds.")
if __name__ == "__main__":

View File

@@ -1,11 +0,0 @@
from abc import ABC, abstractmethod
class Solver(ABC):
@abstractmethod
def solve_part_1(self, input: str) -> None:
pass
@abstractmethod
def solve_part_2(self, input: str) -> None:
pass

View File

@@ -0,0 +1,83 @@
import re
number_word_map = {
"one": "1",
"two": "2",
"three": "3",
"four": "4",
"five": "5",
"six": "6",
"seven": "7",
"eight": "8",
"nine": "9",
"zero": "0",
}
decimal_only_pattern = re.compile("[0-9]")
left_decimal_and_words_pattern = re.compile(
"[0-9]|" + "|".join(word for word in number_word_map.keys())
)
right_decimal_and_words_pattern = re.compile(
"[0-9]|" + "|".join(word[::-1] for word in number_word_map.keys())
)
def _recover_calibration_value(
line: str,
left_symbol_pattern: re.Pattern,
right_symbol_pattern: re.Pattern,
symbol_map: dict[str, str],
) -> int:
left_symbol_match = left_symbol_pattern.search(line)
right_symbol_match = right_symbol_pattern.search(line[::-1])
if not left_symbol_match or not right_symbol_match:
raise ValueError(f'The calibration value of line "{line}" is unrecoverable.')
left_symbol = left_symbol_match.group()
right_symbol = right_symbol_match.group()[::-1]
first_digit = symbol_map.get(left_symbol, left_symbol)
second_digit = symbol_map.get(right_symbol, right_symbol)
return int(first_digit + second_digit)
def _recover_all_calibration_values(
input: str,
left_symbol_pattern: re.Pattern,
right_symbol_pattern: re.Pattern,
symbol_map: dict[str, str],
) -> int:
return sum(
_recover_calibration_value(
line,
left_symbol_pattern,
right_symbol_pattern,
symbol_map,
)
for line in input.split("\n")
)
def recover_calibration_digits_only(input: str) -> str:
return str(
_recover_all_calibration_values(
input,
decimal_only_pattern,
decimal_only_pattern,
{},
)
)
def recover_calibration_digits_and_words(input: str) -> str:
return str(
_recover_all_calibration_values(
input,
left_decimal_and_words_pattern,
right_decimal_and_words_pattern,
number_word_map,
)
)