advent-of-code-2021/src/main/scala/de.qwertyuiop.aoc/2021/day11.scala
Alexander Gehrke 537ec6de18 Day 11
2021-12-12 02:12:44 +01:00

59 lines
1.9 KiB
Scala

package de.qwertyuiop.aoc.`2021`
import de.qwertyuiop.aoc.lib.*
import cats.*, cats.implicits.given
import Vectors.{*, given}
def day11(using InputSource): Unit =
import Octopodes.*
val fieldRaw = inputF(_.map(_ - '0').toVector)(Vector)
val field = (
for
x <- 0 until fieldRaw.size
y <- 0 until fieldRaw(0).size
yield Vec2D(x,y) -> fieldRaw(x)(y)
).toMap
val r = render(fieldRaw.size, fieldRaw(0).size)
val (finalField, finalFlashes) =
(1 to 100).foldLeft((field, 0)){ case ((field, flashes), _) =>
val (newField, newFlashes) = energize(field)
(newField, flashes + newFlashes)
}
println(s"After $finalFlashes flashes:")
r(finalField)
val inSync = findSync(field, 0)
println(s"In sync after $inSync steps")
object Octopodes:
def render(xSize: Int, ySize: Int)(field: Map[Vec2D[Int], Int]) =
for x <- 0 until xSize do
for y <- 0 until ySize do
print(field(Vec2D(x,y)).toHexString)
println()
def energize(f: Map[Vec2D[Int], Int]): (Map[Vec2D[Int], Int], Int) =
@annotation.tailrec
def flashOctopodes(f: Map[Vec2D[Int], Int], flashed: Set[Vec2D[Int]]): (Map[Vec2D[Int], Int], Int) =
val flashing = f.filter((coord, v) => v > 9).keySet &~ flashed
if flashing.isEmpty then
(f.view.mapValues(v => if v > 9 then 0 else v).toMap, flashed.size + flashing.size)
else
val neighs = flashing.toVector.flatMap(_.neighbours).occurrences
val newF = f.map((coord, v) => coord -> (
if v > 9 || flashing.contains(coord) then 12
else (v + neighs.getOrElse(coord, 0)).min(11)
))
flashOctopodes(newF, flashed | flashing)
flashOctopodes(f.mapValuesS(_ + 1), Set.empty)
def findSync(f: Map[Vec2D[Int], Int], step: Int): Int =
val (newField, newFlashes) = energize(f)
if newFlashes == f.size then step + 1
else findSync(newField, step + 1)