Advertisement
lluque

AoC day 11

Dec 13th, 2016
387
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 4.99 KB | None | 0 0
  1. package day11
  2.  
  3. import scala.collection.mutable.ListBuffer
  4.  
  5. object Prog {
  6.  
  7.   sealed class Item(val element: String, val purpose: Char) {
  8.     def isCounterpart(other: Item): Boolean = other.element.equals(element) && other.purpose != purpose
  9.     override def toString: String = element.toUpperCase.substring(0, 2) + purpose
  10.   }
  11.  
  12.   val inventory: ListBuffer[Map[String, Item]] = ListBuffer()
  13.  
  14.   def canCoexist(items: List[Item]): Boolean =  {
  15.     val pairing = items.groupBy(_.element)
  16.     val singles = pairing.values.filter(_.size == 1).flatten
  17.     singles.groupBy(_.purpose).size <= 1
  18.   }
  19.  
  20.   def canBeMovedUp(items: (Item, Item), floor: Int): Boolean = items match {
  21.     case (x, y) if x.isCounterpart(y) => true
  22.     case (x, y) =>
  23.       val nextFloor = inventory(floor + 1) + (x.toString -> x) + (y.toString -> y)
  24.       val thisFloor = inventory(floor) - x.toString - y.toString
  25.       canCoexist(nextFloor.values.toList) && canCoexist(thisFloor.values.toList)
  26.   }
  27.  
  28.   def canBeMovedDown(item: Item, floor: Int): Boolean = {
  29.     val nextFloor = inventory(floor - 1) + (item.toString -> item)
  30.     val thisFloor = inventory(floor) - item.toString
  31.     canCoexist(nextFloor.values.toList) && canCoexist(thisFloor.values.toList)
  32.   }
  33.  
  34.   def moveUp(items: (Item, Item), floor: Int): Any = {
  35.     val (x, y) = items
  36.     inventory(floor) -= (x.toString, y.toString)
  37.     inventory(floor + 1) += ((x.toString -> x), (y.toString -> y))
  38.   }
  39.  
  40.   def moveDown(item: Item, floor: Int): Any = {
  41.     inventory(floor) -= item.toString
  42.     inventory(floor - 1) += (item.toString -> item)
  43.   }
  44.  
  45.   def getCounterparts(floor: Int): Option[List[Item]] = {
  46.     val pairs = inventory(floor).groupBy(_._2.element).values.filter (_.size == 2)
  47.     if (pairs.nonEmpty) Option(List(pairs.head.head._2, pairs.head.last._2))
  48.     else Option.empty
  49.   }
  50.  
  51.   def allPairs(floor: Int): List[(Item, Item)] = {
  52.     inventory(floor).values.toList.combinations(2).toList.map(x => (x.head, x.last))
  53.   }
  54.  
  55.   def getNonCounterparts(floor: Int): Option[List[Item]] = {
  56.     val solutions = allPairs(floor).filter(x => canBeMovedUp(x, floor))
  57.     if (solutions.isEmpty) Option.empty else Option(List(solutions.head._1, solutions.head._2))
  58.   }
  59.  
  60.   def getPair(floor: Int): List[Item] = {
  61.     // Heuristic:
  62.     // Always take two items when going up
  63.     // If there are two items of same element (counterparts) use them
  64.     // else pick some other valid combination
  65.     getCounterparts(floor).getOrElse(getNonCounterparts(floor).get)
  66.   }
  67.  
  68.   def getSingle(floor: Int): Item = {
  69.     // Heuristic:
  70.     // Always bring just one item down
  71.     // Take the item that has a counterpart on floor below
  72.     // If none exists just take some valid item
  73.     val singles = inventory(floor).values.filter(x => canBeMovedDown(x, floor))
  74.     val singlesWithCounterpart = singles.filter(
  75.       s => inventory(floor - 1).values.exists(v => v.isCounterpart(s))
  76.     )
  77.     if (singlesWithCounterpart.nonEmpty) singlesWithCounterpart.head else singles.head
  78.   }
  79.  
  80.   def itemCount: Int = inventory.foldLeft(0)((x, i) => x + i.values.size)
  81.  
  82.   def canGoDown(floor: Int): Boolean = {
  83.     floor > 0 && inventory(floor - 1).values.nonEmpty
  84.   }
  85.  
  86.   def canGoUp(floor: Int): Boolean = {
  87.     floor < 3 && inventory(floor + 1).values.size < itemCount
  88.   }
  89.  
  90.   def solve(): Any = {
  91.     var e = 0
  92.     var moves = 0
  93.     var upwards = true
  94.     while (inventory.last.values.size < itemCount) {
  95.       while (upwards) {
  96.         if (canGoUp(e)) {
  97.           val pair = getPair(e)
  98.           moveUp((pair.head, pair.last), e)
  99.           println("MOVED " + pair + " UP TO FLOOR #" + (e + 2))
  100.           moves = moves + 1
  101.           e  = e + 1
  102.         } else {
  103.           upwards = false
  104.         }
  105.       }
  106.       while (!upwards) {
  107.         if (canGoDown(e)) {
  108.           val single = getSingle(e)
  109.           moveDown(single, e)
  110.           println("MOVED " + single + " DOWN TO FLOOR #" + e)
  111.           moves = moves + 1
  112.           e = e - 1
  113.         } else {
  114.           upwards = true
  115.         }
  116.       }
  117.     }
  118.     println("TOTAL MOVES: " + moves)
  119.   }
  120.  
  121.   def run = {
  122.     val items = List[Map[String, Item]](
  123.        Map(
  124.          "THG" -> new Item("Thulium", 'G'),
  125.          "THM" -> new Item("Thulium", 'M'),
  126.          "PLG" -> new Item("Plutonium", 'G'),
  127.          "STG" -> new Item("Strontium", 'G')
  128.        ), Map(
  129.          "PLM" -> new Item("Plutonium", 'M'),
  130.          "STM" -> new Item("Strontium", 'M')
  131.        ), Map(
  132.          "PRG" -> new Item("Promethium", 'G'),
  133.          "PRM" -> new Item("Promethium", 'M'),
  134.          "RUG" -> new Item("Ruthenium", 'G'),
  135.          "RUM" -> new Item("Ruthenium", 'M')
  136.        ), Map()
  137.       )
  138.  
  139.     // Part One
  140.     items.foreach(i => inventory += i)
  141.     solve()
  142.  
  143.     // Part Two
  144.     inventory.remove(0, 4)
  145.     items.foreach(i => inventory += i)
  146.     inventory(0) += (
  147.      ("ELG" -> new Item("Elerium", 'G')), ("ELM" -> new Item("Elerium", 'M')),
  148.      ("DIM" -> new Item("Dilithium", 'M')), ("DIG" -> new Item("Dilithium", 'G')))
  149.     solve()
  150.   }
  151. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement