Add files via upload

This commit is contained in:
kamoshi 2019-12-09 11:08:57 +01:00 committed by GitHub
parent a3f03ffcda
commit 3b20909ed1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 344 additions and 0 deletions

View file

@ -0,0 +1,20 @@
package day09
import day09.intcode.Machine
class Day09(original: Array[Long])
{
def solveP1(): Long =
{
val machine = new Machine(original)
machine.runUntilIO().runInput(1)
machine.runUntilIO().runOutput()
}
def solveP2(): Long =
{
val machine = new Machine(original)
machine.runUntilIO().runInput(2)
machine.runUntilIO().runOutput()
}
}

View file

@ -0,0 +1,20 @@
package day09
import kamlib.{Reader, Wrapper}
object Main {
def main(args: Array[String]): Unit =
{
// Initialize initial program memory
val memory: Array[Long] = Array.ofDim[Long](1200)
val input: Array[Long] = Reader.readString("/input9.txt").split("[^\\d-]+").map(x => x.toLong)
for(i <- input.indices) { memory(i) = input(i)}
val solution: Day09 = new Day09(memory)
println("Part 1:")
Wrapper(solution.solveP1()).print()
println("Part 2:")
Wrapper(solution.solveP2()).print()
}
}

View file

@ -0,0 +1,78 @@
package day09.intcode
import day09.intcode.opcode.{Action, Input, Jump, OpCode9, OpCode99, Output}
class Machine(input: Array[Long])
{
private[this] val original = input.clone()
private[this] var software = input.clone()
private[this] var pointer = 0
private[this] var relative: Long = 0
private[this] var halted = false
def isHalted: Boolean = halted
def reset(): Machine = {
software = original.clone()
halted = false
pointer = 0
this
}
@scala.annotation.tailrec
final def runUntilIO(): Machine =
{
val tuple = OpCode99.parseInt(software(pointer).toInt);
tuple match
{
case (_, _, _, OpCode99) =>
halted = true
this
case (_, _, _, outputInstr: Output) => this
case (_, _, _, inputInstr: Input) => this
case (m3, m2, m1, instruction: Jump) =>
val (bool, jmpPtr) = instruction.checkConditionAndJump(software, relative, 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, relative, software(pointer+1), software(pointer+2), software(pointer+3), m1, m2, m3)
pointer += instruction.length
runUntilIO()
case (_, _, m1, OpCode9) =>
relative += OpCode9.exec(software, relative, software(pointer+1), m1)
pointer += OpCode9.length
runUntilIO()
case _ => throw new Exception("Something went wrong")
}
}
def runInput(input: Long): Machine =
{
val tuple = OpCode99.parseInt(software(pointer).toInt)
tuple match
{
case (_, _, _, OpCode99) => this
case (_, _, m1, inputInstr: Input) =>
inputInstr.input(software, relative, software(pointer+1), m1, input)
pointer += inputInstr.length
this
case _ => throw new Exception("Unexpected instruction")
}
}
def runOutput(): Long =
{
val tuple = OpCode99.parseInt(software(pointer).toInt)
tuple match
{
case (_, _, _, OpCode99) => 0
case (_, _, m1, outputInstr: Output) =>
val out = outputInstr.output(software, relative, software(pointer+1), m1)
pointer += outputInstr.length
out
case _ => throw new Exception("Unexpected instruction")
}
}
}

View file

@ -0,0 +1,7 @@
package day09.intcode.opcode
trait Action extends OpCode
{
/** Executes instruction for given parameters and modes */
def exec(tape: Array[Long], relative: Long, param1: Long, param2: Long, param3: Long, mode1: Int, mode2: Int, mode3: Int)
}

View file

@ -0,0 +1,7 @@
package day09.intcode.opcode
trait Input extends OpCode
{
/** Executes instruction for given parameters and modes */
def input(tape: Array[Long], relative: Long, param1: Long, mode1: Int, input: Long): Unit
}

View file

@ -0,0 +1,8 @@
package day09.intcode.opcode
trait Jump extends OpCode
{
/** Checks if the condition for jumping is fulfilled, returns boolean and jump pointer */
def checkConditionAndJump(tape: Array[Long], relative: Long, param1: Long, param2: Long, param3: Long, mode1: Int, mode2: Int, mode3: Int): (Boolean, Int)
}

View file

@ -0,0 +1,60 @@
package day09.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 (a, b, c, 9) => (a, b, c, OpCode9)
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(relative: Long, param: Long, mode: Int, tape: Array[Long]): Long =
{
mode match
{
case 0 => /* println("Reading "+tape(param)+" from array("+param+")");*/ tape(param.toInt)
case 1 => /*println("Reading "+param+" immediate");*/ param
case 2 => tape((param+relative).toInt)
case p => throw new Exception("HCF: wrong accessor parameter " + p)
}
}
/**
* Writes something to the tape
* @param tape Program memory
* @param relative Relative index
* @param param Location where to write
* @param mode Where to write: 0->tape(param1); 2->tape(param1+relative)
* @param value What to write to the tape
*/
protected[this] def writer(tape: Array[Long], relative: Long, param: Long, mode: Int, value: Long): Unit =
{
mode match
{
case 0 => tape(param.toInt) = value//; println("Writing "+value+" to array("+param+")")
case 1 => throw new Exception("HCF: unimplemented writer parameter 1")
case 2 => tape((param+relative).toInt) = value
case p => throw new Exception("HCF: wrong writer parameter " + p)
}
}
}

View file

@ -0,0 +1,15 @@
package day09.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[Long], relative: Long, param1: Long, param2: Long, param3: Long, mode1: Int, mode2: Int, mode3: Int): Unit =
{
val result = accessor(relative, param1, mode1, tape) + accessor(relative, param2, mode2, tape)
writer(tape, relative, param3, mode3, result)
}
}

View file

@ -0,0 +1,15 @@
package day09.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[Long], relative: Long, param1: Long, param2: Long, param3: Long, mode1: Int, mode2: Int, mode3: Int): Unit =
{
val result = accessor(relative, param1, mode1, tape) * accessor(relative, param2, mode2, tape)
writer(tape, relative, param3, mode3, result) // Write mode is 0 default for now
}
}

View file

@ -0,0 +1,14 @@
package day09.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[Long], relative: Long, param1: Long, mode1: Int, input: Long): Unit =
{
writer(tape, relative, param1, mode1, input)
}
}

View file

@ -0,0 +1,14 @@
package day09.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[Long], relative: Long, param1: Long, mode1: Int): Long =
{
accessor(relative, param1, mode1, tape)
}
}

View file

@ -0,0 +1,14 @@
package day09.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[Long], relative: Long, param1: Long, param2: Long, param3: Long, mode1: Int, mode2: Int, mode3: Int): (Boolean, Int) =
{
if (accessor(relative, param1, mode1, tape) != 0) (true, accessor(relative, param2, mode2, tape).toInt)
else (false, 0)
}
}

View file

@ -0,0 +1,14 @@
package day09.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[Long], relative: Long, param1: Long, param2: Long, param3: Long, mode1: Int, mode2: Int, mode3: Int): (Boolean, Int) =
{
if (accessor(relative, param1, mode1, tape) == 0) (true, accessor(relative, param2, mode2, tape).toInt)
else (false, 0)
}
}

View file

@ -0,0 +1,16 @@
package day09.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[Long], relative: Long, param1: Long, param2: Long, param3: Long, mode1: Int, mode2: Int, mode3: Int): Unit =
{
if (accessor(relative, param1, mode1, tape) < accessor(relative, param2, mode2, tape))
writer(tape, relative, param3, mode3, 1)
else
writer(tape, relative, param3, mode3, 0)
}
}

View file

@ -0,0 +1,16 @@
package day09.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[Long], relative: Long, param1: Long, param2: Long, param3: Long, mode1: Int, mode2: Int, mode3: Int): Unit =
{
if (accessor(relative, param1, mode1, tape) == accessor(relative, param2, mode2, tape))
writer(tape, relative, param3, mode3, 1)
else
writer(tape, relative, param3, mode3, 0)
}
}

View file

@ -0,0 +1,13 @@
package day09.intcode.opcode
case object OpCode9 extends OpCode
{
/** Find what to add to relative */
def exec(tape: Array[Long], relative: Long, param1: Long, mode1: Int): Long =
{
accessor(relative, param1, mode1, tape)
}
/** length of an instruction */
override val length: Int = 2
}

View file

@ -0,0 +1,6 @@
package day09.intcode.opcode
case object OpCode99 extends OpCode {
/** length of an instruction */
override val length: Int = 1
}

View file

@ -0,0 +1,7 @@
package day09.intcode.opcode
trait Output extends OpCode
{
/** Executes instruction for given parameters and modes */
def output(tape: Array[Long], relative: Long, param1: Long, mode1: Int): Long
}