Skip to content

Commit b6b3af8

Browse files
committed
Day 18 finished
1 parent c9ebd4f commit b6b3af8

File tree

6 files changed

+3563
-7
lines changed

6 files changed

+3563
-7
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2025 James Carman
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package adventofcode.day18
18+
19+
import adventofcode.util.geom.plane.Point2D
20+
import adventofcode.util.graph.Graphs
21+
import adventofcode.util.grid.TextGrid
22+
23+
fun String.parsePoints(): List<Point2D> = lines()
24+
.map { it.split(',').map { split -> split.toInt() } }
25+
.map { (x, y) -> Point2D(x, y) }
26+
27+
fun List<Point2D>.generateMap() = TextGrid(List(maxOf { it.y } + 1) { ".".repeat(maxOf { it.x } + 1) })
28+
29+
fun String.findFirstByteThatBlocksExit(): Point2D {
30+
val points = parsePoints()
31+
val map = points.generateMap()
32+
val start = map.coordinates().first()
33+
val end = map.coordinates().last()
34+
val vertices = map.coordinates().filter { map[it] != '#' }.toSet()
35+
val neighbors = { p: Point2D -> p.neighbors().filter { it in map }.filter { map[it] != '#' } }
36+
return points.find { p ->
37+
map[p] = '#'
38+
!Graphs.shortestPaths(start, vertices, neighbors).pathExists(end)
39+
} ?: throw IllegalStateException("No byte blocks exit")
40+
}
41+
42+
fun String.findShortestPathToExitAfter(nBytes: Int): Int {
43+
val points = parsePoints()
44+
val map = points.generateMap()
45+
points.take(nBytes).forEach { map[it] = '#' }
46+
val vertices = map.coordinates().filter { map[it] != '#' }.toSet()
47+
val neighbors = { p: Point2D -> p.neighbors().filter { it in map }.filter { map[it] != '#' } }
48+
return Graphs.shortestPaths(
49+
map.coordinates().first(),
50+
vertices,
51+
neighbors
52+
) { _, _ -> 1.0 }.pathTo(map.coordinates().last()).size - 1
53+
}

src/main/kotlin/adventofcode/util/graph/Graphs.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ object Graphs {
8989
start: V,
9090
vertices: Set<V>,
9191
neighbors: (V) -> List<V>,
92-
weight: (V, V) -> Double
92+
weight: (V, V) -> Double = { _, _ -> 1.0 }
9393
): ShortestPaths<V> {
9494
val pred = mutableMapOf<V, V>()
9595
val dist = mutableMapOf<V, Double>()

src/test/kotlin/adventofcode/Day18Test.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,35 @@
1616

1717
package adventofcode
1818

19+
import adventofcode.day18.findFirstByteThatBlocksExit
20+
import adventofcode.day18.findShortestPathToExitAfter
21+
import adventofcode.util.geom.plane.Point2D
1922
import io.kotest.matchers.shouldBe
2023
import org.junit.jupiter.api.Test
2124

2225
class Day18Test {
2326

2427
@Test
2528
fun example1() {
26-
calculatePart1(readExample1()) shouldBe 0
29+
calculatePart1(readExample1(), 12) shouldBe 22
2730
}
2831

2932
@Test
3033
fun part1() {
31-
calculatePart1(readInput()) shouldBe 0
34+
calculatePart1(readInput(), 1024) shouldBe 326
3235
}
3336

3437
@Test
3538
fun example2() {
36-
calculatePart2(readExample2()) shouldBe 0
39+
calculatePart2(readExample2()) shouldBe Point2D(6,1)
3740
}
3841

3942
@Test
4043
fun part2() {
41-
calculatePart2(readInput()) shouldBe 0
44+
calculatePart2(readInput()) shouldBe Point2D(18,62)
4245
}
4346

44-
private fun calculatePart1(input: String): Int = 0
47+
private fun calculatePart1(input: String, bytes:Int): Int = input.findShortestPathToExitAfter(bytes)
4548

46-
private fun calculatePart2(input: String): Int = 0
49+
private fun calculatePart2(input: String): Point2D = input.findFirstByteThatBlocksExit()
4750
}

src/test/resources/day18-example1.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
5,4
2+
4,2
3+
4,5
4+
3,0
5+
2,1
6+
6,3
7+
2,4
8+
1,5
9+
0,6
10+
3,3
11+
2,6
12+
5,1
13+
1,2
14+
5,5
15+
2,5
16+
6,5
17+
1,4
18+
0,4
19+
6,4
20+
1,1
21+
6,1
22+
1,0
23+
0,5
24+
1,6
25+
2,0

src/test/resources/day18-example2.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
5,4
2+
4,2
3+
4,5
4+
3,0
5+
2,1
6+
6,3
7+
2,4
8+
1,5
9+
0,6
10+
3,3
11+
2,6
12+
5,1
13+
1,2
14+
5,5
15+
2,5
16+
6,5
17+
1,4
18+
0,4
19+
6,4
20+
1,1
21+
6,1
22+
1,0
23+
0,5
24+
1,6
25+
2,0

0 commit comments

Comments
 (0)