day(06): refactor
Signed-off-by: Matej Focko <me@mfocko.xyz>
This commit is contained in:
parent
965f2ea9f5
commit
b78c91e5db
1 changed files with 32 additions and 45 deletions
77
src/Day06.kt
77
src/Day06.kt
|
@ -1,9 +1,11 @@
|
||||||
|
private typealias Vector = Pair<Int, Int>
|
||||||
|
|
||||||
class Day06(
|
class Day06(
|
||||||
inputType: String,
|
inputType: String,
|
||||||
) : Day<Int, Int>() {
|
) : Day<Int, Int>() {
|
||||||
private val map: Array<CharArray> = readInput(6, inputType).map { it.toCharArray() }.toTypedArray()
|
private val map: Array<CharArray> = readInput(6, inputType).map { it.toCharArray() }.toTypedArray()
|
||||||
|
|
||||||
private val initialPosition: Pair<Int, Int> =
|
private val initialPosition: Vector =
|
||||||
let {
|
let {
|
||||||
for (row in map.withIndex()) {
|
for (row in map.withIndex()) {
|
||||||
for (cell in row.value.withIndex()) {
|
for (cell in row.value.withIndex()) {
|
||||||
|
@ -16,76 +18,61 @@ class Day06(
|
||||||
error("there's always at least one guard")
|
error("there's always at least one guard")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val route: Set<Pair<Int, Int>> =
|
private val route: Set<Vector> = guard(null).let { (visited, _) -> visited.map { (_, p) -> p }.toSet() }
|
||||||
let {
|
|
||||||
var pos = initialPosition
|
|
||||||
var direction = 0 to -1
|
|
||||||
|
|
||||||
val seen = mutableSetOf<Pair<Int, Int>>()
|
|
||||||
while (inBounds(pos)) {
|
|
||||||
seen.add(pos)
|
|
||||||
|
|
||||||
var next = move(pos, direction)
|
|
||||||
while (!canMoveTo(next)) {
|
|
||||||
direction = rotate(direction)
|
|
||||||
next = move(pos, direction)
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = next
|
|
||||||
}
|
|
||||||
|
|
||||||
return@let seen
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun precompute() {
|
override fun precompute() {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inBounds(p: Pair<Int, Int>): Boolean =
|
private fun inBounds(p: Vector): Boolean =
|
||||||
p.let { (x, y) ->
|
p.let { (x, y) ->
|
||||||
y >= 0 && y < map.size && x >= 0 && x < map[y].size
|
y >= 0 && y < map.size && x >= 0 && x < map[y].size
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun move(
|
private fun move(
|
||||||
p: Pair<Int, Int>,
|
p: Vector,
|
||||||
d: Pair<Int, Int>,
|
d: Vector,
|
||||||
): Pair<Int, Int> {
|
): Vector {
|
||||||
val (x, y) = p
|
val (x, y) = p
|
||||||
val (dx, dy) = d
|
val (dx, dy) = d
|
||||||
return x + dx to y + dy
|
return x + dx to y + dy
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun canMoveTo(p: Pair<Int, Int>): Boolean =
|
private fun canMoveTo(p: Vector): Boolean =
|
||||||
p.let { (x, y) ->
|
p.let { (x, y) ->
|
||||||
!inBounds(p) || map[y][x] != '#'
|
!inBounds(p) || map[y][x] != '#'
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun rotate(d: Pair<Int, Int>): Pair<Int, Int> =
|
private fun rotate(d: Vector): Vector =
|
||||||
d.let { (dx, dy) ->
|
d.let { (dx, dy) ->
|
||||||
-dy to dx
|
-dy to dx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun guard(obstacle: Vector?): Pair<Set<Pair<Vector, Vector>>, Vector> {
|
||||||
|
var pos = initialPosition
|
||||||
|
var direction = 0 to -1
|
||||||
|
|
||||||
|
val visited = mutableSetOf<Pair<Vector, Vector>>()
|
||||||
|
while (inBounds(pos) && !visited.contains(direction to pos)) {
|
||||||
|
visited.add(direction to pos)
|
||||||
|
|
||||||
|
var next = move(pos, direction)
|
||||||
|
while (next == obstacle || !canMoveTo(next)) {
|
||||||
|
direction = rotate(direction)
|
||||||
|
next = move(pos, direction)
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = next
|
||||||
|
}
|
||||||
|
|
||||||
|
return visited to pos
|
||||||
|
}
|
||||||
|
|
||||||
override fun part1(): Int = route.size
|
override fun part1(): Int = route.size
|
||||||
|
|
||||||
override fun part2(): Int =
|
override fun part2(): Int =
|
||||||
route.filter { it != initialPosition }.count { o ->
|
route.filter { it != initialPosition }.count {
|
||||||
var pos = initialPosition
|
guard(it).let { (_, pos) -> inBounds(pos) }
|
||||||
var direction = 0 to -1
|
|
||||||
|
|
||||||
val visited = mutableSetOf<Pair<Pair<Int, Int>, Pair<Int, Int>>>()
|
|
||||||
while (inBounds(pos) && !visited.contains(direction to pos)) {
|
|
||||||
visited.add(direction to pos)
|
|
||||||
|
|
||||||
var next = move(pos, direction)
|
|
||||||
while (next == o || !canMoveTo(next)) {
|
|
||||||
direction = rotate(direction)
|
|
||||||
next = move(pos, direction)
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = next
|
|
||||||
}
|
|
||||||
|
|
||||||
inBounds(pos)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue