97 lines
2.8 KiB
Scala
97 lines
2.8 KiB
Scala
package aoc.y2017
|
|
|
|
import aoc.Day
|
|
|
|
object Day25 extends Day {
|
|
|
|
import fastparse._, MultiLineWhitespace._
|
|
|
|
case class State(name: String)
|
|
case class InState(state: State, whenZero: Branch, whenOne: Branch)
|
|
case class Branch(write: Int, move: Direction, stateChange: State)
|
|
sealed trait Direction {
|
|
def change: Int
|
|
}
|
|
case object MoveLeft extends Direction {
|
|
override def change: Int = -1
|
|
}
|
|
case object MoveRight extends Direction {
|
|
override def change: Int = 1
|
|
}
|
|
case class Program(
|
|
beginIn: State,
|
|
diagnosticCount: Int,
|
|
states: Map[State, InState],
|
|
index: Int = 0,
|
|
tape: Map[Int, Int] = Map()
|
|
) {
|
|
|
|
def step: Program = {
|
|
val ndc = diagnosticCount - 1
|
|
val cs = states(beginIn)
|
|
val cc = tape.getOrElse(index, 0)
|
|
val br = cc match {
|
|
case 0 => cs.whenZero
|
|
case 1 => cs.whenOne
|
|
}
|
|
val wr = br.write
|
|
val mv = br.move
|
|
val ns = br.stateChange
|
|
val nm = tape + (index -> wr)
|
|
Program(ns, ndc, states, index + mv.change, nm)
|
|
}
|
|
|
|
}
|
|
|
|
def stateParser[_: P]: P[State] = P("state" ~ CharIn("A-Z").rep.!).map(State)
|
|
def writeParser[_: P]: P[Int] = P("- Write the value" ~ ("0" | "1").! ~ ".").map(_.toInt)
|
|
|
|
def directionParser[_: P]: P[Direction] = P("- Move one slot to the" ~ ("left" | "right").! ~ ".").map {
|
|
case "left" => MoveLeft
|
|
case "right" => MoveRight
|
|
}
|
|
def stateChangeParser[_: P]: P[State] = P("- Continue with" ~ stateParser ~ ".")
|
|
|
|
def branchParser[_: P]: P[Branch] = P(writeParser ~ directionParser ~ stateChangeParser).map {
|
|
case (write, dir, state) => Branch(write, dir, state)
|
|
}
|
|
|
|
def inStateParser[_: P]: P[InState] =
|
|
P(
|
|
"In" ~ stateParser ~ ":" ~ "If the current value is 0:" ~ branchParser ~ "If the current value is 1:" ~ branchParser
|
|
).map {
|
|
case (state, v0, v1) => InState(state, v0, v1)
|
|
}
|
|
|
|
def programParser[_: P]: P[Program] =
|
|
P(
|
|
"Begin in" ~ stateParser ~ "." ~
|
|
"Perform a diagnostic checksum after" ~ CharIn("0-9").rep(1).!.map(_.toInt) ~ "steps." ~
|
|
inStateParser.rep.map(f => {
|
|
val z = f.map(_.state).zip(f)
|
|
z.toMap
|
|
})
|
|
).map {
|
|
case (begin, steps, states) => Program(begin, steps, states)
|
|
}
|
|
|
|
override def part1(input: String): String = {
|
|
val Parsed.Success(program, _) = parse(input, programParser(_))
|
|
def finalState(p: Program): Program = {
|
|
val np = p.step
|
|
print(s"\rInstructions Left: ${np.diagnosticCount}${" " * program.diagnosticCount.toString.length}")
|
|
np.diagnosticCount match {
|
|
case 0 => np
|
|
case _ => finalState(np)
|
|
}
|
|
}
|
|
println()
|
|
finalState(program).tape.values.count(_ == 1).toString
|
|
}
|
|
|
|
override def part2(input: String): String = {
|
|
"You Win!"
|
|
}
|
|
|
|
}
|