diff --git a/README.md b/README.md index 1f19c0e..73af92a 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Advent of Code is an Advent calendar of small programming puzzles by [Eric Wastl - Day 5: [Print Queue](https://adventofcode.com/2024/day/5) -- [Day5.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day5.kt) - Day 7: [Bridge Repair](https://adventofcode.com/2024/day/7) -- [Day7.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day7.kt) - Day 8: [Resonant Collinearity](https://adventofcode.com/2024/day/8) -- [Day8.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day8.kt) +- Day 10: [Hoof It](https://adventofcode.com/2024/day/10) -- [Day10.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day10.kt) - Day 12: [Garden Groups](https://adventofcode.com/2024/day/12) -- [Day12.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day12.kt) - Day 14: [Restroom Redoubt](https://adventofcode.com/2024/day/14) -- [Day14.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day14.kt) - Day 18: [RAM Run](https://adventofcode.com/2024/day/18) -- [Day18.kt](https://github.com/andilau/advent-of-code-2024/blob/main/src/main/kotlin/days/Day18.kt) diff --git a/src/main/kotlin/days/Day10.kt b/src/main/kotlin/days/Day10.kt new file mode 100644 index 0000000..ce32df5 --- /dev/null +++ b/src/main/kotlin/days/Day10.kt @@ -0,0 +1,58 @@ +package days + +import java.util.PriorityQueue + +@AdventOfCodePuzzle( + name = "Hoof It", + url = "https://adventofcode.com/2024/day/10", + date = Date(day = 10, year = 2024) +) +class Day10(val input: List) : Puzzle { + + val map: Map = findAllIgnoring().toMap() + val starts: Set = map.filter { (_, v) -> v == 0 }.keys + val exits: Set = map.filter { (_, v) -> v == 9 }.keys + + override fun partOne() = starts.sumOf { start -> scoreTrail(start, exits) } + + override fun partTwo() = starts.sumOf { start -> scoreTrail2(start, exits) } + + private fun findAllIgnoring(): List> = input + .flatMapIndexed { y, line -> line.mapIndexedNotNull() { x, c -> if (c.isDigit()) Point(x, y) to c.digitToInt() else null } } + + private fun scoreTrail(start: Point, exits: Set): Int { + var reached = mutableSetOf() + val queue = PriorityQueue> { a, b -> a.second.compareTo(b.second) } + queue.add(start to 0) + val seen = mutableSetOf() + + while (queue.isNotEmpty()) { + val (next, cost) = queue.poll() + + if (next in seen) continue + seen += next + if (next in exits) reached += next + next.neighbors() + .filter { it in map } + .filter { map[it]!! - map[next]!! == 1 } + .forEach { queue.add(it to cost + 1) } + } + return reached.size + } + + private fun scoreTrail2(start: Point, exits: Set): Int { + var reached = mutableListOf() + val queue = PriorityQueue> { a, b -> a.size.compareTo(b.size) } + queue.add(listOf(start)) + while (queue.isNotEmpty()) { + val path = queue.poll() + + if (path.last() in exits) reached += path.last() + path.last().neighbors() + .filter { it in map } + .filter { map[it]!! - map[path.last()]!! == 1 } + .forEach { queue.add(path + it) } + } + return reached.size + } +} \ No newline at end of file diff --git a/src/main/resources/input_day_10.txt b/src/main/resources/input_day_10.txt new file mode 100644 index 0000000..67fbd24 --- /dev/null +++ b/src/main/resources/input_day_10.txt @@ -0,0 +1,43 @@ +1089890105678121432132101232127321012354321 +0178763234589030543045000345018018985467610 +3298954103490347656106215496789123876508998 +4567832234321258985287306784100034565012567 +2356541025652767014396454993211239654523498 +1403456710787854320478567884589748703012367 +0512109876598941231569545675679856412721456 +7657238102345410542349830901298764567810565 +8998341201986789621056721850347543201998776 +7087650345679878700876545765456670102367985 +6121065436901263210980238750105985434451234 +5432376327874354890121129653234356321010105 +2345981210965568765430098544234067865430096 +1296590210567809012321107230165123956721187 +0187645323456918456789236109877034847810256 +0099236012567823565018045234578765432901340 +1678107101998894654327102198679896001076541 +2363218900806765785210231087988587123189832 +1454300210712567892104345896107698894898321 +0510321345643498763569856745234565765765410 +9621410478761098954478765030109874327656731 +8734589569454167410349034121918969018549843 +9435678400123256301256121030876878129450652 +4521017312321343214787036980125561034321781 +5670901205430456345698347898234432211289690 +4989874396012387210510256723478934300478541 +3090765487801091234423105410560125410367630 +2101051234945670542394576321021076523458921 +1672340545234987691087689987688987984361010 +0589655676101296789079012896590868970154301 +3438764985054385674108543003481078561567210 +0127123078765676543287632112872369432018923 +6546042129654778904398910001965454342129854 +7237653434569865215897601223450569243036765 +8198548521010764346710510319321678154545678 +9011239630781453454323423408765321069694789 +0100348749692354320345014503455430678783210 +3217654458543765211276769612786726789698701 +8348983267012891200989838764691810652189610 +9456678101101010341234542123500901643076521 +8764569434514567650765430054411898701103430 +7623430127603498769876121069322345632212341 +6510121098012389858789012378443454543303454 \ No newline at end of file diff --git a/src/test/kotlin/SolutionsTest.kt b/src/test/kotlin/SolutionsTest.kt index 774e5b2..5490130 100644 --- a/src/test/kotlin/SolutionsTest.kt +++ b/src/test/kotlin/SolutionsTest.kt @@ -16,6 +16,7 @@ class SolutionsTest { Day5(InputReader.getInputAsList(5)) to Pair(6041, 4884), Day7(InputReader.getInputAsList(7)) to Pair(267566105056L, 116094961956019L), Day8(InputReader.getInputAsList(8)) to Pair(371, 1229), + Day10(InputReader.getInputAsList(10)) to Pair(501, 1017), Day12(InputReader.getInputAsList(12)) to Pair(1464678, 877492), Day14(InputReader.getInputAsList(14)) to Pair(214109808L, 7687), Day18(InputReader.getInputAsList(18)) to Pair(370, "65,6"), diff --git a/src/test/kotlin/days/Day10Test.kt b/src/test/kotlin/days/Day10Test.kt new file mode 100644 index 0000000..d5b58d5 --- /dev/null +++ b/src/test/kotlin/days/Day10Test.kt @@ -0,0 +1,124 @@ +package days + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.DynamicTest +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestFactory + +@DisplayName("Day 10") +class Day10Test { + val trailheadScore1 = """ + 0123 + 1234 + 8765 + 9876""".trimIndent().lines() + + val trailheadScore2 = """ + ...0... + ...1... + ...2... + 6543456 + 7.....7 + 8.....8 + 9.....9""".trimIndent().lines() + val trailheadScore3 = """ + ..90..9 + ...1.98 + ...2..7 + 6543456 + 765.987 + 876.... + 987....""".trimIndent().lines() + val trailheadScore4 = """ + 10..9.. + 2...8.. + 3...7.. + 4567654 + ...8..3 + ...9..2 + .....01""".trimIndent().lines() + val trailheadScore5 = """ + 89010123 + 78121874 + 87430965 + 96549874 + 45678903 + 32019012 + 01329801 + 10456732""".trimIndent().lines() + + @Nested + @DisplayName("Part 1") + inner class Part1 { + + @TestFactory + fun `What is the sum of the scores of all trailheads on your topographic map`() = + listOf( + trailheadScore1 to 1, + trailheadScore2 to 2, + trailheadScore3 to 4, + trailheadScore4 to 3, + trailheadScore5 to 36, + ).map { (map, score) -> + DynamicTest.dynamicTest("The sum of the scores of all trailheads on the topographic map is $score") { + assertThat(Day10(map).partOne()).isEqualTo(score) + } + } + + } + + @Nested + @DisplayName("Part 2") + inner class Part2 { + + val trailheadScore6 = """ + .....0. + ..4321. + ..5..2. + ..6543. + ..7..4. + ..8765. + ..9....""".trimIndent().lines() + + val trailheadScore7 = """ + ..90..9 + ...1.98 + ...2..7 + 6543456 + 765.987 + 876.... + 987....""".trimIndent().lines() + + val trailheadScore8 = """ + 012345 + 123456 + 234567 + 345678 + 4.6789 + 56789.""".trimIndent().lines() + val trailheadScore9 = """ + 89010123 + 78121874 + 87430965 + 96549874 + 45678903 + 32019012 + 01329801 + 10456732""".trimIndent().lines() + + @TestFactory + fun `What is the sum of the scores of all trailheads on your topographic map`() = + listOf( + trailheadScore6 to 3, + trailheadScore7 to 13, + trailheadScore8 to 227, + trailheadScore9 to 81, + ).map { (map, score) -> + DynamicTest.dynamicTest("The sum of the scores of all trailheads on the topographic map is $score") { + assertThat(Day10(map).partTwo()).isEqualTo(score) + } + } + } +} \ No newline at end of file