Advertisement
lluque

AoC day 24

Dec 24th, 2016
260
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 2.39 KB | None | 0 0
  1. import io.Source
  2. import collection.mutable
  3.  
  4. object day24 extends App {
  5.  
  6.   case class Delta(x: Int, y: Int)
  7.   case class Point(x: Int, y: Int, wall: Boolean, value: Int) {
  8.     def isOfInterest = value > -1
  9.   }
  10.  
  11.   val input = Source.fromFile("day24.txt").getLines.toList
  12.   val points: Array[Array[Point]] = input.indices.toArray.map(
  13.     y => input(y).indices.toArray.map(
  14.       x => {
  15.         val p = input(y)(x)
  16.         Point(x, y, p == '#', if (p.isDigit) p.asDigit else -1)
  17.     })
  18.   )
  19.  
  20.   def getNext(p: Point, d: Delta): Point = {
  21.     points(p.y + d.y)(p.x + d.x)
  22.   }
  23.  
  24.   def aStar(start: Point, goal: Point)(costFn: (Point, Point) => Int): Map[Point, Int] = {
  25.     val frontier = mutable.ListBuffer[(Point, Int)]((start, 0))
  26.     val costs = mutable.Map[Point, Int](start -> 0)
  27.     while (frontier.nonEmpty) {
  28.       val current = frontier.minBy(_._2)
  29.       frontier -= current
  30.       if (current._1 == goal) frontier.clear
  31.       else {
  32.         val newCost = costs(current._1) + 1
  33.         val neighbors = List(Delta(0, -1), Delta(0, 1), Delta(1, 0), Delta(-1, 0))
  34.           .map(getNext(current._1, _)).filter(p => !p.wall)
  35.         for (next <- neighbors) {
  36.           if (!costs.contains(next) || newCost < costs(next)) {
  37.             costs(next) = newCost
  38.             val priority = newCost + costFn(goal, next)
  39.             frontier += ((next, priority))
  40.           }
  41.         }
  42.       }
  43.     }
  44.     costs.toMap
  45.   }
  46.  
  47.   def dist(k: (Point, Point), m: Map[(Point, Point), Int]) = {
  48.     // distance is symmetric so order of two points does not matter
  49.     if (m.keySet.contains(k)) m(k) else m((k._2, k._1))
  50.   }
  51.  
  52.   def pathLength(path: List[Point], distances: Map[(Point, Point), Int]) =
  53.     path.sliding(2).foldLeft(0)((a, b) => a + dist((b.head, b.last), distances))
  54.  
  55.   val placesOfInterest = points.flatten.filter(p => p.isOfInterest)
  56.   val pairs = placesOfInterest.combinations(2).map(p => (p.head, p.last))
  57.   def costFn = (a: Point, b: Point) => math.abs(a.x - b.x) + math.abs(a.y - b.y)
  58.   val distances = pairs.map(p => p -> aStar(p._1, p._2)(costFn)(p._2)).toMap
  59.   val start = placesOfInterest.find(_.value == 0).get
  60.   val paths = (placesOfInterest.toList diff List(start)).permutations.map(l => start +: l).toList
  61.   println(paths.toList.map(pathLength(_, distances)).min)
  62.   // Part 2
  63.   val paths2 = paths.map (p => p :+ start)
  64.   println(paths2.toList.map(pathLength(_, distances)).min)
  65.  
  66. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement