Day 18
This commit is contained in:
184
src/main/kotlin/com/basdado/adventofcode/Day18.kt
Normal file
184
src/main/kotlin/com/basdado/adventofcode/Day18.kt
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
package com.basdado.adventofcode
|
||||||
|
|
||||||
|
import java.util.stream.Collectors
|
||||||
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
|
const val DAY18_INPUT = "/day/18/input.txt"
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
|
||||||
|
val day = Day18()
|
||||||
|
day.puzzle1()
|
||||||
|
println("Puzzle 2 took " + measureTimeMillis { day.puzzle2() } + " ms")
|
||||||
|
}
|
||||||
|
|
||||||
|
class Day18 {
|
||||||
|
|
||||||
|
fun puzzle1() {
|
||||||
|
|
||||||
|
val area = parseInput()
|
||||||
|
|
||||||
|
val afterTime = evaluateTime(area, 10)
|
||||||
|
|
||||||
|
val lumberCount = afterTime.area.count { it == AcreType.LUMBERYARD }
|
||||||
|
val treeCount = afterTime.area.count { it == AcreType.TREES }
|
||||||
|
|
||||||
|
println(lumberCount * treeCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun puzzle2() {
|
||||||
|
|
||||||
|
val area = parseInput()
|
||||||
|
|
||||||
|
val afterTime = evaluateTime(area, 1000000000)
|
||||||
|
|
||||||
|
val lumberCount = afterTime.area.count { it == AcreType.LUMBERYARD }
|
||||||
|
val treeCount = afterTime.area.count { it == AcreType.TREES }
|
||||||
|
|
||||||
|
println(lumberCount * treeCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun evaluateTime(area: LumberArea, minutes: Int): LumberArea {
|
||||||
|
|
||||||
|
var oldArea = area.clone()
|
||||||
|
|
||||||
|
val seen = mutableMapOf(Pair(area, 0))
|
||||||
|
|
||||||
|
var minute = 1
|
||||||
|
while(minute <= minutes) {
|
||||||
|
|
||||||
|
val newArea = LumberArea(area.width, area.height)
|
||||||
|
|
||||||
|
for (y in 0 until oldArea.height) {
|
||||||
|
for (x in 0 until oldArea.width) {
|
||||||
|
when (oldArea.get(x, y)) {
|
||||||
|
AcreType.OPEN -> newArea.set(
|
||||||
|
x, y,
|
||||||
|
if (oldArea.countAdjacent(x, y, AcreType.TREES) >= 3)
|
||||||
|
AcreType.TREES
|
||||||
|
else
|
||||||
|
AcreType.OPEN
|
||||||
|
)
|
||||||
|
AcreType.TREES -> newArea.set(
|
||||||
|
x, y,
|
||||||
|
if (oldArea.countAdjacent(x, y, AcreType.LUMBERYARD) >= 3)
|
||||||
|
AcreType.LUMBERYARD
|
||||||
|
else
|
||||||
|
AcreType.TREES
|
||||||
|
)
|
||||||
|
AcreType.LUMBERYARD -> newArea.set(
|
||||||
|
x, y,
|
||||||
|
if (oldArea.countAdjacent(x, y, AcreType.LUMBERYARD) >= 1 && oldArea.countAdjacent(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
AcreType.TREES
|
||||||
|
) >= 1
|
||||||
|
) {
|
||||||
|
AcreType.LUMBERYARD
|
||||||
|
} else {
|
||||||
|
AcreType.OPEN
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val repeatingMinute = seen[newArea]
|
||||||
|
if (repeatingMinute != null) {
|
||||||
|
val repeatLength = minute - repeatingMinute
|
||||||
|
val cycleSkip = ((minutes - minute) / repeatLength) * repeatLength
|
||||||
|
println("Found cycle of $repeatLength minutes between $minute and $repeatingMinute, skipping $cycleSkip")
|
||||||
|
minute += cycleSkip
|
||||||
|
seen.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
seen[newArea] = minute
|
||||||
|
|
||||||
|
oldArea = newArea
|
||||||
|
|
||||||
|
minute++
|
||||||
|
}
|
||||||
|
return oldArea
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseInput(): LumberArea {
|
||||||
|
|
||||||
|
val input = lines(DAY18_INPUT).collect(Collectors.toList())
|
||||||
|
|
||||||
|
val res = LumberArea(input[0].length, input.size)
|
||||||
|
for (y in 0 until input.size) {
|
||||||
|
for(x in 0 until input[y].length) {
|
||||||
|
res.set(x, y, acreType(input[y][x]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fun acreType(c: Char): AcreType = AcreType.values().find { it.char == c }!!
|
||||||
|
|
||||||
|
enum class AcreType(val char: kotlin.Char) {
|
||||||
|
OPEN('.'), TREES('|'), LUMBERYARD('#')
|
||||||
|
}
|
||||||
|
class LumberArea(val width: Int, val height: Int, val area: Array<AcreType> = Array(width * height) { AcreType.OPEN }) {
|
||||||
|
|
||||||
|
private fun index(x: Int, y: Int): Int = y * width + x
|
||||||
|
fun get(x: Int, y: Int): AcreType {
|
||||||
|
return if (x !in 0 until width || y !in 0 until height)
|
||||||
|
AcreType.OPEN
|
||||||
|
else
|
||||||
|
area[index(x, y)]
|
||||||
|
}
|
||||||
|
fun set(x: Int, y: Int, acre: AcreType) {
|
||||||
|
area[index(x, y)] = acre
|
||||||
|
}
|
||||||
|
|
||||||
|
fun countAdjacent(x: Int, y: Int, type: AcreType): Int {
|
||||||
|
return (if (get(x + 1, y) == type) 1 else 0) +
|
||||||
|
(if (get(x + 1, y + 1) == type) 1 else 0) +
|
||||||
|
(if (get(x, y + 1) == type) 1 else 0) +
|
||||||
|
(if (get(x - 1, y + 1) == type) 1 else 0) +
|
||||||
|
(if (get(x - 1, y) == type) 1 else 0) +
|
||||||
|
(if (get(x - 1, y - 1) == type) 1 else 0) +
|
||||||
|
(if (get(x, y - 1) == type) 1 else 0) +
|
||||||
|
(if (get(x + 1, y - 1) == type) 1 else 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
|
||||||
|
val res = StringBuilder()
|
||||||
|
for(y in 0 until height) {
|
||||||
|
for(x in 0 until width) {
|
||||||
|
res.append(get(x, y).char)
|
||||||
|
}
|
||||||
|
res.append("\r\n")
|
||||||
|
}
|
||||||
|
return res.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as LumberArea
|
||||||
|
|
||||||
|
if (width != other.width) return false
|
||||||
|
if (height != other.height) return false
|
||||||
|
if (!area.contentEquals(other.area)) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = width
|
||||||
|
result = 31 * result + height
|
||||||
|
result = 31 * result + area.contentHashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clone(): LumberArea {
|
||||||
|
return LumberArea(width, height, area.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/main/resources/day/18/example.txt
Normal file
10
src/main/resources/day/18/example.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
.#.#...|#.
|
||||||
|
.....#|##|
|
||||||
|
.|..|...#.
|
||||||
|
..|#.....#
|
||||||
|
#.#|||#|#|
|
||||||
|
...#.||...
|
||||||
|
.|....|...
|
||||||
|
||...#|.#|
|
||||||
|
|.||||..|.
|
||||||
|
...#.|..|.
|
||||||
50
src/main/resources/day/18/input.txt
Normal file
50
src/main/resources/day/18/input.txt
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
.|#.#|..#...|..##||...|#..##..#..|#|....#.#|.|....
|
||||||
|
.||....#..#...|#....#.||....||...||...|..#|..||..|
|
||||||
|
......|.|.#.#.#..|.....#.###.....#........|.||..#|
|
||||||
|
..|.....||...#||#.#|#.....|##.|.|....|#....#|..#.#
|
||||||
|
|...#.|..#|#.#....|.#.#.|.#...#..#|#.....##|#..#.|
|
||||||
|
#....|#|......#.|||..#..#..||...#.#...|||##|..|#..
|
||||||
|
.#||.|....|.......#|##...|.#.....#.##...|.|.#...#|
|
||||||
|
....#|.|.|...##.......|#.....|..#......#...#|.#..#
|
||||||
|
...#.|....#.|.#...|||......##..|#|||#..#...|.|#.#.
|
||||||
|
.#..|...|..#.|##.#.#......#...||.||.#...|.#.#.#|..
|
||||||
|
|...#.|||...#|.#||.......|.##.....|..||...####...|
|
||||||
|
.##..|..##|...##.#...#...#.#|.|###...#............
|
||||||
|
|.....||...#.......|.#..|#.....|.|#.|..||.##.|#|..
|
||||||
|
.#..##|.#|.|..|.#..#.|.#..#|......##...#.#.......#
|
||||||
|
...#.##.|..|.#.....#....#..#.............|.|##||..
|
||||||
|
||.##.||.|.|..|..#.|.|.##|.|...|.#.|#.......#.|...
|
||||||
|
..|#.##..#|.#|#.#...........|.|........#...#|...#|
|
||||||
|
....|.#|..|.#|#|...|.|.#..#.....#|##|||##.#....#..
|
||||||
|
...###.#.....#.||......#|#..##...|#....#....|#|.#.
|
||||||
|
.##.|.##|.#.||....#|....|.#.|#.|....##..#.##|.....
|
||||||
|
|...|...#|....#....#...#|#...|..#.#.|.|.....|.#|..
|
||||||
|
.|.|.#.#.#|.#.|#....|.|###..#......|...|...#.|#...
|
||||||
|
..|...||.|..##|...|..|#|...|......#.||.#...#..|#.|
|
||||||
|
........|..#||..|....|.....|.|#..#....|#..|.#.....
|
||||||
|
#.|.|#....#...|..|....|.#.....||.....|..|........#
|
||||||
|
...||||....|.#.|....#..#....|###....|...#...##....
|
||||||
|
|||........|.#|.|......||#.|.....|.||#|.##....#|..
|
||||||
|
.....|#|#..||#...|##.|..||....####.|#.|..#....|.#.
|
||||||
|
.||..#||....#.....#.#|.|....|.##|..|.#..|##....##.
|
||||||
|
.|#.#|#|#|.....||..|.|.|.#......#..|.#..#..|.#||#.
|
||||||
|
|.|#.......|..#|#|....|.#.#.#.|...|.......##.|||#|
|
||||||
|
..|.....#...||.|....|##|...#..#.#.....|##|##.##...
|
||||||
|
.|.|..##.#|..|.|#.......#....#||.|...||#...|......
|
||||||
|
|.|##.#....|#..|....#..#..|##.|.##..#......#|##|..
|
||||||
|
..#....#.|#...#.#...|.....|.||.#.#|.#.|###..|..#.#
|
||||||
|
..|.##...........|..###.||.|.##.|....|.|.#|#.#.|#|
|
||||||
|
..|....|.|#|...#|#...|.#......#.#||...|.#|...#.|#.
|
||||||
|
..#.......|.||.....||.|....|#||..........#...|#...
|
||||||
|
.|..#....|#|||#..##||..#|.......|..|###..|.#...|.|
|
||||||
|
|..|.#|.#...#....|.....#.....#....#...|..|.|.#.|.#
|
||||||
|
....###.#....|.#..#...#...###.|.|.....#|...#.....|
|
||||||
|
..#....##.....##..|.#.||#.|.#|#||..|...#|..|.#....
|
||||||
|
|#..#.#|||#.|#..#........#......||...#.|..#|....#|
|
||||||
|
......#|...#.|...#...|.|...|#|#......#|.##.#|.|.#|
|
||||||
|
#||.#......#.##......#..||.##|.|.||..|#....#..#...
|
||||||
|
#.#...#.|.#|#||#.#......#....|##|.........##.#|...
|
||||||
|
.....###...#||....|####..#|||...#..#|.|....#|..#..
|
||||||
|
......|#..#.#.#..|.#|#||..||.|...#....##...|......
|
||||||
|
...#...|..#..##.||.#.#.....|.###.....##|#||..#..#|
|
||||||
|
.#..#||.#....||....|##..|||...|.||...#..##.#....#.
|
||||||
Reference in New Issue
Block a user