From 33f362db657357ca12d7ae560edfb817a8ce487e Mon Sep 17 00:00:00 2001 From: Luc Rubio Date: Tue, 10 Dec 2024 21:52:44 +0100 Subject: [PATCH] AoC 2024 day 10 part 1 --- aoc2024/src/day10/__init__.py | 0 aoc2024/src/day10/python/__init__.py | 0 aoc2024/src/day10/python/solution.py | 57 ++++++++++++++++++++++ aoc2024/test/day10/__init__.py | 0 aoc2024/test/day10/python/__init__.py | 0 aoc2024/test/day10/python/example1.txt | 7 +++ aoc2024/test/day10/python/example2.txt | 7 +++ aoc2024/test/day10/python/example3.txt | 7 +++ aoc2024/test/day10/python/example4.txt | 8 +++ aoc2024/test/day10/python/input.txt | 55 +++++++++++++++++++++ aoc2024/test/day10/python/test_solution.py | 41 ++++++++++++++++ 11 files changed, 182 insertions(+) create mode 100644 aoc2024/src/day10/__init__.py create mode 100644 aoc2024/src/day10/python/__init__.py create mode 100644 aoc2024/src/day10/python/solution.py create mode 100644 aoc2024/test/day10/__init__.py create mode 100644 aoc2024/test/day10/python/__init__.py create mode 100644 aoc2024/test/day10/python/example1.txt create mode 100644 aoc2024/test/day10/python/example2.txt create mode 100644 aoc2024/test/day10/python/example3.txt create mode 100644 aoc2024/test/day10/python/example4.txt create mode 100644 aoc2024/test/day10/python/input.txt create mode 100644 aoc2024/test/day10/python/test_solution.py diff --git a/aoc2024/src/day10/__init__.py b/aoc2024/src/day10/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/aoc2024/src/day10/python/__init__.py b/aoc2024/src/day10/python/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/aoc2024/src/day10/python/solution.py b/aoc2024/src/day10/python/solution.py new file mode 100644 index 0000000..d44507a --- /dev/null +++ b/aoc2024/src/day10/python/solution.py @@ -0,0 +1,57 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from typing import Sequence + +type Pos = tuple[int, int] + +_TRAILHEAD = 0 +_SUMMIT = 9 +_IS_GRADUAL_SLOPE = lambda level, next_level: next_level == level + 1 + + +def _find_trailheads(topographic_map: Sequence[str]) -> tuple[Pos, ...]: + """Finds the positions of trailheads. A trailhead is represented by '0'.""" + trailhead_positions = [] + for y in range(len(topographic_map)): + for x in range(len(topographic_map[0])): + if int(topographic_map[y][x]) == _TRAILHEAD: + trailhead_positions.append((y, x)) + return tuple(trailhead_positions) + + +def _count_reachable_summits(topo_map: Sequence[str], curr_pos: Pos, visited: set[Pos], num_summits: list[int]): + curr_level = int(topo_map[curr_pos[0]][curr_pos[1]]) + if curr_level == _SUMMIT and curr_pos not in visited: + num_summits[0] += 1 + visited.add(curr_pos) + return + visited.add(curr_pos) + for step in ((-1, 0), (0, 1), (1, 0), (0, -1)): + next_pos = (curr_pos[0] + step[0]), (curr_pos[1] + step[1]) + within_map = 0 <= next_pos[0] < len(topo_map) and 0 <= next_pos[1] < len(topo_map[0]) + if next_pos not in visited and within_map: + next_level = int(topo_map[next_pos[0]][next_pos[1]]) + if _IS_GRADUAL_SLOPE(curr_level, next_level): + _count_reachable_summits(topo_map, next_pos, visited, num_summits) + + +def get_score_sum(topographic_map: Sequence[str]) -> int: + """Gets the sum of all the trails from all the trailheads.""" + sum_scores = 0 + trailheads_positions: tuple[Pos, ...] = _find_trailheads(topographic_map) + for trailhead_pos in trailheads_positions: + num_summits = [0] # Pass by reference. + _count_reachable_summits(topographic_map, trailhead_pos, set(), num_summits) + sum_scores += num_summits[0] + return sum_scores diff --git a/aoc2024/test/day10/__init__.py b/aoc2024/test/day10/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/aoc2024/test/day10/python/__init__.py b/aoc2024/test/day10/python/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/aoc2024/test/day10/python/example1.txt b/aoc2024/test/day10/python/example1.txt new file mode 100644 index 0000000..cb0fbc6 --- /dev/null +++ b/aoc2024/test/day10/python/example1.txt @@ -0,0 +1,7 @@ +1110111 +1111111 +1112111 +6543456 +7111117 +8111118 +9111119 \ No newline at end of file diff --git a/aoc2024/test/day10/python/example2.txt b/aoc2024/test/day10/python/example2.txt new file mode 100644 index 0000000..0ee251e --- /dev/null +++ b/aoc2024/test/day10/python/example2.txt @@ -0,0 +1,7 @@ +1190119 +1111198 +1112117 +6543456 +7651987 +8761111 +9871111 \ No newline at end of file diff --git a/aoc2024/test/day10/python/example3.txt b/aoc2024/test/day10/python/example3.txt new file mode 100644 index 0000000..a44d564 --- /dev/null +++ b/aoc2024/test/day10/python/example3.txt @@ -0,0 +1,7 @@ +1011911 +2111811 +3111711 +4567654 +1118113 +1119112 +1111101 \ No newline at end of file diff --git a/aoc2024/test/day10/python/example4.txt b/aoc2024/test/day10/python/example4.txt new file mode 100644 index 0000000..7bb1248 --- /dev/null +++ b/aoc2024/test/day10/python/example4.txt @@ -0,0 +1,8 @@ +89010123 +78121874 +87430965 +96549874 +45678903 +32019012 +01329801 +10456732 \ No newline at end of file diff --git a/aoc2024/test/day10/python/input.txt b/aoc2024/test/day10/python/input.txt new file mode 100644 index 0000000..9d94799 --- /dev/null +++ b/aoc2024/test/day10/python/input.txt @@ -0,0 +1,55 @@ +3431014564567889856765432104561217856787834345650410767 +4321023673078974323896901223650306945698981298701321898 +5891134982100165010187878910765445034567820543432456734 +6780147890121016978776965010896532121054210612549345321 +5491056787630967869987654123987034910123341701678763430 +2312349896549890154890123234569123871431259898569321541 +1009456785656743213765012234678034565430968367878490651 +3238543876871056902153212105765123470121875454965581740 +0147612987962347810042309876894325989430960323784670891 +1254101796651258923031498121256716788567871212693021892 +2760189845640769854120567010343805697634543000542136763 +9871456732239878765987632129452934314523652101239545654 +8102320121148543651456783478761043203410789654318767650 +9810112510098652100347894567898110112341898769101658941 +8723203450567787621239998456987567543898101678102347632 +7654310961421298692108783015823458672189012363210412345 +8941201872330178787145654324310569789076543654789301256 +2300312360545689656014345678210655690343218945689430987 +1412543451986770145123212109198744521256707650176521230 +0503694012876871234338905410012633230569876543287810321 +7654789323905965129847654321710123145678107434496929454 +8969876454914456056789878930891231010103298921345218765 +9878705967823327643056767011765310121012367800234309454 +3210214877012018034145654322654301234189456012125498723 +4569823898901219123233458743543210945676788321054321610 +2378778767432301012012769658652101876501699490167600501 +1267129876541018723103818569785438987612588588998010432 +0398034567898129654278903478694323986543437677650323234 +5487603478987034563365412323456410076345321761541454143 +6034512987656189879450343015667567125256780890132969056 +7123432100141098508761261018798258934101298743210878765 +8923521231232987612567876529680112343210129654323769876 +9812340321201236903498985434543209852101234569834954301 +6701054450120145812385890365434901769015101078015867232 +5432365965034566703456581270125892378754098129126798103 +1019879870103875410787610789816765498763137430934567874 +2988218789212980325692101296700012187212346501887656985 +3678305654310341236543062345341123098703256232796540176 +4549456789423467877879871056732014567890107145601230234 +0032966761294558906978787810847812346921298050129821965 +1121879850387643216785696921956909855430386765434745874 +2340960345465434105898585430341098760987438876125636434 +3651451276576123434703450121252387721236589980030127123 +8960301289789016521012445696761456872345670891234898034 +7871210348058907897654332781890018965645671432105677645 +6210143232167812898101221650170123454534982145694789876 +4301250143456103763218760521985439210122173036783296765 +5654367897876554654109654432676098341013054921042107654 +8769016788985467891010123354342187657894567832030078503 +9878323412832345672561034565223476678743698948121899812 +6765467803421232983478743470110569569652107819238987601 +5653456912980221012989856789029678454765432108747896542 +1012321233470110103456765891098763243854549654656505632 +2187410345561256714987654302187654132923458743215014701 +7896509876456349876878963213456565001210567898304323892 \ No newline at end of file diff --git a/aoc2024/test/day10/python/test_solution.py b/aoc2024/test/day10/python/test_solution.py new file mode 100644 index 0000000..8a04d4e --- /dev/null +++ b/aoc2024/test/day10/python/test_solution.py @@ -0,0 +1,41 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import unittest + +from common.python3.AdventOfCodeTestCase import AdventOfCodeTestCase +from aoc2024.src.day10.python.solution import get_score_sum + + +class TestDay09Solution(AdventOfCodeTestCase): + def __init__(self, *args, **kwargs): + (super(TestDay09Solution, self).__init__(__file__, *args, **kwargs)) + + def test_part1_withExample_getsScore(self): + self.assertEqual(2, get_score_sum(self.examples[0])) + + def test_part1_withExample2_getsScore(self): + self.assertEqual(4, get_score_sum(self.examples[1])) + + def test_part1_withExample3_getsScore(self): + self.assertEqual(3, get_score_sum(self.examples[2])) + + def test_part1_withExample4_getsScore(self): + self.assertEqual(36, get_score_sum(self.examples[3])) + + def test_part1_withPuzzleInput_getsScore(self): + self.assertEqual(825, get_score_sum(self.input)) + + +if __name__ == '__main__': + unittest.main()