Day 17: Clumsy Crucible

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
  • cvttsd2si@programming.dev
    ·
    edit-2
    11 months ago

    Scala3

    Learning about scala-graph yesterday seems to have paid off already. This explicitly constructs the entire graph of allowed moves, and then uses a naive dijkstra run. This works, and I don't have to write a lot of code, but it is fairly inefficient.

    import day10._
    import day10.Dir._
    import day11.Grid
    
    // standing on cell p, having entered from d
    case class Node(p: Pos, d: Dir)
    
    def connect(p: Pos, d: Dir, g: Grid[Int], dists: Range) = 
        val from = Seq(-1, 1).map(i => Dir.from(d.n + i)).map(Node(p, _))
        val ends = List.iterate(p, dists.last + 1)(walk(_, d)).filter(g.inBounds)
        val costs = ends.drop(1).scanLeft(0)(_ + g(_))
        from.flatMap(f => ends.zip(costs).drop(dists.start).map((dest, c) => WDiEdge(f, Node(dest, d), c)))
    
    def parseGrid(a: List[List[Char]], dists: Range) =
        val g = Grid(a.map(_.map(_.getNumericValue)))
        Graph() ++ g.indices.flatMap(p => Dir.all.flatMap(d => connect(p, d, g, dists)))
    
    def compute(a: List[String], dists: Range): Long =
        val g = parseGrid(a.map(_.toList), dists)
        val source = Node(Pos(-1, -1), Right)
        val sink = Node(Pos(-2, -2), Right)
        val start = Seq(Down, Right).map(d => Node(Pos(0, 0), d)).map(WDiEdge(source, _, 0))
        val end = Seq(Down, Right).map(d => Node(Pos(a(0).size - 1, a.size - 1), d)).map(WDiEdge(_, sink, 0))
        val g2 = g ++ start ++ end
        g2.get(source).shortestPathTo(g2.get(sink)).map(_.weight).getOrElse(-1.0).toLong
    
    def task1(a: List[String]): Long = compute(a, 1 to 3)
    def task2(a: List[String]): Long = compute(a, 4 to 10)