Skip to content

Commit f93ac4d

Browse files
committed
Day 17, prepare for part two
* be able to save and restore the internal state * make the register Ints Long * replace the A/2^x calculations with A shr x
1 parent 4029763 commit f93ac4d

File tree

2 files changed

+71
-30
lines changed

2 files changed

+71
-30
lines changed
Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
package de.ronny_h.aoc.year24.day17
2-
31
import de.ronny_h.aoc.AdventOfCode
42
import kotlin.math.pow
53
import kotlin.properties.Delegates
@@ -8,10 +6,23 @@ fun main() = ChronospatialComputer().run("4,1,7,6,4,1,0,2,7", "TODO")
86

97
class ChronospatialComputer : AdventOfCode<String>(2024, 17) {
108
override fun part1(input: List<String>): String {
11-
return ThreeBitComputer().runProgram(input)
9+
return ThreeBitComputer(input).runProgram().joinToString(",")
1210
}
1311

14-
override fun part2(input: List<String>): String = "TODO"
12+
override fun part2(input: List<String>): String {
13+
val computer = ThreeBitComputer(input)
14+
val initState = computer.save()
15+
var registerA = 0L
16+
println("${computer.program} ${computer.program.size}")
17+
while (computer.runProgram() != computer.program) {
18+
registerA++
19+
if (registerA % 1000000 == 0L) {
20+
println("$registerA - ${computer.getOutputList()} ${computer.getOutputList().size}")
21+
}
22+
computer.restore(initState, registerA)
23+
}
24+
return "$registerA"
25+
}
1526
}
1627

1728
/**
@@ -38,50 +49,53 @@ class ChronospatialComputer : AdventOfCode<String>(2024, 17) {
3849
* 6 bdv division of A and 2^<combo operand>, truncated result in B
3950
* 7 cdv division of A and 2^<combo operand>, truncated result in C
4051
*/
41-
private class ThreeBitComputer {
52+
private class ThreeBitComputer(input: List<String>) {
4253

4354
private val instructionStep = 2
4455

45-
private lateinit var program: List<Int>
46-
private var registerA by Delegates.notNull<Int>()
47-
private var registerB by Delegates.notNull<Int>()
48-
private var registerC by Delegates.notNull<Int>()
56+
val program = input.readProgram()
57+
private var registerA = input.readRegister('A')
58+
private var registerB = input.readRegister('B')
59+
private var registerC = input.readRegister('C')
4960
private var instructionPointer = 0
5061

5162
private val output = mutableListOf<Int>()
5263

53-
fun init(input: List<String>) {
54-
program = input.readProgram()
55-
registerA = input.readRegister('A')
56-
registerB = input.readRegister('B')
57-
registerC = input.readRegister('C')
58-
instructionPointer = 0
59-
output.clear()
60-
}
64+
fun getOutputList(): List<Int> = output
6165

6266
private val instructions: List<(Int) -> Unit> = listOf(
63-
{ op -> registerA = (registerA / 2.0.pow(combo(op))).toInt(); next() }, // 0 adv
64-
{ op -> registerB = (registerB xor op) ; next() }, // 1 bxl
67+
{ op -> registerA = (registerA shr combo(op).toIntChecked()); next() }, // 0 adv; A/2^x = A shr x
68+
{ op -> registerB = (registerB xor op.toLong()) ; next() }, // 1 bxl
6569
{ op -> registerB = (combo(op) % 8) and 7 ; next() }, // 2 bst; 7=111 -> take only lowest 3 bits
66-
{ op -> if (registerA == 0) next() else instructionPointer = op }, // 3 jnz
70+
{ op -> if (registerA == 0L) next() else instructionPointer = op }, // 3 jnz
6771
{ _ -> registerB = (registerB xor registerC) ; next() }, // 4 bxc
68-
{ op -> output.add((combo(op) % 8) and 7) ; next() }, // 5 out
69-
{ op -> registerB = (registerA / 2.0.pow(combo(op))).toInt(); next() }, // 6 bdv
70-
{ op -> registerC = (registerA / 2.0.pow(combo(op))).toInt(); next() }, // 7 cdv
72+
{ op -> output.add(((combo(op) % 8) and 7).toInt()) ; next() }, // 5 out
73+
{ op -> registerB = (registerA shr combo(op).toIntChecked()); next() }, // 6 bdv
74+
{ op -> registerC = (registerA shr combo(op).toIntChecked()); next() }, // 7 cdv
7175
)
7276

73-
fun runProgram(input: List<String>): String {
74-
init(input)
77+
fun runProgram(): List<Int> {
7578
while (instructionPointer < program.size) {
7679
val instruction = program[instructionPointer]
7780
val op = program[instructionPointer + 1]
7881
instructions[instruction].invoke(op)
7982
}
80-
return output.joinToString(",")
83+
return output
84+
}
85+
86+
fun save() = State(registerA, registerB, registerC, instructionPointer)
87+
fun restore(state: State, registerAOverride: Long) {
88+
this.registerA = registerAOverride
89+
this.registerB = state.registerB
90+
this.registerC = state.registerC
91+
this.instructionPointer = state.instructionPointer
92+
this.output.clear()
8193
}
8294

8395
private fun combo(op: Int) = when (op) {
84-
in 1..3 -> op
96+
1 -> 1L
97+
2 -> 2L
98+
3 -> 3L
8599
4 -> registerA
86100
5 -> registerB
87101
6 -> registerC
@@ -95,11 +109,25 @@ private class ThreeBitComputer {
95109
private fun List<String>.readRegister(register: Char) =
96110
first { it.startsWith("Register $register: ") }
97111
.substringAfter("Register $register: ")
98-
.toInt()
112+
.toLong()
99113

100114
private fun List<String>.readProgram() =
101115
first { it.startsWith("Program: ") }
102116
.substringAfter("Program: ")
103117
.split(",")
104118
.map(String::toInt)
119+
120+
data class State(
121+
val registerA: Long,
122+
val registerB: Long,
123+
val registerC: Long,
124+
val instructionPointer: Int,
125+
)
126+
}
127+
128+
private fun Long.toIntChecked(): Int {
129+
if (this > Int.MAX_VALUE) {
130+
throw IllegalArgumentException("$this exceeds Int range")
131+
}
132+
return this.toInt()
105133
}
Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package de.ronny_h.aoc.year24.day17
22

3+
import ChronospatialComputer
34
import de.ronny_h.aoc.extensions.asList
45
import io.kotest.core.spec.style.StringSpec
56
import io.kotest.matchers.shouldBe
67

78
class ChronospatialComputerTest : StringSpec({
8-
val input = """
9+
val input1 = """
910
Register A: 729
1011
Register B: 0
1112
Register C: 0
@@ -14,6 +15,18 @@ class ChronospatialComputerTest : StringSpec({
1415
""".asList()
1516

1617
"part 1: The program's output" {
17-
ChronospatialComputer().part1(input) shouldBe "4,6,3,5,6,3,5,2,1,0"
18+
ChronospatialComputer().part1(input1) shouldBe "4,6,3,5,6,3,5,2,1,0"
19+
}
20+
21+
val input2 = """
22+
Register A: 2024
23+
Register B: 0
24+
Register C: 0
25+
26+
Program: 0,3,5,4,3,0
27+
""".asList()
28+
29+
"part 2: The value of A so that the program outputs itself" {
30+
ChronospatialComputer().part2(input2) shouldBe "117440"
1831
}
1932
})

0 commit comments

Comments
 (0)