From 53fcb4c10c544b498203b4b2774f10d410c61016 Mon Sep 17 00:00:00 2001 From: Galen Rice Date: Wed, 11 Dec 2024 01:56:42 -0500 Subject: [PATCH] feat: day 10 completed --- 2024/inputs/day10.txt | 45 ++++++++++ 2024/inputs/tests/test_day10.txt | 8 ++ .../src/grice_py_aoc_2024/day10/main.py | 89 +++++++++++++++++-- .../src/grice_py_aoc_2024/day10/test_day10.py | 9 +- 4 files changed, 141 insertions(+), 10 deletions(-) diff --git a/2024/inputs/day10.txt b/2024/inputs/day10.txt index e69de29..0b2e3b4 100644 --- a/2024/inputs/day10.txt +++ b/2024/inputs/day10.txt @@ -0,0 +1,45 @@ +101234653436698943210876543298108967890123211 +900945762567787651028945054167211876965254300 +812876851008632112987632167054340105874367891 +743987945219541003456542108981233234567809892 +657641434349898764565876232190543456452912763 +898530125896701651698965945087612387301103454 +101421056787672340789234876231201293219010989 +012336765410589121470125960140340184678321670 +987449870323431034561076054057653296501234521 +876558901210120345665780143968934187410345438 +034569821025001256676891232877065056309654589 +125678438136789867589872301986174145218789678 +678776569245234798434565432765289036785890541 +589989478910135652329806567874376123896781030 +431276321210023101210715432990145678765432121 +120345290923412302345620121087230109650187656 +098010187874503210989430101256521212341090347 +187623456365694567876543232344560301032181298 +012510589456787655469854741023478912345672107 +143421674307897846988767858910890109852109856 +231256014210978987671056967378765210763296705 +140347123900389034502340191269854307894585014 +051298034891276123216521780350123456765674323 +565434540762345637897435615443210523456001298 +876529651057850136988904306782107610987123367 +985018782348943245077211216790108901278994453 +123427890167654432106310345889299870122185432 +010568921211234501215445432976387761233076541 +129877432100235676301456701265456654394567650 +431066523231145985490389876014012534585658969 +302309012694046796781201078923453421673215678 +213218906783459873212212562112969010984504301 +304567815612163654304323453007878123435643210 +412359854309072345323456894314365036521754965 +563456743218781896210567765101254307810867874 +694105678907690787890698989210345218987980123 +787234563210581654321787876307896210898943321 +894563454671410010987345665456987346787652450 +763674589582323225676298767645459855898101067 +652983673497654134570156958912378764306678998 +341672102108987010987667843003569013215463210 +030501012896109823478766542103454320176354501 +125418923787210734569651033212169010083296101 +654327654654323601234569124349078321190187632 +789210125345434512103678765678767456783276543 diff --git a/2024/inputs/tests/test_day10.txt b/2024/inputs/tests/test_day10.txt index e69de29..cada9b3 100644 --- a/2024/inputs/tests/test_day10.txt +++ b/2024/inputs/tests/test_day10.txt @@ -0,0 +1,8 @@ +89010123 +78121874 +87430965 +96549874 +45678903 +32019012 +01329801 +10456732 diff --git a/2024/python/src/grice_py_aoc_2024/day10/main.py b/2024/python/src/grice_py_aoc_2024/day10/main.py index 1d1613a..56775bf 100644 --- a/2024/python/src/grice_py_aoc_2024/day10/main.py +++ b/2024/python/src/grice_py_aoc_2024/day10/main.py @@ -1,22 +1,101 @@ from __future__ import annotations import time +from functools import cache +from itertools import product from pathlib import Path DIR = Path(__file__).parent FILE = DIR.parents[3] / "inputs" / f"{DIR.stem}.txt" +TRAILHEAD = "0" +END_OF_TRAIL = "9" -def part1(contents: str): - return "Not done yet!" +def num_trails(contents: list[str], x: int, y: int, unique: bool = False) -> int: + @cache + def _find_all_trail_ends(x: int, y: int) -> set[tuple[int, int]]: + nonlocal contents + curr = contents[x][y] + if curr == END_OF_TRAIL: + return {(x, y)} -def part2(contents: str): - return "Not done yet!" + target = str(int(curr) + 1) + trailheads = set() + for dx, dy in [ + [-1, 0], + [0, 1], + [1, 0], + [0, -1], + ]: + newx, newy = x + dx, y + dy + if not 0 <= newx < len(contents) or not 0 <= newy < len(contents[0]): + # new point is outside bounds of the contents, ignore + continue + if contents[newx][newy] == target: + trailheads |= _find_all_trail_ends(x=newx, y=newy) + return trailheads + + @cache + def _find_num_unique_trails(x: int, y: int) -> int: + # Oddly enough, this was the way I initially tried to solve Part 1 + # due to my misunderstanding things. I had to then go back and return a set + # of those trail end coordinates, so as to have a unique set of trail ends, + # which I could then count with len. + # After finding that Part 2 was, indeed, this version, + # I just re-built what I did at first and re-implemented with a flag. + nonlocal contents + curr = contents[x][y] + if curr == END_OF_TRAIL: + return 1 + + target = str(int(curr) + 1) + trails = 0 + for dx, dy in [ + [-1, 0], + [0, 1], + [1, 0], + [0, -1], + ]: + newx, newy = x + dx, y + dy + if not 0 <= newx < len(contents) or not 0 <= newy < len(contents[0]): + # new point is outside bounds of the contents, ignore + continue + if contents[newx][newy] == target: + trails += _find_num_unique_trails(x=newx, y=newy) + return trails + + if unique: + # Part 2 + return _find_num_unique_trails(x=x, y=y) + + # Part 1 + trailhead_set = _find_all_trail_ends(x=x, y=y) + return len(trailhead_set) + + +def part1(contents: list[str]) -> int: + total = 0 + for x, line in enumerate(contents): + for y, char in enumerate(line): + if char == TRAILHEAD: + num = num_trails(contents=contents, x=x, y=y) + total += num + return total + + +def part2(contents: list[str]) -> int: + total = 0 + for x, line in enumerate(contents): + for y, char in enumerate(line): + if char == TRAILHEAD: + num = num_trails(contents=contents, x=x, y=y, unique=True) + total += num + return total def main(): - contents = FILE.read_text() + contents = FILE.read_text().strip().split("\n") _start1 = time.perf_counter() result1 = part1(contents) diff --git a/2024/python/src/grice_py_aoc_2024/day10/test_day10.py b/2024/python/src/grice_py_aoc_2024/day10/test_day10.py index d1220ef..41b9cc2 100644 --- a/2024/python/src/grice_py_aoc_2024/day10/test_day10.py +++ b/2024/python/src/grice_py_aoc_2024/day10/test_day10.py @@ -8,18 +8,17 @@ DIR = Path(__file__).parent TEST_FILE = DIR.parents[3] / "inputs/tests" / f"test_{DIR.stem}.txt" -EXPECTED_PART_1 = "REPLACE ME!" -EXPECTED_PART_2 = "REPLACE ME!" +EXPECTED_PART_1 = 36 +EXPECTED_PART_2 = 81 def test_part1(): - contents = TEST_FILE.read_text() + contents = TEST_FILE.read_text().strip().split("\n") result = part1(contents) assert result == EXPECTED_PART_1 -@pytest.mark.xfail(reason=f"{DIR.stem} P1 incomplete") def test_part2(): - contents = TEST_FILE.read_text() + contents = TEST_FILE.read_text().strip().split("\n") result = part2(contents) assert result == EXPECTED_PART_2