This commit is contained in:
Chris Hodges 2024-12-20 07:19:34 +01:00
parent 9047a97185
commit aa0f1dad74

104
src/aoc2024/Day20.kt Normal file
View File

@ -0,0 +1,104 @@
package aoc2024
import CharGrid
import RelPos
import println
import readInput
import kotlin.math.abs
/*
--- Day 20: Race Condition ---
https://adventofcode.com/2024/day/20
*/
fun main() {
val inlineTestInput = """
###############
#...#...#.....#
#.#.#.#.#.###.#
#S#...#.#.#...#
#######.#.#.###
#######.#.#...#
#######.#.###.#
###..E#...#...#
###.#######.###
#...###...#...#
#.#####.#.###.#
#.#...#.#.#...#
#.#.#.#.#.#.###
#...#...#...###
###############
"""
data class Node(val pos: RelPos, val relLen: Int)
fun getPathCosts(grid: CharGrid, startPos: RelPos, endPos: RelPos): HashMap<RelPos, Int> {
val queue = ArrayDeque<Node>()
queue.add(Node(startPos, 0))
val bestCosts = HashMap<RelPos, Int>()
while (queue.isNotEmpty()) {
val node = queue.removeFirst()
val pos = node.pos
val cost = node.relLen
bestCosts[pos] = cost
if (pos == endPos) {
break
}
queue.addAll(CharGrid.PLUS_POS
.map { pos.translate(it) }
.filter { grid[it] == '.' && !bestCosts.contains(it) }
.map { Node(it, cost + 1) })
}
return bestCosts
}
fun part1(input: List<String>): Int {
val grid = CharGrid(input)
val start = grid.findMatchesRelPos { it == 'S' }[0]
val end = grid.findMatchesRelPos { it == 'E' }[0]
grid[end] = '.'
val cheats = listOf(
RelPos(0, -1), RelPos(-1, 0), RelPos(1, 0), RelPos(0, 1),
RelPos(0, -2), RelPos(-2, 0), RelPos(2, 0), RelPos(0, 2),
)
val pathCosts = getPathCosts(grid, start, end)
return pathCosts.asSequence().sumOf { (pos, cost) ->
cheats.map { pos.translate(it) to (abs(it.dr) + abs(it.dc)) }
.filter { (pathCosts[it.first] ?: 0) - (cost + it.second) >= 100 }
.map { it.first to (pathCosts[it.first]!! - (cost + it.second)) }.count()
}
}
fun part2(input: List<String>): Int {
val grid = CharGrid(input)
val start = grid.findMatchesRelPos { it == 'S' }[0]
val end = grid.findMatchesRelPos { it == 'E' }[0]
grid[end] = '.'
val pathCosts = getPathCosts(grid, start, end)
// manhattan distance!
val pathCostsList = pathCosts.toList()
return pathCostsList.sumOf { (pos, cost) ->
pathCostsList.asSequence().filter { abs(pos.dc - it.first.dc) + abs(pos.dr - it.first.dr) <= 20 }
.filter { (pathCosts[it.first] ?: 0) - (cost + abs(pos.dc - it.first.dc) + abs(pos.dr - it.first.dr)) >= 100 }
.map { it.first to (pathCosts[it.first]!! - (cost + it.second)) }.count()
}
}
// test if implementation meets criteria from the description, like:
val testInput = inlineTestInput.trim().reader().readLines()
//val testInput = readInput("aoc2024/Day20_test")
val testInputPart1Result = part1(testInput)
println("Part 1 Test: $testInputPart1Result")
val testInputPart2Result = part2(testInput)
println("Part 2 Test: $testInputPart2Result")
check(testInputPart1Result == 0)
check(testInputPart2Result == 0)
val input = readInput("aoc2024/Day20")
part1(input).println()
part2(input).println()
}