day(15): add solution
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
01bf675081
commit
acf453d45e
2 changed files with 136 additions and 0 deletions
126
src/year2021/day15/Day15.kt
Normal file
126
src/year2021/day15/Day15.kt
Normal file
|
@ -0,0 +1,126 @@
|
|||
package year2021.day15
|
||||
|
||||
import readInput
|
||||
import java.util.*
|
||||
|
||||
fun validAdjacentIndices(input: List<List<Int>>, y0: Int, x0: Int): Iterable<Pair<Int, Int>> =
|
||||
(y0 - 1..y0 + 1)
|
||||
.flatMap { y -> (x0 - 1..x0 + 1).map { x -> Pair(y, x) } }
|
||||
.filter { (y, x) ->
|
||||
(y != y0 || x != x0) && (y == y0 || x == x0) && (y >= 0 && y < input.size) && (x >= 0 && x < input[y].size)
|
||||
}
|
||||
|
||||
fun validAdjacentIndicesExtended(input: List<List<Int>>, y0: Int, x0: Int): Iterable<Pair<Int, Int>> =
|
||||
(y0 - 1..y0 + 1)
|
||||
.flatMap { y -> (x0 - 1..x0 + 1).map { x -> Pair(y, x) } }
|
||||
.filter { (y, x) ->
|
||||
(y != y0 || x != x0) && (y == y0 || x == x0) && (y >= 0 && y < 5 * input.size) && (x >= 0 && x < 5 * input[0].size)
|
||||
}
|
||||
|
||||
data class Coordinate(val y: Int, val x: Int)
|
||||
|
||||
fun part1(input: List<List<Int>>): Int {
|
||||
val final = Coordinate(input.size - 1, input.last().size - 1)
|
||||
|
||||
val queue = PriorityQueue<Pair<Int, Coordinate>>() { a, b ->
|
||||
a.first - b.first
|
||||
}
|
||||
val distances = mutableMapOf<Coordinate, Int>()
|
||||
val processed = mutableSetOf<Coordinate>()
|
||||
|
||||
queue.add(Pair(0, Coordinate(0, 0)))
|
||||
distances[Coordinate(0, 0)] = 0
|
||||
for (y in input.indices) {
|
||||
for (x in input[y].indices) {
|
||||
queue.add(Pair(Int.MAX_VALUE, Coordinate(y, x)))
|
||||
}
|
||||
}
|
||||
|
||||
while (queue.isNotEmpty()) {
|
||||
val (distance, coordinate) = queue.remove()!!
|
||||
if (processed.contains(coordinate)) {
|
||||
continue
|
||||
}
|
||||
processed.add(coordinate)
|
||||
|
||||
if (coordinate == final) {
|
||||
return distance
|
||||
}
|
||||
|
||||
for ((y, x) in validAdjacentIndices(input, coordinate.y, coordinate.x)) {
|
||||
val neighbour = Coordinate(y, x)
|
||||
val alternative = distance + input[y][x]
|
||||
|
||||
if (alternative < (distances[neighbour] ?: Int.MAX_VALUE)) {
|
||||
distances[neighbour] = alternative
|
||||
queue.add(Pair(alternative, neighbour))
|
||||
}
|
||||
}
|
||||
}
|
||||
return Int.MAX_VALUE
|
||||
}
|
||||
|
||||
fun getDistance(input: List<List<Int>>, y: Int, x: Int): Int {
|
||||
val riskLevel = input[y % input.size][x % input[0].size]
|
||||
val added = y / input.size + x / input[0].size
|
||||
|
||||
if (riskLevel + added > 9) {
|
||||
return riskLevel + added - 9
|
||||
}
|
||||
|
||||
return riskLevel + added
|
||||
}
|
||||
|
||||
fun part2(input: List<List<Int>>): Int {
|
||||
val final = Coordinate(5 * input.size - 1, 5 * input.last().size - 1)
|
||||
|
||||
val queue = PriorityQueue<Pair<Int, Coordinate>>() { a, b ->
|
||||
a.first - b.first
|
||||
}
|
||||
val distances = mutableMapOf<Coordinate, Int>()
|
||||
val processed = mutableSetOf<Coordinate>()
|
||||
|
||||
queue.add(Pair(0, Coordinate(0, 0)))
|
||||
distances[Coordinate(0, 0)] = 0
|
||||
for (y in input.indices) {
|
||||
for (x in input[y].indices) {
|
||||
for (i in 0 until 5) {
|
||||
queue.add(Pair(Int.MAX_VALUE, Coordinate(i * y, i * x)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (queue.isNotEmpty()) {
|
||||
val (distance, coordinate) = queue.remove()!!
|
||||
if (processed.contains(coordinate)) {
|
||||
continue
|
||||
}
|
||||
processed.add(coordinate)
|
||||
|
||||
if (coordinate == final) {
|
||||
return distance
|
||||
}
|
||||
|
||||
for ((y, x) in validAdjacentIndicesExtended(input, coordinate.y, coordinate.x)) {
|
||||
val neighbour = Coordinate(y, x)
|
||||
val alternative = distance + getDistance(input, y, x)
|
||||
|
||||
if (alternative < (distances[neighbour] ?: Int.MAX_VALUE)) {
|
||||
distances[neighbour] = alternative
|
||||
queue.add(Pair(alternative, neighbour))
|
||||
}
|
||||
}
|
||||
}
|
||||
return Int.MAX_VALUE
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val sample = readInput(15, "sample").map { row -> row.map { it.digitToInt() } }
|
||||
val input = readInput(15, "input").map { row -> row.map { it.digitToInt() } }
|
||||
|
||||
check(part1(sample) == 40)
|
||||
println(part1(input))
|
||||
|
||||
check(part2(sample) == 315)
|
||||
println(part2(input))
|
||||
}
|
10
src/year2021/day15/sample.txt
Normal file
10
src/year2021/day15/sample.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
1163751742
|
||||
1381373672
|
||||
2136511328
|
||||
3694931569
|
||||
7463417111
|
||||
1319128137
|
||||
1359912421
|
||||
3125421639
|
||||
1293138521
|
||||
2311944581
|
Loading…
Reference in a new issue