@@ -3,98 +3,121 @@ package de.ronny_h.aoc.year2018.day16
33import de.ronny_h.aoc.AdventOfCode
44import de.ronny_h.aoc.extensions.collections.split
55
6- fun main () = ChronalClassification ().run (531 , 0 )
6+ fun main () = ChronalClassification ().run (531 , 649 )
77
88class 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
100123fun 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+ }
0 commit comments