Skip to content

Commit 4c52726

Browse files
committed
Add solution for Y2024D10.
1 parent 9c65d9d commit 4c52726

File tree

6 files changed

+103
-1
lines changed

6 files changed

+103
-1
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ _"Anything that's worth doing, is worth overdoing."_
1515
Table of contents to jump straight to the problem you're looking for.
1616

1717
<details open>
18-
<summary>2024 (18x⭐)</summary>
18+
<summary>2024 (20x⭐)</summary>
1919

2020
| Day | Title | Stars |
2121
|:---:|:-----------------------------------------------------------|:-----:|
@@ -28,6 +28,7 @@ Table of contents to jump straight to the problem you're looking for.
2828
| 07 | [Bridge Repair](solutions/aockt/y2024/Y2024D07.kt) | ⭐⭐ |
2929
| 08 | [Resonant Collinearity](solutions/aockt/y2024/Y2024D08.kt) | ⭐⭐ |
3030
| 09 | [Disk Fragmenter](solutions/aockt/y2024/Y2024D09.kt) | ⭐⭐ |
31+
| 10 | [Hoof It](solutions/aockt/y2024/Y2024D10.kt) | ⭐⭐ |
3132

3233
</details>
3334

inputs/aockt/y2024/d10/input.txt

2.92 KB
Binary file not shown.
26 Bytes
Binary file not shown.
27 Bytes
Binary file not shown.

solutions/aockt/y2024/Y2024D10.kt

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package aockt.y2024
2+
3+
import aockt.util.parse
4+
import aockt.util.spacial.*
5+
import io.github.jadarma.aockt.core.Solution
6+
7+
object Y2024D10 : Solution {
8+
9+
/** A hiking trail topographical map. */
10+
private class TopographicMap(private val data: Grid<Int>) : Grid<Int> by data {
11+
12+
/** The locations of trailheads, or points with zero altitude. */
13+
val trailHeads: Set<Point> = data.points().mapNotNull { (p, v) -> p.takeIf { v == 0 } }.toSet()
14+
15+
/**
16+
* Calculates the score of this [trailHead], or how many peaks can be reached from here.
17+
* If the point is not a trailhead, the score is 0.
18+
*/
19+
fun scoreOf(trailHead: Point): Int = trailPathsFrom(trailHead, distinct = true).size
20+
21+
/**
22+
* Calculates the rating of this [trailHead], or how many different routes you can take to reach a peak.
23+
* If the point is not a trailhead, the rating is 0.
24+
*/
25+
fun ratingOf(trailHead: Point): Int = trailPathsFrom(trailHead, distinct = false).size
26+
27+
/**
28+
* Finds all the trail paths from the [start] point, and returns the location of their peaks.
29+
* If the point is not a trailhead, returns an empty list.
30+
* If [distinct], duplicate paths to the same peak are discarded.
31+
*/
32+
private fun trailPathsFrom(start: Point, distinct: Boolean): List<Point> = buildList {
33+
if (start !in trailHeads) return@buildList
34+
val area = Area(width, height)
35+
val visited = mutableSetOf<Point>()
36+
37+
fun recurse(point: Point) {
38+
val altitude = data[point]
39+
40+
if (altitude == 9) {
41+
if (!distinct || point !in visited) add(point)
42+
visited.add(point)
43+
}
44+
45+
Direction.all
46+
.asSequence()
47+
.map(point::move)
48+
.filter { it in area }
49+
.filter { data[it] == altitude + 1 }
50+
.forEach(::recurse)
51+
}
52+
53+
recurse(start)
54+
}
55+
}
56+
57+
/** Parse the [input] and return the [TopographicMap] of the hiking region. */
58+
private fun parseInput(input: String): TopographicMap = parse {
59+
val data = Grid(input) { it.digitToInt() }
60+
TopographicMap(data)
61+
}
62+
63+
override fun partOne(input: String): Int = parseInput(input).run { trailHeads.sumOf(::scoreOf) }
64+
override fun partTwo(input: String): Int = parseInput(input).run { trailHeads.sumOf(::ratingOf) }
65+
}

tests/aockt/y2024/Y2024D10Test.kt

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package aockt.y2024
2+
3+
import io.github.jadarma.aockt.test.AdventDay
4+
import io.github.jadarma.aockt.test.AdventSpec
5+
6+
@AdventDay(2024, 10, "Hoof It")
7+
class Y2024D10Test : AdventSpec<Y2024D10>({
8+
9+
val example1 = """
10+
0123
11+
1234
12+
8765
13+
9876
14+
""".trimIndent()
15+
16+
val example2 = """
17+
89010123
18+
78121874
19+
87430965
20+
96549874
21+
45678903
22+
32019012
23+
01329801
24+
10456732
25+
""".trimIndent()
26+
27+
partOne {
28+
example1 shouldOutput 1
29+
example2 shouldOutput 36
30+
}
31+
32+
partTwo {
33+
example1 shouldOutput 16
34+
example2 shouldOutput 81
35+
}
36+
})

0 commit comments

Comments
 (0)