Day 18.
This commit is contained in:
parent
b0e4461a7d
commit
1b2332a49e
@ -75,11 +75,11 @@ class CharGrid {
|
||||
val data: Array<CharArray>
|
||||
val bChar: Char
|
||||
|
||||
constructor(width: Int, height: Int, borderChar: Char = ' ') {
|
||||
constructor(width: Int, height: Int, borderChar: Char = ' ', fillChar: Char = borderChar) {
|
||||
bChar = borderChar
|
||||
this.width = width
|
||||
this.height = height
|
||||
data = Array(height) { CharArray(width) { bChar } }
|
||||
data = Array(height) { CharArray(width) { fillChar } }
|
||||
}
|
||||
|
||||
constructor(input: List<String>, borderChar: Char = ' ') {
|
||||
|
127
src/aoc2024/Day18.kt
Normal file
127
src/aoc2024/Day18.kt
Normal file
@ -0,0 +1,127 @@
|
||||
package aoc2024
|
||||
|
||||
import CharGrid
|
||||
import RelPos
|
||||
import println
|
||||
import readInput
|
||||
import splitInts
|
||||
import java.util.*
|
||||
|
||||
/*
|
||||
--- Day 18: RAM Run ---
|
||||
https://adventofcode.com/2024/day/18
|
||||
*/
|
||||
fun main() {
|
||||
|
||||
val inlineTestInput = """
|
||||
5,4
|
||||
4,2
|
||||
4,5
|
||||
3,0
|
||||
2,1
|
||||
6,3
|
||||
2,4
|
||||
1,5
|
||||
0,6
|
||||
3,3
|
||||
2,6
|
||||
5,1
|
||||
1,2
|
||||
5,5
|
||||
2,5
|
||||
6,5
|
||||
1,4
|
||||
0,4
|
||||
6,4
|
||||
1,1
|
||||
6,1
|
||||
1,0
|
||||
0,5
|
||||
1,6
|
||||
2,0
|
||||
"""
|
||||
|
||||
data class Node(val pos: RelPos, val relLen: Int)
|
||||
|
||||
fun part1(input: List<String>, steps: Int, wh: Int): Int {
|
||||
val posList = input.map { it.splitInts(",").toIntArray() }
|
||||
val grid = CharGrid(wh, wh, '#', fillChar = '.')
|
||||
posList.take(steps).forEach { grid[it[0], it[1]] = '#' }
|
||||
val queue = PriorityQueue<Node>(Comparator.comparing { -it.pos.dc - it.pos.dr })
|
||||
queue.add(Node(RelPos(0, 0), 0))
|
||||
val bestCosts = HashMap<RelPos, Int>()
|
||||
var minCost = Int.MAX_VALUE
|
||||
while (queue.isNotEmpty()) {
|
||||
val node = queue.remove()
|
||||
val pos = node.pos
|
||||
val cost = node.relLen
|
||||
if (pos.dc == wh - 1 && pos.dr == wh - 1) {
|
||||
minCost = minCost.coerceAtMost(cost)
|
||||
continue
|
||||
}
|
||||
if ((bestCosts[pos] ?: Int.MAX_VALUE) < cost) {
|
||||
continue
|
||||
}
|
||||
bestCosts[pos] = cost
|
||||
queue.addAll(CharGrid.PLUS_POS
|
||||
.map { pos.translate(it) }
|
||||
.filter { grid[it] == '.' && (bestCosts[it] ?: Int.MAX_VALUE) > cost + 1 }
|
||||
.map { Node(it, cost + 1) })
|
||||
}
|
||||
return minCost
|
||||
}
|
||||
|
||||
fun part2(input: List<String>, wh: Int): RelPos {
|
||||
val posList = input.map { it.splitInts(",").toIntArray() }
|
||||
var lowerBound = 0
|
||||
var higherBound = posList.size
|
||||
do {
|
||||
val grid = CharGrid(wh, wh, '#', fillChar = '.')
|
||||
val boulderPos = (lowerBound + higherBound) / 2
|
||||
posList.take(boulderPos).forEach { grid[it[0], it[1]] = '#' }
|
||||
|
||||
var foundPath = false
|
||||
val queue = PriorityQueue<Node>(Comparator.comparing { -it.pos.dc - it.pos.dr })
|
||||
queue.add(Node(RelPos(0, 0), 0))
|
||||
val bestCosts = HashMap<RelPos, Int>()
|
||||
while (queue.isNotEmpty()) {
|
||||
val node = queue.remove()
|
||||
val pos = node.pos
|
||||
val cost = node.relLen
|
||||
if (pos.dc == wh - 1 && pos.dr == wh - 1) {
|
||||
foundPath = true
|
||||
break
|
||||
}
|
||||
if ((bestCosts[pos] ?: Int.MAX_VALUE) < cost) {
|
||||
continue
|
||||
}
|
||||
bestCosts[pos] = cost
|
||||
queue.addAll(CharGrid.PLUS_POS
|
||||
.map { pos.translate(it) }
|
||||
.filter { grid[it] == '.' && (bestCosts[it] ?: Int.MAX_VALUE) > cost + 1 }
|
||||
.map { Node(it, cost + 1) })
|
||||
}
|
||||
if (foundPath) {
|
||||
lowerBound = boulderPos + 1
|
||||
} else {
|
||||
higherBound = boulderPos
|
||||
}
|
||||
} while (lowerBound < higherBound)
|
||||
println("$lowerBound $higherBound")
|
||||
return RelPos(posList[lowerBound - 1][0], posList[lowerBound - 1][1])
|
||||
}
|
||||
|
||||
// test if implementation meets criteria from the description, like:
|
||||
val testInput = inlineTestInput.trim().reader().readLines()
|
||||
//val testInput = readInput("aoc2024/Day18_test")
|
||||
val testInputPart1Result = part1(testInput, 12, 7)
|
||||
println("Part 1 Test: $testInputPart1Result")
|
||||
val testInputPart2Result = part2(testInput, 7)
|
||||
println("Part 2 Test: $testInputPart2Result")
|
||||
check(testInputPart1Result == 22)
|
||||
check(testInputPart2Result == RelPos(6, 1))
|
||||
|
||||
val input = readInput("aoc2024/Day18")
|
||||
part1(input, 1024, 71).println()
|
||||
part2(input, 71).println()
|
||||
}
|
Loading…
Reference in New Issue
Block a user