package be.vandewalleh.aoc.days import be.vandewalleh.aoc.utils.input.Day import be.vandewalleh.aoc.utils.input.Lines import org.eclipse.collections.impl.factory.primitive.IntLists import org.eclipse.collections.impl.factory.primitive.IntSets @Day(8) class Day08(@Lines val input: List) { private val instructions = input.map { val words = it.split(" ") Instruction(Operation.valueOf(words[0].capitalize()), words[1].toInt()) }.toTypedArray() fun part1() = run(instructions).let { when (it) { is VmResult.Looped -> it.acc is VmResult.Terminated -> it.acc } } private fun run(instructions: Array): VmResult { var acc = 0 var ptr = 0 val visited = IntSets.mutable.empty() while (visited.add(ptr)) { val instruction = instructions[ptr] when (instruction.operation) { Operation.Acc -> { acc += instruction.argument ptr++ } Operation.Jmp -> ptr += instruction.argument Operation.Nop -> ptr++ } if (ptr !in instructions.indices) { return VmResult.Terminated(acc) } } return VmResult.Looped(acc) } fun part2(): Int { val possibleMutations = IntLists.mutable.empty() instructions.forEachIndexed { i, e -> if (e.operation == Operation.Jmp || e.operation == Operation.Nop) possibleMutations.add(i) } for (index in possibleMutations.toArray()) { val copy = instructions.copyOf().also { val modifiedOperation = if (it[index].operation == Operation.Nop) Operation.Jmp else Operation.Nop it[index] = it[index].copy(operation = modifiedOperation) } val res = run(copy) if (res is VmResult.Terminated) return res.acc } error("No result found") } } private enum class Operation { Acc, Jmp, Nop } private data class Instruction(val operation: Operation, val argument: Int) private sealed class VmResult { data class Looped(val acc: Int) : VmResult() data class Terminated(val acc: Int) : VmResult() }