diff --git a/src/main/kotlin/com/basdado/adventofcode/day5/Day5.kt b/src/main/kotlin/com/basdado/adventofcode/day5/Day5.kt index bcb3d0d..94b9c9f 100644 --- a/src/main/kotlin/com/basdado/adventofcode/day5/Day5.kt +++ b/src/main/kotlin/com/basdado/adventofcode/day5/Day5.kt @@ -1,39 +1,47 @@ package com.basdado.adventofcode.day5 -import com.basdado.adventofcode.day5.Day5.puzzle1 import com.basdado.adventofcode.line const val DAY5_INPUT_PATH = "/day/5/input.txt" fun main() { - puzzle1() + Day5.puzzle1() + Day5.puzzle2() + +// Day5.Program(intArrayOf(3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8), Day5.puzzle2OpCodes, 5).execute() } object Day5 { - val opcodes = mapOf( + private val puzzle1OpCodes = mapOf( Pair(1, OpCode(1, 3, ::add)), Pair(2, OpCode(2, 3, ::multiply)), Pair(3, OpCode(3, 1, ::saveInput)), Pair(4, OpCode(4, 1, ::writeOutput)) ) + val puzzle2OpCodes = puzzle1OpCodes + mapOf( + Pair(5, OpCode(5, 2, ::jumpIfTrue)), + Pair(6, OpCode(6, 2, ::jumpIfFalse)), + Pair(7, OpCode(7, 3, ::lessThan)), + Pair(8, OpCode(8, 3, ::equals)) + ) + fun puzzle1() { - val program = Program(line(DAY5_INPUT_PATH).split(",").map { it.toInt() }.toIntArray(), + val program = Program(line(DAY5_INPUT_PATH).split(",").map { it.toInt() }.toIntArray(), puzzle1OpCodes, 1) - var pointer = 0 - while (program.data[pointer] != 99) { + program.execute() + } - println(pointer) + fun puzzle2() { - val instruction = Instruction.parse(program.data[pointer], pointer) - instruction.opcode.operation.invoke(instruction, program) + val program = Program(line(DAY5_INPUT_PATH).split(",").map { it.toInt() }.toIntArray(), puzzle2OpCodes, + 5) - pointer += instruction.opcode.paramCount + 1 - } + program.execute() } class Instruction( @@ -43,8 +51,8 @@ object Day5 { ) { companion object { - fun parse(input: Int, pointer: Int): Instruction { - val opcode = opcodes[input % 100] ?: throw IllegalArgumentException("Uknown opcode for operation $input") + fun parse(input: Int, pointer: Int, opcodes: Map): Instruction { + val opcode = opcodes[input % 100] ?: throw IllegalArgumentException("Unknown opcode for operation $input") val paramModes = BooleanArray(opcode.paramCount) for (i in 0 until opcode.paramCount) { paramModes[i] = (input % pow10(i + 3)) / pow10(i + 2) == 1 @@ -54,7 +62,8 @@ object Day5 { } } - class Program(val data: IntArray, val input: Int) { + class Program(val data: IntArray, val opCodes: Map, val input: Int, + var pointer: Int = 0) { fun getValue(instruction: Instruction, i: Int): Int { return if (instruction.paramModeImmediate[i]) { @@ -68,6 +77,22 @@ object Day5 { // Setters don't care about parameter modes, they are always "position" based data[data[instruction.pos + i + 1]] = x } + + fun execute() { + while (data[pointer] != 99) { + + val instruction = Instruction.parse(data[pointer], pointer, opCodes) + val operationResult = instruction.opcode.operation.invoke(instruction, this) + + if (operationResult.output != null) { + println(operationResult.output) + } + + if (operationResult.moveToNextInstruction) { + pointer += instruction.opcode.paramCount + 1 + } + } + } } fun pow10(n: Int): Int { @@ -85,23 +110,60 @@ object Day5 { else -> throw IllegalArgumentException("Int overflowing with pow10($n)") } } - private fun add(instruction: Instruction, program: Program) { + private fun add(instruction: Instruction, program: Program): OperationResult { program.setValue(instruction, 2, program.getValue(instruction, 0) + program.getValue(instruction, 1)) + return VOID } - private fun multiply(instruction: Instruction, program: Program) { + private fun multiply(instruction: Instruction, program: Program): OperationResult { program.setValue(instruction, 2, program.getValue(instruction, 0) * program.getValue(instruction, 1)) + return VOID } - private fun saveInput(instruction: Instruction, program: Program) { + private fun saveInput(instruction: Instruction, program: Program): OperationResult { program.setValue(instruction, 0, program.input) + return VOID } - private fun writeOutput(instruction: Instruction, program: Program) { - // I guess we just write to console? - println(program.getValue(instruction, 0)) + private fun writeOutput(instruction: Instruction, program: Program): OperationResult { + return OperationResult(output = program.getValue(instruction, 0)) } - data class OpCode(val code: Int, val paramCount: Int, val operation: (instruction: Instruction, program: Program) -> Unit) + private fun jumpIfTrue(instruction: Instruction, program: Program): OperationResult { + return if (program.getValue(instruction, 0) != 0) { + program.pointer = program.getValue(instruction, 1) + OperationResult(moveToNextInstruction = false) + } else { + return VOID + } + } + + private fun jumpIfFalse(instruction: Instruction, program: Program): OperationResult { + + return if (program.getValue(instruction, 0) == 0) { + program.pointer = program.getValue(instruction, 1) + OperationResult(moveToNextInstruction = false) + } else { + VOID + } + } + + private fun lessThan(instruction: Instruction, program: Program): OperationResult { + program.setValue(instruction, 2, + if (program.getValue(instruction, 0) < program.getValue(instruction, 1)) 1 else 0) + return VOID + } + + private fun equals(instruction: Instruction, program: Program): OperationResult { + program.setValue(instruction, 2, + if (program.getValue(instruction, 0) == program.getValue(instruction, 1)) 1 else 0) + return VOID + } + + data class OpCode(val code: Int, val paramCount: Int, val operation: (instruction: Instruction, program: Program) -> OperationResult) + + data class OperationResult(val moveToNextInstruction: Boolean = true, val output: Int? = null) + + val VOID = OperationResult() } \ No newline at end of file