Day 5, puzzle 2
This commit is contained in:
@@ -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()
|
||||
}
|
||||
Reference in New Issue
Block a user