77 lines
2.4 KiB
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
|
|
}
|
|
|
|
}
|