From 06d7128ac1f6ad49b4e0b2cafe9b9a0e6ec59b55 Mon Sep 17 00:00:00 2001 From: Alexander Gehrke Date: Mon, 20 Dec 2021 22:02:42 +0100 Subject: [PATCH] Day 20. First attempt at visualization --- input/2021/day20-sample1.txt | 7 ++ input/2021/day20.txt | 102 ++++++++++++++++++ .../scala/de.qwertyuiop.aoc/2021/day20.scala | 81 +++++++++++++- .../scala/de.qwertyuiop.aoc/lib/vectors.scala | 4 + 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 input/2021/day20-sample1.txt create mode 100644 input/2021/day20.txt diff --git a/input/2021/day20-sample1.txt b/input/2021/day20-sample1.txt new file mode 100644 index 0000000..8fa4bd4 --- /dev/null +++ b/input/2021/day20-sample1.txt @@ -0,0 +1,7 @@ +..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..# + +#..#. +#.... +##..# +..#.. +..### diff --git a/input/2021/day20.txt b/input/2021/day20.txt new file mode 100644 index 0000000..e3014d7 --- /dev/null +++ b/input/2021/day20.txt @@ -0,0 +1,102 @@ +##...#####.###...##.##..###.#..####..#.####......#.#.##..#.###.##.#..#...##.#.##..######..##.#.##..#..##.......#.#.#.######......#.##...##.#.#...###...#.##.###.##.#.##.#..#.####.#.#.####.#..#.#.##.....#####.#..##......####...#..####..#.##.#.#...#.#.#.#...#..##.###..#..##.#...#.##.###..#######.#.###.###.###.#.#.###.#####...#.#.###.##...#..##.#.#..#...#####.....##..###.###..#.#.#.#...####.#...#.####.#.##.#.##...###.####.#.#.###..#...#.##.##.##..#...##.#....#####..#..#..#...#..#.#.#.#..####....#.#....#..###.#. + +.####..####.#.##..##..###...#.##.......##.##..####....##.##.#..##......####..#.#....###....#.....##. +.##.###...###.#.#..#..#...###......##..####...#.###..##.###..##....#####.##..##..#####.#.#.....##.## +...#.#.##...#.....#..##.#.##...#####..#.##.#.##...###.###......#...##...#.###...####..###..#.#####.# +###.#.###.......#.#..##.#..##.##.###..#....#.#...#.#..##.#...##.#.#..#.####..###...####.#..#.#..#... +##..##..####...######.####.####...#...##.......#...##..#####..#..#....###.#..#.#..#.##.#.##.##.#.... +#..######.#.....#...#...#...#.#.##.#..##.##.##.#.........##.###.##.#..###..#......#.#.#..#.##...#.#. +#..#.######.####.###.#.##.####.#.#...####.#.###.######.##....#.#.....###..###.#.###.#...#######.###. +#.###.#..........#..###..#.####.#.##.##.####.#...##.#####.#...##...#.###...#..#.##.##..#####.##..#.# +.##..####.#..##..###...###.###.##.##...##...##...##.#......###.#..#.##.##...........#.#...##.##.#... +...###....##.#....#...###...##.##.#...###..####...#.#...#.....###.#.##.####.##.#..#....#..#.####..#. +.####.##.#..##..#..###.####..#####.#..##.####.#.####...##.##..##.#.###.###.#...##..##.#.##..#.##..#. +..#..##..##...##..#.#.#.#.#####.#.##.#....#.######.##.....#.....##..#..##.##....##..#....######.#.## +#.######.###.####.#####..#.#...###..###.###.#.##.#.##########........####...#.##......#..#...#.###.. +######...##..#.###.###.##.....#.###.##..#..##......#..#..#..#..##..#...#.#..#####..#....#.####..##.. +.#.......#.#.##..#.##.#...####.##.##..##.##.#.######.##..###.##.###....#.#.#.##.#...#.####.#.#.#.##. +...#.#.#.###....###.#.#..###.#..#..#..#....##..##.#..##..#..#...#..#...#...####.#.#.#.###..#.#...#.# +##.#..#..####.#..#...#.#.##...#.#..#...###..####.#.......##.######.##....##...#.#...##.#.##.#...#..# +....##..#..##.....#.#.######.##.#.#.#.####.##.###.###.##.#.....#.##..###.##.##.#.#..#..##..##..#.#.# +#.##.#.#.#..#.####.#####...#.##.#.##.###..###.#.##.....####.#..##.###....#...###.#.#.#.#.##.#.#..### +###......###..####..###....#.#######.#.###.##.##..######..#.#..#####..####.....#.##...#..##..#.....# +####..#..#...####..##..#####..###.##.#...#.##..#..###.#......#...####.#.#..##..#.##.##..####..#..#.# +..##..###..#.##..###..#....##.#.....#.#.##.#..##...##.#.#.....#..##.......##..#...#.##.#.#.....#.#.. +#.#.#..##.##...##.###.#.##...###..##..###...#...#.#.#.#..##.#.#..#..#.#...###.#.#....#.#....###.#### +##..####...##..#.#..#....####.##...##.#..#..##.#.###.##..#..#..#...##.#.....##.###..#.##.###..#.#..# +##..#.......##.#.#.##.######.#..##.###.###..##...##.#.#.#.###..###.##.##..#.#..#..##.#.##.##.....### +##...#.##......##....#..#..#####...##.###.####.#.#.#.#...##..#####.....#...##.#.###..##.###...##...# +#..##.#..#.##...##.#..#.###..#..##...#...#..#.##.#...####..##........##.....#.#####.#.##.###.#...##. +.#.##....####.##..##.##..##.###.#..#.##..##..#.#...#.#.....#.#..####.###.##.####...#.#####.#....#... +.#..#####.#..##..##..#..#..####.#.....#.#..##..##.#.#...##..##.#..#.##.#.##...##.#.#.#...#.#.#..##.. +#..........##..#..#...#.#.##.#...##..###..#...#.#...#.####.#.#..#..#.###.#.##...######..#..#..###..# +..#.##.###.####...####..##...#..####.#.#.####.##.###.......#.#.#.##....#.##.##...##.#.#....##..#...# +.##..#.###.#.#.#.#..#####..#..#.....####..#####.#######.......#.####.#.#...##..#..#...#........###.. +.#.#.#..#.#.###..##.##....#..#...#.#####.#.####...#.#...#.##...#.##....#..##.##.##..#.##..#.#..#..#. +..##...##..###.....#.#......###.##.#.###.#.#.#......#..#..##..##..#...##.......####.#.#.#.#.#..#..## +..#.#..#.#.##.##.##.....#..#####.#..####.##...#..##..#..###..##...###.#......#..##.#.......###.##.## +.#...##....#....####.##.###.##.#.##..#..###.##...##..##..##..###.#..#....##...#####...####...#.#..## +....####...#..#.#.#.###.##..#..#######.#..#..#.##..####.#...#..##..#.##.###.##.###...#...#...####### +..####.##....###...#.....##.##...##......####..#.###...####....#.###...#.#.#######....##.##.#####... +........#.########.#.#.###...#..##.#..##.###.##...#...#.###.##.#.....#...#.#.#.#####.###....####.#.. +...#....#...#.##.#....##.###..##.#.#...#.##..#...#..##........####.#.###.#...####.##..##...#.####... +#.#.#..##.#.#...........#.#.#.##..#.#...####.#########...#.##.###.#.#####..###.#.#..#...#####.####.. +..##.####...##.##.#.###..##...#...####.##....#.##..####.#.##.#...#....#...#.##..##.##....#.#.....##. +#.#.##.#.#####.###.##......###..#..#####.#...#####..###.###.#####.#..#####.#.##.#.#.#.....##.#.##..# +#...#..###..#...#.#.###...#.###.##.#.###.###..##...##.#...##.#.###....##..#...##....#.....###..#.#.# +...##.##.#.###.###......#.##.####.#...##.##.#.#..####..####.###.##....#..#...##....#..#.####.##..#.# +##...#...##..#######.#.#..##.#..#...#.#.##.##.#.##...####...######.#######.#..###..#.#.##.#####..##. +####..#####.####.#####..#..###..###...#.#..#..##.#..#.###.#.####..###..#....##....#####..###.#....#. +.###..#.##...######..#######.##..#....#######...##.#..#.##.#.###..#.####....#...##..#...####....#.#. +##....#.##.#.##.##.##.#.##..###.#.#...##..#..##..#.#######......#.###.#.#.#...#..##..##....#...##... +.#.#.#..##.....########..###.##..#....#..#####.##...#...####.####.##..###..#....#.######.##.#..####. +#.##.#.#...##.###.#.#.#.#.##....#...####..##...##....###.#....#...##.##..##...#.#.##....#.##..#..### +.##.#...###.....#.#.#.##..#.#.......#....##.#.#.#..##.####.##..##.#.##.##.########.....#....###.##.# +##..#..#.#.####.###.###...##...#...####.####..#...#....#..###...##.#.#...##...###.#.##.###.##.##.##. +.#..####.##..#.#...##..####.#..##.#....##.####..#.#.#.#..#####....###..##.#..#.#..#..#.###.#....#.## +##..####.#....##.###.#....#.....#..##..#.......#...##.###...#...####.#.###.#.####...###.#####.#..#.# +###...#.##.###...###..#....#.#...#..##..##...###....#.##....#.#...##.##..##.#..#.#.##.#.........#### +##..#.#######.##..#..###.###..#.#.####...##..####....########.#.###.#....#####.....#.#....##..##...# +##.####.....###...##.....##.#..######..##..##.##..##..#..##.##.#......##.#.##....#...#.....##...#... +#.#.##.##.#.####...#.#..#.#...###.#####.#...##.##..#.##.#.#.#####.##..#.##..##.#..##..#.###.#...#.## +#.###.#..###.#.##...#.....####.##.##..##..#....##.##......#.#.#..#####...##....#...#.####.#.##.##.## +##..####....#####.##..##.#.#####.##.###.##..#.#####...#....#.###....##.#..#....#.##...#.#.##..#....# +#..##.###.#.##..###.#...####..##.########.#.#......#.###.##...#.#.#..##....#.##....##..#.##..#.#.#.# +#.#..#..#.####.#.##.#####.#..#.....#####..#..#..##.####.#.#..#..##.#.#.#..#.#....#.########.##...... +#...#.##.####..###.#....#.#...#..##.##.##..#...#...###.#########..##..#########..##.##########..##.. +#..##..#.#.##..........#....#.#..####.#.##.###.#.#####..##....#.......#..#..#.#.##.#.####.####.##..# +##.#####...##.#######.#..#.###.###..####.#..##.###.#..##.##.##...###..###..##.#..###.###......####.. +###.#.#####.###..####...##..#.###.##...#####.#####..######...####.#..####.#..##.##.#.#.#.##.###.##.# +.#..##.##....#..#..##.##.#.#.###..#.#.#.....####..###.#..#.#.#.##...#.#.##.#...##.#.##..####.#####.. +....###..##.#.###.#..#.##...##.##.#..###..#.#...#....##...########..####.###.#.##.#..##...#....#.### +#.####..##..######.####....#.#.....#.#.#.....#....##.#......####..######..#..#..###..#..#.....##..#. +.#..#..#...#.#...###.#..#####......#....#.#...#.####.....#..#..#.#.#...###.#.###.###.#######.#..#.#. +###.#...#.##.#..##...#..#....##.##.#..###..#..#.###.#.....##..##..#.#####.#.#....#.#.#.#...######### +##..#...#######.###.#.##.#.###.#..##.###...#.#..##.####....#####..######..##..#.#####.####.....#.... +#..##..##.#...#.#..#.#....##..#..#.##.#.....#.#...#.#.#####.....#...#.##..#.....#.###..#####...##.#. +##...####.###.#.##.#....##.##....##..##.##....#....#.....##..##.###.##.##....#..#...###..##..#.##### +##.#.##.##..#..#....#.#..#.######.#.###.#.##.#..#....##.#.#.##....#####.#...#.#####...#.#....###.... +###...#..##..##.#....##.##..#..#..####..#.##.#..####..####...#.#.###.#....###..##.#.##...####.###..# +...#..##.#.##..###.##....#..#########...##.#####.#..##.#####.##.##..###.#.#.##.####.#....##.#.##.#.# +..##..#.###.##.#....#.####....#.#......#####..######..##...#...#.##.##.##.#......#..#..#.###..#.##.. +#.#.....###.##.###.#.##.#.#..#...#..#.#.#.######.##..#.##.##.#.#.##..#.#.#.#....######....#.####.##. +#.......###..######.....#..##.##...#####.#.##..#..##..##...##.#....#....####..#..##.#..###.#..##.#.. +..#.###.##.#.#.#.#..###...#.###.#.#.##....#..##..#...##...#.##...##.#..###.........###...#.#....#..# +#.#..#..#.....###..#.##..#...#.....###..##..#..#..#..#.#.##.#.##..####..#....##..##.##.#.#.#.....### +.##.#####..#.####....########.#.##.##.#..###..####..###.###.#...###.##.##.#########.###....#..#...## +.###.#..#....#.#######.#....##.#.#..##.##.#####.##..#####..##.#.######.#..##....#...#....#...#####.# +.##.#..##.#.##..###.##..##...#.#..####.##.###....##..##.#...#..#..#....########.###.##.#.#.##.#.###. +.#..####..#.#####...#####..##...####..####......#..##.##.##.#..#.....##..#........##.##.#...##.#.... +###.#...#.....######..##.#..#....##.###..#...###.##.#..#...###.###...####.#..#......##.##.#..###..## +..##.##.###...#..##..####.##..#.#.#..#..#####...#.#.#..##.#..#.#.###..##.###.#..##.##.##..##.##..### +###..#....#.#.....##.##..####........##.###.#..#####....###..##.###.##.##..###...#.##.#.####.####.#. +#.....#..#.###.#######.###.#..#.##.#.##.###.###.##.##.###....######.#...#...#....##.#..###..###.#..# +.#.#.###.#.#..##...#.#.#..#...#.##..##.....###.###....##.#...#.#....#...###.#..#.##...#.#.#...##..## +...#..###....###.###.#.#.#..#.#.###.#.###...#......#..#..#..#.#.#..#.####...##.......###.#..######## +#.###..#..###..#.#.#.####.#..##..#.####...#.##...###...#..#.##...#..##.#######...#.#.#.##..##.#..... +#.#.#..#...#..#..#....##..###.##.##..#.##.#.###..##.#.##.##..#..........#..##..##..###..#......#.#.. +.##########.#.#.##.#.####.###.#.#...##..#..#.######.#...##.####..#..##...#.....##..###..##...#.#...# +#..##.##.##.##.####..#.##...##..###.#.##.#.#..#.##..###..#..#...#.#.####.....#.##..#...##....##..##. +.##.#....##..#.##...##.#.##.##....###.#.#####..##.....#.##..#.###.#....###.##...###.###.#....#..##.# +..####..#..####.#...#.#.#..####.#...######.####.###.##....#.###.#.######.##.#..###..####......#..#.. +.###..##.###....###...##.##..####...##..##....#....#.#.##.#..###.#....##.##.#....##..#.#..#...#.#### diff --git a/src/main/scala/de.qwertyuiop.aoc/2021/day20.scala b/src/main/scala/de.qwertyuiop.aoc/2021/day20.scala index 9f42879..ca4f0ff 100644 --- a/src/main/scala/de.qwertyuiop.aoc/2021/day20.scala +++ b/src/main/scala/de.qwertyuiop.aoc/2021/day20.scala @@ -2,5 +2,84 @@ package de.qwertyuiop.aoc.`2021` import de.qwertyuiop.aoc.lib.* import cats.*, cats.implicits.given +import Vectors.* +import CanYouEnhanceThat.* -def day20(using InputSource): Unit = ??? +import java.nio.file.{Files, Paths} + +type Image = Map[Vec2D[Int], Char] +def day20(using InputSource): Unit = + val algo :: _ :: values = input(_.map(c => (if c == '#' then '1' else '0')).toVector) + + val image = (for (line, x) <- values.zipWithIndex ; (chr, y) <- line.zipWithIndex yield Vec2D(x, y) -> chr).toMap + + // ZOOM (out), ENHANCE! + def enhanceN(steps: Int) = enhance(algo, image, 0, values.size - 1)(steps)(renderPBM(-steps, values.size - 1 + steps)) + + val (enhanced, enhancedRenders) = enhanceN(2) + val (veryEnhanced, veryEnhancedRenders) = enhanceN(50) + + /* Visualization! + * Uncomment, run this, then run: + * + * % ffmpeg -r 5 -f image2 -s ${size}x${size} -i /tmp/%02d.pbm -vcodec libx264 -crf 25 -pix_fmt yuv420p ENHANCE.mp4 + * + * where $size = iterations * 2 + values.size + */ + //veryEnhancedRenders.reverse.zipWithIndex.foreach((pbm, i) => Files.writeString(Paths.get(f"/tmp/$i%02d.pbm"), pbm)) + + println(s"After 2 iterations: ${enhanced.count((_, c) => c == '1')} lights on") + println(s"After 50 iterations: ${veryEnhanced.count((_, c) => c == '1')} lights on") + + +object CanYouEnhanceThat: + extension (c: Char) + def flip = if c == '1' then '0' else '1' + + def enhance[T](algo: Vector[Char], image: Image, min: Int, max: Int, outer: Char = '0', renders: List[T] = Nil)(steps: Int)(renderer: Image => T): (Image, List[T]) = + def lookup(pos: Vec2D[Int]) = + val binStr = pos.kernel3x3.map(p => image.getOrElse(p, outer)).mkString + algo(Integer.parseInt(binStr, 2)) + + val rendersNew = renderer(image) :: renders + if(steps == 0) (image, rendersNew) + else + val newImage = ( + for + x <- (min - 1) to (max + 1) + y <- (min - 1) to (max + 1) + yield + val p = Vec2D(x,y) + p -> lookup(p) + ).toMap + enhance(algo, newImage, min - 1, max + 1, if algo(0) == '1' then outer.flip else outer, rendersNew)(steps - 1)(renderer) + + + /** + * Output an Image to the terminal + */ + def printImage(image: Image) = + val min = image.keys.minBy(_.x).x + val max = image.keys.maxBy(_.x).x + print("\u001B[H") + for x <- min - 2 to max + 2 do + for y <- min - 2 to max + 2 do + print(image.get(Vec2D(x,y)).map(c => if c == '1' then '#' else ' ').getOrElse(' ')) + println() + + /** + * Render image as a PBM file. min and max set the range of coordinates to render. + * This doesn't take the blinking outer part into account, to prevent seizures. + */ + def renderPBM(min: Int, max: Int)(image: Image) = + val width = max - min + 1 + val even = width % 2 + s"P1\n${width + even} ${width + even}\n" + + ( + for x <- min to max + even yield + ( + for y <- min to max + even yield image.getOrElse(Vec2D(x,y), '0') + ).mkString(" ") + ).mkString("\n") + + def noop(image: Image): Null = null diff --git a/src/main/scala/de.qwertyuiop.aoc/lib/vectors.scala b/src/main/scala/de.qwertyuiop.aoc/lib/vectors.scala index c7f841f..c8d1a1e 100644 --- a/src/main/scala/de.qwertyuiop.aoc/lib/vectors.scala +++ b/src/main/scala/de.qwertyuiop.aoc/lib/vectors.scala @@ -118,6 +118,10 @@ object Vectors: def neighbours: Vector[Vec2D[T]] = neighbourCoords(2).map(n => a + (n(0), n(1))) + def kernel3x3: Vector[Vec2D[T]] = + val (pre,post) = neighbours.splitAt(4) + pre.appended(a) ++ post + def orthoNeighbours(sizeX: T, sizeY: T)(using Ordering[T]): Vector[Vec2D[T]] = val n = summon[Numeric[T]] import math.Ordering.Implicits.infixOrderingOps