diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..e079e6f --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,53 @@ + + +# How to be productive in this repository (short, specific) + +This repo contains per-day Advent of Code solutions under `src/advent_of_code/year_/day_.py` with test cases under `tests/year_/test_day_.py` and input files in `inputs/year_/.dat`. + +Follow these concrete rules and patterns when making changes or adding new solutions: + +- Entrypoint contract: each day module should expose a function `main(input_file)` which accepts a path to the input file (string) and performs/prints the solution. `scripts/run_day.py` dynamically imports `advent_of_code.year_.day_` and calls `main(input_file)`. +- Input handling: use `src/advent_of_code/utils/input_handling.py::read_input(f)` to load inputs as a list of stripped lines. Input files live at `inputs/year_/.dat` and use zero-padded two-digit day names (e.g. `01.dat`). +- Filenames & modules: code files are named `day_01.py`, `day_02.py`, etc. The module import path is `advent_of_code.year_2025.day_01` (note the zero padding in the module filename). +- Tests & pytest: tests are under `tests/year_/test_day_.py`. The project config (pyproject.toml) sets `pythonpath = "src"` and `--import-mode=importlib`, so prefer importable modules and avoid relying on working-directory-only imports. + +Quick commands (examples you can run locally): + +- Run one day (example for year 2025 day 1): + python3 scripts/run_day.py --year 2025 --day 1 + +- Run all discovered solutions (skips days without input files): + python3 scripts/run_all_solutions.py + +- Generate a new day + test from templates (templates in `scripts/templates`): + python3 scripts/generate_new_day_skeleton_files_from_templates.py --year 2025 --day 1 + +- Run tests: + pytest + +Key files to inspect when changing behavior: + +- `scripts/run_day.py` — dynamic import + `main(input_file)` invocation. If you change the `main` contract, update this script. +- `scripts/run_all_solutions.py` — discovery logic: scans `src/advent_of_code` for `year_*` directories and filenames matching `day_\d{2}\.py`. It will skip running days with no corresponding `inputs/year_/.dat` file. +- `src/advent_of_code/utils/input_handling.py` — canonical helpers for reading inputs and parsing simple formats used across days. +- `scripts/generate_new_day_skeleton_files_from_templates.py` and `scripts/templates/*` — used to scaffold new day modules and tests; templates include `{day}` and `{year}` placeholders. +- `pyproject.toml` — pytest configuration (`pythonpath=src`, `--import-mode=importlib`), black formatting, and build backend (hatchling). Use these settings when adding CI or packaging. + +Project-specific conventions and gotchas (be precise): + +- Zero-padding is significant: day files and input files are named with two-digit zero padding (e.g., `day_01.py` ↔ `01.dat`). `run_day.py` zero-pads the provided `--day` argument. +- `run_all_solutions.py` relies on simple `os.listdir` ordering; do not assume nested directories beyond `src/advent_of_code/year_/`. +- The repo uses `python3` in scripts; local development should use a Python 3.8+ interpreter (pyproject says >=3.8). Black config targets Python 3.9 but code is compatible with 3.8+. +- Tests import the package from `src/` via pytest config. When editing tests or modules, ensure the module path `advent_of_code.year_.day_` is importable. + +Small implementation checklist for a new/updated day module: + +1. Create `src/advent_of_code/year_/day_.py` using templates or follow the `main(input_file)` contract. +2. Add `inputs/year_/.dat` (zero-padded). +3. Add/verify `tests/year_/test_day_.py` follows existing test style. +4. Use `utils.read_input` where appropriate to keep input parsing consistent. +5. Run `python3 scripts/run_day.py --year --day ` and `pytest`. + +If you need to change a project-wide behavior (import rules, test config, discovery), update `pyproject.toml` and the scripts above; prefer small, backward-compatible changes because many scripts dynamically import day modules. + +If anything here is unclear or you'd like the instructions to be stricter (for example, enforcing a return value contract instead of printing), tell me which style you'd prefer and I will update this file. diff --git a/inputs/year_2025/01.dat b/inputs/year_2025/01.dat new file mode 100644 index 0000000..5890128 --- /dev/null +++ b/inputs/year_2025/01.dat @@ -0,0 +1,4188 @@ +R31 +R49 +L47 +R35 +L20 +L24 +L6 +L41 +L39 +R26 +L13 +R48 +R6 +L5 +L36 +R45 +L17 +R11 +R39 +L19 +R20 +R21 +L20 +L9 +R19 +L6 +R47 +L15 +L41 +R4 +R5 +L13 +L30 +R19 +R27 +R37 +L17 +R12 +L29 +R21 +L49 +R43 +R11 +R10 +L29 +L15 +L25 +L13 +L24 +R13 +R53 +R60 +L60 +L72 +L28 +L22 +R54 +L32 +R89 +R89 +L51 +L27 +R14 +L14 +L50 +L50 +R59 +R16 +L89 +L20 +L59 +R97 +L14 +L96 +R48 +L26 +L84 +R62 +R95 +L89 +R68 +R32 +L95 +R34 +R33 +L45 +R73 +L46 +L94 +R53 +R87 +R38 +R62 +L41 +R24 +R17 +R47 +R1 +R36 +R16 +L27 +L80 +R907 +L20 +L55 +L25 +L77 +R77 +L35 +L18 +L53 +L94 +L46 +L61 +R68 +L237 +L41 +L21 +R38 +R213 +L413 +R8 +R92 +R42 +L5 +R49 +R66 +R948 +R64 +L64 +R68 +L6 +R38 +R34 +L8 +R74 +L83 +L17 +L450 +R85 +L23 +R6 +R19 +R25 +R38 +R34 +L34 +L45 +L42 +R95 +L96 +L22 +L27 +R19 +R61 +L143 +R71 +L471 +R39 +L51 +L77 +R388 +R546 +R37 +L782 +L63 +L37 +R56 +L24 +R62 +L60 +L369 +R635 +L74 +L935 +L88 +R11 +L45 +R31 +R599 +R18 +L46 +L471 +R55 +R45 +R491 +L23 +L501 +L27 +R67 +R46 +R47 +L87 +L13 +R33 +L35 +L98 +L56 +L844 +R94 +L94 +L4 +R10 +L6 +R76 +L613 +R992 +L41 +L14 +L47 +R852 +L805 +L72 +R50 +R22 +R902 +R98 +R90 +R46 +L36 +R85 +L967 +L618 +R1 +R99 +R54 +L28 +R74 +R11 +L35 +R416 +R8 +L39 +R11 +L44 +R59 +L87 +L28 +L680 +R707 +R80 +R19 +L44 +R76 +L42 +L32 +L52 +R96 +L692 +R92 +R646 +R33 +L60 +R41 +R51 +R63 +R63 +R41 +R22 +L48 +L456 +L90 +R94 +R17 +R69 +R23 +L9 +L47 +R57 +R31 +R759 +L3 +R438 +R52 +L87 +L397 +R63 +R735 +R99 +L85 +L462 +R731 +R16 +L93 +R40 +L4 +L43 +L88 +L412 +R88 +L52 +R64 +L82 +R38 +R844 +L95 +R99 +L69 +L43 +L92 +L12 +L88 +R89 +L86 +L87 +R84 +L51 +L49 +L88 +L25 +R13 +L15 +R746 +L931 +R72 +R877 +R19 +L18 +R50 +R815 +L940 +L75 +R95 +L95 +R4 +R37 +R3 +R45 +L49 +L40 +L2 +L31 +R69 +R414 +R96 +L49 +L39 +L44 +L14 +L16 +L84 +R52 +R48 +L85 +L88 +R7 +R572 +L24 +R618 +R44 +L44 +R61 +L61 +R846 +R21 +L383 +L84 +L781 +L75 +R56 +R17 +R83 +L88 +L89 +R77 +L76 +L939 +L98 +L88 +L28 +R27 +L84 +L66 +L66 +L48 +R38 +R4 +L6 +L6 +L164 +L58 +R958 +R92 +R84 +L76 +L58 +R85 +R73 +R5 +L356 +R51 +L45 +R345 +L89 +L77 +L82 +L52 +R4 +L23 +L72 +L9 +L74 +L26 +R61 +R46 +R93 +R44 +R6 +R14 +R36 +L701 +L69 +L691 +R61 +L64 +R64 +R781 +L97 +L549 +L850 +R8 +R88 +R19 +L457 +R10 +R17 +L66 +L104 +R26 +R74 +L18 +L82 +R13 +R287 +L31 +L40 +L29 +R54 +L625 +L73 +L56 +R94 +L56 +R94 +R1 +R93 +R74 +L2 +R2 +L693 +R696 +L82 +L42 +L121 +L58 +L9 +L91 +R63 +R11 +R815 +L989 +R875 +L15 +R856 +R6 +R594 +L70 +R54 +R75 +R79 +L52 +R98 +R32 +L37 +L335 +L60 +R96 +R4 +R99 +L25 +R72 +L46 +L55 +R441 +L86 +R493 +L93 +R94 +L46 +L49 +L51 +L48 +R95 +L864 +R94 +L75 +L32 +L4 +L6 +R778 +L520 +L66 +R90 +R10 +L692 +L23 +L85 +L36 +R36 +L24 +R48 +R176 +L395 +L5 +L74 +L55 +L330 +R59 +R69 +L65 +R34 +R62 +R52 +R12 +L75 +R53 +L12 +L642 +R30 +R82 +R79 +L55 +L26 +R2 +R870 +R11 +L81 +L80 +R80 +R65 +R35 +R56 +R53 +R91 +L484 +L371 +R23 +L89 +L1 +R99 +R51 +L45 +R417 +R17 +R83 +L51 +L7 +R558 +R76 +R91 +L67 +L498 +L66 +R38 +L80 +R6 +R37 +R63 +R513 +L50 +L85 +R3 +R19 +R36 +L61 +L9 +L33 +R83 +R33 +R851 +R56 +L59 +L82 +L236 +L46 +L990 +R30 +R496 +L879 +R13 +L145 +R42 +L49 +R80 +R6 +L48 +R50 +L739 +R40 +R94 +L72 +L62 +L69 +R69 +L40 +L39 +L73 +L80 +R76 +R46 +R10 +L74 +R11 +R63 +L92 +L8 +R3 +L3 +R80 +R20 +L33 +R33 +R518 +L95 +R226 +L71 +L78 +R9 +L9 +R12 +L12 +L16 +R316 +L28 +L50 +L49 +R27 +R30 +R44 +L62 +R33 +L13 +L32 +L1 +R11 +L960 +L37 +R47 +R40 +L69 +R34 +L438 +R89 +L14 +L702 +L37 +R806 +R31 +R681 +R92 +R24 +L50 +R16 +R70 +R66 +L99 +R78 +L71 +R87 +L94 +L736 +L217 +L47 +L69 +R69 +L78 +R53 +L95 +R259 +R47 +L86 +R76 +R24 +L22 +R722 +R418 +L713 +R95 +L83 +L21 +R21 +L10 +R83 +L17 +L23 +L98 +R48 +L65 +R65 +R34 +L33 +R92 +R7 +L381 +L94 +R452 +R69 +L802 +L244 +L86 +R2 +L16 +L55 +L45 +R171 +R7 +R87 +L12 +R47 +L18 +R85 +L87 +L26 +R146 +L361 +L39 +L97 +R60 +L96 +L670 +L97 +R58 +R36 +R773 +R42 +L511 +R11 +R81 +L90 +R68 +L99 +L369 +L34 +R34 +L32 +R10 +L8 +R751 +L873 +L501 +L393 +L9 +R18 +L6 +L65 +R26 +R14 +R47 +L34 +L45 +R61 +R59 +R773 +L44 +L521 +L29 +L21 +R22 +L10 +L660 +R84 +R44 +L223 +L47 +R112 +R45 +R155 +R46 +R88 +R66 +L785 +L415 +L87 +R87 +R8 +L51 +L59 +R35 +R17 +R883 +R67 +R76 +L236 +R20 +L60 +R21 +L75 +L83 +L3 +L49 +L1 +L287 +R77 +L33 +R33 +R36 +R61 +L829 +R32 +L47 +L53 +R137 +R37 +R56 +R457 +L587 +R202 +L202 +L90 +L710 +R57 +L441 +L602 +R81 +L18 +R90 +R757 +L24 +R107 +R93 +L98 +R92 +R710 +R606 +R590 +L29 +R25 +R4 +R984 +L84 +L23 +L91 +R40 +R33 +L53 +R94 +R10 +R885 +L31 +L36 +L28 +L67 +R76 +L549 +R315 +R925 +R726 +L784 +R97 +R55 +L40 +L117 +L37 +L354 +R2 +R63 +R34 +L84 +L24 +R850 +L32 +R45 +R43 +L843 +R11 +L6 +L5 +L87 +L13 +L18 +R80 +L62 +R76 +L34 +R637 +R21 +L474 +R74 +L67 +R191 +R88 +R37 +R32 +R3 +L64 +R80 +R20 +L40 +R97 +R32 +L42 +L96 +R86 +R43 +L92 +L14 +R85 +R24 +R50 +R47 +R92 +L861 +R80 +L53 +L458 +R11 +R89 +R369 +L357 +R57 +R31 +R92 +R8 +L2 +R5 +L912 +R9 +L5 +L37 +R542 +L97 +L44 +R641 +L93 +R88 +L295 +L47 +L77 +R78 +L22 +L32 +L653 +R53 +L48 +R32 +R719 +R97 +R565 +R35 +L94 +L6 +R766 +R4 +R104 +L43 +L31 +L53 +L47 +R33 +L55 +L716 +R283 +R73 +L23 +R5 +R908 +L71 +R27 +L37 +L23 +L4 +R81 +L23 +L16 +R105 +R53 +R646 +R54 +R78 +R22 +L50 +L29 +R769 +R301 +R197 +R2 +R10 +L294 +R794 +R11 +L4 +R30 +R436 +R31 +L4 +L86 +R86 +R407 +R93 +L68 +L52 +R96 +R829 +L65 +R41 +R19 +R36 +R92 +L540 +R791 +L479 +L27 +L92 +L38 +R357 +L45 +L91 +R274 +L19 +L59 +L99 +L161 +L50 +L50 +R43 +R857 +R49 +L49 +R15 +R21 +L35 +L60 +L42 +R1 +R37 +R74 +R71 +R18 +R861 +R83 +L27 +R91 +R92 +R19 +R481 +R75 +R25 +L72 +L28 +L8 +L533 +R41 +L708 +R17 +L9 +R1 +R90 +R45 +R64 +R97 +L947 +L73 +L37 +L39 +R96 +L53 +L39 +R95 +L89 +L81 +L494 +R26 +R38 +L40 +R63 +L23 +R81 +L81 +L67 +R12 +L79 +L71 +R5 +R8 +R92 +R790 +R87 +R347 +R53 +L77 +L20 +R69 +R89 +R691 +R39 +R74 +L32 +R15 +R67 +L92 +R989 +R94 +R48 +L14 +R83 +L168 +L232 +L41 +L759 +L56 +R12 +L5 +L92 +L59 +R20 +L20 +R930 +R370 +R791 +L91 +L733 +L67 +L63 +R74 +R14 +L382 +L31 +R64 +L462 +L48 +L30 +L33 +R997 +R33 +L99 +R49 +R17 +L59 +L9 +R487 +L89 +L30 +R850 +R27 +L86 +L91 +L78 +R266 +L81 +L64 +R269 +R473 +L656 +R47 +R51 +L79 +R41 +L23 +L418 +L48 +R48 +R59 +R52 +R3 +R870 +L2 +L5 +L14 +R93 +R20 +R83 +L207 +R51 +L31 +R963 +R3 +L86 +L75 +L25 +R915 +L15 +R11 +R93 +L4 +L1 +L99 +L38 +R72 +R66 +L436 +L64 +R82 +R18 +L66 +R66 +L41 +L75 +L57 +R73 +R33 +R967 +R301 +R299 +R22 +L81 +R4 +R667 +R4 +R79 +L81 +R60 +R59 +R816 +R741 +R90 +R18 +L954 +R40 +L82 +R21 +R77 +R86 +L38 +R52 +R3 +R76 +R21 +L36 +R36 +R586 +L4 +R51 +L33 +R77 +R49 +L285 +R17 +R94 +R65 +R65 +R18 +L767 +R67 +L265 +L70 +L65 +R35 +L405 +L634 +R3 +R1 +R2 +L817 +L64 +L14 +R7 +R35 +L64 +L550 +L935 +L21 +L271 +L65 +L843 +L1 +R444 +R19 +L15 +L59 +R12 +L59 +L41 +R124 +L35 +L89 +L88 +L68 +R610 +L668 +L11 +L375 +L56 +R56 +R32 +L62 +R30 +R1 +R99 +L657 +L76 +L60 +R16 +L56 +R16 +R446 +L46 +L79 +L94 +R62 +L233 +R61 +L81 +R55 +L54 +R80 +R738 +R62 +L374 +L159 +L6 +L21 +R21 +R138 +R1 +L53 +R53 +L68 +L532 +R95 +L95 +L74 +R75 +L46 +L72 +L783 +L68 +R61 +L93 +L17 +L83 +L15 +R15 +L52 +R59 +L82 +R73 +R2 +L24 +R24 +R46 +R81 +L27 +R50 +R83 +L82 +L451 +L59 +L157 +L84 +R38 +R62 +L13 +R13 +L33 +R438 +L42 +L83 +L20 +R46 +L6 +L878 +R371 +L93 +L13 +R58 +L961 +R37 +R65 +R14 +L5 +L23 +R23 +L49 +R385 +R24 +L136 +L19 +L66 +R7 +R58 +R1 +L12 +R12 +R46 +L73 +L73 +R98 +L98 +R79 +L62 +L17 +R75 +R15 +L40 +L15 +L885 +R41 +R402 +L571 +L83 +R64 +R21 +L922 +R98 +R53 +R41 +L94 +L95 +L16 +L54 +R765 +R71 +L35 +R12 +L24 +L24 +R254 +R79 +L31 +L2 +R38 +R198 +L433 +L32 +R44 +R85 +L122 +R22 +L15 +R91 +R5 +L681 +L48 +L42 +R90 +R245 +L72 +R66 +R61 +R602 +R39 +R59 +R341 +L90 +L35 +L16 +L85 +R85 +L45 +R34 +L602 +L487 +R55 +R23 +L77 +R22 +L23 +R675 +R25 +R863 +L63 +L64 +R64 +R9 +R28 +L37 +R37 +R27 +L64 +R88 +R82 +L41 +R16 +L45 +L44 +R76 +L1 +L31 +R85 +L85 +R25 +R75 +R27 +L29 +L77 +R32 +R780 +L33 +R34 +L65 +R91 +L50 +R90 +L48 +R81 +R467 +R99 +R967 +L67 +L99 +R849 +R851 +L44 +R92 +R52 +L76 +R62 +R27 +L613 +L66 +L84 +R50 +R60 +R99 +L59 +R57 +R843 +L79 +L18 +R50 +L253 +L13 +R13 +L3 +L841 +L56 +L760 +L38 +R56 +L99 +R94 +R86 +L49 +R486 +L41 +R7 +R64 +R57 +R71 +L31 +L3 +L83 +L17 +R35 +R36 +R8 +R39 +L619 +L60 +L39 +L60 +L83 +R32 +L989 +R22 +L28 +R6 +L69 +L56 +R41 +R49 +L76 +L789 +R85 +L85 +L39 +R51 +L62 +L4 +R254 +R66 +L196 +R21 +R9 +L71 +L29 +R586 +R33 +R97 +R87 +L23 +L20 +R40 +R3 +R60 +R21 +L84 +R10 +L15 +R40 +R65 +R45 +L45 +R55 +R54 +L67 +L42 +R90 +L15 +R49 +R71 +L95 +L864 +R63 +R90 +R11 +R55 +L19 +R4 +L32 +L8 +L22 +R18 +R4 +R411 +R69 +L46 +L12 +L222 +L30 +R932 +L336 +R93 +R30 +R184 +L87 +L86 +L35 +R35 +L44 +R14 +R60 +L64 +L788 +R22 +R74 +R26 +L175 +R27 +L51 +R176 +R23 +R98 +L98 +R20 +R80 +L49 +L126 +R275 +L15 +L85 +L97 +R97 +R79 +L581 +R88 +R4 +R78 +R48 +R85 +L801 +R45 +R19 +L64 +R609 +R80 +R82 +L571 +R98 +L39 +L59 +R90 +R39 +R87 +R61 +L77 +R40 +L74 +R995 +L961 +L86 +L14 +L867 +R67 +L42 +R198 +L16 +L40 +L122 +L97 +R43 +R443 +R33 +R92 +R15 +L20 +L29 +L92 +L97 +R31 +R89 +L34 +R31 +R39 +R61 +R584 +R30 +R378 +R49 +R3 +R84 +R286 +L39 +R892 +L453 +L785 +R96 +R24 +L80 +L87 +L73 +R91 +R86 +R718 +R120 +R90 +L956 +L44 +L50 +R65 +L81 +R66 +R383 +L83 +R59 +L96 +R57 +R954 +R298 +L72 +R4 +R653 +R91 +R94 +R40 +L706 +L435 +R59 +R743 +L11 +R90 +L22 +L27 +R5 +R51 +R12 +L404 +L66 +L71 +R41 +R39 +L30 +L50 +L88 +R3 +R85 +R53 +L169 +L84 +L480 +R80 +L58 +R58 +L76 +R76 +L636 +R65 +L24 +L78 +L852 +L25 +L35 +R87 +R540 +L9 +L57 +L86 +L90 +R38 +L13 +R83 +R92 +L94 +R523 +R35 +L47 +L38 +L79 +R76 +L50 +R98 +L24 +L79 +L92 +L232 +L332 +L33 +L88 +L89 +R712 +L19 +L848 +L47 +L37 +L6 +R55 +R81 +L68 +R22 +L192 +R43 +L75 +R35 +L911 +L64 +R33 +R31 +R80 +L133 +L65 +L81 +L1 +L559 +R29 +L70 +R13 +L19 +R73 +L967 +L82 +L18 +R96 +L96 +R78 +R622 +L77 +L51 +L66 +R94 +R24 +R50 +R92 +R81 +L81 +L66 +R2 +R62 +R53 +R83 +R62 +L59 +R34 +L37 +R14 +R86 +R36 +L69 +R70 +R60 +L97 +L617 +L83 +R67 +R827 +R62 +L55 +R520 +L44 +L377 +L5 +R958 +R47 +R45 +R55 +L82 +L18 +L65 +L275 +L275 +L84 +L1 +L89 +L55 +R44 +L436 +R36 +R15 +R60 +L26 +L43 +L893 +L13 +L64 +R10 +R18 +R44 +R68 +R24 +R89 +L89 +R61 +L23 +R14 +R55 +L94 +R17 +L85 +R63 +R721 +R50 +R14 +L45 +R52 +R30 +R70 +R85 +R15 +R66 +R47 +L75 +L45 +R74 +R33 +R27 +L27 +R18 +R56 +L38 +L136 +L9 +L91 +R39 +R251 +R34 +L74 +R26 +L76 +L903 +R3 +L40 +R558 +R82 +R80 +L58 +R452 +L24 +L50 +L27 +R27 +L89 +R7 +L173 +R86 +L49 +L82 +L26 +R13 +R395 +R6 +L34 +L754 +R20 +R71 +L91 +R71 +L71 +R8 +L63 +L12 +L10 +L23 +L74 +L26 +R88 +R53 +L102 +R49 +L31 +R85 +R58 +L87 +R87 +L78 +R14 +L52 +R58 +R934 +R24 +L79 +L64 +L657 +R454 +L70 +L84 +R274 +L22 +R48 +R50 +R50 +L7 +R7 +L60 +L56 +L86 +R846 +R80 +L24 +L666 +L769 +L65 +R51 +L26 +R27 +L56 +L810 +L253 +R67 +R47 +L47 +L91 +R95 +L4 +L71 +R71 +L77 +L60 +R2 +L165 +L63 +R55 +R8 +R389 +R11 +R68 +R69 +R963 +R6 +L86 +R18 +R362 +R662 +L662 +L83 +R83 +L18 +R66 +R52 +R60 +R10 +L66 +L90 +L14 +L33 +L967 +R94 +R92 +L486 +R46 +L46 +R70 +R5 +R38 +L813 +L9 +R709 +R638 +L6 +R71 +R57 +L837 +R377 +R63 +R70 +L33 +R27 +R55 +R897 +R21 +L59 +R13 +R5 +R45 +R96 +L90 +R76 +L86 +L10 +L90 +R67 +L18 +R51 +L45 +R57 +R31 +R962 +R95 +L65 +L416 +L50 +L565 +R53 +R98 +R21 +R32 +L8 +R97 +L97 +L49 +L40 +R7 +R82 +L28 +L690 +L81 +R683 +R89 +R72 +L84 +R975 +L33 +L890 +R87 +L39 +R50 +R89 +L85 +R459 +L74 +L67 +R67 +R52 +R48 +L60 +R63 +L3 +R48 +L12 +L99 +L737 +R9 +R22 +R10 +R26 +R71 +R41 +L79 +L87 +L46 +L710 +L55 +L2 +R89 +R67 +R37 +L93 +R11 +R489 +R74 +R326 +R940 +L93 +L86 +R48 +L89 +L997 +L64 +R141 +L22 +L376 +L386 +L116 +R82 +L16 +L866 +R68 +L68 +R94 +L10 +R25 +L9 +L702 +R66 +L64 +R52 +R906 +R42 +R70 +R51 +R24 +L56 +R11 +L26 +L24 +L23 +R11 +L29 +L127 +R18 +R366 +L66 +L85 +L13 +R40 +L42 +L67 +L33 +L3 +L41 +L56 +R90 +L50 +R60 +R82 +R34 +R11 +L91 +R295 +L46 +L36 +L760 +L62 +L99 +R57 +R72 +R43 +R47 +R37 +L641 +L60 +R50 +L80 +R88 +L469 +L19 +L53 +L33 +R84 +R49 +L74 +R574 +L5 +R20 +L36 +R59 +L39 +L399 +R96 +R35 +L443 +R12 +L6 +R3 +L98 +R23 +R34 +R67 +L39 +L53 +L39 +L64 +L90 +R31 +R74 +R457 +L22 +L478 +R4 +R91 +L95 +R19 +L70 +L49 +R51 +R55 +L119 +R13 +R92 +L85 +L19 +R7 +R10 +R52 +L157 +R53 +L53 +L616 +L384 +R360 +L37 +L10 +L62 +L51 +R11 +R257 +L368 +L790 +R21 +L56 +R32 +L7 +L37 +R37 +L93 +L77 +R39 +L5 +R83 +R10 +L57 +R403 +L75 +R72 +R5 +R143 +R52 +L72 +L28 +L196 +L4 +R40 +L75 +R35 +R58 +L56 +L56 +L47 +R25 +L36 +L30 +R42 +R37 +R89 +L126 +R61 +R12 +L73 +L79 +L55 +R34 +R61 +R153 +R86 +L83 +R61 +L883 +R90 +L30 +R49 +R15 +L40 +L79 +L28 +R96 +L92 +L455 +L95 +R74 +R6 +L9 +L803 +R6 +R83 +R50 +R68 +R662 +L285 +R83 +L62 +R588 +L61 +L26 +L46 +L54 +R6 +L506 +L463 +R63 +L58 +L42 +L21 +L91 +R58 +R27 +L10 +L63 +L917 +R805 +L988 +R79 +L79 +R29 +R44 +R14 +L42 +R90 +L11 +R81 +R95 +L660 +L40 +L33 +L921 +L513 +R263 +L39 +L354 +L3 +L371 +R71 +L69 +R69 +L909 +R468 +R9 +L12 +R44 +R29 +L229 +L448 +L63 +R98 +L330 +L90 +R93 +R240 +L35 +R72 +L67 +L70 +L20 +L280 +L35 +R363 +R77 +L5 +L73 +L27 +R76 +L30 +R11 +R36 +L97 +R4 +L97 +R45 +R52 +L46 +L26 +L28 +L68 +L72 +R15 +R64 +R44 +L63 +R80 +L67 +R67 +R30 +R79 +R31 +L52 +R12 +L8 +L40 +R48 +L75 +R82 +L5 +R73 +R25 +L483 +R74 +L91 +L83 +R25 +R11 +L53 +L41 +R42 +R99 +R47 +L30 +R85 +L86 +R36 +R48 +L67 +R99 +L70 +R45 +L7 +L5 +L46 +L49 +L36 +R28 +R58 +L53 +L21 +R24 +L63 +L2 +L35 +L59 +R66 +L386 +L77 +L67 +R25 +L2 +R1 +R15 +R84 +L37 +R37 +L17 +R61 +R28 +L72 +R93 +L10 +R47 +R70 +L72 +L28 +L18 +L82 +L36 +L64 +L91 +R612 +L129 +R52 +L44 +R64 +L52 +L53 +R41 +R89 +L95 +L94 +R62 +L27 +R86 +R79 +R221 +R671 +R8 +R58 +R842 +R15 +L624 +R111 +L8 +R6 +R67 +R92 +R49 +R11 +L319 +R26 +L62 +L91 +R28 +R38 +L39 +R49 +R451 +L18 +R18 +R3 +L3 +R34 +R824 +R12 +R18 +L88 +R76 +L281 +L10 +R99 +R56 +R39 +L79 +R26 +R74 +L85 +L954 +L961 +L51 +R51 +L30 +R67 +R63 +R494 +R206 +R84 +R16 +R21 +L66 +R375 +R85 +L44 +L71 +R56 +R21 +R15 +L92 +R52 +R72 +R97 +R79 +R70 +R30 +L79 +L20 +L1 +R795 +R32 +R73 +L15 +L785 +R80 +L45 +L35 +L36 +R36 +R57 +L838 +R65 +R51 +R802 +R63 +L41 +R541 +L60 +L29 +R289 +R53 +L65 +L45 +R32 +R10 +L48 +R78 +R79 +L54 +R60 +R80 +L373 +R93 +R85 +R15 +L62 +L23 +R85 +L96 +L4 +L64 +R41 +R23 +L404 +L150 +L85 +R22 +L984 +L62 +L21 +R84 +L8 +R24 +L16 +R98 +L125 +L73 +R23 +R92 +R11 +R30 +R44 +R31 +L71 +R40 +R472 +R23 +L50 +L98 +R53 +L46 +R5 +L73 +R51 +R135 +R60 +R954 +R14 +L14 +R14 +L298 +L85 +L17 +L37 +R37 +R487 +R3 +L90 +R6 +L52 +R98 +R37 +L89 +R90 +R132 +L14 +R27 +L235 +R74 +L755 +R99 +R651 +L69 +R55 +L445 +R409 +L19 +L39 +L81 +L98 +L930 +R48 +R98 +R97 +R9 +R33 +R51 +L461 +R924 +L51 +R65 +L465 +R654 +L54 +R21 +L16 +R25 +L49 +L89 +L28 +R36 +R83 +R17 +R85 +L985 +R37 +R72 +L9 +L83 +R83 +R73 +L73 +L34 +R5 +R2 +L22 +L85 +R34 +L30 +R73 +R537 +R95 +L82 +L2 +L78 +R11 +R76 +L44 +L456 +L52 +R452 +L81 +R51 +L70 +L47 +L325 +L91 +R91 +R672 +R34 +R66 +R74 +R173 +R97 +L751 +R7 +R63 +L21 +R58 +R78 +L78 +L718 +R18 +L90 +L10 +R572 +L18 +R73 +R97 +L24 +R93 +R29 +R41 +L63 +L53 +L606 +R96 +R30 +L130 +L77 +R62 +L22 +L48 +R24 +R49 +L25 +R48 +L8 +R329 +L41 +L28 +R57 +R88 +R55 +R30 +R97 +L97 +R70 +L70 +L30 +L18 +R66 +R332 +R97 +L77 +R40 +R70 +R61 +R524 +R15 +R9 +R50 +L69 +L107 +L87 +L806 +L88 +R44 +R479 +L635 +R32 +R97 +L29 +R87 +R13 +L59 +R85 +R59 +L13 +L72 +R28 +R94 +L171 +L71 +R20 +L88 +L311 +L1 +L58 +L980 +R53 +L15 +R93 +R65 +L449 +L97 +R68 +L43 +R55 +L131 +R439 +R49 +L4 +R55 +L123 +R23 +R19 +R87 +R63 +L2 +R79 +R454 +R489 +L275 +L95 +R81 +R590 +R10 +R34 +L34 +L98 +L13 +R45 +R17 +L66 +R72 +L18 +R19 +R442 +L57 +R657 +L177 +L81 +R453 +R32 +R87 +L31 +L83 +L82 +R8 +R75 +L11 +L81 +R83 +R208 +L32 +L18 +R51 +L85 +R84 +R91 +R39 +R370 +R20 +R80 +R142 +R81 +R847 +R86 +L3 +R323 +L23 +R647 +R120 +R57 +R72 +R151 +L75 +L11 +L37 +R23 +R52 +L52 +L42 +L158 +R13 +R329 +L65 +L92 +L57 +R782 +R90 +L34 +L66 +R59 +L59 +L79 +L12 +L409 +L1 +L29 +L76 +R43 +R34 +R29 +R66 +L66 +L90 +L10 +L79 +R879 +L52 +L25 +R35 +R42 +L55 +L331 +R86 +R55 +L370 +R4 +R325 +L66 +L48 +R63 +R737 +L32 +L78 +R90 +L36 +L10 +L70 +L64 +L58 +L925 +L66 +R49 +R946 +L90 +L84 +L12 +L60 +R36 +R64 +R14 +L17 +L873 +L178 +R62 +L30 +R22 +L16 +R19 +R74 +R21 +L98 +R88 +L13 +R25 +R503 +L3 +R56 +R71 +R927 +L54 +L29 +L432 +R41 +L80 +R62 +R66 +L28 +L473 +R73 +L24 +L88 +R43 +R45 +L78 +R2 +L84 +R84 +R53 +L53 +L77 +R1 +L76 +L6 +L16 +L63 +R37 +L65 +R65 +L20 +R86 +L429 +R463 +L548 +R26 +R495 +L38 +R65 +L88 +L12 +L41 +L315 +R26 +L50 +R80 +L51 +L49 +R55 +R40 +R80 +L20 +R65 +R980 +L45 +R645 +L17 +R23 +R59 +L65 +L6 +R906 +L29 +L66 +L105 +R406 +L62 +R73 +L8 +L92 +L254 +L64 +L99 +R55 +R104 +R140 +L44 +R48 +L30 +R1 +L32 +R58 +L88 +R42 +L54 +R898 +R4 +R98 +R382 +L61 +L75 +L6 +R860 +L54 +L55 +R46 +R893 +L66 +L88 +R261 +R63 +R5 +R95 +R11 +L811 +R301 +R99 +R732 +R573 +R395 +R16 +L97 +R99 +R20 +R362 +R16 +L7 +R34 +L43 +L63 +R63 +L483 +L33 +L67 +L7 +L10 +R8 +R99 +R93 +L43 +L49 +L37 +L520 +L51 +L24 +L76 +L255 +L344 +R8 +R694 +L3 +R32 +L53 +L16 +R81 +L44 +L74 +R751 +R23 +L92 +R78 +R678 +L11 +L89 +L37 +L66 +L38 +L23 +R31 +R92 +R277 +L71 +L7 +L810 +R588 +R44 +R39 +R94 +R21 +L936 +R17 +L64 +R78 +R7 +R796 +L8 +L88 +L55 +R55 +R570 +L5 +R35 +L55 +L94 +R32 +L88 +R304 +R1 +L73 +L29 +R64 +L64 +R43 +L841 +R34 +R74 +L8 +R68 +L363 +R80 +L63 +R22 +R39 +L83 +L48 +L19 +L44 +L78 +L64 +L47 +L20 +R58 +R62 +R96 +R88 +L63 +R6 +R184 +R589 +R48 +R10 +R893 +L1 +L50 +R40 +R60 +L55 +L83 +R173 +L432 +R97 +R193 +R46 +L41 +R43 +L92 +L1 +R6 +L54 +L703 +L494 +L3 +L84 +L216 +L253 +L33 +L10 +L4 +L76 +L24 +L405 +L71 +L24 +L196 +R96 +R69 +L13 +R44 +L26 +R20 +R38 +R68 +R29 +R3 +R698 +L70 +R41 +L1 +L28 +R26 +R61 +L59 +L45 +R19 +R963 +L58 +L79 +L3 +L97 +L2 +L98 +L26 +R2 +L39 +R463 +R641 +R905 +R654 +R75 +L75 +R59 +R52 +L75 +L36 +L31 +R31 +R308 +R92 +R69 +R31 +L2 +L20 +L26 +L32 +R53 +L73 +R33 +R67 +R216 +L33 +L83 +R73 +R427 +L90 +R349 +L59 +L46 +R86 +R60 +L781 +R49 +R91 +L68 +L48 +L43 +L40 +R40 +R80 +R20 +R23 +R734 +R15 +R82 +R7 +R39 +R959 +R67 +R10 +L813 +R425 +L86 +L514 +L581 +L67 +R15 +R85 +L76 +R61 +R3 +R12 +L5 +R5 +L4 +R44 +L63 +R25 +L26 +R24 +L33 +L709 +R66 +R10 +R94 +L744 +R85 +L69 +L227 +L257 +L12 +R40 +R53 +R34 +R72 +R23 +R87 +R92 +L40 +L61 +R96 +R37 +L537 +L38 +R38 +R10 +L310 +L135 +R39 +R178 +R18 +R88 +R12 +L81 +L965 +L65 +R11 +R546 +R354 +R64 +L476 +L5 +R88 +L71 +L88 +R514 +R21 +L424 +L74 +L84 +R91 +L32 +L24 +L33 +L14 +L82 +L815 +R987 +R57 +L70 +L430 +R48 +R392 +L372 +R18 +L703 +R354 +R639 +L276 +L94 +R28 +R661 +R15 +L71 +R61 +R85 +R79 +L64 +L82 +R86 +R96 +L3 +R94 +L91 +L307 +R74 +L67 +R15 +R68 +L83 +R85 +L85 +L86 +R41 +L37 +R82 +R99 +L99 +R48 +R38 +L86 +R56 +L230 +L64 +L648 +R86 +R9 +R91 +R62 +R52 +L14 +L33 +R33 +L23 +L77 +L748 +R93 +R24 +L69 +R56 +R54 +L31 +R21 +R916 +R21 +L37 +R36 +L901 +L79 +R44 +R87 +R7 +R6 +L64 +R64 +R49 +R91 +R13 +L14 +L785 +L584 +R30 +L25 +R73 +L99 +L449 +L602 +R13 +R89 +R457 +L57 +R1 +R89 +R93 +L83 +L4 +L96 +R449 +L778 +L171 +R52 +L52 +R94 +R48 +R34 +L93 +R58 +R48 +L89 +L3 +L10 +L87 +R93 +L38 +L55 +R55 +R67 +R76 +R96 +R11 +L5 +R32 +R68 +R64 +R92 +L56 +R5 +R95 +L9 +R109 +R96 +R485 +L6 +R62 +L441 +L544 +L52 +L77 +L4 +R81 +R73 +R47 +L720 +L15 +L57 +L680 +R52 +L14 +L6 +L2 +R22 +L766 +L79 +L55 +L78 +R253 +R25 +L19 +R19 +L333 +L86 +L23 +L49 +L36 +L569 +R99 +R97 +R7 +R45 +R29 +R19 +R15 +R37 +L69 +R17 +R22 +L22 +R86 +L93 +L93 +R57 +R35 +L21 +L49 +R46 +R2 +R530 +L32 +R53 +R20 +L475 +R10 +R996 +R56 +L41 +R71 +L68 +L43 +R81 +L28 +R850 +R97 +L36 +R957 +R32 +L56 +R56 +R306 +L77 +L29 +L52 +L48 +L85 +L446 +R64 +L33 +L33 +L767 +L36 +R84 +L75 +R56 +L229 +R57 +L51 +R94 +L68 +L80 +R86 +R95 +R518 +L66 +L743 +L131 +L145 +R980 +L78 +L72 +R962 +L72 +L9 +R17 +L94 +R43 +L604 +L39 +R545 +L45 +R5 +L48 +L79 +L78 +L33 +R191 +R86 +R56 +R93 +L78 +R68 +L54 +L74 +L955 +R625 +L199 +R74 +R493 +R607 +R41 +L36 +R17 +L45 +L76 +R47 +R52 +L22 +L878 +L59 +L41 +R25 +R70 +R5 +L57 +L43 +R36 +L37 +L42 +R42 +L89 +R691 +R24 +L53 +R73 +L78 +L80 +R24 +R89 +L35 +L650 +L22 +L94 +R70 +R31 +R65 +L99 +L60 +R117 +L13 +L35 +L28 +R53 +L245 +L55 +R1 +L33 +R35 +L303 +R213 +R147 +R40 +R37 +R87 +R67 +L291 +L22 +R22 +R43 +L17 +R2 +L97 +R10 +R372 +R687 +L81 +R58 +R61 +R26 +L66 +R2 +R651 +R65 +L216 +L49 +L241 +L48 +L22 +R40 +R86 +L84 +R718 +R58 +R42 +R17 +L17 +R82 +R30 +R88 +R4 +R90 +R6 +L125 +L52 +L12 +R581 +R66 +L686 +L58 +L13 +R77 +L9 +R207 +R24 +L95 +R84 +R73 +L62 +L23 +R19 +L38 +R42 +L728 +R528 +R74 +R26 +R60 +L834 +L98 +L728 +L96 +R44 +L98 +L83 +R85 +R48 +R9 +L9 +L90 +L556 +L93 +R39 +L512 +L30 +R42 +R92 +R37 +R325 +R92 +R324 +R494 +L89 +R678 +R411 +L231 +L33 +R368 +L3 +R35 +R13 +R4 +L817 +R69 +L69 +L325 +L75 +R872 +L681 +R409 +L56 +R31 +L75 +L55 +L3 +L51 +L7 +R716 +R51 +R49 +R24 +R76 +R37 +L83 +L92 +L62 +R22 +R32 +R22 +R24 +R679 +L22 +R66 +L32 +R51 +L36 +R225 +R94 +L33 +R25 +R6 +L25 +L98 +R512 +L11 +L1 +R44 +R56 +L95 +L75 +R71 +R99 +R10 +R69 +L79 +R66 +R44 +L4 +R94 +L83 +R1 +L67 +R28 +R3 +R18 +R456 +R550 +L34 +L171 +L217 +R29 +L13 +L68 +L14 +L91 +R845 +R28 +R60 +L60 +R38 +L38 +R65 +R35 +R80 +R20 +R825 +R58 +L90 +R25 +L40 +L78 +R16 +L3 +R581 +L11 +L61 +R78 +R41 +L227 +L114 +L85 +L15 +R153 +L53 +R16 +R62 +R46 +L39 +L786 +R98 +L897 +L21 +L79 +L346 +R54 +R27 +L62 +L7 +R214 +L180 +L198 +L94 +L32 +R24 +L18 +R60 +L242 +L80 +R15 +R93 +R72 +L594 +R81 +R44 +R96 +R73 +L36 +R36 +R96 +L93 +R88 +L91 +L46 +R47 +R299 +R59 +L259 +R46 +R593 +L78 +R747 +L343 +R39 +L4 +L316 +L84 +R34 +L84 +R50 +R34 +L76 +R69 +R73 +L1 +L78 +R46 +R41 +L6 +L2 +L139 +L37 +R1 +L1 +L73 +L51 +R41 +L13 +L50 +L32 +R980 +R74 +R51 +R449 +R12 +R74 +R14 +R795 +L781 +R10 +R695 +R81 +R58 +L48 +R62 +R86 +L58 +L16 +L384 +L718 +L28 +R23 +L11 +R34 +L88 +R78 +R97 +L87 +L54 +L46 +L25 +L7 +R93 +R39 +R79 +R60 +L82 +L57 +R77 +L72 +R89 +L94 +L65 +R65 +R62 +L58 +R54 +R95 +R5 +L78 +R46 +R74 +R64 +L68 +R4 +R37 +L30 +L36 +R43 +L46 +R32 +L61 +R98 +L9 +L98 +R46 +L11 +L86 +R21 +L54 +R54 +R28 +R67 +L10 +R24 +L23 +L18 +L7 +R50 +L14 +L29 +R21 +L34 +L13 +R20 +L47 +R23 +R10 +R27 +R9 +R17 +L49 +R4 +L18 +L15 +L2 +L36 +R23 +L13 +R26 +R45 +L25 +L23 +L31 +L4 +L48 +L3 +L35 +R2 +L45 +L43 +L1 +R10 +L39 +R6 +L6 +R19 +L3 +L33 +L1 +L29 +R31 +L43 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index d091ba5..4bd2836 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,4 +31,8 @@ addopts = [ [tool.black] line-length = 88 -target-version = ['py39'] \ No newline at end of file +target-version = ['py39'] + +[project.scripts] +# Console script for running day solutions: after `pip install -e .` you can run `aoc --year 2025 --day 1` +aoc = "advent_of_code.cli:main" \ No newline at end of file diff --git a/src/advent_of_code/__main__.py b/src/advent_of_code/__main__.py new file mode 100644 index 0000000..75d8e16 --- /dev/null +++ b/src/advent_of_code/__main__.py @@ -0,0 +1,12 @@ +"""Allow running the package with `python -m advent_of_code`. + +Example: + python -m advent_of_code --year 2025 --day 1 + +This file delegates to `advent_of_code.cli:main`. +""" +from .cli import main + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/advent_of_code/cli.py b/src/advent_of_code/cli.py new file mode 100644 index 0000000..452bd5a --- /dev/null +++ b/src/advent_of_code/cli.py @@ -0,0 +1,62 @@ +"""CLI entrypoint for the advent_of_code package. + +Provides a small, modern CLI so the project can be run as: + +- `python -m advent_of_code --year 2025 --day 1` +- or, after editable install: `aoc --year 2025 --day 1` + +This duplicates the behavior of `scripts/run_day.py` but lives inside the package. +""" +from __future__ import annotations + +import argparse +import importlib +import sys +from typing import Sequence, Optional + + +def main(argv: Optional[Sequence[str]] = None) -> int: + """Console entry point. + + Args: + argv: list of args (None -> sys.argv[1:]) + + Returns: + exit code (0 on success). + """ + parser = argparse.ArgumentParser(prog="aoc", description="Run an Advent of Code solution module") + parser.add_argument("--year", required=True, type=int, help="Year directory (e.g. 2025)") + parser.add_argument("--day", required=True, type=str, help="Day number (1 or 01)") + + args = parser.parse_args(argv) + + day_zero_padded_str = str(args.day).zfill(2) + input_file = f"inputs/year_{args.year}/{day_zero_padded_str}.dat" + + day_module = f"advent_of_code.year_{args.year}.day_{day_zero_padded_str}" + + try: + module = importlib.import_module(day_module) + except ModuleNotFoundError as exc: + print(f"Could not find module: {day_module}") + # Helpful hint: if running from the repository root, make sure `src` is on PYTHONPATH or install the package editable + print("Hint: run with `PYTHONPATH=src python -m advent_of_code ...` or `pip install -e .` to make the package importable") + if isinstance(exc, ModuleNotFoundError): + # show original message + print(str(exc)) + return 1 + + if hasattr(module, "main"): + try: + module.main(input_file) + return 0 + except Exception: + # Bubble up stack trace for debugging convenience + raise + else: + print(f"The module {day_module} does not have a 'main(input_file)' function.") + return 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/advent_of_code/year_2025/day_01.py b/src/advent_of_code/year_2025/day_01.py new file mode 100644 index 0000000..d781652 --- /dev/null +++ b/src/advent_of_code/year_2025/day_01.py @@ -0,0 +1,77 @@ +from advent_of_code.utils.input_handling import read_input + +DIAL_STARTING_POSITION = 50 +DIAL_START = 0 +DIAL_END = 99 +DIAL_SIZE = DIAL_END - DIAL_START + 1 + +def parse_instruction(instruction): + turn_direction = instruction[0] + if turn_direction == "L": + turn_direction = -1 + elif turn_direction == "R": + turn_direction = 1 + else: + raise ValueError(f"Invalid turn direction: {turn_direction}") + + distance = int(instruction[1:]) + return (turn_direction, distance) + +def turn_dial(current_position, turn_direction, distance): + return (current_position + turn_direction * distance) % DIAL_SIZE + +def target_position_counter(current_position, target_position=0, ): + if current_position == target_position: + return 1 + return 0 + +def points_at_zero_counter(current_position, turn_direction, distance): + full_loops = distance // DIAL_SIZE + + partial_loops = 0 + + # Check if we passed zero in the remaining distance after full loops + new_position = turn_dial(current_position, turn_direction, distance) + if new_position > current_position and turn_direction == -1 and current_position != 0 and new_position != 0: + partial_loops += 1 + elif new_position < current_position and turn_direction == 1 and current_position != 0 and new_position != 0: + partial_loops += 1 + + # check if we landed on zero + if new_position == 0: + partial_loops += 1 + + return full_loops + partial_loops + +def solve(parsed_input): + + current_position = DIAL_STARTING_POSITION + target_position_count = 0 + points_at_zero_count = 0 + + for instruction in parsed_input: + turn_direction, distance = parse_instruction(instruction) + new_position = turn_dial(current_position, turn_direction, distance) + + target_position_count += target_position_counter(new_position) + points_at_zero_count += points_at_zero_counter(current_position, turn_direction, distance) + # update start position + current_position = new_position + + part_1_solution = target_position_count + part_2_solution = points_at_zero_count + return (part_1_solution, part_2_solution) + + +def main(input_file): + input = read_input(input_file) + (result_part_1, result_part_2) = solve(input) + print( + f"Day 01: " + f" Result for part 1 is {result_part_1}. " + f" Result for part 2 is {result_part_2}. " + ) + + +if __name__ == "__main__": + main() diff --git a/tests/year_2025/test_day_01.py b/tests/year_2025/test_day_01.py new file mode 100644 index 0000000..a6f1770 --- /dev/null +++ b/tests/year_2025/test_day_01.py @@ -0,0 +1,84 @@ +import pytest +from advent_of_code.year_2025.day_01 import ( + solve, + turn_dial, + target_position_counter, + points_at_zero_counter, +) + + +@pytest.fixture +def day_01_test_input(): + return [ + "L68", + "L30", + "R48", + "L5", + "R60", + "L55", + "L1", + "L99", + "R14", + "L82", + ] + + +@pytest.fixture +def day_01_expected_output(): + return (3, 6) + + +def test_solver(day_01_test_input, day_01_expected_output): + result = solve(day_01_test_input) + assert result == day_01_expected_output + +@pytest.fixture(params=[ + (50 , -1 , 68 , 82 , 0 , 1 ), # case 0 + (82 , -1 , 30 , 52 , 0 , 0 ), # case 1 + (52 , 1 , 48 , 0 , 1 , 1 ), # case 2 + (0 , -1 , 5 , 95 , 0 , 0 ), # case 3 + (95 , 1 , 60 , 55 , 0 , 1 ), # case 4 + (55 , -1 , 55 , 0 , 1 , 1 ), # case 5 + (0 , -1 , 1 , 99 , 0 , 0 ), # case 6 + (99 , -1 , 99 , 0 , 1 , 1 ), # case 7 + (0 , 1 , 14 , 14 , 0 , 0 ), # case 8 + (14 , -1 , 82 , 32 , 0 , 1 ), # case 9 + ], +) +def turn_case(request): + """ + (current_position, turn_direction, distance, expected_new_position, part_1_count, part_2_count) + + """ + return request.param + +def test_turn_dial(turn_case): + current_position, turn_direction, distance, expected_new_position, _, _ = turn_case + new_position = turn_dial(current_position, turn_direction, distance) + assert new_position == expected_new_position + + +def test_target_position_counter(turn_case): + _, _, _, expected_new_position, expected_count, _ = turn_case + actual_count = target_position_counter(expected_new_position) + assert actual_count == expected_count + +def test_points_at_zero_counter(turn_case): + current_position, turn_direction, distance, _, _, expected_count = turn_case + actual_count = points_at_zero_counter(current_position, turn_direction, distance) + assert actual_count == expected_count + +@pytest.mark.parametrize( + "start_position, turn_direction, distance, expected_count", + [ + (50, 1, 1000, 10), + (50, 1, 1050, 11), + (0, 1, 100, 1), + (0, 1, 1, 0), + (50 , -1, 68, 1), + (50 , 1, 68, 1), + ] +) +def test_points_at_zero_counter_extra_test_cases(start_position, turn_direction, distance, expected_count): + count = points_at_zero_counter(start_position, turn_direction, distance) + assert count == expected_count \ No newline at end of file