From 51a777a8e5178b26f962b33b897e16f6acd3c216 Mon Sep 17 00:00:00 2001 From: James Lawlor Date: Wed, 10 Dec 2025 11:25:30 +0200 Subject: [PATCH 1/2] d4 p1+2 --- inputs/year_2025/04.dat | 139 +++++++++++++++++++++++++ src/advent_of_code/utils/problem.py | 94 +++++++++++++++++ src/advent_of_code/year_2025/day_04.py | 107 +++++++++++++++++++ tests/year_2025/test_day_04.py | 123 ++++++++++++++++++++++ 4 files changed, 463 insertions(+) create mode 100644 inputs/year_2025/04.dat create mode 100644 src/advent_of_code/utils/problem.py create mode 100644 src/advent_of_code/year_2025/day_04.py create mode 100644 tests/year_2025/test_day_04.py diff --git a/inputs/year_2025/04.dat b/inputs/year_2025/04.dat new file mode 100644 index 0000000..539f7e5 --- /dev/null +++ b/inputs/year_2025/04.dat @@ -0,0 +1,139 @@ +...@@@@@..@@@@@@@@@..@@@@.@@@@..@@.@@@@@.@.@@@@.@@@@@@@.@@@@@@@...@@.@@@.@.@@..@.@@@@..@.@@@@@@@..@@@@@@@@@@@.@@.@@@@.@@@.@.@@@.@@@@.@..@@. +@@.@@@@@.@@@..@.@@@@@@.@@@@.@.@.@@..@.@.@..@.@@@@@@.@@.@@@@..@.@@@@@@.@.@@.@.@@@..@.@@.@.@@@.@@.@@...@@..@@.@.@@@@..@..@@@@..@.@.@...@@@@@. +..@.@.@@@.@@@@@@...@@@.@.@@.@@@.@.@@@@@.@...@.@.@@@..@.@@@@@.@..@@.....@@@@@@@@@.@@.@..@@@@@...@@@@..@.@@@@@.@@@@@.@@.@@@@@@.@@@...@.@@@@@@ +.@@.@.@@@.@.@@@@@.@@..@@@@@@@@.@@...@.@..@.@.@@.@@@.@@@@.@..@.@@..@.@@.@@@@..@@@@@@@@@.@@@@@@@@@..@@@@....@..@@@.@.@@@@@@@@.@.@@.@@...@.@@. +@..@@@@.@@...@@@@@@@@@@...@@@@@@@@.@.@@@@.@@@@.@@.@@..@@@@@@.@@@@@.@@@@@@@@..@.@.@@.@@@@.@@@@@...@@@@@.@@.@..@@@..@@@@..@@..@.@@@@.@@.@...@ +@@@..@@..@.@@.@.@@@.@@.@...@@@@@.@@@@@...@@..@@.@@@@@@@@@.@.@@..@@@@.@@@@@..@@..@@@@@@@@@@@...@@.@@.@@@.@..@....@.@@@@@@@.@..@....@@@@@.@.. +@@@@.@@@@.@@@@@..@@@.@.@@@@@@@@.@...@@.@@..@@@..@@.@@@@@.@....@@.@@.@@.@.@.@@@@..@.@....@@@.@.@...@@.@.@@@@@@..@@@..@.@@@.@...@.@@@.@.@@@@@ +@@@@@@..@@@@@@.@@@@@@@@@@..@@@@.@.@@@.@@@..@@@@@@@....@@..@@.@@@@..@.@@.@.@@.@@@@.@@@@@..@...@@@@@@@@@@@.@@@.@@.@.@..@@@.@@..@@.@@@@@@@..@. +@@.@@@..@.@@@@.@@@@@@@@@@@@.@@@@@@.@@.@..@@@@..@@@@@@@@....@.@@@.@@.@@@.@@.@.@@@@@@@..@@...@@@@.@@@@..@@@@.@@.@...@....@.@...@@@.@@..@@...@ +@.@@.@@@@@@@@@@.@@@.@@@@.@@@@@@.@..@..@@@@@..@@.@@..@@.@@@.@@.@@..@@@.@@@@@@.....@@@@.@..@@@@.@@..@...@.@@@@..@.@@@.@@@..@@@@..@@@@@@@@@.@@ +...@@@@@.@@.@@@.@...@.@..@@.@@..@@@@@@@@@.@@@@@@@@..@@.@@@...@@...@@@@@@@@@@...@.@@.@.@@.@@@@@@.@@@@...@@@@@@@@@@@@.@..@@@@@.....@@@@@..@@@ +@...@@.@@@@.@@@@@....@@@@.@@..@@@..@.@@..@.@.@@...@.@...@@......@.@@@@..@@@@@@.@@@@.@@@@@@@@@@@..@@@@@@.@@.@@@@..@@@@.@.@@@.@@.@@.@..@...@@ +@@@@.@.@@.@.@.@@.@@..@@@@.@.@.@..@@@@..@@...@@@@.@@@@@.@.@@.@@@@@.@@@@@@@@...@.@@..@@@..@@@.@@@@.@@.@@.@@.@.@@..@@.@.@.@@@@@@.@@...@@@..@.. +@.@....@@@@@...@@@@@.@@@.@.@@@.@@.@.@@@@@@@@.@@.@@.@@@@.@.@@@...@@@@@@.@..@@@.@.@.@@@.@@@@.@@@..@@@@..@.@@@@.@@@@@@.@.@@@@.@.@.@@@..@@..@@@ +@@@@@.@.@.@@@@....@@.@.@.@@@@.@@..@@.@..@@@@.....@@@.@@.@.@@.@@@@@@@@.@...@@@@@...@@.@@@@@@@@.@@@@@@@.@@...@@@@.@.@@@.@....@@@@....@@@...@@ +@@@@@@@@.@@.@@@@..@.@.@..@@.@.@..@@@@@@@.@..@@@@@.....@....@@@.@@.@@.@.@@.@@.@@@@.@.@@.@..@@.@@..@@@..@@@.@@@@@@@.@@.@@@.@..@@@@@..@@@.@.@@ +@@@..@.@.@@.@@.@@.@.@....@@@@.@@@@@.@@...@@@@@@...@@.@@@@@@@@@..@.@...@.@....@.@@@@@@@...@@..@.@@@.@@@@.@@.@@@@@.@@@@@@@@..@.@.@@@@@@@.@@@. +@@@.@@@@@.@..@@.@@@..@.@@....@.@@.@.@@@@@.@@@@@.@..@.@@@@@.@@..@@.@.@@@..@.@@@@.@@@@..@@@@.@@@@@.@@.@@.@@@.@@@@@@@@@@@.@.@.@@@@@@@@.@@...@. +@@...@.@@@.@@..@@.@@@.@..@.@...@@.@@@@@@@..@..@@.@...@@@@@.@@@.@@@@..@@@@.@@@@@@@@.@@@.@@@@....@@@@@.@@..@.@.@@@.@@@@@.@.@@@@@@@@.@.@@@@@@@ +@@@@..@@...@@.@@@..@@.@.@@.@@.@@@.@@@.@@.@@@.@...@@@@@..@.@@@@@.@@@@..@@@@.@.@....@..@@@@@@@......@.@@..@.@@@.@@@@@@.@.@@@.@.@@@..@@@@@@@@. +@.@@.@..@@@.@@@@@@..@@@.@@@..@@.@@@@@@.@@@.@@@@@@@@@.@.@...@@.@.@.@@.@@@@@@..@@@@@.@@@@@.@.@@@...@@@...@@@@@@@@@..@.@.@@..@@..@@@..@.@@@@.@ +@@@@.@@@@@@@@@@@@@@.@@@@@@.@@@.@@@@@@..@@@@..@@@@@@@@.@...@....@@@@.@@...@@@@@.@@@@...@@.@@@@@@.@@.@@@..@..@...@@@@@@@@.@@@@.@@@.@@@@@@.@@@ +.....@@@@@@@........@....@@@@@..@@.@@.@...@@@..@@@@@@..@.@@@.@@@@@.@..@@.@@.@@.@@.@@@@@.@@@@.@@@@@.@.@@@..@@..@@.@.@.@.@.@@@.@@@.@@.@.@...@ +.@@.@@..@@@.@@.@...@@@@@.@@@...@@@@@@@@@..@@.@@@.@@.@@@..@@@...@@@@@.@@@@...@@@.@@@...@.@@.@@@.@@..@.@.@@@@.@@@.@@@..@.@@@@@@@@@@.@@@.@.@.@ +.@@@@..@@@@@.@.@.@.@@@@@@@@.@@.@@@@.@.@..@@@@@@@@@.@@@@@.@@@@@@@@.@@@.@@@@@@..@..@@@.@@@..@@@....@.@@@@@..@@.@..@@.@@..@@@.@@..@@@@@@..@@.@ +@..@@@.@..@.@@@@@@@@..@@@.@@.@..@...@@...@@@@@@@@@.@@@@@@.@@.@@@@@@@@.@@@...@@.@.@..@.@@@@.@....@@@@@@.@..@@@.@@@@.@@@.@@@.@.@.@@.@@@.@@@@@ +@.@@@@@@.@@@@@@.@@@@@@@@.@.@.@@......@@@@@..@..@@@@@..@@@.@.@.@@@@.@@@.@...@..@@@@@.@@@@..@@@@@@@@@..@@@@.@@@@@..@@@@.@@@.@@@@@.@.@.@@..@@@ +..@..@@.@@.@.@@@@.@@.@@@.@@@@@..@@@@@@..@@@@@@.@.@......@@..@@@.@.@@.....@@.@.@@@...@..@@@@@.@@.@.@....@@.@.@@..@@@@.@@.@@@.@@.@@@@..@.@..@ +@@@@@..@@@@@@..@@.@@@.@..@@@.@@.@@.@@@@.@.@.@..@@@@@@@@@@@@..@@..@.@@.@@.@@.@.@@.@.@@...@.@.@.@@@.@@@.@@@@@@@@@@..@@@@@.@.@.@.@@@.@@..@.@@@ +@@.@.@@@@.@@.@.@@.@.@@.@@..@@@@@@...@@@@.@@.@@@..@@@.@..@.@.@@@@@..@@@@@.@@@@@@.@@@@.@.@@@@...@..@@@.@.@..@@..@@..@@....@@.@@@@@@@@..@@@@@@ +..@.@....@@@@.@@..@@.@@...@@.@@@...@.@..@@.@@@@.@@@@@..@.@@@@..@@@@@@@.@@@.@.@@.@@@@@@@.@@@.@.....@..@@@@.@.@@@@.@@@.@@@.@..@@@@@.@@@@@.@@. +@@..@@@@@.@@@@@@@.@@@@.@@@@....@..@..@@..@@@@...@..@@.@.@@@@@@@@..@@@.@..@@@@@@@..@@@.@@@@@@@@@@@@@@.@@.@@@@@.@.@.@.@.@@.@@.@.@.@@@@.@.@@@@ +@@@.@@@@@.@..@.@@@@@@.@@@@@.@.@@@...@@.@..@.@@@@@@.@.@@.@@@@@.@@@..@@.@..@@@@..@.@.@..@@.@.@@.@@.@@@@...@@@..@@@@@@@@.@@@@@@.@...@..@@@@@@. +...@@@@@@@@@..@@@.@@..@@.@@.@@@.@@@@@@@..@..@@.@@@@@@@@@.@...@@@.@..@@@@.@@@@.@@@@@.@.@....@.@.@..@...@@.@.@@@@@.@@@@@.@.@@@@@@@@@.@.@@.@@. +@@.@.@@@@..@.@@@@@.@@@@@@@@.@.@.@..@@.@.@..@@@@@@@@.@@@.@..@@.@@@@@@@@@@@.@@.@@.@@@.@@@@.@@@.@..@@...@@@...@.@...@@.@...@@@...@@.@.@@.@@@.. +..@@@@@..@@...@@@@@...@@.@@@.@@@@@@@@..@.@@.@@@@.@.@@@@@@@@...@@.@...@@@.@@.@@@@.@@@@..@@.@@@@@@@..@.@@@@@..@..@@.@@..@..@.@@@.@@@@.@....@@ +.@@.@.@...@@.@@@@.@@.@@.@@@.@@@@.@.@@@@.@..@@@@@@@@.@@@...@@.@.@..@.@.@@.@....@.@@@..@@.@@@@@@@@..@.@...@@@@@@@@@@@..@..@@@..@.@.@..@@@..@@ +@@.@@.@@@@@@@.@@..@@@@.@@@@.@@..@@.@..@@.@@@@@.@..@.@@@@@@@@.@@.@@..@..@@@@@@.@..@@@@.@@.@.@@.@@@@@.@@@@.@@@@@@@.@.@@@..@@@@@.@@@@..@@@@@@@ +@@@@.@.@@@@@@@@@.@@.@@@@@@..@@.@.....@@@@@..@@@@@@@.@....@@@@.@@.@@@@..@@@@...@.@@@@@.@..@@@@@@@.@.@@..@@@@@@.@@@.@@@@.@.@.@@.@@@@@@@@@@@.@ +.@@.@.@@@@@....@@..@..@.@.@..@@.@@..@.@@@@@@@..@@@@@@@.@@@@@.@..@.@.@@@@@@@@.@@.@@@@@@.@@@@@@@.@@@.@@@@@@@@@@@@@.@@.@..@@@@@.@@.@.@.@.@.@@@ +@@.@@@@@.@@@@@...@@@.@.@.@.@...@.@.@@..@@@@@.@.@.@.@.@@@@..@.@@.@@@@@@.@@@@@@.@@@@@..@@@.@@@@@@@.@@.@@@@..@..@.@@..@.@.@.@..@@.@@.@..@...@@ +@@@@@..@@.@@@@..@@@@@@@@@@@@@@..@@@@@@@.@.@.@@.@@@.@...@.@@@@..@@.@.@.@@@.@.@@.@@@@..@.@@@@..@@@@@.@@@@@@@@..@.@@@@@.@@.@@@@.@.@.@@...@..@. +@@@@@@.@.@.@@@.@.@@@@@.@@@@.@.@@@@.@..@@@@@.@@@@.@.@..@.@.@@.@.@@..@@@@@@.@.....@@@@.@.@..@@..@@@..@.@.@.@@.....@@..@@..@@.@@@.@@@@.@@.@..@ +@@.@@@.@@.@@.@@.@@@@@@@@@.@@..@@..@@.@@@@.@@@.@.@.@@@@@@@@@...@@.@@@@@@@@@.@.@@@@@@@.@@@..@.@@.@@..@@.@.@@@.@@@@@@@@..@@@@@@@..@@@.@@@@@@.. +@@@@@..@.@.@.@.@@@@@@@.@@@@@@@@.@@@.@@..@@.@.@.@@@@..@@@@.@@@@@@@.@@....@..@.@@..@@@@.@....@@@@.@.@.@@@@@.@@@@@.@.@@@@..@@@.@@.@....@@.@@@@ +.@@@@@@@..@@.@@.@.@.@@..@..@@..@@@@.@@..@@@.@@@@@@@@@.@.@@.@.@@@@@@@@..@@....@..@@@@@@..@.@.@@@.@@.@.@@@.@..@@@.@@@@@@@..@@.@@@..@@@@.@@@@@ +@...@@@...@@.@...@.@@@@.@@@@..@.@@@@..@@..@@..@@.@..@@@.@@.@..@.@.@@@@.@@@@@.@.@@@..@@.@@@@@@@@.@@.@.@@@.@.@@@@@@.@.@@@@@@@@@.@@.@@@@@.@.@@ +.@@.@.@...@@@.@@@..@...@@.@@.@...@@@.@....@.@@@.@@@@@@.@.@...@@.....@@.@@..@@@@@@@@@.@.@.@@@.@...@@....@@..@@@@@.@@@@@@@@@@.@..@@.@@@@...@@ +..@@@@@.@..@@@@@.@..@@@.@..@.@@@....@@@..@@@@.@@.@.@@@@...@@.@.@.@@@..@@@@@@.@@@@@@@..@@@@@@@....@@.@@....@@@@.@.@.@@..@.@@@.@.@..@@@@@..@@ +@.@.@@@@@@@.@@@.@.@@@@@@@@@.@.@@.@@@..@@@.@@@..@@@@.@.@@@@.@..@.@@@@@@@@@@@@@.@@....@@@@@@.@@@.@@@.@@@@@@@.@@.@@@@.@@@@@..@.@@...@@@@@@..@@ +.@@@@@..@@.@@@.@@.@.@@..@@@@@@@.@.@..@@@@.@@@@@@@@@..@@@...@@.@@@@@@@@@@..@..@@@@@@@@.@.@@@@@@@..@@@@@@@@@@@..@.@@@.@..@.@.@@..@.@@@..@@.@. +...@@@@@@.@@@@@@@@@.@@@@@@@..@@@@.@@@.@.@@@@@@..@.@@@@..@@.@@@@@.@@@.@.@@.@..@.@@@@@.@.@@.@@.@..@@@..@@..@@@.@@@.@.@@@..@.@@@....@@@..@@@@@ +@..@..@@@@@@@@@@@@@@@....@@@@@@.@@@@@...@@@@.@@@.@.@@@..@....@@@@@..@@...@@..@@@@.@@..@@@@@.@@.@..@@.@...@@@@..@.@@@@@@.@.@.@@.@@.@@.@.@@@@ +....@.@@@..@@@...@.@@.@@@@.@@.@@@@..@@@@@@@.@@@@.@@@@@.@@@.@@..@@...@@.@@..@.@@@@@.@@@@@..@.@@...@@.@@.@.@@@.@.....@@@.@@.@@.@@..@..@.@@@.@ +@@@@@@@.@@@@@@..@..@.@@@.@@..@@@@@@@.@.@@@..@@@@@@..@@.@@@@@@@@@.@@@@@@@@@@@.@.@@.@@@@..@.@..@@.@@.@@@@.@@.@...@@@@@@@@.@@.@@..@@@@..@@@@.. +@@@@@@.@@@@.@.@.@@.@@..@@@.@...@@@.@@@@.@@@@..@.@..@@@@.@..@@@.@@@@@@@@.@@@@..@@@..@@.@@@.@@@@.@@@.@.@.@@@@@.@@.@@@@@...@.@....@.@.@@.@.@@@ +@@..@@@...@@.@@@.@.@@...@@@@@@@@@.@@@.@@..@@@.@@.@@@@@.@.@@@@@@..@@@@@@@@@@.@@@...@....@@....@..@@.@.@@..@@@@@@@@@.@@@@@@@.@...@..@@.@@@.@@ +@@.@.@@.@@@@@@..@.@@.@...@@@@@@@.@@@.@.@@@@@.@@@@@@.@..@@@@@@@.@@.@@@@...@..@..@@.@@.@..@@@@..@.@@@@.@@@.@@...@@.@...@@@.@.@@@.@@.@.@@@..@@ +@..@.@.@@.@......@.@@@@@@.@@.@@.@@...@@@@@@@@@@@@.@@@@@@@@.@.@.@@.@..@@.@@.@@@@@.@@.@.@..@@@.@@@@@@.@@@@@.@.@@@@@.@@..@@@.@@@.@.@@.@@@@.@@. +@..@@.@.@.@@.@.@.@.@.@......@@@.@@@@@@....@.@@@.@.@@@.....@@@@@@.@@@@@@@@@@@...@..@@@@@@..@.@.@@@@.@@@...@@@@...@@@.@@@@.@.@.@..@@@@@.@.@.. +@@@.@@...@...@.@@@@@@....@@@@@.@.@@@@...@.@@..@@..@.@.@@.@..@.@@@@.@@.@.@@.@@@@@@@@@@@@.@@@@.@.@@@@@@...@@@.@@.@@@@@...@@@@@@.@.@@..@@@.@@@ +.@.@..@@.@@@.@@@.@...@@.@@.@.@@@@...@...@@@.@@@@..@.@@.@@..@@..@@.@@@.@.@@.@.@.@.@@@@.@@@@@@@@@@@.@@@@@@@@@@@@.@.@@@.@....@@.@.@@@..@@@@.@@ +@@..@.@@.@.@.@@.@.@@@@@@@@@@.@..@@.@@@..@.@@.@@@@..@...@@.@.@@@@...@@@@@.@.@@..@@@.@@@@@@@@.....@@@.@@@..@@@@@@@@.@@@..@@..@.@@.@.@.@@.@..@ +..@@.@@.@@.@.@@@@.@..@..@@@@.@@.@@@@@@.@@@@@..@@@.@@@.@.@@@@..@..@@@@@@@@.@@..@@@@@@@.@.@@@@@..@@@@@@.@@@.@@.@@@.@...@@@@@@@@@..@.@.@...@@. +@@.@@@.@.@.@@@@@@@.@@@@@@.@@@@@..@@.@@@.@@@@@...@@@..@.@@@@.@@@@@..@.@..@.@@@@.@@.@..@@@@@@@@@@.@.@.@.@@@@@@@@.@.@@..@@@@.@@@.@..@.@.@...@@ +.@@@.@@@.@@@@.@.@.@@@@@@@..@@@@...@@.@@.@.@@@@@..@@.@@@@.@@.@@.@@@@.@@.@.@@.@@.@@..@@@@@...@.@.@@@...@@@@.@..@@@.@@@..@@..@..@.@@.@@@@@@... +@.@@@@@@...@@@@@@.@@@@.@@.@..@@@@@@@@@.@.@@@..@..@@.@...@.@@@@.@@@.@..@@.@@@...@@.@@@@.@.@.@@@@@.@@@@@.@@...@.@...@.@@@@@@@..@.@.@.@@.@.@@. +@@@..@@@.@@@@@@@@@@@..@.@.@.@..@@@@.@@@..@@.@@.@@.@.@....@.@.@@.@@.@@@@@.@@@..@@@@@@@@@..@..@......@.@.@.@@@@.@.@.@@.@@@@@.@@.@.@@.@@.@@..@ +.@...@.@@@@@@..@@@@.@.@@@@@@@.@@@@@..@@@@@@..@.@@@@...@@@@..@@@@@@...@@@@.@@@@@....@@@.@@@@@@@.@..@@@..@@..@@@@...@@.@.@@@.@@.@...@@.@@.@.. +@@@@..@@@@@@..@@@@@.@.@@@@@@@@@@....@..@@@.@@@.@.@.@..@@@@.@....@@@@@@@@@...@@@.@@@@@@@.@@@.@@@@@@@@@@@@...@@.@@@@@@@@.@@@.@@@.@@.@@@.@@@.@ +@@@.@.@@.@.@@@@@.@.@@@@.@@.@@@..@@.@.@.@@.@@.@@..@@@@.@@@@@@..@@@@@..@.@@@@@@@@@@@@.@@.@@.@@.@@.@..@..@..@.@@@...@@@.@.@.@@@...@@@@@@@@.@@. +.@@....@...@@..@@@.@@@@@.@@.@@@..@@...@@@@.@.@@@@@@.@..@@@..@@@@..@@@@@@@@.@....@@.@.@@@@@.@@@@@..@@@@@@@.@..@@.@@@@@.@@@@..@@.@.@.@@@.@@@@ +@....@@@@.@.@@.@@.@@@@@..@@@.@.@@@@....@@@@.@@.@@@.@..@.@@@@..@@@.@@@.@.@@..@.@...@@@.@....@@@@@..@@@@..@@@..@..@.@@@.....@....@@@.@@@@@.@@ +.@@@@@.@.@.....@.@@@@@@...@@@...@@.@@.@.@@..@@@@@@@.@@.@@.@@@@.@@@@@.@.@@.@@@..@@.@..@@....@.@.@..@@@.@.@@.@@@@@.@@.@@.@@@@@..@.@@.@@.@@@@. +.@@.@@@.@@.@.@.@..@.@.@..@@@@....@@@@..@@@...@@@...@@.@.@...@@...@@@@@.@.@@...@@.@@.@@.@.@@..@@..@@.@@@@@.@@@@@@@@@@@.....@@@.....@...@@@.@ +@.@.@@@.@@.@@@@@.@.@..@@.@@@@.@.@@@@@@@.@@@@@.@@@@@@.@...@.@@.@@.@.@@@.@@@@@@@@@@@@@@.@.@@..@@@@@@@@...@.@.@.@.@@..@@@@@@@@@@@@.@@@@..@..@. +.@.@@.@@@..@.@.@.@@..@.@@@..@@@..@.@..@@.@.@@@.@@@@@.@.@.@@.@@@@.@@@@....@@.....@@@..@@@.@@@@@@@@.@@.@@..@@@@@@..@..@.@@.@@....@@@@@@@.@.@. +..@.@@.@@@@@@@@.@..@@@.@@@...@.@@@.@@@...@.@.@..@.@@@@@@@..@..@..@...@@@@@.@@@..@.@@.@@@@.@.@@@@..@.@@.@..@@..@.@@....@@@.@.@@@.@.@@..@@@.@ +@..@@@.@@..@@@.@@@.@@..@.@@..@@@@@@.@@@.@.@.@@@.@@@@@.@..@@..@@@@@.@.@.@@...@.@...@@.@@.@@@@.@@@.@.@@@.@....@@.@@...@@@@@..@@@..@@@@.@@@@@@ +.@.@@@@@@@@@@@..@@.@@.@@@..@@.@@.@@@.@.@@@@.@.@@@@@.@@@@...@.@@@@.@..@@@@@.@.@@@.@@@...@..@@.@@@@@..@@@@@@@.@.@@@..@.@@@..@@@.@.@@@..@....@ +@@@.@@@..@@..@@.@.@@@@..@.@@@@@@@@@@....@@@.@@.@.@@.@.@.@@@.@@@.@..@@@@@@.@@@@@@...@@...@@@@..@@@@@@@@@@@....@@@@@@.@@@.@@.@@@@@@@@.@@@@.@@ +.@@@@.@..@@@@@@@@.@@@@@.....@@@@@@.@....@@.@@@@..@..@.@.@.@@@@@..@@@@..@.@@@.@@@@.@@.@@@..@..@@@@@.@@@..@@.@.@@.@@.@.@.@.@@.@.@@@..@@@@@@@@ +@@@@@@@@@@@...@.@..@.@.@@@.@@@.@.@.@..@@.@.@.@@@@@@.@@@..@.@@.@@@@@.@..@@@@@@.@.@@@@@@@.@.@..@@@.@.@@@.@@@@.@@@.@.@..@.@@@@@@@@.@@@.@@@@@@@ +..@.@..@@.@...@@@@@@@@@@@@@.@.@@@.@@@@@.....@@@@@@@@@@@.@@..@@@.@.@@@@....@.@.@@@.@@..@.@@@.@@@..@@@@@@@@.@..@@@@@@@@.@@@@@.@.@@.@@@..@@..@ +@.@.@.@@....@@.@@@@@@.@.@.@@@.@@.@...@.@@@@@.@@..@@.@@...@@@@@@@.@@@@@@@@@@..@.@..@.@.@.@.@.@..@@@@@@.@.@@@@.@..@.@.@@.@..@@@...@..@..@.@.. +@@@.@@@.@@@@@@@@.@@.@..@..@@.@.@@@@@@@@@@@@@@@@@..@@@@@@@.@@@@@.@.@..@..@@..@@.@@@@@.@@@@@.@@...@.@@@@@..@@@@@@@@.@@@.@@@@@@@..@@@@.@@.@... +@@@@.@@.@@@@.@@.@@.@.@.@@@@.@@@@.@.@.@@@@@@...@..@.@@@...@@@@.@@@@@@.@@.@..@@@@@@@..@@@@@@.@..@@@.....@@....@@@@.@@@.@@.@.@..@..@@@@@.....@ +..@@@.@.@@.@@@@@@@.@.@@@@@..@.@@@@@..@@..@@@.@@.@@@@@@@@@@@..@@@.@.@@.@.@.@@..@.@@.@@.@.@@@@@@@@.@@@@@@@.@.@.@@@@@.@@@...@@@@..@@.@@@...@@@ +@@.@@..@.@@@@@..@@..@@@.@@@..@..@.@@.@@@@@@@@.@@@@@@@@.@@.@@@.@...@@@@@@@@.@...@...@@@...@@@@@.@@.@.@..@.@..@@@@@@@..@@.@.@@@.@@@.@...@..@@ +@@.@..@.@@.@.@@@.@@.@...@@.@@.@@.@@@@@@@@.@@.@@@@@@@@.@@.@.@@@@@.@..@@@@@@@@.@@@@...@.@@@...@@@@@...@@@..@@@@@@.@@@...@.@@@@@@@.@@@@@@.@... +@.@@@.@..@@@.@@@@@@..@@@...@@.@@@@.@@.@@.@..@@@@..@@.@@@@@..@...@.@@.@@..@@..@@..@@@@@...@@@@@@@@.@@@@.@.@@@..@@...@.@@@...@@@@@@.@@..@@.@@ +@@@@.@@.@@..@@.@@.@.@.@@@@.@@@@@@.@...@@@@@.@@@@@@....@@@@.@@@@@@@@@@@@@@..@@@@@@@..@@@@....@@@@.@..@@....@@@@@@@.@.@@@@@@@@@@@@@@@@..@@..@ +@@@@.@.@..@.@@@@.@@@@.@@@@@@.@@@@...@@@@@@...@.@@@@....@@@@.@@@@..@@.@@@@.@@@@@..@@@@.@.@@@.....@@.@@@.@..@@@@.@@.@@.@@.@@.@@...@...@@@@..@ +.@@@@@.@..@..@@.@@@@@@@@@..@@.@..@.@@.@@..@@@@@@@@@@.@..@.@@@@@@@.@...@@.@@..@..@..@@@...@@@@.@@@@@@@.@@.@.@.@@..@.@..@.@@.@@@@@@@@.@.@.@.. +@@@@@@@..@@@@@@.@.@@@@@@@@.@@.@.@..@.@@.@@@@..@.@@.@.@@@@@@@..@@@@.@@@....@@@.@@@@.@@..@@@..@...@.@@.@.@@@@@.@@@..@@@....@..@@@..@@@@@.@@.. +@.@...@.@.@@@.@@.@.@@@@..@.@.@...@..@.@@@@...@.@@@@@..@@@@@@@@...@.@@.@.@.@@@@@@@@@..@@@.@@@@@@@@@@@@@@@@..@.@.@.@@@@@.@@.@@@@@.@@@@@.@@@@@ +@@@@.@@@@@@@.@@.@@.@@@@.@@.......@..@.@@...@@@@@@@@.@@@@@.@.@@@@@@@@.@@....@@...@.@@@..@@@@@@..@.@@...@.@.@@@@.@@@.@....@@@@@@@..@@@@@.@@@@ +.@@..@.@@@.@@@..@@@@@@@@@@@@@.@...@@@@.@@@.@@@@@@@@.@@@@@.@@@..@@.@@@.@@@@@.@@@@@.@@@@@@@@@@@...@..@@.@.@.@.@@@.@@.@@...@@.@@..@@@@..@.@.@@ +.@@.@.@..@@@@.@@.@@@.@@..@@.@@@@@@@@@@@@@@....@.@@..@.@@@..@@@@.@@..@@@.@@@@@@@.@..@......@.@.@@@@..@..@@@@.@@@@..@@@.@@@@..@@.@.@@@@@@.@@. +@..@@@@..@@.@@..@@..@@.@@@@@@.@@@@.@...@.@.@.@@.@@.@@.@@@@..@@@@@@@@@@@...@@@@@.@@.@.@@..@@........@.@@@@@.@..@@@@..@.@......@@@@.@@@@@@@.@ +.@.@.@@@..@@@@@@@@@..@@@@@@@@.@.@@@@@...@@..@@@..@.@@@@.@@..@.@@.@@@@.@@..@.@.@@@.@@.@@@@@@@@@@@@@..@@..@@.@@@@...@@...@@@@@@@@.@@@.@@.@@@@ +@..@@.@@@@@@@@@..@@@@@@.@..@.@@@..@@.@.@@.@..@@@@@@@.@@@@.@@@.@@.@@...@@..@@@.@@..@@@@.@..@.@.@.@@.@@@@@@@@.@...@@.@.@@@@@.@.@@@.@.@@.@.@.@ +.@@@...@.@....@@@.@@@@...@@..@@.@@@@@@@@@@@@..@..@.@@@.@.@@..@.@@.@.@@@@.@.@..@.@@@@@@@.@.@.@..@@@@@...@@@@@@@@...@@@@@@@@@.@@@@@@@..@@@@@@ +.....@...@.@@@..@@@.@@@@@.@@.@.@.....@@.@@...@@@@.....@@@@.@@@@@@@@.@@@..@@..@@.@@.@@@@@@@@..@..@..@@..@.@..@@@.@@@@.@@@@@@@..@@@.@@@..@@@. +.@@@@.@@..@@.@@@@@@@..@@@.@@@.@@@@@@.@@....@@@@.@@.@.@.@@@..@..@.@@..@@@@@@@@.@@@.@..@@@@.@@@.@.@@@.@@.@@@..@@@@@@@..@.@@@@@.@...@.....@... +.@@@@.@@@@..@.@@@@@@...@@@@@..@@.@@@@..@.@@.@@..@@@@@@..@@@@@.@@@@.@....@@@@@@@@@.@.@@..@@@@.@@@@@@.@.@@@@@@@@@@@@.@.@@@@@@@@@@..@.@.@.@... +@@..@@@.@@@.@@@@@@..@@@@@@.@@@@@@..@@@.@@..@@@@@@@..@@@@@@.@@@@@@@@@@@@@..@.@.@.@..@.@@@@@@.@@@..@....@.@.@@@...@@.@.@.@@@@@@.@.@..@@..@@@@ +@@..@@.@@@@@@@@@.@@@@@@..@@@@@..@@@.@@..@@@@@@@@..@..@.@.@.@.@.@..@....@@.@@@.@@@@@@@@.@@@.@@@@@@.@.@.@@.@..@@@@@@@@@.@@@@..@..@.@@...@.@@@ +@@@@@@@@@@@@.@@@.@@@@@@@@@..@.@.@....@@@.@@.@@@@@@....@@@.@@...@@@.@.@@@..@@@.@@@.@@@@@@.@@@.@@@@.@.....@@@@@@@@.@@.@@@@@@@.@.@.@.@@.@@.@@@ +@..@@@..@.@..@@.@@.@@@@@@@@@@@@@@@@.@@@...@.@..@...@.@@@@@@@@@..@@.@@@@.@.@@@@..@.@@@@@@@..@@...@@@..@..@..@@.@@@@.@@@.@@@..@...@.@.@@.@@@@ +@@@.@@.@@@..@..@@@@@@@@@@.@...@@@@.@@@.@.@.@.@@@@@.@.@@@@@.@@.@@..@...@@@..@.@.@.@@@@@@.@@@@..@@@@.@.@..@....@@@.@@.@@@@.@@@@@@..@@...@@.@. +.@@@@.@@@@@@.@@@@@...@@@@.@@@@.@@@..@@@@@@@.@@@@@@@@@@...@@...@@@@@@...@@@@@@@.@@@..@..@@@.@..@.....@..@.@@..@@@@@@@@@..@@.@.@..@@@@@@.@@@@ +@@.@@@...@.@@@@@.@...@@@.@@@@.@@@.@@.@@@.@.@@@@...@@@@.@@.@@@.@@@...@.@..@@@.@@@@@.@.@@@.@@@@@@@.@@..@@@@...@..@...@@@..@@@@@@@.@..@@..@@@. +@@@@@.@@.@..@@...@@@@.@@@@@..@@@..@@...@...@@@@@@@@@@.@@.@.@.@@.@@@@@@..@@@@@@.@@@@@@@@.@@@.@.@..@@.@@@@...@..@@@@@@.@.@@..@@..@@....@.@@@. +.@@@..@.@.@@@@@@.@@.@@@@@@.@@@.@@.@.@.@@..@...@.@@@.@.@@.@@@@@@.@@.@@@@@..@@@@...@@@..@...@@...@@..@.@.@@@.@.@@@@@.@@.@@@@.@@@.@@@@...@@@@@ +@@.@.@..@@....@@.@@@@@@@.@@@.@..@@@@..@@@@.@.@@@@@.@@....@@@@@@@@@.@@..@.@@....@.@.@.@@@@@@@@.@@@@..@..@.@@.@@@..@...@@@@@.@..@@..@@@.@.@@. +@@.....@@@@@@@..@@@....@@@.@..@..@@.@..@@..@..@.@@@@.@@.@@@@@@.@@@..@@@.@@.@.@.@@@@@@@@@.@@..@.@.@@.@@@@@...@.@@@@@@@@.@@@@.@@@@.@@@..@.@@@ +.@@....@@@@@@@.@@@.@.@@@.@.@@..@.@@@.@@@@@@.@@@@@..@@.@@@.@@..@.@@..@@@@@@@@@@@@@@...@@@@.@.@....@..@@@.@@@@@..@@@@@.@@@@@@@@@@@.@...@@@@@. +..@@@@.@@..@@@@@.@@@@@@@.@@..@@@@@.@...@@..@.@@@@@@@@@@@@@@@.@@@@..@@@.@@@@@@@@..@@@@@...@@@@@.@@@@@@.@.@.@...@@@...@@@@@@.@@@@.@@..@@@@@@@ +@@@.@@@@@..@@@....@.@.@@@.@..@@.@@@@@@@@.@@..@@.@.@@@@.@..@@@.@@.@@@@@@@@@@.@.@.@@.......@@@@@..@@@..@@@@.@@@@@@@@@.@.@@@.@@..@@..@@.@@@..@ +...@@@@.@@@@@@@@@@@@@@..@@.@..@.@@.@@@@@@@@@@@.@@.@@@@.@.@@@@.@@@@@...@.@@@.@@@@@.@@.@@@..@@@..@@@@@@@@@@@@@@@@@@@@@@@..@.@.@.@.@@.@.@@@.@@ +@.....@@@@.@@@..@@@@..@.@@.@@@.@@.@@@@@@..@@@@@@@@@@..@..@@.@@@.@@@@@.@@@.@@@@@@.@.@@@@@@@@@@@@@@..@@..@.@@.@@@@..@@@.@@@..@@@...@@@@.@@@@@ +@...@.@.@@.@@@@@@@..@.@@.@@@...@@@@@@@@@@@@.@@@@@@@@.......@@@..@@.@@@..@.@@.@.@@@@@..@...@@.@..@.@.@@@@@@@@@.@@.@.@...@@@.@@@@.@@@.@..@@@. +@@@@@@...@@.@@@@.@@@@.....@@.@@@.@..@@.@@@@@@@.@@.@@@@@@.@.@.@@@@@.@..@@@@@@@@@.@..@@.@@@.@@@.@.@.@@@..@@..@@@.....@....@@@@@@@.@@@@.@.@..@ +.@@..@@@@@@@@@@.@@@.@@@@..@@@.@@@@.@@@@@...@..@@@.@@.@@@@.@..@@.@@@.@.@@...@@@@@@...@@@.@@@@@@@@@@..@..@.@@@@@...@.@@@@@..@@@@.@.@.@@@@.@.. +@@@@..@@..@@@@@@.@@@.@@@@@...@@@@.@@@..@@.@@@@@@.@.@@@@.@@..@@@@.@@@.@...@......@@@@@@..@@@@@@.@@.@@@@..@@.@@@@.@@.@@@.@@.@@@@.@@..@@..@@.@ +@@@..@@@@.@.@@...@@.@@@@@@@....@.@@..@@@@@..@.@@@@@@@..@@@@@@..@.@@.@.@@...@...@@@.@@@@@@..@.@@..@@@..@@@.....@.@@@@@@.@@.@@@.@@.@@@@@@.... +...@@@.@..@@@.@.@@@@@...@@.@@.@@@.@@.@.@.@@.@@@@@@@.@@@@..@@@@@@...@@@..@..@.@.@@.@@@@@....@@@@@@.@@@@@@@..@@..@.@@@@@@@@@@@.@@@@.@@.@@@@@@ +@..@@@@@..@@@@...@.@@@.@@@.@@@@..@@@.@@@@@@@@@@..@...@@..@@@@@@.@@@@..@@@@@@@@@.@.@.@@@..@@@@@@.@.@@@...@@@.@@@.@@@@@@@@@@.@@.@.@...@@@@@@. +..@@@@@@.@@@.@@@@@@.@@@@@@@..@.@.@@.@@@@@@@@.@.@@@@@.@@.@.@@..@@@@@@.@@..@..@@@.@@@@@@..@.@...@@@@.@@@@..@@@@@@@@@@.@.@@.@...@@@....@@..@.@ +.@....@...@@@@@@..@.@.....@@.@@@.@.@.@@.@.@.@.@@@@@.@@@@.@@@@@.@@.@@@@@@.@@@.@@@.@..@@@@@.@..@@@@@.@.@..@@.@@...@@.@.@@@.@@@.@.@@@@@.@@@@@@ +...@.@@@@@@@@@@@..@..@@@.@@@@@@@.@@@.@.@@.@@@....@.@@@.@@@@..@@.@@.@@.@.@.@@@@@@...@.@@..@@.@.@@..@.@@@@.@@@...@..@.@@@..@..@@@@@@@@..@@..@ +@@.@@@@@@@....@.@@..@.@@.@@@.@.@@@......@.@@@..@.@.@.@...@@..@@@.@@@.@.@@@@@..@@@@.@..@@@@@@@...@@@@@.@....@.@@..@@@@@@@@.@.@@@.@@@@..@..@@ +@@.@@.@.@@.@@@@......@..@.@@@@@.@@.@@@@@@@@@@@.@@@@@@@@@@@@@@@@@@..@@..@@@.@@@.@@@@@.@.@@@@@..@.@@...@@@@..@.@.@...@@@@@@@@@.@.@@@.@.@@@@.@ +@@@.@@@@@@@@@@@@@@@.....@@@..@@@.@.@.@@@.@..@.@.@.@@...@..@..@.@@@.@.@@@@@@.@@...@.@@@@..@@@@@.@@.@@@.@..@@..@@@@@@.@@@..@.@.@@.@@@@@@..... +@@..@@@@.@.@.@@@@@@@@.@@@@@...@@.@@@@@@@.@@@@@@@.@@@@@.@@@.....@.@@@@....@.@.@@@.@.@.@.@@@@@@....@.@@@...@@@@.@@@@...@@@@@@@.@@.@@@....@.@@ +@@@@@.@@.@...@@....@..@@@..@@.@@@...@.@@@@@.@.@@@@@.@@@@@@.@@@@@.@.@@@@..@.@@.@@@@@@.@.@@@@@@@@.@@...@.@@..@@..@.@.@@@.@@@@@@@@@@.@....@@.@ +@@@@.@.@..@.@..@.@.@@@@@.@@@.@@@@...@@@..@.@@.@...@.@@.@@.@@@@..@@@@@@@@@@@@.@@@@@.@.@@@@.@@@@.@.@.@....@@@@@.@.@.@@.@@@@@@@@@..@@@@@..@@.@ +@@.@@@@.@.@....@@@.@@@@.@..@@@@@@@.@@@@@@@....@@...@@@@@@...@@@.@@.@@@@.@@@@@@@@@@@.@.@@@@.@@@@@@@@@.@.@@@.@@@.@....@@.@.@..@@@@@@@@@.@.@@@ \ No newline at end of file diff --git a/src/advent_of_code/utils/problem.py b/src/advent_of_code/utils/problem.py new file mode 100644 index 0000000..5ae3920 --- /dev/null +++ b/src/advent_of_code/utils/problem.py @@ -0,0 +1,94 @@ +from typing import List, Optional, Tuple +from pathlib import Path + +from advent_of_code.utils.input_handling import read_input + + +class Problem: + """Base class for Advent of Code day modules. + + Subclass this and implement `solve(self, input_lines)` which returns + a tuple (part1, part2). Subclasses should set YEAR and DAY class attributes. + + This base class provides a `run(input_file)` helper which reads the + input using the repo's `read_input` helper and prints results in the + canonical format used across the repo. + """ + + YEAR: Optional[int] = None + DAY: Optional[int] = None + title: Optional[str] = None + + def part1(self, input_lines: List[str]) -> Optional[object]: + """Override in subclasses to implement part 1. + + Args: + input_lines: list of stripped lines from the day's input file. + + Returns: + part1 result (or None) + """ + raise NotImplementedError("Subclasses must implement part1(input_lines)") + + def part2(self, input_lines: List[str]) -> Optional[object]: + """Override in subclasses to implement part 2. + + Same shape as `part1`. + """ + raise NotImplementedError("Subclasses must implement part2(input_lines)") + + def solve(self, input_lines: List[str]) -> Tuple[Optional[object], Optional[object]]: + """Run both parts and return a (part1, part2) tuple. + + This moves the usual `solve` boilerplate into the base class so + subclasses only need to implement `part1` and `part2`. + """ + return (self.part1(input_lines), self.part2(input_lines)) + + def run(self, input_file: str) -> Tuple[Optional[object], Optional[object]]: + """Read the input file, run solve, print results and return them. + + Keeps the same `main(input_file)` contract used across the project. + """ + input_lines = read_input(input_file) + result_part_1, result_part_2 = self.solve(input_lines) + + day_str = f"{self.DAY:02d}" if isinstance(self.DAY, int) else str(self.DAY) + print( + f"Day {day_str} \n" + f" Result for part 1 is {result_part_1} \n" + f" Result for part 2 is {result_part_2} \n" + ) + + return (result_part_1, result_part_2) + + + @classmethod + def main(cls, input_file: Optional[str] = None): + """Construct, run, and return results. + + If `input_file` is None the method will attempt to locate the + repository's default input file at + `inputs/year_/
.dat` (matching the project's convention). + + Raises FileNotFoundError if the inferred input file does not exist + or ValueError if YEAR/DAY are not set on the subclass. + """ + if input_file is None: + if cls.YEAR is None or cls.DAY is None: + raise ValueError( + "Either pass input_file or set YEAR and DAY on the Problem subclass" + ) + + # Determine repository root relative to this file: src/advent_of_code/utils/problem.py + repo_root = Path(__file__).resolve().parents[3] + candidate = repo_root / "inputs" / f"year_{cls.YEAR}" / f"{cls.DAY:02d}.dat" + if candidate.exists(): + input_file = str(candidate) + else: + raise FileNotFoundError( + f"Input file not found at {candidate}. Provide `input_file` explicitly." + ) + + instance = cls() + return instance.run(input_file) diff --git a/src/advent_of_code/year_2025/day_04.py b/src/advent_of_code/year_2025/day_04.py new file mode 100644 index 0000000..eefd987 --- /dev/null +++ b/src/advent_of_code/year_2025/day_04.py @@ -0,0 +1,107 @@ +from advent_of_code.utils.problem import Problem +import numpy as np + +def parse_input_to_array(inp): + tmp = [] + for line in inp: + tmp.append([x for x in line]) + return np.array(tmp) + +def check_is_roll(arr, i, j, roll_char="@"): + if arr[i, j] == roll_char: + return True + else: + return False + +def check_roll_accessible(arr, i, j, max_i, max_j): + + threshold = 4 + neighbouring_roll_count = 0 + + # check above + if i > 0: + if check_is_roll(arr, i-1, j): + neighbouring_roll_count += 1 + + # check above and right + if i > 0 and j < max_j - 1: + if check_is_roll(arr, i-1, j+1): + neighbouring_roll_count += 1 + + # check above and left + if i > 0 and j > 0: + if check_is_roll(arr, i-1, j-1): + neighbouring_roll_count += 1 + + # check right + if j < max_j - 1: + if check_is_roll(arr, i, j+1): + neighbouring_roll_count += 1 + + # check below and right + if i < max_i - 1 and j < max_j - 1: + if check_is_roll(arr, i+1, j+1): + neighbouring_roll_count += 1 + + # check below + if i < max_i - 1: + if check_is_roll(arr, i+1, j): + neighbouring_roll_count += 1 + + # check below and left + if i < max_i - 1 and j > 0: + if check_is_roll(arr, i+1, j-1): + neighbouring_roll_count += 1 + + # check left + if j > 0: + if check_is_roll(arr, i, j-1): + neighbouring_roll_count += 1 + + if neighbouring_roll_count >= threshold: + return False + else: + return True + + +def check_whole_array(arr): + max_i, max_j = arr.shape + accessible_rolls_indices = [] + for i in range(max_i): + for j in range(max_j): + if check_is_roll(arr, i, j): + if check_roll_accessible(arr, i, j, max_i, max_j): + accessible_rolls_indices.append((i, j)) + return accessible_rolls_indices + + +def update_array(arr, indices_to_remove, replacement_char="."): + for (i, j) in indices_to_remove: + arr[i, j] = replacement_char + return arr + +class Day04(Problem): + YEAR = 2025 + DAY = 4 + + def part1(self, input_lines): + arr = parse_input_to_array(input_lines) + result = len(check_whole_array(arr)) + return result + + def part2(self, input_lines): + arr = parse_input_to_array(input_lines) + total_rolls_removed = 0 + rolls_removed_this_iteration = 1 + + while rolls_removed_this_iteration > 0: + result = check_whole_array(arr) + rolls_removed_this_iteration = len(result) + total_rolls_removed += rolls_removed_this_iteration + arr = update_array(arr, result) + return total_rolls_removed + +main = Day04.main + +if __name__ == "__main__": + Day04.main() diff --git a/tests/year_2025/test_day_04.py b/tests/year_2025/test_day_04.py new file mode 100644 index 0000000..0c2a238 --- /dev/null +++ b/tests/year_2025/test_day_04.py @@ -0,0 +1,123 @@ +import pytest +from advent_of_code.year_2025.day_04 import ( + Day04, + parse_input_to_array, + check_is_roll, + check_roll_accessible, +) +import numpy as np + +@pytest.fixture +def day_04_test_input(): + return [ + "..@@.@@@@.", + "@@@.@.@.@@", + "@@@@@.@.@@", + "@.@@@@..@.", + "@@.@@@@.@@", + ".@@@@@@@.@", + ".@.@.@.@@@", + "@.@@@.@@@@", + ".@@@@@@@@.", + "@.@.@@@.@.", + ] + + +@pytest.fixture +def day_04_expected_output(): + return (13, 43) + + +def test_solver(day_04_test_input, day_04_expected_output): + # Use the Day04 class' solve method (matches the new Problem base API) + result = Day04().solve(day_04_test_input) + assert result == day_04_expected_output + + +@pytest.mark.parametrize( + "input_str, expected_output", + [ + ( + [ + "..@@", + "@@@.", + "@@@@", + ], + np.array( + [ + [".",".","@","@"], + ["@","@","@","."], + ["@","@","@","@"], + ] + ), + ), + ], +) +def test_parse_input_to_array(input_str, expected_output): + assert np.array_equal(expected_output, parse_input_to_array(input_str)) + + + +@pytest.mark.parametrize( + "inp_arr, i, j, expected_output", + [ + ( + np.array( + [ + [".",".",], + ["@","@",], + ["@",".",], + ] + ), + 0, 0, False + ), + ( + np.array( + [ + [".",".",], + ["@","@",], + ["@",".",], + ] + ), + 1, 1, True + ), + ], +) +def test_check_is_roll(inp_arr, i, j, expected_output): + assert expected_output == check_is_roll(inp_arr, i, j) + + +@pytest.mark.parametrize( + "i, j, expected", + [ + (0, 2, True), + (1, 1, False), + (1, 0, True), + (0, 7, False), + (0, 8, True), + (2, 1, False), + ], +) +def test_check_roll_accessible(day_04_test_input, i, j, expected): + """Parametrized tests for check_roll_accessible using the provided fixture. + + Each tuple is (i, j, expected) where expected is True if the roll at (i,j) + has at least one adjacent non-roll cell, and False otherwise. + + Fixture with accessible rolls replaced with `x` + ..xx.xx@x. + x@@.@.@.@@ + @@@@@.x.@@ + @.@@@@..@. + x@.@@@@.@x + .@@@@@@@.@ + .@.@.@.@@@ + x.@@@.@@@@ + .@@@@@@@@. + x.x.@@@.x. + + """ + arr = parse_input_to_array(day_04_test_input) + max_i, max_j = arr.shape + + assert check_roll_accessible(arr, i, j, max_i, max_j) is expected From 836985a705443b5c4db8445d086fca56239dd0e4 Mon Sep 17 00:00:00 2001 From: James Lawlor Date: Wed, 10 Dec 2025 11:26:03 +0200 Subject: [PATCH 2/2] update progress --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d4f45d2..5981e33 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Scripts | 01 | ⭐️ | ⭐️ | | 02 | ⭐️ | ⭐️ | | 03 | ⭐️ | ⭐️ | +| 04 | ⭐️ | ⭐️ | ### 2024 Progress