Cleanup day 1 solution
This commit is contained in:
@@ -1,20 +0,0 @@
|
||||
from pathlib import Path
|
||||
|
||||
from puzzle import solve_pt_1, solve_pt_2
|
||||
|
||||
|
||||
def main():
|
||||
input = (
|
||||
Path(__file__)
|
||||
.parent.joinpath("calibration_document.txt")
|
||||
.read_text()
|
||||
.strip()
|
||||
.split("\n")
|
||||
)
|
||||
print("Calibration Numbers:")
|
||||
print("Part 1 -", solve_pt_1(input))
|
||||
print("Part 2 -", solve_pt_2(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
File diff suppressed because it is too large
Load Diff
67
01/puzzle.py
67
01/puzzle.py
@@ -1,67 +0,0 @@
|
||||
import re
|
||||
|
||||
pt_1_first_digit_pattern = re.compile("([0-9])")
|
||||
pt_1_last_digit_pattern = pt_1_first_digit_pattern
|
||||
pt_1_symbol_map = {str(n): str(n) for n in range(10)}
|
||||
|
||||
pt_2_first_digit_pattern = re.compile(
|
||||
"([0-9]|one|two|three|four|five|six|seven|eight|nine|zero)"
|
||||
)
|
||||
pt_2_last_digit_pattern = re.compile(
|
||||
"([0-9]|eno|owt|eerht|ruof|evif|xis|neves|thgie|enin|orez)"
|
||||
)
|
||||
pt_2_symbol_map = {
|
||||
**pt_1_symbol_map,
|
||||
"one": "1",
|
||||
"two": "2",
|
||||
"three": "3",
|
||||
"four": "4",
|
||||
"five": "5",
|
||||
"six": "6",
|
||||
"seven": "7",
|
||||
"eight": "8",
|
||||
"nine": "9",
|
||||
"zero": "0",
|
||||
}
|
||||
|
||||
|
||||
def _solve(
|
||||
input: list[str],
|
||||
first_digit_pattern: re.Pattern,
|
||||
last_digit_pattern: re.Pattern,
|
||||
symbol_map: dict[str, str],
|
||||
) -> int:
|
||||
total = 0
|
||||
|
||||
for line in input:
|
||||
first_digit_match = first_digit_pattern.search(line)
|
||||
last_digit_match = last_digit_pattern.search(line[::-1])
|
||||
|
||||
if not first_digit_match or not last_digit_match:
|
||||
raise ValueError(f'Line "{line}" calibration document contains no digits.')
|
||||
|
||||
first_digit = symbol_map[first_digit_match.group(1)]
|
||||
last_digit = symbol_map[last_digit_match.group(1)[::-1]]
|
||||
|
||||
line_calibration_number = int(first_digit + last_digit)
|
||||
total += line_calibration_number
|
||||
|
||||
return total
|
||||
|
||||
|
||||
def solve_pt_1(input: list[str]) -> int:
|
||||
return _solve(
|
||||
input,
|
||||
pt_1_first_digit_pattern,
|
||||
pt_1_first_digit_pattern,
|
||||
pt_1_symbol_map,
|
||||
)
|
||||
|
||||
|
||||
def solve_pt_2(input: list[str]) -> int:
|
||||
return _solve(
|
||||
input,
|
||||
pt_2_first_digit_pattern,
|
||||
pt_2_last_digit_pattern,
|
||||
pt_2_symbol_map,
|
||||
)
|
@@ -1,33 +0,0 @@
|
||||
from puzzle import (pt_1_first_digit_pattern, pt_1_last_digit_pattern,
|
||||
solve_pt_1, solve_pt_2)
|
||||
|
||||
|
||||
def test_solve_pt_1():
|
||||
assert (
|
||||
solve_pt_1(
|
||||
[
|
||||
"1abc2",
|
||||
"pqr3stu8vwx",
|
||||
"a1b2c3d4e5f",
|
||||
"treb7uchet",
|
||||
]
|
||||
)
|
||||
== 142
|
||||
)
|
||||
|
||||
|
||||
def test_solve_pt_2():
|
||||
assert (
|
||||
solve_pt_2(
|
||||
[
|
||||
"two1nine",
|
||||
"eightwothree",
|
||||
"abcone2threexyz",
|
||||
"xtwone3four",
|
||||
"4nineeightseven2",
|
||||
"zoneight234",
|
||||
"7pqrstsixteen",
|
||||
]
|
||||
)
|
||||
== 281
|
||||
)
|
@@ -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),
|
||||
}
|
||||
|
@@ -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__":
|
||||
|
@@ -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
|
83
advent_of_code/trebuchet.py
Normal file
83
advent_of_code/trebuchet.py
Normal 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,
|
||||
)
|
||||
)
|
@@ -12,3 +12,6 @@ test = ["pytest", "types-requests"]
|
||||
|
||||
[project.scripts]
|
||||
advent-of-code-2023 = "advent_of_code.__main__:main"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
|
66
tests/trebuchet_test.py
Normal file
66
tests/trebuchet_test.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import re
|
||||
from advent_of_code.trebuchet import (
|
||||
recover_calibration_digits_and_words,
|
||||
recover_calibration_digits_only,
|
||||
_recover_all_calibration_values,
|
||||
_recover_calibration_value,
|
||||
)
|
||||
|
||||
|
||||
def test_recover_calibration_value():
|
||||
assert (
|
||||
_recover_calibration_value(
|
||||
"..ab..cd..",
|
||||
re.compile("ab|cd"),
|
||||
re.compile("ba|dc"),
|
||||
{"ab": "1", "cd": "2"},
|
||||
)
|
||||
== 12
|
||||
)
|
||||
|
||||
|
||||
def test_recover_all_calibration_values():
|
||||
assert (
|
||||
_recover_all_calibration_values(
|
||||
"..ab..cd..\n..cd..ab..",
|
||||
re.compile("ab|cd"),
|
||||
re.compile("ba|dc"),
|
||||
{"ab": "1", "cd": "2"},
|
||||
)
|
||||
== 33
|
||||
)
|
||||
|
||||
|
||||
def test_recover_calibration_digits_only():
|
||||
assert (
|
||||
recover_calibration_digits_only(
|
||||
"\n".join(
|
||||
[
|
||||
"1abc2",
|
||||
"pqr3stu8vwx",
|
||||
"a1b2c3d4e5f",
|
||||
"treb7uchet",
|
||||
]
|
||||
)
|
||||
)
|
||||
== "142"
|
||||
)
|
||||
|
||||
|
||||
def test_recover_calibration_digits_and_words():
|
||||
assert (
|
||||
recover_calibration_digits_and_words(
|
||||
"\n".join(
|
||||
[
|
||||
"two1nine",
|
||||
"eightwothree",
|
||||
"abcone2threexyz",
|
||||
"xtwone3four",
|
||||
"4nineeightseven2",
|
||||
"zoneight234",
|
||||
"7pqrstsixteen",
|
||||
]
|
||||
)
|
||||
)
|
||||
== "281"
|
||||
)
|
Reference in New Issue
Block a user