|
| 1 | +package me.peckb.aoc._2024.calendar.day17 |
| 2 | + |
| 3 | +import javax.inject.Inject |
| 4 | +import me.peckb.aoc.generators.InputGenerator.InputGeneratorFactory |
| 5 | +import kotlin.math.pow |
| 6 | + |
| 7 | +class Day17 @Inject constructor( |
| 8 | + private val generatorFactory: InputGeneratorFactory, |
| 9 | +) { |
| 10 | + fun partOne(filename: String) = generatorFactory.forFile(filename).read { input -> |
| 11 | + val computer = Computer.fromInput(input) |
| 12 | + val output = runProgram(computer) |
| 13 | + output.joinToString(",") |
| 14 | + } |
| 15 | + |
| 16 | + fun partTwo(filename: String) = generatorFactory.forFile(filename).read { input -> |
| 17 | + val computer = Computer.fromInput(input) |
| 18 | + |
| 19 | + findProgram(computer, computer.operations.map{ it.toLong() }) |
| 20 | + } |
| 21 | + |
| 22 | + private fun findProgram(computer: Computer, target: List<Long>): Long { |
| 23 | + var aStart = if (target.size > 1) { |
| 24 | + 8 * findProgram(computer, target.drop(1)) |
| 25 | + } else { 0 } |
| 26 | + |
| 27 | + while(runProgram(computer.copy(aReg = aStart)) != target) { |
| 28 | + aStart++ |
| 29 | + } |
| 30 | + |
| 31 | + return aStart |
| 32 | + } |
| 33 | + |
| 34 | + private fun runProgram(c: Computer): List<Long> { |
| 35 | + val output = mutableListOf<Long>() |
| 36 | + var programPointer = 0 |
| 37 | + |
| 38 | + while(programPointer < c.operations.size - 1) { |
| 39 | + val opcode = c.operations[programPointer] |
| 40 | + val operand = c.operations[programPointer + 1] |
| 41 | + |
| 42 | + programPointer += 2 |
| 43 | + |
| 44 | + val comboOperand by lazy { |
| 45 | + when (operand) { |
| 46 | + 0, 1, 2, 3 -> operand.toLong() |
| 47 | + 4 -> c.aReg |
| 48 | + 5 -> c.bReg |
| 49 | + 6 -> c.cReg |
| 50 | + else -> throw IllegalArgumentException("Invalid operand: $operand") |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + when (opcode) { |
| 55 | + 0 -> c.aReg = (c.aReg / 2.0.pow(comboOperand.toDouble())).toLong() |
| 56 | + 1 -> c.bReg = c.bReg xor operand.toLong() |
| 57 | + 2 -> c.bReg = comboOperand % 8 |
| 58 | + 3 -> if (c.aReg != 0L) { programPointer = operand } |
| 59 | + 4 -> c.bReg = c.bReg xor c.cReg |
| 60 | + 5 -> output.add(comboOperand % 8) |
| 61 | + 6 -> c.bReg = (c.aReg / 2.0.pow(comboOperand.toDouble())).toLong() |
| 62 | + 7 -> c.cReg = (c.aReg / 2.0.pow(comboOperand.toDouble())).toLong() |
| 63 | + } |
| 64 | + } |
| 65 | + |
| 66 | + return output |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | +data class Computer(var aReg: Long, var bReg: Long, var cReg: Long, val operations: List<Int>) { |
| 71 | + companion object { |
| 72 | + fun fromInput(input: Sequence<String>): Computer { |
| 73 | + val data = input.toList() |
| 74 | + val aReg = data[0].split("A: ")[1].toLong() |
| 75 | + val bReg = data[1].split("B: ")[1].toLong() |
| 76 | + val cReg = data[2].split("C: ")[1].toLong() |
| 77 | + |
| 78 | + val program = data[4].split(": ")[1].split(",").map { it.toInt() } |
| 79 | + |
| 80 | + return Computer(aReg, bReg, cReg, program) |
| 81 | + } |
| 82 | + } |
| 83 | +} |
0 commit comments