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

127 lines
3.7 KiB
Scala

package aoc.y2017
import aoc.Day
object Day08 extends Day {
import fastparse._, NoWhitespace._
sealed trait Instruction {
def result(regValue: Int, input: Int): Int
}
case object Dec extends Instruction {
override def result(regValue: Int, input: Int): Int = regValue - input
}
case object Inc extends Instruction {
override def result(regValue: Int, input: Int): Int = regValue + input
}
sealed trait Test {
def result(regValue: Int, input: Int): Boolean
}
case object Lt extends Test {
override def result(regValue: Int, input: Int): Boolean = regValue < input
}
case object Gt extends Test {
override def result(regValue: Int, input: Int): Boolean = regValue > input
}
case object Leq extends Test {
override def result(regValue: Int, input: Int): Boolean = regValue <= input
}
case object Geq extends Test {
override def result(regValue: Int, input: Int): Boolean = regValue >= input
}
case object Eq extends Test {
override def result(regValue: Int, input: Int): Boolean = regValue == input
}
case object Neq extends Test {
override def result(regValue: Int, input: Int): Boolean = regValue != input
}
case class FullInstruction(reg: String, op: Instruction, v: Int)
case class FullTest(reg: String, op: Test, v: Int)
case class Line(i: FullInstruction, t: FullTest)
def registerParser[_: P] = P(CharIn("a-z").rep(1).!)
def numberParser[_: P] = P(("-".? ~ CharIn("0-9").rep(1)).!).map(_.toInt)
def instructionParser[_: P] = P(("inc" | "dec").!).map {
case "inc" => Inc
case "dec" => Dec
}
def testParser[_: P] = P(("<=" | ">=" | "<" | ">" | "==" | "!=").!).map {
case "<" => Lt
case ">" => Gt
case "<=" => Leq
case ">=" => Geq
case "==" => Eq
case "!=" => Neq
}
def fullInstructionParser[_: P] = P(registerParser ~ " " ~ instructionParser ~ " " ~ numberParser).map {
case (reg, op, v) => FullInstruction(reg, op, v)
}
def fullTestParser[_: P] = P(registerParser ~ " " ~ testParser ~ " " ~ numberParser).map {
case (reg, op, v) => FullTest(reg, op, v)
}
def lineParser[_: P] = P(fullInstructionParser ~ " if " ~ fullTestParser).map {
case (i, t) => Line(i, t)
}
def listParser[_: P] = P(lineParser.rep(1, "\n")).map(_.toList)
def getProgram(input: String): List[Line] = {
val Parsed.Success(list, _) = parse(input, listParser(_))
list
}
override def part1(input: String): String = {
val list = getProgram(input)
val allRegs = (list.map(_.i.reg) ++ list.map(_.t.reg)).distinct
val regMap: Map[String, Int] = allRegs.map(r => (r, 0)).toMap
val o = list.foldLeft(regMap)((map, cl) => {
print(s"\r$cl")
val testReg = map(cl.t.reg)
val test = cl.t.op
val v = cl.t.v
if (test.result(testReg, v)) {
val inReg = map(cl.i.reg)
val in = cl.i.op
val iv = cl.i.v
map + (cl.i.reg -> in.result(inReg, iv))
} else {
map
}
})
println()
o.values.max.toString
}
override def part2(input: String): String = {
val list = getProgram(input)
val allRegs = (list.map(_.i.reg) ++ list.map(_.t.reg)).distinct
val regMap: Map[String, Int] = allRegs.map(r => (r, 0)).toMap
val (_, max) = list.foldLeft((regMap, 0)) {
case ((map, hm), cl) =>
print(s"\r$cl")
val testReg = map(cl.t.reg)
val test = cl.t.op
val v = cl.t.v
val inReg = map(cl.i.reg)
if (test.result(testReg, v)) {
val in = cl.i.op
val iv = cl.i.v
val nv = in.result(inReg, iv)
(map + (cl.i.reg -> nv), Math.max(hm, nv))
} else {
(map, Math.max(hm, inReg))
}
}
println()
max.toString
}
}