Day 16: The Floor Will Be Lava
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
Scala3
This could be much more efficient (and quite a bit shorter), but I wanted to try out the scala-graph library (https://www.scala-graph.org)
import day10._ import day10.Dir._ import scalax.collection.edges.DiEdge import scalax.collection.immutable.Graph import scalax.collection.edges.DiEdgeImplicits import scalax.collection.generic.AnyEdge import scalax.collection.generic.Edge case class Node(ps: Set[Pos]) def getNode(p: Pos, d: Dir) = Node(Set(p, walk(p, d))) def connect(p: Pos, d1: Dir, d2: Dir) = List(getNode(p, d1) ~> getNode(p, d2), getNode(p, d2) ~> getNode(p, d1)) def parseGrid(a: List[List[Char]]) = def parseCell(s: Char, pos: Pos) = s match case '.' => connect(pos, Left, Right) ++ connect(pos, Up, Down) case '/' => connect(pos, Left, Up) ++ connect(pos, Right, Down) case '\\' => connect(pos, Left, Down) ++ connect(pos, Right, Up) case '-' => connect(pos, Left, Right) ++ List( getNode(pos, Up) ~> getNode(pos, Left), getNode(pos, Up) ~> getNode(pos, Right), getNode(pos, Down) ~> getNode(pos, Left), getNode(pos, Down) ~> getNode(pos, Right), ) case '|' => connect(pos, Up, Down) ++ List( getNode(pos, Left) ~> getNode(pos, Up), getNode(pos, Left) ~> getNode(pos, Down), getNode(pos, Right) ~> getNode(pos, Up), getNode(pos, Right) ~> getNode(pos, Down), ) case _ => List().ensuring(false) val edges = a.zipWithIndex.flatMap((r, y) => r.zipWithIndex.map((v, x) => v -> Pos(x, y))).map(parseCell).reduceLeft((a, b) => a ++ b) Graph() ++ edges def illuminationFrom(p: Pos, d: Dir, g: Graph[Node, DiEdge[Node]], inBounds: Pos => Boolean): Long = val es = getNode(p, d.opposite) ~> getNode(p, d) val g2 = g + es val n = g2.get(getNode(p, d)) n.outerNodeTraverser.flatMap(_.ps).toSet.filter(inBounds).size def inBounds(a: List[String])(p: Pos) = p.x >= 0 && p.x < a(0).size && p.y >= 0 && p.y < a.size def task1(a: List[String]): Long = illuminationFrom(Pos(-1, 0), Right, parseGrid(a.map(_.toList)), inBounds(a)) def task2(a: List[String]): Long = val inits = (for y <- a.indices yield Seq((Pos(-1, y), Right), (Pos(a(y).size, y), Left))) ++ (for x <- a(0).indices yield Seq((Pos(x, -1), Down), (Pos(x, a.size), Up))) val g = parseGrid(a.map(_.toList)) inits.flatten.map((p, d) => illuminationFrom(p, d, g, inBounds(a))).max