Add files via upload
This commit is contained in:
parent
90d51d7adc
commit
0fdd2a7faa
21
2019/Scala/day07/Day07.scala
Normal file
21
2019/Scala/day07/Day07.scala
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package day07
|
||||||
|
|
||||||
|
import day07.intcode.Solver
|
||||||
|
|
||||||
|
class Day07(original: Array[Int])
|
||||||
|
{
|
||||||
|
val phases: List[Array[Int]] = Array(0, 1, 2, 3, 4).permutations.toList
|
||||||
|
def solveP1(): (Int, List[Int]) =
|
||||||
|
{
|
||||||
|
val solver = new Solver(original)
|
||||||
|
phases.map(seq => (solver.solveSequenceSingleRun(seq), seq.toList)).maxBy(_._1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val phases2: List[Array[Int]] = Array(5, 6, 7, 8, 9).permutations.toList
|
||||||
|
def solveP2(): (Int, List[Int]) =
|
||||||
|
{
|
||||||
|
val solver = new Solver(original)
|
||||||
|
phases2.map(seq => (solver.solveSequenceMultiRun(seq), seq.toList)).maxBy(_._1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
17
2019/Scala/day07/Main.scala
Normal file
17
2019/Scala/day07/Main.scala
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package day07
|
||||||
|
|
||||||
|
import kamlib.{Reader, Wrapper}
|
||||||
|
|
||||||
|
object Main {
|
||||||
|
|
||||||
|
def main(args: Array[String]): Unit =
|
||||||
|
{
|
||||||
|
val input: Array[Int] = Reader.readString("/input7.txt").split("[^\\d-]+").map(x => x.toInt)
|
||||||
|
val solution: Day07 = new Day07(input)
|
||||||
|
|
||||||
|
println("Part 1:")
|
||||||
|
Wrapper(solution.solveP1()).print()
|
||||||
|
println("Part 2:")
|
||||||
|
Wrapper(solution.solveP2()).print()
|
||||||
|
}
|
||||||
|
}
|
72
2019/Scala/day07/intcode/Amplifier.scala
Normal file
72
2019/Scala/day07/intcode/Amplifier.scala
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package day07.intcode
|
||||||
|
|
||||||
|
import day07.intcode.opcode.{Action, Input, Jump, OpCode99, Output}
|
||||||
|
|
||||||
|
class Amplifier(input: Array[Int])
|
||||||
|
{
|
||||||
|
private[this] val original = input.clone()
|
||||||
|
private[this] var software = input.clone()
|
||||||
|
|
||||||
|
private[this] var pointer = 0
|
||||||
|
private[this] var halted = false
|
||||||
|
|
||||||
|
def isHalted: Boolean = halted
|
||||||
|
|
||||||
|
def reset(): Amplifier = {
|
||||||
|
software = original.clone()
|
||||||
|
halted = false
|
||||||
|
pointer = 0
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
def runUntilIO(): Amplifier =
|
||||||
|
{
|
||||||
|
val tuple = OpCode99.parseInt(software(pointer));
|
||||||
|
tuple match
|
||||||
|
{
|
||||||
|
case (_, _, _, OpCode99) =>
|
||||||
|
halted = true
|
||||||
|
this
|
||||||
|
case (_, _, m1, outputInstr: Output) => this
|
||||||
|
case (_, _, m1, inputInstr: Input) => this
|
||||||
|
case (m3, m2, m1, instruction: Jump) =>
|
||||||
|
val (bool, jmpPtr) = instruction.checkConditionAndJump(software, software(pointer+1), software(pointer+2), software(pointer+3), m1, m2, m3)
|
||||||
|
if (bool) pointer = jmpPtr
|
||||||
|
else pointer += instruction.length
|
||||||
|
runUntilIO()
|
||||||
|
case (m3, m2, m1, instruction: Action) =>
|
||||||
|
instruction.exec(software, software(pointer+1), software(pointer+2), software(pointer+3), m1, m2, m3)
|
||||||
|
pointer += instruction.length
|
||||||
|
runUntilIO()
|
||||||
|
case _ => throw new Exception("Something went wrong")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def runInput(input: Int): Amplifier =
|
||||||
|
{
|
||||||
|
val tuple = OpCode99.parseInt(software(pointer))
|
||||||
|
tuple match
|
||||||
|
{
|
||||||
|
case (_, _, _, OpCode99) => this
|
||||||
|
case (_, _, m1, inputInstr: Input) =>
|
||||||
|
inputInstr.input(software, software(pointer+1), m1, input)
|
||||||
|
pointer += inputInstr.length
|
||||||
|
case _ => throw new Exception("Unexpected instruction")
|
||||||
|
}
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
def runOutput(): Int =
|
||||||
|
{
|
||||||
|
val tuple = OpCode99.parseInt(software(pointer))
|
||||||
|
tuple match
|
||||||
|
{
|
||||||
|
case (_, _, _, OpCode99) => 0
|
||||||
|
case (_, _, m1, outputInstr: Output) =>
|
||||||
|
val out = outputInstr.output(software, software(pointer+1), m1)
|
||||||
|
pointer += outputInstr.length
|
||||||
|
out
|
||||||
|
case _ => throw new Exception("Unexpected instruction")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
2019/Scala/day07/intcode/Solver.scala
Normal file
56
2019/Scala/day07/intcode/Solver.scala
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package day07.intcode
|
||||||
|
|
||||||
|
class Solver(software: Array[Int])
|
||||||
|
{
|
||||||
|
val amps: Array[Amplifier] = Array(new Amplifier(software), new Amplifier(software), new Amplifier(software), new Amplifier(software), new Amplifier(software))
|
||||||
|
|
||||||
|
def reset(): Unit =
|
||||||
|
amps.foreach(_.reset())
|
||||||
|
|
||||||
|
def setupPhases(phases: Array[Int]): Unit =
|
||||||
|
{
|
||||||
|
amps.foreach(_.runUntilIO())
|
||||||
|
amps(0).runInput(phases(0))
|
||||||
|
amps(1).runInput(phases(1))
|
||||||
|
amps(2).runInput(phases(2))
|
||||||
|
amps(3).runInput(phases(3))
|
||||||
|
amps(4).runInput(phases(4))
|
||||||
|
}
|
||||||
|
|
||||||
|
def solveSequence(lastOutput: Int = 0): Int =
|
||||||
|
{
|
||||||
|
val res0 = amps(0).runUntilIO().runInput(lastOutput).runUntilIO().runOutput()
|
||||||
|
val res1 = amps(1).runUntilIO().runInput(res0).runUntilIO().runOutput()
|
||||||
|
val res2 = amps(2).runUntilIO().runInput(res1).runUntilIO().runOutput()
|
||||||
|
val res3 = amps(3).runUntilIO().runInput(res2).runUntilIO().runOutput()
|
||||||
|
val res4 = amps(4).runUntilIO().runInput(res3).runUntilIO().runOutput()
|
||||||
|
res4
|
||||||
|
}
|
||||||
|
|
||||||
|
def solveSequenceSingleRun(phases: Array[Int]): Int =
|
||||||
|
{
|
||||||
|
reset()
|
||||||
|
setupPhases(phases)
|
||||||
|
solveSequence()
|
||||||
|
}
|
||||||
|
|
||||||
|
@scala.annotation.tailrec
|
||||||
|
final def solveSequenceFeedback(lastOutput: Int = 0): Int =
|
||||||
|
{
|
||||||
|
val res0 = amps(0).runUntilIO().runInput(lastOutput).runUntilIO().runOutput()
|
||||||
|
val res1 = amps(1).runUntilIO().runInput(res0).runUntilIO().runOutput()
|
||||||
|
val res2 = amps(2).runUntilIO().runInput(res1).runUntilIO().runOutput()
|
||||||
|
val res3 = amps(3).runUntilIO().runInput(res2).runUntilIO().runOutput()
|
||||||
|
val res4 = amps(4).runUntilIO().runInput(res3).runUntilIO().runOutput()
|
||||||
|
if (amps.foldLeft(false) {(bool, amp) => bool || amp.isHalted}) lastOutput
|
||||||
|
else solveSequenceFeedback(res4)
|
||||||
|
}
|
||||||
|
|
||||||
|
def solveSequenceMultiRun(phases: Array[Int]): Int =
|
||||||
|
{
|
||||||
|
reset()
|
||||||
|
setupPhases(phases)
|
||||||
|
solveSequenceFeedback()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
7
2019/Scala/day07/intcode/opcode/Action.scala
Normal file
7
2019/Scala/day07/intcode/opcode/Action.scala
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
trait Action extends OpCode
|
||||||
|
{
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
def exec(tape: Array[Int], param1: Int, param2: Int, param3: Int, mode1: Int, mode2: Int, mode3: Int)
|
||||||
|
}
|
7
2019/Scala/day07/intcode/opcode/Input.scala
Normal file
7
2019/Scala/day07/intcode/opcode/Input.scala
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
trait Input extends OpCode
|
||||||
|
{
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
def input(tape: Array[Int], param1: Int, mode1: Int, input: Int): Unit
|
||||||
|
}
|
8
2019/Scala/day07/intcode/opcode/Jump.scala
Normal file
8
2019/Scala/day07/intcode/opcode/Jump.scala
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
trait Jump extends OpCode
|
||||||
|
{
|
||||||
|
/** Checks if the condition for jumping is fulfilled, returns boolean and jump pointer */
|
||||||
|
def checkConditionAndJump(tape: Array[Int], param1: Int, param2: Int, param3: Int, mode1: Int, mode2: Int, mode3: Int): (Boolean, Int)
|
||||||
|
}
|
||||||
|
|
50
2019/Scala/day07/intcode/opcode/OpCode.scala
Normal file
50
2019/Scala/day07/intcode/opcode/OpCode.scala
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
trait OpCode
|
||||||
|
{
|
||||||
|
/** length of an instruction */
|
||||||
|
val length: Int
|
||||||
|
|
||||||
|
/** Parse int to full OpCode */
|
||||||
|
def parseInt(code: Int): (Int, Int, Int, OpCode) = // Dunno how to make this static lmao
|
||||||
|
{
|
||||||
|
val opCodeInt: Int = code % 100 // Instruction Code
|
||||||
|
val modeStr = code.toString.substring(0, {if (code.toString.length > 1) code.toString.length - 2 else 0})
|
||||||
|
val modes = "000".substring(modeStr.length) + modeStr
|
||||||
|
(modes(0).asDigit, modes(1).asDigit, modes(2).asDigit, opCodeInt) match
|
||||||
|
{
|
||||||
|
case (a, b, c, 1) => (a, b, c, OpCode1)
|
||||||
|
case (a, b, c, 2) => (a, b, c, OpCode2)
|
||||||
|
case (a, b, c, 3) => (a, b, c, OpCode3)
|
||||||
|
case (a, b, c, 4) => (a, b, c, OpCode4)
|
||||||
|
case (a, b, c, 5) => (a, b, c, OpCode5)
|
||||||
|
case (a, b, c, 6) => (a, b, c, OpCode6)
|
||||||
|
case (a, b, c, 7) => (a, b, c, OpCode7)
|
||||||
|
case (a, b, c, 8) => (a, b, c, OpCode8)
|
||||||
|
case (_, _, _, 99) => (0, 0, 0, OpCode99)
|
||||||
|
case c => throw new Exception("Wrong instruction code " + c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns correct value, immediate or positional */
|
||||||
|
protected[this] def accessor(param: Int, mode: Int, tape: Array[Int]): Int =
|
||||||
|
{
|
||||||
|
mode match
|
||||||
|
{
|
||||||
|
case 0 => /* println("Reading "+tape(param)+" from array("+param+")");*/ tape(param)
|
||||||
|
case 1 => /*println("Reading "+param+" immediate");*/ param
|
||||||
|
case p => throw new Exception("HCF: wrong accessor parameter " + p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Writes to the tape in a manner specified by the mode */
|
||||||
|
protected[this] def writer(param: Int, mode: Int, tape: Array[Int], value: Int): Unit =
|
||||||
|
{
|
||||||
|
mode match
|
||||||
|
{
|
||||||
|
case 0 => tape(param) = value//; println("Writing "+value+" to array("+param+")")
|
||||||
|
case 1 => throw new Exception("HCF: unimplemented writer parameter 1")
|
||||||
|
case p => throw new Exception("HCF: wrong writer parameter " + p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
2019/Scala/day07/intcode/opcode/OpCode1.scala
Normal file
15
2019/Scala/day07/intcode/opcode/OpCode1.scala
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
/** Sum */
|
||||||
|
case object OpCode1 extends Action
|
||||||
|
{
|
||||||
|
/** length of an instruction */
|
||||||
|
override val length: Int = 4
|
||||||
|
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
override def exec(tape: Array[Int], param1: Int, param2: Int, param3: Int, mode1: Int, mode2: Int, mode3: Int): Unit =
|
||||||
|
{
|
||||||
|
val result = accessor(param1, mode1, tape) + accessor(param2, mode2, tape)
|
||||||
|
writer(param3, 0, tape, result) // Write mode is 0 default for now
|
||||||
|
}
|
||||||
|
}
|
15
2019/Scala/day07/intcode/opcode/OpCode2.scala
Normal file
15
2019/Scala/day07/intcode/opcode/OpCode2.scala
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
/** Multiplication */
|
||||||
|
case object OpCode2 extends Action
|
||||||
|
{
|
||||||
|
/** length of an instruction */
|
||||||
|
override val length: Int = 4
|
||||||
|
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
override def exec(tape: Array[Int], param1: Int, param2: Int, param3: Int, mode1: Int, mode2: Int, mode3: Int): Unit =
|
||||||
|
{
|
||||||
|
val result = accessor(param1, mode1, tape) * accessor(param2, mode2, tape)
|
||||||
|
writer(param3, 0, tape, result) // Write mode is 0 default for now
|
||||||
|
}
|
||||||
|
}
|
15
2019/Scala/day07/intcode/opcode/OpCode3.scala
Normal file
15
2019/Scala/day07/intcode/opcode/OpCode3.scala
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
/** Input */
|
||||||
|
case object OpCode3 extends Input
|
||||||
|
{
|
||||||
|
/** length of an instruction */
|
||||||
|
override val length: Int = 2
|
||||||
|
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
override def input(tape: Array[Int], param1: Int, mode1: Int, input: Int): Unit =
|
||||||
|
{
|
||||||
|
//println(s"<< input: $input")
|
||||||
|
writer(param1, 0, tape, input)
|
||||||
|
}
|
||||||
|
}
|
14
2019/Scala/day07/intcode/opcode/OpCode4.scala
Normal file
14
2019/Scala/day07/intcode/opcode/OpCode4.scala
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
/** Output */
|
||||||
|
case object OpCode4 extends Output
|
||||||
|
{
|
||||||
|
/** length of an instruction */
|
||||||
|
override val length: Int = 2
|
||||||
|
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
override def output(tape: Array[Int], param1: Int, mode1: Int): Int =
|
||||||
|
{
|
||||||
|
accessor(param1, mode1, tape)
|
||||||
|
}
|
||||||
|
}
|
14
2019/Scala/day07/intcode/opcode/OpCode5.scala
Normal file
14
2019/Scala/day07/intcode/opcode/OpCode5.scala
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
case object OpCode5 extends Jump
|
||||||
|
{
|
||||||
|
/** length of an instruction */
|
||||||
|
override val length: Int = 3
|
||||||
|
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
override def checkConditionAndJump(tape: Array[Int], param1: Int, param2: Int, param3: Int, mode1: Int, mode2: Int, mode3: Int): (Boolean, Int) =
|
||||||
|
{
|
||||||
|
if (accessor(param1, mode1, tape) != 0) (true, accessor(param2, mode2, tape))
|
||||||
|
else (false, 0)
|
||||||
|
}
|
||||||
|
}
|
14
2019/Scala/day07/intcode/opcode/OpCode6.scala
Normal file
14
2019/Scala/day07/intcode/opcode/OpCode6.scala
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
case object OpCode6 extends Jump
|
||||||
|
{
|
||||||
|
/** length of an instruction */
|
||||||
|
override val length: Int = 3
|
||||||
|
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
override def checkConditionAndJump(tape: Array[Int], param1: Int, param2: Int, param3: Int, mode1: Int, mode2: Int, mode3: Int): (Boolean, Int) =
|
||||||
|
{
|
||||||
|
if (accessor(param1, mode1, tape) == 0) (true, accessor(param2, mode2, tape))
|
||||||
|
else (false, 0)
|
||||||
|
}
|
||||||
|
}
|
16
2019/Scala/day07/intcode/opcode/OpCode7.scala
Normal file
16
2019/Scala/day07/intcode/opcode/OpCode7.scala
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
case object OpCode7 extends Action
|
||||||
|
{
|
||||||
|
/** length of an instruction */
|
||||||
|
override val length: Int = 4
|
||||||
|
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
override def exec(tape: Array[Int], param1: Int, param2: Int, param3: Int, mode1: Int, mode2: Int, mode3: Int): Unit =
|
||||||
|
{
|
||||||
|
if (accessor(param1, mode1, tape) < accessor(param2, mode2, tape))
|
||||||
|
writer(param3, 0, tape, 1)
|
||||||
|
else
|
||||||
|
writer(param3, 0, tape, 0)
|
||||||
|
}
|
||||||
|
}
|
16
2019/Scala/day07/intcode/opcode/OpCode8.scala
Normal file
16
2019/Scala/day07/intcode/opcode/OpCode8.scala
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
case object OpCode8 extends Action
|
||||||
|
{
|
||||||
|
/** length of an instruction */
|
||||||
|
override val length: Int = 4
|
||||||
|
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
override def exec(tape: Array[Int], param1: Int, param2: Int, param3: Int, mode1: Int, mode2: Int, mode3: Int): Unit =
|
||||||
|
{
|
||||||
|
if (accessor(param1, mode1, tape) == accessor(param2, mode2, tape))
|
||||||
|
writer(param3, 0, tape, 1)
|
||||||
|
else
|
||||||
|
writer(param3, 0, tape, 0)
|
||||||
|
}
|
||||||
|
}
|
6
2019/Scala/day07/intcode/opcode/OpCode99.scala
Normal file
6
2019/Scala/day07/intcode/opcode/OpCode99.scala
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
case object OpCode99 extends OpCode {
|
||||||
|
/** length of an instruction */
|
||||||
|
override val length: Int = 1
|
||||||
|
}
|
7
2019/Scala/day07/intcode/opcode/Output.scala
Normal file
7
2019/Scala/day07/intcode/opcode/Output.scala
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package day07.intcode.opcode
|
||||||
|
|
||||||
|
trait Output extends OpCode
|
||||||
|
{
|
||||||
|
/** Executes instruction for given parameters and modes */
|
||||||
|
def output(tape: Array[Int], param1: Int, mode1: Int): Int
|
||||||
|
}
|
Loading…
Reference in a new issue