Day 5
This commit is contained in:
parent
ea871d612e
commit
abf2060411
3 changed files with 165 additions and 36 deletions
|
@ -5,52 +5,29 @@ import cats.data.State
|
||||||
|
|
||||||
object Day02 extends Day {
|
object Day02 extends Day {
|
||||||
|
|
||||||
case class Machine(memory: List[Int], pointer: Int)
|
import Day05.Machine, Day05.MachineState, Day05.executeMachine
|
||||||
type MachineState = State[Machine, Boolean]
|
|
||||||
|
|
||||||
val ops: Map[Int, (Int, Int) => Int] = Map(
|
def initialReplacement(noun: Int, verb: Int): MachineState = State { m =>
|
||||||
1 -> (_ + _),
|
(m.copy(m.memory.updated(1, noun).updated(2, verb)), false)
|
||||||
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 {
|
def runMachine(memory: Vector[Int], noun: Int, verb: Int): Int = {
|
||||||
case Machine(memory, pointer) =>
|
val initialState = Machine(memory)
|
||||||
memory(pointer) match {
|
val runMachine = for {
|
||||||
case 99 => (Machine(memory, pointer), true)
|
_ <- initialReplacement(noun, verb)
|
||||||
case opcode =>
|
run <- executeMachine
|
||||||
val inputAAddress = memory(pointer + 1)
|
} yield run
|
||||||
val inputBAddress = memory(pointer + 2)
|
val endState = runMachine.runS(initialState).value
|
||||||
val valueA = memory(inputAAddress)
|
endState.memory(0)
|
||||||
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 = {
|
override def part1(input: String): String = {
|
||||||
val memory = input.split(",").map(_.toInt).toList
|
val memory = input.split(",").map(_.toInt).toVector
|
||||||
runMachine(memory, 12, 2).toString
|
runMachine(memory, 12, 2).toString
|
||||||
}
|
}
|
||||||
|
|
||||||
override def part2(input: String): String = {
|
override def part2(input: String): String = {
|
||||||
val memory = input.split(",").map(_.toInt).toList
|
val memory = input.split(",").map(_.toInt).toVector
|
||||||
val magic = 19690720
|
val magic = 19690720
|
||||||
val solutions = for {
|
val solutions = for {
|
||||||
noun <- 0 to 99
|
noun <- 0 to 99
|
||||||
|
|
151
aoc/src/main/scala/aoc/y2019/Day05.scala
Normal file
151
aoc/src/main/scala/aoc/y2019/Day05.scala
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
package aoc.y2019
|
||||||
|
|
||||||
|
import cats._
|
||||||
|
import cats.implicits._
|
||||||
|
import aoc.Day
|
||||||
|
import cats.data.State
|
||||||
|
|
||||||
|
object Day05 extends Day {
|
||||||
|
|
||||||
|
case class Oresult(result: Option[Int], appendOutput: Vector[Int], newPointer: Option[Int])
|
||||||
|
object Oresult {
|
||||||
|
def apply(result: Int): Oresult = Oresult(result.some, Vector.empty, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed trait Operation {
|
||||||
|
val opcode: Int
|
||||||
|
val operandCount: Int
|
||||||
|
val inputCount: Int
|
||||||
|
def apply(operands: Vector[Int], inputs: Vector[Int]): Oresult
|
||||||
|
}
|
||||||
|
case object Add extends Operation {
|
||||||
|
override val opcode: Int = 1
|
||||||
|
override val operandCount: Int = 2
|
||||||
|
override val inputCount: Int = 0
|
||||||
|
def apply(operands: Vector[Int], inputs: Vector[Int]): Oresult = Oresult(operands(0) + operands(1))
|
||||||
|
}
|
||||||
|
case object Multiply extends Operation {
|
||||||
|
override val opcode: Int = 2
|
||||||
|
override val operandCount: Int = 2
|
||||||
|
override val inputCount: Int = 0
|
||||||
|
override def apply(operands: Vector[Int], inputs: Vector[Int]): Oresult = Oresult(operands(0) * operands(1))
|
||||||
|
}
|
||||||
|
case object Input extends Operation {
|
||||||
|
override val opcode: Int = 3
|
||||||
|
override val operandCount: Int = 0
|
||||||
|
override val inputCount: Int = 1
|
||||||
|
override def apply(operands: Vector[Int], inputs: Vector[Int]): Oresult = Oresult(inputs.headOption, Vector.empty, None)
|
||||||
|
}
|
||||||
|
case object Output extends Operation {
|
||||||
|
override val opcode: Int = 4
|
||||||
|
override val operandCount: Int = 1
|
||||||
|
override val inputCount: Int = 0
|
||||||
|
override def apply(operands: Vector[Int], inputs: Vector[Int]): Oresult = Oresult(None, operands, None)
|
||||||
|
}
|
||||||
|
case object JumpIfTrue extends Operation {
|
||||||
|
override val opcode: Int = 5
|
||||||
|
override val operandCount: Int = 2
|
||||||
|
override val inputCount: Int = 0
|
||||||
|
override def apply(operands: Vector[Int], inputs: Vector[Int]): Oresult = Oresult(None, Vector.empty, Option.when(operands(0) != 0)(operands(1)))
|
||||||
|
}
|
||||||
|
case object JumpIfFalse extends Operation {
|
||||||
|
override val opcode: Int = 6
|
||||||
|
override val operandCount: Int = 2
|
||||||
|
override val inputCount: Int = 0
|
||||||
|
override def apply(operands: Vector[Int], inputs: Vector[Int]): Oresult = Oresult(None, Vector.empty, Option.when(operands(0) == 0)(operands(1)))
|
||||||
|
}
|
||||||
|
case object LessThan extends Operation {
|
||||||
|
override val opcode: Int = 7
|
||||||
|
override val operandCount: Int = 2
|
||||||
|
override val inputCount: Int = 0
|
||||||
|
override def apply(operands: Vector[Int], inputs: Vector[Int]): Oresult = Oresult(if(operands(0) < operands(1)) 1 else 0)
|
||||||
|
}
|
||||||
|
case object Equal extends Operation {
|
||||||
|
override val opcode: Int = 8
|
||||||
|
override val operandCount: Int = 2
|
||||||
|
override val inputCount: Int = 0
|
||||||
|
override def apply(operands: Vector[Int], inputs: Vector[Int]): Oresult = Oresult(if(operands(0) == operands(1)) 1 else 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Operation {
|
||||||
|
val all: Map[Int, Operation] = Seq(
|
||||||
|
Add,
|
||||||
|
Multiply,
|
||||||
|
Input,
|
||||||
|
Output,
|
||||||
|
JumpIfTrue,
|
||||||
|
JumpIfFalse,
|
||||||
|
LessThan,
|
||||||
|
Equal
|
||||||
|
).map(op => (op.opcode, op)).toMap
|
||||||
|
}
|
||||||
|
|
||||||
|
case class Machine(memory: Vector[Int], pointer: Int = 0 , input: Vector[Int] = Vector.empty, output: Vector[Int] = Vector.empty)
|
||||||
|
type MachineState = State[Machine, Boolean]
|
||||||
|
|
||||||
|
def inputNumber(num: Int): MachineState = State { machine =>
|
||||||
|
(machine.copy(input = machine.input :+ num), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val executeMachine: MachineState = State { machine =>
|
||||||
|
lazy val states: LazyList[(Machine, Boolean)] =
|
||||||
|
(machine, false) #:: states.map {
|
||||||
|
case (state, true) => (state, true)
|
||||||
|
case (m @ Machine(memory, pointer, input, output), false) =>
|
||||||
|
memory(pointer) match {
|
||||||
|
case 99 => (m, true)
|
||||||
|
case opcode =>
|
||||||
|
val operation = Operation.all(opcode % 100)
|
||||||
|
val operandCount = operation.operandCount
|
||||||
|
val inputCount = operation.inputCount
|
||||||
|
val inputs = input.take(inputCount)
|
||||||
|
val immediateParameters = (1 to operandCount).toVector.map { operandNum =>
|
||||||
|
val divide = Math.pow(10, operandNum + 1).toInt
|
||||||
|
val modulo = Math.pow(10, operandNum + 2).toInt
|
||||||
|
((opcode % modulo) / divide) == 1
|
||||||
|
}
|
||||||
|
val operands = (1 to operandCount).toVector.zip(immediateParameters).map {
|
||||||
|
case (operandNum, false) => memory(memory(pointer + operandNum))
|
||||||
|
case (operandNum, true) => memory(pointer + operandNum)
|
||||||
|
}
|
||||||
|
val Oresult(result, appendOutput, changePointer) = operation(operands, inputs)
|
||||||
|
|
||||||
|
val newMemory = result match {
|
||||||
|
case Some(result) => memory.updated(memory(pointer + operandCount + 1), result)
|
||||||
|
case None => memory
|
||||||
|
}
|
||||||
|
val newPointer = (result, changePointer) match {
|
||||||
|
case (_, Some(newAddress)) => newAddress
|
||||||
|
case (Some(_), None) => pointer + operandCount + 2
|
||||||
|
case (None, None) => pointer + operandCount + 1
|
||||||
|
}
|
||||||
|
val newInput = input.drop(inputCount)
|
||||||
|
val newOutput = output ++ appendOutput
|
||||||
|
|
||||||
|
(Machine(newMemory, newPointer, newInput, newOutput), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states.takeWhile(!_._2).last
|
||||||
|
}
|
||||||
|
|
||||||
|
def diagnostic(input: String, diagnosticNumber: Int): Int = {
|
||||||
|
val memory = input.split(",").toVector.map(_.toInt)
|
||||||
|
val initialState = Machine(memory)
|
||||||
|
val machineInput = diagnosticNumber
|
||||||
|
val runMachine: MachineState = for {
|
||||||
|
_ <- inputNumber(machineInput)
|
||||||
|
ran <- executeMachine
|
||||||
|
} yield ran
|
||||||
|
val endState = runMachine.runS(initialState).value
|
||||||
|
endState.output.last
|
||||||
|
}
|
||||||
|
|
||||||
|
override def part1(input: String): String = {
|
||||||
|
diagnostic(input, 1).toString
|
||||||
|
}
|
||||||
|
|
||||||
|
override def part2(input: String): String = {
|
||||||
|
diagnostic(input, 5).toString
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ package object y2019 extends Year {
|
||||||
"2" -> Day02,
|
"2" -> Day02,
|
||||||
"3" -> Day03,
|
"3" -> Day03,
|
||||||
"4" -> Day04,
|
"4" -> Day04,
|
||||||
|
"5" -> Day05,
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue