Skip to content

Commit be48364

Browse files
committed
20
1 parent 5f975b3 commit be48364

File tree

5 files changed

+287
-17
lines changed

5 files changed

+287
-17
lines changed

.idea/workspace.xml

Lines changed: 32 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/kotlin/16.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ fun solve16b(lines: List<String>): Int {
9797
return visitedBackwards.map { it.first }.toSet().size
9898
}
9999

100-
private sealed interface MazeField
101-
private object MazeWall : MazeField
102-
private object MazeEmpty : MazeField
103-
104100
private data class Input16(val maze: Map<Point, MazeField>, val start: Point, val end: Point)
105101

106102
private fun parseInput(lines: List<String>): Input16 {

src/main/kotlin/20.kt

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
fun main() {
2+
println(solve20a(readInputLines("20")))
3+
println(solve20b(readInputLines("20")))
4+
}
5+
6+
fun solve20a(lines: List<String>): Int = solve20ForDistance(lines, cheatingDistance = 2)
7+
fun solve20b(lines: List<String>): Int = solve20ForDistance(lines, cheatingDistance = 20)
8+
9+
private fun solve20ForDistance(lines: List<String>, cheatingDistance: Int): Int {
10+
val (maze, start, end) = parseInput(lines)
11+
12+
val scoresFromStart = getDistancesFromPoint(maze, start)
13+
val scoresFromEnd = getDistancesFromPoint(maze, end)
14+
val withoutCheating = checkNotNull(scoresFromStart[end])
15+
16+
var count = 0
17+
for ((p, _) in maze.entries.filter {
18+
it.value is MazeEmpty && scoresFromStart.getOrDefault(
19+
it.key, Int.MAX_VALUE
20+
) < withoutCheating
21+
}) {
22+
val fromStart = checkNotNull(scoresFromStart[p])
23+
val availableFields =
24+
getPointsWithinDistance(maze, p, cheatingDistance).filter { maze[it] is MazeEmpty && it in scoresFromEnd }
25+
26+
for (p2 in availableFields) {
27+
val total = fromStart + p2.distance(p) + checkNotNull(scoresFromEnd[p2])
28+
29+
if (withoutCheating - total >= 100) {
30+
count += 1
31+
}
32+
}
33+
}
34+
35+
return count
36+
}
37+
38+
private data class Input20(val maze: Map<Point, MazeField>, val start: Point, val end: Point)
39+
40+
private fun parseInput(lines: List<String>): Input20 {
41+
val map = mutableMapOf<Point, MazeField>()
42+
var start: Point? = null
43+
var end: Point? = null
44+
45+
for ((y, line) in lines.withIndex()) {
46+
for ((x, c) in line.withIndex()) {
47+
val p = Point(x, y)
48+
if (c == 'E') {
49+
end = p
50+
} else if (c == 'S') {
51+
start = p
52+
}
53+
54+
val field = if (c == '#') MazeWall else MazeEmpty
55+
map[p] = field
56+
}
57+
}
58+
59+
return Input20(map, checkNotNull(start), checkNotNull(end))
60+
}
61+
62+
private fun getDistancesFromPoint(maze: Map<Point, MazeField>, start: Point): Map<Point, Int> {
63+
val visited = mutableSetOf(start)
64+
val dq = ArrayDeque<Pair<Point, Int>>()
65+
dq.addLast(Pair(start, 0))
66+
val scores = mutableMapOf(Pair(start, 0))
67+
68+
while (dq.isNotEmpty()) {
69+
val (p, s) = dq.removeFirst()
70+
scores[p] = s
71+
72+
for (d in Direction.values()) {
73+
val p2 = move(d, p)
74+
if (maze[p2] is MazeEmpty && p2 !in visited) {
75+
visited.add(p2)
76+
dq.addLast(Pair(p2, s + 1))
77+
}
78+
}
79+
}
80+
81+
return scores
82+
}
83+
84+
fun getPointsWithinDistance(maze: Map<Point, MazeField>, start: Point, distance: Int): Set<Point> {
85+
val visited = mutableSetOf(start)
86+
val dq = ArrayDeque<Pair<Point, Int>>()
87+
dq.addLast(Pair(start, 0))
88+
89+
while (dq.isNotEmpty()) {
90+
val (p, s) = dq.removeFirst()
91+
92+
if (s == distance) {
93+
continue
94+
}
95+
96+
for (d in Direction.values()) {
97+
val p2 = move(d, p)
98+
if (p2 !in visited && p2 in maze) {
99+
visited.add(p2)
100+
dq.addLast(Pair(p2, s + 1))
101+
}
102+
}
103+
}
104+
105+
return visited - start
106+
}

src/main/kotlin/Common.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import java.io.File
2+
import java.lang.Math.abs
23

34
private fun getFile(fileName: String): File = File("src/main/kotlin/input/${fileName}.txt")
45

@@ -14,6 +15,8 @@ data class Point(val x: Int, val y: Int) {
1415
if (newY < 0) newY + v.y else newY
1516
)
1617
}
18+
19+
fun distance(p2: Point): Int = abs(p2.x - x) + abs(p2.y - y)
1720
}
1821
data class PointL(val x: Long, val y: Long) {
1922
operator fun plus(v: VectorL): PointL = PointL(x + v.x, y + v.y)
@@ -63,4 +66,8 @@ fun rotateCounterclockwise(d: Direction): Direction =
6366
Direction.LEFT -> Direction.DOWN
6467
Direction.DOWN -> Direction.RIGHT
6568
Direction.RIGHT -> Direction.UP
66-
}
69+
}
70+
71+
sealed interface MazeField
72+
object MazeWall : MazeField
73+
object MazeEmpty : MazeField

0 commit comments

Comments
 (0)