Skip to content

Commit c30ded8

Browse files
committed
Solution 2018-16 (Chronal Classification)
1 parent 7994405 commit c30ded8

File tree

2 files changed

+91
-38
lines changed

2 files changed

+91
-38
lines changed

src/main/kotlin/de/ronny_h/aoc/year2018/day16/ChronalClassification.kt

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,98 +3,121 @@ package de.ronny_h.aoc.year2018.day16
33
import de.ronny_h.aoc.AdventOfCode
44
import de.ronny_h.aoc.extensions.collections.split
55

6-
fun main() = ChronalClassification().run(531, 0)
6+
fun main() = ChronalClassification().run(531, 649)
77

88
class ChronalClassification : AdventOfCode<Int>(2018, 16) {
99
override fun part1(input: List<String>): Int {
10-
val samples = input.parseCPUSamples()
11-
val device = WristDevice()
12-
return device.behaveLikeNumberOfOpcodes(samples).filter { it > 2 }.size
10+
val device = WristDevice(input)
11+
return device.behaveLikeNumberOfOpcodes().filter { it > 2 }.size
1312
}
1413

1514
override fun part2(input: List<String>): Int {
16-
return 0
15+
val device = WristDevice(input)
16+
val operations = device.deduceOpcodeMapping()
17+
return device.runProgram(operations)
1718
}
1819
}
1920

20-
class WristDevice {
21+
class WristDevice(input: List<String>) {
22+
private val samples = input.parseCPUSamples()
23+
private val testProgram = input.parseTestProgram()
2124
private val registers = mutableListOf(0, 0, 0, 0)
2225

2326
private val addr = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
2427
registers[outC] = registers[inA] + registers[inB]
2528
}
26-
2729
private val addi = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
2830
registers[outC] = registers[inA] + inB
2931
}
30-
3132
private val mulr = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
3233
registers[outC] = registers[inA] * registers[inB]
3334
}
34-
3535
private val muli = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
3636
registers[outC] = registers[inA] * inB
3737
}
38-
3938
private val banr = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
4039
registers[outC] = registers[inA] and registers[inB]
4140
}
42-
4341
private val bani = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
4442
registers[outC] = registers[inA] and inB
4543
}
46-
4744
private val borr = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
4845
registers[outC] = registers[inA] or registers[inB]
4946
}
50-
5147
private val bori = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
5248
registers[outC] = registers[inA] or inB
5349
}
54-
5550
private val setr = { inA: Int, _: Int, outC: Int, registers: MutableList<Int> ->
5651
registers[outC] = registers[inA]
5752
}
58-
5953
private val seti = { inA: Int, _: Int, outC: Int, registers: MutableList<Int> ->
6054
registers[outC] = inA
6155
}
62-
6356
private val gtir = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
6457
registers[outC] = if (inA > registers[inB]) 1 else 0
6558
}
66-
6759
private val gtri = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
6860
registers[outC] = if (registers[inA] > inB) 1 else 0
6961
}
70-
7162
private val gtrr = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
7263
registers[outC] = if (registers[inA] > registers[inB]) 1 else 0
7364
}
74-
7565
private val eqir = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
7666
registers[outC] = if (inA == registers[inB]) 1 else 0
7767
}
78-
7968
private val eqri = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
8069
registers[outC] = if (registers[inA] == inB) 1 else 0
8170
}
82-
8371
private val eqrr = { inA: Int, inB: Int, outC: Int, registers: MutableList<Int> ->
8472
registers[outC] = if (registers[inA] == registers[inB]) 1 else 0
8573
}
8674

8775
private val operations =
8876
listOf(addr, addi, mulr, muli, banr, bani, borr, bori, setr, seti, gtir, gtri, gtrr, eqir, eqri, eqrr)
8977

90-
fun behaveLikeNumberOfOpcodes(samples: List<CPUSample>) =
91-
samples.map { sample ->
92-
operations.count { op ->
93-
val registers = sample.registersBefore.toMutableList()
94-
op(sample.a, sample.b, sample.c, registers)
95-
registers == sample.registersAfter
78+
fun behaveLikeNumberOfOpcodes() =
79+
samples.map { sample -> operations.count { it.producesTheRightOutput(sample) } }
80+
81+
fun deduceOpcodeMapping(): List<(Int, Int, Int, MutableList<Int>) -> Unit> {
82+
val samplesByOpcode = samples.groupBy { it.opcode }
83+
val opCodesToOperationCandidates = buildList {
84+
for (i in operations.indices) {
85+
add(operations.filter { op ->
86+
samplesByOpcode.getValue(i).all { op.producesTheRightOutput(it) }
87+
})
9688
}
9789
}
90+
91+
val opCodeMapping = MutableList<((Int, Int, Int, MutableList<Int>) -> Unit)?>(16) { null }
92+
val alreadyMappedOperations = mutableSetOf<(Int, Int, Int, MutableList<Int>) -> Unit>()
93+
94+
while (alreadyMappedOperations.size < 16) {
95+
opCodesToOperationCandidates.forEachIndexed { i, ops ->
96+
val remainingOps = ops - alreadyMappedOperations
97+
if (remainingOps.size == 1) {
98+
opCodeMapping[i] = remainingOps.first()
99+
alreadyMappedOperations.add(remainingOps.first())
100+
}
101+
}
102+
}
103+
check(opCodeMapping.all { it != null })
104+
return opCodeMapping.filterNotNull().toList()
105+
}
106+
107+
private fun ((Int, Int, Int, MutableList<Int>) -> Unit).producesTheRightOutput(
108+
sample: CPUSample
109+
): Boolean {
110+
val registers = sample.registersBefore.toMutableList()
111+
this(sample.a, sample.b, sample.c, registers)
112+
return registers == sample.registersAfter
113+
}
114+
115+
fun runProgram(operations: List<(Int, Int, Int, MutableList<Int>) -> Unit>): Int {
116+
testProgram.forEach {
117+
operations[it.opCode](it.a, it.b, it.c, registers)
118+
}
119+
return registers[0]
120+
}
98121
}
99122

100123
fun List<String>.parseCPUSamples(): List<CPUSample> {
@@ -122,3 +145,24 @@ data class CPUSample(
122145
val c: Int,
123146
val registersAfter: List<Int>
124147
)
148+
149+
data class ProgramStep(val opCode: Int, val a: Int, val b: Int, val c: Int)
150+
151+
fun List<String>.parseTestProgram(): List<ProgramStep> {
152+
var emptyLines = 0
153+
val iterator = iterator()
154+
while (emptyLines < 3) {
155+
val line = iterator.next()
156+
if (line.isEmpty()) {
157+
emptyLines++
158+
} else {
159+
emptyLines = 0
160+
}
161+
}
162+
return buildList {
163+
while (iterator.hasNext()) {
164+
val (opCode, a, b, c) = iterator.next().split(" ").map { it.toInt() }
165+
add(ProgramStep(opCode, a, b, c))
166+
}
167+
}
168+
}

src/test/kotlin/de/ronny_h/aoc/year2018/day16/ChronalClassificationTest.kt

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,36 @@ class ChronalClassificationTest : StringSpec({
2323
8 1 0 1
2424
""".asList()
2525

26-
"input can be parsed" {
26+
"cpu samples can be parsed" {
2727
input.parseCPUSamples() shouldBe listOf(
2828
CPUSample(listOf(3, 2, 1, 1), 9, 2, 1, 2, listOf(3, 2, 2, 1)),
2929
CPUSample(listOf(3, 2, 1, 1), 9, 2, 1, 2, listOf(3, 2, 2, 1)),
3030
)
3131
}
3232

33+
"the test progarm can be parsed" {
34+
input.parseTestProgram() shouldBe listOf(
35+
ProgramStep(7, 3, 2, 0),
36+
ProgramStep(7, 2, 1, 1),
37+
ProgramStep(7, 1, 0, 3),
38+
ProgramStep(8, 1, 0, 1),
39+
)
40+
}
41+
3342
"the given sample behaves like three opcodes" {
34-
WristDevice().behaveLikeNumberOfOpcodes(
35-
listOf(
36-
CPUSample(listOf(3, 2, 1, 1), 9, 2, 1, 2, listOf(3, 2, 2, 1))
37-
)
38-
) shouldBe listOf(3)
43+
val input = """
44+
Before: [3, 2, 1, 1]
45+
9 2 1 2
46+
After: [3, 2, 2, 1]
47+
48+
49+
50+
7 3 2 0
51+
""".asList()
52+
WristDevice(input).behaveLikeNumberOfOpcodes() shouldBe listOf(3)
3953
}
4054

4155
"part 1: both of the given samples behave like three opcodes" {
4256
ChronalClassification().part1(input) shouldBe 2
4357
}
44-
45-
"part 2" {
46-
val input = listOf("")
47-
ChronalClassification().part2(input) shouldBe 0
48-
}
4958
})

0 commit comments

Comments
 (0)