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

71 lines
2.4 KiB
Scala

package aoc.y2019
import aoc.Day
import aoc.y2019.intcode.Machine
import cats._
import cats.implicits._
import scala.annotation.tailrec
object Day07 extends Day {
@tailrec def runAmplifiers(machine: Machine, order: Seq[Int], input: BigInt = 0): BigInt = {
if(order.isEmpty) {
input
} else {
val firstInput = order.head
val secondInput = input
val runAmplifier = for {
_ <- Machine.input(firstInput)
_ <- Machine.input(secondInput)
ran <- Machine.run()
} yield ran
val output = runAmplifier.runS(machine).value.output.head
runAmplifiers(machine, order.tail, output)
}
}
override def part1(input: String): String = {
val memory = input.split(",").map(BigInt(_)).toVector
val initialState = Machine(memory)
val maximumSignal = (0 to 4).permutations.map(runAmplifiers(initialState, _)).max
maximumSignal.toString
}
def loopAmplifiers(base: Machine, initialInputs: Seq[Int]): BigInt = {
val numAmplifiers = initialInputs.size
val initialMachines = Vector.fill(numAmplifiers)(base).zip(initialInputs).map {
case (machine, phase) => machine.copy(input = machine.input :+ phase)
}
val haltCondition = for {
waitingForInput <- Machine.waitingForInput
isHalted <- Machine.isHalted
} yield waitingForInput || isHalted
val runToNextMachine = Machine.run(haltCondition = haltCondition)
@tailrec def go(index: Int, machines: Vector[Machine], lastOutput: BigInt = 0): Vector[Machine] = {
if(machines.traverse(machine => Machine.isHalted.runA(machine)).value.forall(identity)) machines
else {
val thisMachine = machines(index)
val inputAndRun = for {
inputLastOutput <- Machine.input(lastOutput)
runAsFarAsPossible<- runToNextMachine
} yield runAsFarAsPossible
val ranMachine = inputAndRun.runS(thisMachine).value
val nextOutput = ranMachine.output.last
val nextIndex = (index + 1) % machines.size
val nextMachines = machines.updated(index, ranMachine)
go(nextIndex, nextMachines, nextOutput)
}
}
go(0, initialMachines).last.output.last
}
override def part2(input: String): String = {
val memory = input.split(",").map(BigInt(_)).toVector
val initialState = Machine(memory)
val maximumSignal = (5 to 9).permutations.map(loopAmplifiers(initialState, _)).max
maximumSignal.toString
}
}