Advertisement
Guest User

Untitled

a guest
Dec 17th, 2022
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 5.24 KB | None | 0 0
  1. package scalaExercises.adventOfCode2022
  2. package Day16
  3.  
  4. import scala.io.Source
  5. import scala.collection.mutable
  6. import scala.collection.immutable._
  7. import scala.util.control.Breaks._
  8. import scala.util.Random
  9.  
  10. val problemInput = Source.fromFile("/Users/mik/IdeaProjects/scala-exercises/src/scalaExercises/adventOfCode2022/Day16/input.txt")
  11. val testSmall = Source.fromString(
  12.   """Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
  13.    |Valve BB has flow rate=13; tunnels lead to valves CC, AA
  14.    |Valve CC has flow rate=2; tunnels lead to valves DD, BB
  15.    |Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
  16.    |Valve EE has flow rate=3; tunnels lead to valves FF, DD
  17.    |Valve FF has flow rate=0; tunnels lead to valves EE, GG
  18.    |Valve GG has flow rate=0; tunnels lead to valves FF, HH
  19.    |Valve HH has flow rate=22; tunnel leads to valve GG
  20.    |Valve II has flow rate=0; tunnels lead to valves AA, JJ
  21.    |Valve JJ has flow rate=21; tunnel leads to valve II
  22.    |""".stripMargin)
  23.  
  24. val valveRE = """Valve ([A-Z]{2}) has flow rate=(\d+); tunnels? leads? to valves? ([,A-Z ]+)""".r.anchored
  25.  
  26. class Valve(val flowRate : Int, var open : Boolean, val neighbors : Seq[String])
  27.  
  28. object State {
  29.   val graph: mutable.Map[String, Valve] = mutable.Map()
  30.   val paths: mutable.Map[String, mutable.Map[String, Seq[String]]] = mutable.Map()
  31.  
  32.   def process(line: String): Unit = line match {
  33.     case valveRE(id, fr, tunnels) => graph.update(id, new Valve(fr.toInt, false, tunnels.split(", ")))
  34.   }
  35.  
  36.   def findPaths(start: String): Unit = {
  37.     if (!paths.contains(start)) paths.update(start, mutable.Map(start -> Seq[String]()))
  38.     val heads: mutable.Queue[String] = mutable.Queue(start)
  39.     while (heads.nonEmpty) {
  40.       breakable {
  41.         val head = heads.dequeue()
  42.         val nbrs = graph(head).neighbors.filter(nb => !paths(start).contains(nb))
  43.         for (nb <- nbrs) {
  44.           paths(start).update(nb, paths(start)(head).appended(nb))
  45.           heads.enqueue(nb)
  46.         }
  47.       }
  48.     }
  49.   }
  50.  
  51.  
  52.   sealed trait Action
  53.   case class Move(destination: String) extends Action
  54.   case class Open() extends Action
  55.   case class Minute(choice: Action, pressureRelease: Int)
  56.  
  57.   var currentPosition = "AA"
  58.   def nextPosition(cp: String) = State.graph.filter((i, v) => !v.open).maxBy((i, v) => v.flowRate - State.paths(cp)(i).size)._1
  59.   def releases() = State.graph.filter((i, v) => v.open).values.map(v => v.flowRate).sum
  60.   val log: mutable.Queue[Minute] = mutable.Queue()
  61.  
  62.   def simulate(path: Seq[String]): Seq[Minute] = {
  63.     val graph : mutable.Map[String, Valve] = this.graph.clone()
  64.     graph.foreach((i,v) => v.open = false)
  65.     val log: mutable.Queue[Minute] = mutable.Queue()
  66.     var currentPosition = "AA"
  67.     for (next <- path) {
  68.       val release = releases()
  69.       log.enqueueAll(
  70.         paths(currentPosition)(next).map(p => Minute(Move(p), release))
  71.       )
  72.       log.enqueue(Minute(Open(), release))
  73.       graph(next).open = true
  74.       currentPosition = next
  75.     }
  76.     val release = releases()
  77.     (log.dequeueAll(_ => true) ++ Seq.fill(30)(Minute(Move(currentPosition), release))).take(30).toSeq
  78.   }
  79.  
  80.   def time(path : Seq[String]) : Int = {
  81.     path.foldLeft[(String,Int)](("AA",0))((fv,t) => (t, fv._2 + paths(fv._1)(t).size+1))._2
  82.   }
  83.  
  84.   def init(source : Source) = {
  85.     source.getLines().foreach(process)
  86.     valves = graph.filter((i,v) => v.flowRate > 0).map((i,v) => i).toSeq
  87.     findPaths("AA")
  88.     valves.foreach(findPaths)
  89.   }
  90.  
  91.   var maxEnergy : Double = Double.NegativeInfinity
  92.   var valves : Seq[String] = Seq()
  93.  
  94.   object simulatedAnnealing {
  95.     def swap(i : Int, j : Int) : Seq[String] =
  96.       valves.updated(i, valves(j)).updated(j, valves(i))
  97.  
  98.     def flip(ix : Int) : Seq[String] = swap(ix, ix+1)
  99.  
  100.     def deltaTime(newValves : Seq[String]) : Int =
  101.       time(valves) - time(newValves)
  102.  
  103.     def deltaRelease(newValves : Seq[String]) : Int =
  104.       simulate(valves).map(m => m.pressureRelease).sum -
  105.         simulate(newValves).map(m => m.pressureRelease).sum
  106.  
  107.     def energy(path : Seq[String]) : Double =
  108.       simulate(path).take(30).map(m => m.pressureRelease).sum.toDouble
  109.  
  110.     val T0 : Double = 100.0
  111.     val dT : Double = -0.01
  112.     val Tlo : Double= 0.01
  113.     val Tsteps : Int = 5
  114.     def temperature(k : Int) : Double =
  115.       math.max(Tlo, T0 + (k/Tsteps) * dT)
  116.  
  117.     def accept(newValves : Seq[String], k : Int) : Double =
  118.       if(energy(newValves) > energy(valves)) 1.0
  119.       else math.exp(-(energy(valves)-energy(newValves))/temperature(k))
  120.  
  121.     def step(k : Int) : Seq[String] = {
  122.       val i = Random.between(0, valves.size)
  123.       val j = Random.between(0, valves.size)
  124.       val newValves = swap(i,j)
  125.  
  126.       maxEnergy = math.max(maxEnergy, energy(valves))
  127.  
  128.       val P = accept(newValves, k)
  129.       if(k % 1000 == 0)
  130.         println(s"""Swap ${valves.mkString("-")} to ${newValves.mkString("-")}
  131.  k: ${k/1000},  T: ${temperature(k)},  E: ${energy(valves)} to ${energy(newValves)},  P: $P
  132.        """)
  133.       if(math.random() < P) newValves
  134.       else valves
  135.     }
  136.   }
  137. }
  138.  
  139.  
  140. // To use this:
  141. // import scalaExercises.adventOfCode2022.Day16._
  142. // State.init(problemInput)
  143. // (1 to 150_000).toList.foreach(k => State.valves = State.simulatedAnnealing.step(k))
  144. // State.maxEnergy
Tags: AoC2022
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement