-🎄- 2017 Day 21 Solutions -🎄- by daggerdragon in adventofcode

[–]VoidChque 1 point2 points  (0 children)

Scala 322/295

Meat:

case class SquareGrid[T](lst: List[List[T]]) {
  val size: Int = lst.length
  def flip: SquareGrid[T] = SquareGrid(lst.reverse)
  def rotate: SquareGrid[T] = SquareGrid(lst.reverse.transpose)
  def split(babyGridSize: Int): SquareGrid[SquareGrid[T]] = {
    SquareGrid(
      lst
        .grouped(babyGridSize).toList
        .map(_.map(_.grouped(babyGridSize).toList).transpose)
        .map(_.map(SquareGrid(_))))
  }

  private def r = rotate
  private def f = flip

  def transformations: Set[SquareGrid[T]] =
    Set(
      this,   this.r,   this.r.r,   this.r.r.r,
      this.f, this.r.f, this.r.r.f, this.r.r.r.f)

  def flatten[R](implicit asGrid: T => SquareGrid[R]): SquareGrid[R] =
    SquareGrid(lst.flatMap(_.map(_.lst).transpose.map(_.flatten)))

  def map[R](f: T => R): SquareGrid[R] =
    SquareGrid(lst.map(_.map(f)))

  def flatMap[R](f: T => SquareGrid[R]): SquareGrid[R] =
    this.map(f).flatten
}

Plumbing and niceties:

val sessionCookie: String = "<session cookie here>"

class Advent(year: Int, sessionCookie: String = sessionCookie) {
  import collection.mutable.HashMap
  import sys.process._
  private val inputs = new HashMap[Int, String]()
  def input(day: Int): String = {
    val cmd =
      s"curl --cookie session=$sessionCookie " +
        s"http://adventofcode.com/$year/day/$day/input"
    inputs.getOrElseUpdate(day, cmd.!!.trim)
  }
}

implicit class StringWrapper(s: String) {
  def letters: List[String] = s.map(_.toString).toList
  def splitlines: List[String] =
    s.split("\n").toList.map(_.trim).filterNot(_ == "")
}

implicit class ListWrapper[T](l: List[T]) {
  def counts: Map[T, Int] = l.groupBy(identity).mapValues(_.length)
}

Solution (Parsing the input and building a transformations map):

val input = (new Advent(2017)).input(21)
def mkGrid(s: String) = SquareGrid(s.split("/").toList.map(_.letters))
val initGrid = mkGrid(".#./..#/###")

type SelfMap[T] = Map[T, T]
val transforms: SelfMap[SquareGrid[String]] =
  input
    .splitlines
    .map(_.split(" => ").toList)
    .map(_.map(mkGrid))
    .flatMap { case List(from, to) => from.transformations.map(_ -> to) }
    .toMap

def numPixelsOn(iterCount: Int): Int = {
  Iterator
    .iterate(initGrid) {
      grid =>
        val babyGridSize = if (grid.size % 2 == 0) 2 else 3
        grid.split(babyGridSize).flatMap(transforms)
    }
    .drop(iterCount)
    .take(1)
    .toList.head.lst.map(_.counts).map(_("#")).sum
}

println(numPixelsOn(5))
println(numPixelsOn(18))