aoc-old/aoc/src/main/scala/aoc/y2017/Day07.scala

77 lines
2.4 KiB
Scala

package aoc.y2017
import aoc.Day
object Day07 extends Day {
import fastparse._, SingleLineWhitespace._
case class TowerRef(name: String, weight: Int, children: List[String]) {
def resolve(trs: List[TowerRef]): Tower =
Tower(name, weight, children.map(c => trs.find(_.name == c).get.resolve(trs)))
}
case class Tower(name: String, weight: Int, children: List[Tower]) {
def childWeights: List[Int] = children.map(_.totalWeight)
def totalWeight: Int = weight + childWeights.sum
}
def childrenParser[_: P]: P[List[String]] =
P(("->" ~ CharIn("a-z").rep(1).!.rep(1, ",")).?).map(_.fold(List[String]())(_.toList))
def towerParser[_: P]: P[TowerRef] =
P(CharIn("a-z").rep(1).! ~ "(" ~ CharIn("0-9").rep(1).! ~ ")" ~ childrenParser).map {
case (name, weight, children) => TowerRef(name, weight.toInt, children)
}
def towerListParser[_: P]: P[List[TowerRef]] = towerParser.rep(1, "\n").map(_.toList)
def lowest(trs: List[TowerRef]): TowerRef = {
val allChildren = trs.flatMap(_.children)
val name = trs.map(_.name).filterNot(allChildren.contains).head
trs.find(_.name == name).get
}
override def part1(input: String): String = {
val Parsed.Success(trs: List[TowerRef], _) = parse(input, towerListParser(_))
lowest(trs).name
}
override def part2(input: String): String = {
val Parsed.Success(trs: List[TowerRef], _) = parse(input, towerListParser(_))
val lowestT = lowest(trs)
val resolved = lowestT.resolve(trs)
def searchForUnevenness(tower: Tower): List[Int] = {
if (tower.childWeights.distinct.size == 1) {
tower.children.flatMap(searchForUnevenness)
} else {
if (tower.childWeights.isEmpty) {
List()
} else {
val ds = tower.childWeights.distinct
val (w1, w2) = (ds.head, ds.last)
val (c1, c2) = (tower.childWeights.count(_ == w1), tower.childWeights.count(_ == w2))
val (offWeight, onWeight) = if (Math.max(c1, c2) == c1) {
(w2, w1)
} else {
(w1, w2)
}
val offChild = tower.children.find(_.totalWeight == offWeight).get
if (offChild.childWeights.distinct.size == 1) {
List((onWeight - offWeight) + offChild.weight)
} else {
offChild.children.flatMap(searchForUnevenness)
}
}
}
}
searchForUnevenness(resolved).head.toString
}
}