Last active
December 11, 2021 11:06
-
-
Save pchmielowski/94392ec124b293aab5880097a828c012 to your computer and use it in GitHub Desktop.
Advent of code 2021, day 11
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.File | |
fun main() { | |
val file = File("input.txt") | |
val lines = file.readLines() | |
val initial = parseInitialStep(lines) | |
println(countFlashes(initial, steps = 100)) | |
println(findFirstStepWithSyncFlash(initial)) | |
} | |
fun parseInitialStep(input: List<String>) = input | |
.map { line -> | |
line | |
.split("") | |
.filterNot(String::isEmpty) | |
.map(::Energy) | |
} | |
.let(::Step) | |
// Day 11, part 1 | |
fun countFlashes(initial: Step, steps: Int): Int { | |
var current = initial | |
var count = 0 | |
repeat(steps + 1) { | |
count += current.flashesCount | |
current = current | |
.reset() | |
.increaseEnergies() | |
.triggerFlashes() | |
} | |
return count | |
} | |
// Day 11, part 2 | |
fun findFirstStepWithSyncFlash(initial: Step): Int { | |
var current = initial | |
var step = 0 | |
while (true) { | |
if (current.areFlashesInSync) { | |
return step | |
} | |
current = current | |
.reset() | |
.increaseEnergies() | |
.triggerFlashes() | |
step++ | |
} | |
} | |
data class Step( | |
private val energies: List<List<Energy>>, | |
private val flashes: Set<Coordinate> = emptySet(), | |
) { | |
val areFlashesInSync get() = flashes.size == energies.sumOf { column -> column.size } | |
val flashesCount get() = flashes.size | |
fun increaseEnergies() = copy( | |
energies = energies | |
.map { line -> | |
line.map(Energy::increase) | |
} | |
) | |
fun triggerFlashes(): Step { | |
// Break recursion if no more flashes in this step | |
val flashing = findNextFlash() ?: return this | |
val updated = energies.mapIndexed { rowIndex, row -> | |
row.mapIndexed { columnIndex, energy -> | |
if (isAdjacent(flashing, row = rowIndex, column = columnIndex)) { | |
energy.increase() | |
} else { | |
energy | |
} | |
} | |
} | |
return copy(energies = updated, flashes = flashes + flashing).triggerFlashes() | |
} | |
private fun findNextFlash(): Coordinate? { | |
energies.forEachIndexed { rowIndex, row -> | |
row.forEachIndexed { columnIndex, energy -> | |
val coordinate = Coordinate(rowIndex, columnIndex) | |
if (energy.canFlash && !flashes.contains(coordinate)) { | |
return coordinate | |
} | |
} | |
} | |
return null | |
} | |
private fun isAdjacent(coordinate: Coordinate, row: Int, column: Int): Boolean { | |
if (row == coordinate.row && column == coordinate.column) { | |
return false | |
} | |
if (row in (coordinate.row - 1..coordinate.row + 1)) { | |
if (column in (coordinate.column - 1..coordinate.column + 1)) { | |
return true | |
} | |
} | |
return false | |
} | |
fun reset() = copy( | |
energies = energies.map { column -> | |
column.map(Energy::reset) | |
}, | |
flashes = emptySet(), | |
) | |
data class Coordinate(val row: Int, val column: Int) | |
} | |
@JvmInline | |
value class Energy(private val value: Int) { | |
constructor(raw: String) : this(raw.toInt()) | |
init { | |
require(0 <= value) | |
} | |
val canFlash get() = value > 9 | |
fun increase() = Energy(value + 1) | |
fun reset() = Energy(if (value > 9) 0 else value) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment