package aoc.y2019 import aoc.Day import cats.data.State object Day02 extends Day { case class Machine(memory: List[Int], pointer: Int) type MachineState = State[Machine, Boolean] val ops: Map[Int, (Int, Int) => Int] = Map( 1 -> (_ + _), 2 -> (_ * _) ) def initialReplacement(noun: Int, verb: Int): MachineState = State { case Machine(memory, 0) => (Machine(memory.updated(1, noun).updated(2, verb), 0), false) } val step: MachineState = State { case Machine(memory, pointer) => memory(pointer) match { case 99 => (Machine(memory, pointer), true) case opcode => val inputAAddress = memory(pointer + 1) val inputBAddress = memory(pointer + 2) val valueA = memory(inputAAddress) val valueB = memory(inputBAddress) val outputAddress = memory(pointer + 3) val op = ops(opcode) (Machine(memory.updated(outputAddress, op(valueA, valueB)), pointer + 4), false) } } def runMachine(memory: List[Int], noun: Int, verb: Int): Int = { val initialState = Machine(memory, 0) val initialReplacementState = initialReplacement(noun, verb).run(initialState).value lazy val states: LazyList[(Machine, Boolean)] = initialReplacementState #:: states.map { case (currentState, _) => step.run(currentState).value } val (lastState, _) = states.takeWhile(!_._2).last lastState.memory.head } override def part1(input: String): String = { val memory = input.split(",").map(_.toInt).toList runMachine(memory, 12, 2).toString } override def part2(input: String): String = { val memory = input.split(",").map(_.toInt).toList val magic = 19690720 val solutions = for { noun <- 0 to 99 verb <- 0 to 99 if runMachine(memory, noun, verb) == magic } yield noun * 100 + verb solutions.head.toString } }