Skip to content

Commit 5eb799a

Browse files
committed
Solution 2017-23, part 1 (Coprocessor Conflagration)
Solved by extending solution for day 18 with two additional instructions, Sub and JumpIfNotZero. This solves part 1 directly why it doesn't terminate in reasonable time for part 2. For that, in CoprocessorConflagration.kt a 1:1 transformation of the assembler code functions as a base for further analysis and simplification.
1 parent 8d08fa4 commit 5eb799a

File tree

3 files changed

+150
-11
lines changed

3 files changed

+150
-11
lines changed

src/main/kotlin/de/ronny_h/aoc/year2017/day18/Duet.kt

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class Duet : AdventOfCode<Long>(2017, 18) {
2121
override fun part2(input: List<String>): Long = runBlocking {
2222
val channel0 = Channel<Long>(UNLIMITED)
2323
val channel1 = Channel<Long>(UNLIMITED)
24-
val program0 = Program(input, 0, channel0, channel1)
25-
val program1 = Program(input, 1, channel1, channel0)
24+
val program0 = Program(input, channel0, channel1, mapOf(P_REGISTER to 0, PROGRAM_NUMBER_REGISTER to 0))
25+
val program1 = Program(input, channel1, channel0, mapOf(P_REGISTER to 1, PROGRAM_NUMBER_REGISTER to 1))
2626

2727
val job0 = launch { program0.run() }
2828
val job1 = launch { program1.run() }
@@ -75,6 +75,11 @@ fun List<String>.parseInstructions(
7575
Add(register, value.toValue())
7676
}
7777

78+
"sub" -> {
79+
val (register, value) = parameters.split(" ")
80+
Sub(register, value.toValue())
81+
}
82+
7883
"mul" -> {
7984
val (register, value) = parameters.split(" ")
8085
Multiply(register, value.toValue())
@@ -92,6 +97,11 @@ fun List<String>.parseInstructions(
9297
JumpIfGreaterZero(value.toValue(), offset.toValue())
9398
}
9499

100+
"jnz" -> {
101+
val (value, offset) = parameters.split(" ")
102+
JumpIfNotZero(value.toValue(), offset.toValue())
103+
}
104+
95105
else -> error("unknown instruction: $it")
96106
}
97107
}
@@ -114,9 +124,11 @@ sealed interface Value {
114124
}
115125
}
116126

127+
private const val P_REGISTER = "p"
117128
private const val PROGRAM_NUMBER_REGISTER = "programNumber"
118129
private const val LAST_PLAYED_SOUND_REGISTER = "lastPlayedSound"
119130
private const val NUMBER_OF_SENDS_REGISTER = "numberOfSends"
131+
private const val NUMBER_OF_MULTIPLY_REGISTER = "numberOfMultiply"
120132

121133
sealed interface Instruction {
122134
suspend fun executeOn(registers: MutableMap<String, Long>): Long
@@ -154,9 +166,18 @@ sealed interface Instruction {
154166
}
155167
}
156168

169+
data class Sub(private val register: String, val value: Value) : Instruction {
170+
override suspend fun executeOn(registers: MutableMap<String, Long>): Long {
171+
registers[register] = registers.getValue(register) - value.toNumber(registers)
172+
return registers.getValue(register)
173+
}
174+
}
175+
157176
data class Multiply(private val register: String, val value: Value) : Instruction {
158177
override suspend fun executeOn(registers: MutableMap<String, Long>): Long {
159178
registers[register] = registers.getValue(register) * value.toNumber(registers)
179+
val numberOfMultiplies = registers.getValue(NUMBER_OF_MULTIPLY_REGISTER) + 1
180+
registers[NUMBER_OF_MULTIPLY_REGISTER] = numberOfMultiplies
160181
return registers.getValue(register)
161182
}
162183
}
@@ -186,33 +207,42 @@ sealed interface Instruction {
186207
}
187208
}
188209

189-
data class JumpIfGreaterZero(private val value: Value, private val offset: Value) : Instruction {
210+
sealed interface Jump : Instruction
211+
212+
data class JumpIfGreaterZero(private val value: Value, private val offset: Value) : Jump {
190213
override suspend fun executeOn(registers: MutableMap<String, Long>): Long {
191214
if (value.toNumber(registers) > 0) {
192215
return offset.toNumber(registers)
193216
}
194217
return 1
195218
}
196219
}
220+
221+
data class JumpIfNotZero(private val value: Value, private val offset: Value) : Jump {
222+
override suspend fun executeOn(registers: MutableMap<String, Long>): Long {
223+
if (value.toNumber(registers) != 0L) {
224+
return offset.toNumber(registers)
225+
}
226+
return 1
227+
}
228+
}
197229
}
198230

199231
class Program(
200232
input: List<String>,
201-
programNumber: Long = 0,
202233
sendChannel: Channel<Long>? = null,
203234
receiveChannel: Channel<Long>? = null,
235+
presetRegisters: Map<String, Long> = emptyMap()
204236
) {
205237
var isReceiving = false
238+
private set
206239

207240
private val instructions = input.parseInstructions(sendChannel, receiveChannel)
208-
private val registers = mutableMapOf(
209-
"p" to programNumber,
210-
PROGRAM_NUMBER_REGISTER to programNumber,
211-
).withDefault { 0 }
241+
private val registers = presetRegisters.toMutableMap().withDefault { 0 }
212242
private var instructionPointer = 0L
213243

214244
suspend fun run(): Long {
215-
println("program ${registers[PROGRAM_NUMBER_REGISTER]} started")
245+
println("program ${registers.getValue(PROGRAM_NUMBER_REGISTER)} started")
216246
while (instructionPointer in instructions.indices) {
217247
val instruction = instructions[instructionPointer.toIntChecked()]
218248
if (instruction is Receive) {
@@ -224,15 +254,17 @@ class Program(
224254
println("program ${registers[PROGRAM_NUMBER_REGISTER]}: instruction \"Recover\" with register not zero -> terminating")
225255
return result
226256
}
227-
instructionPointer += if (instruction is JumpIfGreaterZero) {
257+
instructionPointer += if (instruction is Jump) {
228258
result
229259
} else {
230260
1L
231261
}
232262
}
233-
println("program ${registers[PROGRAM_NUMBER_REGISTER]}: instruction pointer ran out of bounds: $instructionPointer -> terminating")
263+
println("program ${registers.getValue(PROGRAM_NUMBER_REGISTER)}: instruction pointer ran out of bounds: $instructionPointer -> terminating")
234264
return -1L
235265
}
236266

237267
fun getNumberOfSends(): Long = registers.getValue(NUMBER_OF_SENDS_REGISTER)
268+
fun getNumberOfMultiplies(): Long = registers.getValue(NUMBER_OF_MULTIPLY_REGISTER)
269+
fun getRegisterValue(register: String): Long = registers.getValue(register)
238270
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package de.ronny_h.aoc.year2017.day23
2+
3+
import de.ronny_h.aoc.AdventOfCode
4+
import de.ronny_h.aoc.year2017.day18.Program
5+
import kotlinx.coroutines.runBlocking
6+
7+
fun main() = CoprocessorConflagration().run(4225, 0)
8+
9+
class CoprocessorConflagration : AdventOfCode<Long>(2017, 23) {
10+
override fun part1(input: List<String>): Long = runBlocking {
11+
val program = Program(input)
12+
program.run()
13+
return@runBlocking program.getNumberOfMultiplies()
14+
}
15+
16+
override fun part2(input: List<String>): Long = runBlocking {
17+
val program = Program(input, presetRegisters = mapOf("a" to 1))
18+
program.run()
19+
return@runBlocking program.getRegisterValue("h")
20+
}
21+
}
22+
23+
private fun partTwoAsKotlin(): Int {
24+
val a = 1
25+
var d = 0
26+
var e = 0
27+
var f = 0
28+
var g = 0
29+
var h = 0
30+
31+
var b = 67
32+
var c = b
33+
if (a != 0) {
34+
b *= 100
35+
b += 100000
36+
c = b
37+
c += 17000
38+
}
39+
while (true) {
40+
f = 1
41+
d = 2
42+
do {
43+
e = 2
44+
do {
45+
g = d
46+
g *= e
47+
g -= b
48+
if (g == 0) {
49+
f = 0
50+
}
51+
e++
52+
g = e
53+
g -= b
54+
} while (g != 0)
55+
d++
56+
g = d
57+
g -= b
58+
} while (g != 0)
59+
if (f == 0) {
60+
h++
61+
}
62+
g = b
63+
g -= c
64+
if (g == 0) {
65+
return h
66+
}
67+
b += 17
68+
}
69+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package de.ronny_h.aoc.year2017.day23
2+
3+
import de.ronny_h.aoc.extensions.asList
4+
import de.ronny_h.aoc.year2017.day18.Instruction.*
5+
import de.ronny_h.aoc.year2017.day18.Value.Number
6+
import de.ronny_h.aoc.year2017.day18.Value.Register
7+
import de.ronny_h.aoc.year2017.day18.parseInstructions
8+
import io.kotest.core.spec.style.StringSpec
9+
import io.kotest.matchers.shouldBe
10+
11+
class CoprocessorConflagrationTest : StringSpec({
12+
13+
val input = """
14+
set h 7
15+
jnz b 2
16+
jnz 1 1
17+
mul b 4
18+
sub c -1
19+
""".asList()
20+
21+
"input can be parsed" {
22+
input.parseInstructions(null, null) shouldBe listOf(
23+
SetValue("h", Number(7)),
24+
JumpIfNotZero(Register("b"), Number(2)),
25+
JumpIfNotZero(Number(1), Number(1)),
26+
Multiply("b", Number(4)),
27+
Sub("c", Number(-1))
28+
)
29+
}
30+
31+
"part 1: there should be 1 multiplication executed in the test input" {
32+
CoprocessorConflagration().part1(input) shouldBe 1
33+
}
34+
35+
"part 2: at the end of the test program h should be 7" {
36+
CoprocessorConflagration().part2(input) shouldBe 7
37+
}
38+
})

0 commit comments

Comments
 (0)