From 37bc98fafb47bb27ef064f84a3fe4545ae6323e8 Mon Sep 17 00:00:00 2001 From: Soren Date: Sat, 7 Dec 2019 18:55:07 -0800 Subject: [PATCH] Day 7 part 2 --- aoc/src/main/scala/aoc/y2019/Day02.scala | 2 +- aoc/src/main/scala/aoc/y2019/Day05.scala | 2 +- aoc/src/main/scala/aoc/y2019/Day07.scala | 45 +++++++++++++++++++--- aoc/src/main/scala/aoc/y2019/Intcode.scala | 12 ++++-- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/aoc/src/main/scala/aoc/y2019/Day02.scala b/aoc/src/main/scala/aoc/y2019/Day02.scala index a82edf1..95ac80d 100644 --- a/aoc/src/main/scala/aoc/y2019/Day02.scala +++ b/aoc/src/main/scala/aoc/y2019/Day02.scala @@ -13,7 +13,7 @@ object Day02 extends Day { val initialState = Intcode.Machine(memory) val runMachine = for { _ <- initialReplacement(noun, verb) - ran <- Intcode.run + ran <- Intcode.run() } yield ran val endState = runMachine.runS(initialState).value endState.memory(0) diff --git a/aoc/src/main/scala/aoc/y2019/Day05.scala b/aoc/src/main/scala/aoc/y2019/Day05.scala index 38d4d3c..edeed4e 100644 --- a/aoc/src/main/scala/aoc/y2019/Day05.scala +++ b/aoc/src/main/scala/aoc/y2019/Day05.scala @@ -13,7 +13,7 @@ object Day05 extends Day { val machineInput = diagnosticNumber val runMachine: Intcode.Operation = for { _ <- Intcode.input(machineInput) - ran <- Intcode.run + ran <- Intcode.run() } yield ran val endState = runMachine.runS(initialState).value endState.output.last diff --git a/aoc/src/main/scala/aoc/y2019/Day07.scala b/aoc/src/main/scala/aoc/y2019/Day07.scala index 155f539..d336099 100644 --- a/aoc/src/main/scala/aoc/y2019/Day07.scala +++ b/aoc/src/main/scala/aoc/y2019/Day07.scala @@ -1,21 +1,22 @@ package aoc.y2019 import aoc.Day - +import cats._ +import cats.implicits._ import scala.annotation.tailrec object Day07 extends Day { - @tailrec def runAmplifiers(machine: Intcode.Machine, order: IndexedSeq[Int], input: Int = 0): Int = { + @tailrec def runAmplifiers(machine: Intcode.Machine, order: Seq[Int], input: Int = 0): Int = { if(order.isEmpty) { input } else { val firstInput = order.head val secondInput = input - val runAmplifier = for { + val runAmplifier = for { _ <- Intcode.input(firstInput) _ <- Intcode.input(secondInput) - ran <- Intcode.run + ran <- Intcode.run() } yield ran val output = runAmplifier.runS(machine).value.output.head runAmplifiers(machine, order.tail, output) @@ -29,5 +30,39 @@ object Day07 extends Day { maximumSignal.toString } - override def part2(input: String): String = ??? + def loopAmplifiers(base: Intcode.Machine, initialInputs: Seq[Int]): Int = { + 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 <- Intcode.watingForInput + isHalted <- Intcode.isHalted + } yield waitingForInput || isHalted + val runToNextMachine = Intcode.run(haltCondition = haltCondition) + @tailrec def go(index: Int, machines: Vector[Intcode.Machine], lastOutput: Int = 0): Vector[Intcode.Machine] = { + if(machines.traverse(machine => Intcode.isHalted.runA(machine)).value.forall(identity)) machines + else { + val thisMachine = machines(index) + val inputAndRun = for { + inputLastOutput <- Intcode.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(",").toVector.map(_.toInt) + val initialState = Intcode.Machine(memory) + val maximumSignal = (5 to 9).permutations.map(loopAmplifiers(initialState, _)).max + maximumSignal.toString + } + } diff --git a/aoc/src/main/scala/aoc/y2019/Intcode.scala b/aoc/src/main/scala/aoc/y2019/Intcode.scala index 7803347..8500285 100644 --- a/aoc/src/main/scala/aoc/y2019/Intcode.scala +++ b/aoc/src/main/scala/aoc/y2019/Intcode.scala @@ -21,7 +21,7 @@ object Intcode { 8 -> Instruction.equals, ) - val parse: State[Machine, (Instruction, LazyList[Boolean])] = State.inspect { + def parse(instructions: Map[Int, Instruction] = instructions): State[Machine, (Instruction, LazyList[Boolean])] = State.inspect { machine: Machine => val instructionAndFlags = machine.memory(machine.pc) val instruction: Instruction = instructions(instructionAndFlags % 100) @@ -32,12 +32,13 @@ object Intcode { } (instruction, flags) } - val step: Operation = for { - (instruction, flags) <- parse + def step(instructions: Map[Int, Instruction] = instructions): Operation = for { + (instruction, flags) <- parse(instructions) _ <- advance(1) result <- instruction.run(flags) } yield result - val run: Operation = step.untilM[Vector](State.inspect(machine => machine.memory(machine.pc) % 100 == 99)).map(_.last) + def run(instructions: Map[Int, Instruction] = instructions, haltCondition: State[Machine, Boolean] = isHalted): Operation = + step(instructions).untilM[Vector](haltCondition).map(_.last) val noop: Operation = State.pure(()) @@ -62,6 +63,9 @@ object Intcode { machine.copy(output = machine.output :+ value) } + val isHalted: State[Machine, Boolean] = State.inspect(machine => machine.memory(machine.pc) % 100 == 99) + val watingForInput: State[Machine, Boolean] = State.inspect(machine => machine.memory(machine.pc) % 100 == 3 && machine.input.isEmpty) + object Instruction { def trans(operandCount: Int, operation: Kleisli[State[Machine, *], Vector[Int], Unit]): Instruction = Kleisli {