From 537ec6de18e500b9f0b8ed41d9db984b090a66d5 Mon Sep 17 00:00:00 2001 From: Alexander Gehrke Date: Sun, 12 Dec 2021 02:12:44 +0100 Subject: [PATCH] Day 11 --- .../scala/de.qwertyuiop.aoc/2021/day11.scala | 54 ++++++++++++++++++- .../de.qwertyuiop.aoc/lib/extensions.scala | 2 + .../scala/de.qwertyuiop.aoc/lib/vectors.scala | 4 ++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/main/scala/de.qwertyuiop.aoc/2021/day11.scala b/src/main/scala/de.qwertyuiop.aoc/2021/day11.scala index be34951..f5ff801 100644 --- a/src/main/scala/de.qwertyuiop.aoc/2021/day11.scala +++ b/src/main/scala/de.qwertyuiop.aoc/2021/day11.scala @@ -3,4 +3,56 @@ package de.qwertyuiop.aoc.`2021` import de.qwertyuiop.aoc.lib.* import cats.*, cats.implicits.given -def day11(using InputSource): Unit = ??? +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) diff --git a/src/main/scala/de.qwertyuiop.aoc/lib/extensions.scala b/src/main/scala/de.qwertyuiop.aoc/lib/extensions.scala index 5d12212..c613daa 100644 --- a/src/main/scala/de.qwertyuiop.aoc/lib/extensions.scala +++ b/src/main/scala/de.qwertyuiop.aoc/lib/extensions.scala @@ -9,6 +9,8 @@ extension [A](input: List[A])(using CanEqual[A,A]) case (h, tail @ (_ :: t)) => h #:: (if keepSeparator then tail else t).split(separator) +extension [A](iterable: Iterable[A]) + def occurrences: Map[A, Int] = iterable.groupMapReduce(identity)(_ => 1)(_ + _) /* Using -Yexplicit-nulls isn't really ready for use with the java standard * library. e.g. String doesn't have `@NotNull` annotations for its methods diff --git a/src/main/scala/de.qwertyuiop.aoc/lib/vectors.scala b/src/main/scala/de.qwertyuiop.aoc/lib/vectors.scala index 685d53d..f6edbd4 100644 --- a/src/main/scala/de.qwertyuiop.aoc/lib/vectors.scala +++ b/src/main/scala/de.qwertyuiop.aoc/lib/vectors.scala @@ -99,6 +99,10 @@ object Vectors: neighs case Some(neighs) => neighs.asInstanceOf[Vector[Vector[T]]] + extension[A](v: IndexedSeq[IndexedSeq[A]]) def get(p: Vec2D[Int]): A = v(p.x)(p.y) + extension[A](v: IndexedSeq[IndexedSeq[IndexedSeq[A]]]) def get(p: Vec3D[Int]): A = v(p.x)(p.y)(p.z) + extension[A](v: IndexedSeq[IndexedSeq[IndexedSeq[IndexedSeq[A]]]]) def get(p: Vec4D[Int]): A = v(p.x)(p.y)(p.z)(p.w) + object Directions: opaque type Dir = Int val East: Dir = 0