This commit is contained in:
2018-12-18 23:22:40 +01:00
parent a4471f5886
commit 576a74d571
4 changed files with 1979 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
package com.basdado.adventofcode
import kotlin.math.max
val DAY17_INPUT = "/day/17/input.txt"
fun main() {
val day = Day17()
day.puzzle1()
day.puzzle2()
}
class Day17 {
fun puzzle1() {
val ground = parseInput()
flowWaterFrom(ground, 500, 0)
println(ground.ground.filter { x -> x == GroundType.FLOWING_WATER || x == GroundType.STILL_WATER }.count())
}
fun puzzle2() {
val ground = parseInput()
flowWaterFrom(ground, 500, 0)
println(ground.ground.filter { x -> x == GroundType.STILL_WATER }.count())
}
private fun flowWaterFrom(ground: Ground, startX: Int, startY: Int) {
// println("Flowing from $startX, $startY")
// println(ground)
var flowStartedLastRound = false
while(true) {
// println(ground)
var y = max(startY, ground.startY)
var x = startX
if (!ground.waterCanPenetrate(x, y)) {
return
}
while (y + 1 < ground.startY + ground.height && ground.waterCanPenetrate(x, y + 1)) {
y++
}
val firstGroundHit = Vector2(x, y)
if (y >= ground.startY + ground.height - 1 || ground.get(x, y + 1) == GroundType.FLOWING_WATER) {
// If we hit flowing water or the end of the ground, we're done, the water flows from the source to here:
for (waterFlowY in max(startY, ground.startY)..y) {
ground.set(x, waterFlowY, GroundType.FLOWING_WATER)
}
return
}
// let's check if we're in a pool-type thing:
while (ground.waterCanPenetrate(x, y) && ground.waterCanFlowOn(x, y + 1)) {
x++
}
val wallRight = ground.get(x, y) == GroundType.CLAY
val wallRightX = x
x = firstGroundHit.x
y = firstGroundHit.y
while (ground.waterCanPenetrate(x, y) && ground.waterCanFlowOn(x, y + 1)) {
x--
}
val wallLeft = ground.get(x, y) == GroundType.CLAY
val wallLeftX = x
// If we're in a pool-type thing, we're dealing with still water
// If we're not in a pool-type thing, we're dealing with flowing water
if (wallLeft && wallRight) {
((wallLeftX + 1)..(wallRightX - 1)).forEach { waterX -> ground.set(waterX, y, GroundType.STILL_WATER) }
flowStartedLastRound = false
} else if (!flowStartedLastRound) {
if (!wallLeft) {
flowWaterFrom(ground, wallLeftX, y)
flowStartedLastRound = true
}
if (!wallRight) {
flowWaterFrom(ground, wallRightX, y)
flowStartedLastRound = true
}
} else {
((wallLeftX + 1)..(wallRightX - 1)).forEach { waterX -> ground.set(waterX, y, GroundType.FLOWING_WATER) }
flowStartedLastRound = false
}
}
}
fun parseInput(): Ground {
val scannerRegex = Regex("""([xy])=(\d+),\s*([xy])=(\d+)..(\d+)""")
val clayCoordinates = mutableSetOf<Vector2>()
lines(DAY17_INPUT)
.map { scannerRegex.matchEntire(it)!! }
.forEach{
if (it.groupValues[1] == "x") {
val x = it.groupValues[2].toInt()
assert(it.groupValues[3] == "y")
for (y in it.groupValues[4].toInt()..it.groupValues[5].toInt()) {
clayCoordinates.add(Vector2(x, y))
}
} else {
val y = it.groupValues[2].toInt()
assert(it.groupValues[3] == "x")
for (x in it.groupValues[4].toInt()..it.groupValues[5].toInt()) {
clayCoordinates.add(Vector2(x, y))
}
}
}
val minX = clayCoordinates.map { it.x }.min()!!
val maxX = clayCoordinates.map { it.x }.max()!!
val minY = clayCoordinates.map { it.y }.min()!!
val maxY = clayCoordinates.map { it.y }.max()!!
val width = maxX - minX + 1
val height = maxY - minY + 1
val ground = Ground(width, height, minX, minY)
clayCoordinates.forEach{ ground.set(it.x, it.y, GroundType.CLAY )}
return ground
}
enum class GroundType(val char: kotlin.Char) {
CLAY('#'), SAND('.'), STILL_WATER('~'), FLOWING_WATER('|')
}
data class Vector2(val x: Int, val y: Int)
class Ground (val width: Int, val height: Int, val startX: Int, val startY: Int) {
var ground: Array<GroundType> = Array(width * height) {GroundType.SAND}
fun index(x: Int, y: Int): Int = (y - startY) * width + (x - startX)
fun set(x: Int, y: Int, groundType: GroundType) {
ground[index(x, y)] = groundType
}
fun get (x: Int, y: Int): GroundType = ground[index(x, y)]
fun waterCanPenetrate(x: Int, y: Int): Boolean {
val type = get(x, y)
return type == GroundType.SAND
}
fun waterCanFlowOn(x: Int, y: Int): Boolean {
val type = get(x, y)
return type == GroundType.CLAY || type == GroundType.STILL_WATER
}
override fun toString(): String {
val res = StringBuilder()
for (y in startY until (startY + height)) {
for (x in startX until (startX + width)) {
res.append(get(x, y).char)
}
res.append("\r\n")
}
return res.toString()
}
}
}

View File

@@ -0,0 +1,8 @@
x=495, y=2..7
y=7, x=495..501
x=501, y=3..7
x=498, y=2..4
x=506, y=1..2
x=498, y=10..13
x=504, y=10..13
y=13, x=498..504

View File

@@ -0,0 +1,8 @@
x=488, y=1..2
x=510, y=1..2
x=495, y=2..7
x=505, y=2..7
y=7, x=495..505
x=490, y=10..13
x=500, y=10..13
y=13, x=490..500

File diff suppressed because it is too large Load Diff