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
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<Int, OpCode>): 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<Int, OpCode>, 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()
}