Day 5, puzzle 2

This commit is contained in:
2019-12-05 22:49:26 +01:00
parent 7f3e1580b7
commit 23d5f0233f

View File

@@ -1,39 +1,47 @@
package com.basdado.adventofcode.day5 package com.basdado.adventofcode.day5
import com.basdado.adventofcode.day5.Day5.puzzle1
import com.basdado.adventofcode.line import com.basdado.adventofcode.line
const val DAY5_INPUT_PATH = "/day/5/input.txt" const val DAY5_INPUT_PATH = "/day/5/input.txt"
fun main() { 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 { object Day5 {
val opcodes = mapOf( private val puzzle1OpCodes = mapOf(
Pair(1, OpCode(1, 3, ::add)), Pair(1, OpCode(1, 3, ::add)),
Pair(2, OpCode(2, 3, ::multiply)), Pair(2, OpCode(2, 3, ::multiply)),
Pair(3, OpCode(3, 1, ::saveInput)), Pair(3, OpCode(3, 1, ::saveInput)),
Pair(4, OpCode(4, 1, ::writeOutput)) 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() { 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) 1)
var pointer = 0 program.execute()
while (program.data[pointer] != 99) {
println(pointer)
val instruction = Instruction.parse(program.data[pointer], pointer)
instruction.opcode.operation.invoke(instruction, program)
pointer += instruction.opcode.paramCount + 1
} }
fun puzzle2() {
val program = Program(line(DAY5_INPUT_PATH).split(",").map { it.toInt() }.toIntArray(), puzzle2OpCodes,
5)
program.execute()
} }
class Instruction( class Instruction(
@@ -43,8 +51,8 @@ object Day5 {
) { ) {
companion object { companion object {
fun parse(input: Int, pointer: Int): Instruction { fun parse(input: Int, pointer: Int, opcodes: Map<Int, OpCode>): Instruction {
val opcode = opcodes[input % 100] ?: throw IllegalArgumentException("Uknown opcode for operation $input") val opcode = opcodes[input % 100] ?: throw IllegalArgumentException("Unknown opcode for operation $input")
val paramModes = BooleanArray(opcode.paramCount) val paramModes = BooleanArray(opcode.paramCount)
for (i in 0 until opcode.paramCount) { for (i in 0 until opcode.paramCount) {
paramModes[i] = (input % pow10(i + 3)) / pow10(i + 2) == 1 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<Int, OpCode>, val input: Int,
var pointer: Int = 0) {
fun getValue(instruction: Instruction, i: Int): Int { fun getValue(instruction: Instruction, i: Int): Int {
return if (instruction.paramModeImmediate[i]) { return if (instruction.paramModeImmediate[i]) {
@@ -68,6 +77,22 @@ object Day5 {
// Setters don't care about parameter modes, they are always "position" based // Setters don't care about parameter modes, they are always "position" based
data[data[instruction.pos + i + 1]] = x 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 { fun pow10(n: Int): Int {
@@ -85,23 +110,60 @@ object Day5 {
else -> throw IllegalArgumentException("Int overflowing with pow10($n)") 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)) 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)) 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) program.setValue(instruction, 0, program.input)
return VOID
} }
private fun writeOutput(instruction: Instruction, program: Program) { private fun writeOutput(instruction: Instruction, program: Program): OperationResult {
// I guess we just write to console? return OperationResult(output = program.getValue(instruction, 0))
println(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()
} }