This commit is contained in:
Chris Hodges 2024-12-18 07:05:44 +01:00
parent b0e4461a7d
commit 1b2332a49e
2 changed files with 129 additions and 2 deletions

View File

@ -75,11 +75,11 @@ class CharGrid {
val data: Array<CharArray> val data: Array<CharArray>
val bChar: Char val bChar: Char
constructor(width: Int, height: Int, borderChar: Char = ' ') { constructor(width: Int, height: Int, borderChar: Char = ' ', fillChar: Char = borderChar) {
bChar = borderChar bChar = borderChar
this.width = width this.width = width
this.height = height this.height = height
data = Array(height) { CharArray(width) { bChar } } data = Array(height) { CharArray(width) { fillChar } }
} }
constructor(input: List<String>, borderChar: Char = ' ') { constructor(input: List<String>, borderChar: Char = ' ') {

127
src/aoc2024/Day18.kt Normal file
View 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()
}