Day 16
This commit is contained in:
@@ -3,6 +3,7 @@ package com.basdado.adventofcode
|
||||
import java.util.Arrays.stream
|
||||
import java.util.function.Function
|
||||
import java.util.stream.Collectors
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
const val DAY15_INPUT = "/day/15/input.txt"
|
||||
|
||||
@@ -10,7 +11,7 @@ fun main() {
|
||||
|
||||
val day = Day15()
|
||||
day.puzzle1()
|
||||
day.puzzle2()
|
||||
println("Puzzle 2: " + measureTimeMillis { day.puzzle2() } + " ms")
|
||||
}
|
||||
|
||||
class Day15 {
|
||||
|
||||
149
src/main/kotlin/com/basdado/adventofcode/Day16.kt
Normal file
149
src/main/kotlin/com/basdado/adventofcode/Day16.kt
Normal file
@@ -0,0 +1,149 @@
|
||||
package com.basdado.adventofcode
|
||||
|
||||
import java.util.*
|
||||
import java.util.stream.Collectors
|
||||
|
||||
const val DAY16_INPUT = "/day/16/input.txt"
|
||||
|
||||
fun main() {
|
||||
|
||||
val day = Day16()
|
||||
day.puzzle1()
|
||||
day.puzzle2()
|
||||
|
||||
}
|
||||
|
||||
class Day16 {
|
||||
|
||||
fun puzzle1() {
|
||||
|
||||
val input = lines(DAY16_INPUT).collect(Collectors.toList())
|
||||
val beforeRegex = Regex("""Before:\s+\[(\d+), (\d+), (\d+), (\d+)\]""")
|
||||
val afterRegex = Regex("""After:\s+\[(\d+), (\d+), (\d+), (\d+)\]""")
|
||||
|
||||
var result = 0;
|
||||
|
||||
val iterator = input.iterator()
|
||||
while(iterator.hasNext()) {
|
||||
val line = iterator.next()
|
||||
val beforeMatch = beforeRegex.matchEntire(line)
|
||||
if (beforeMatch != null) {
|
||||
val regs = beforeMatch.groupValues.stream().skip(1).map { it.toInt() }.collect(Collectors.toList<Int>()).toIntArray()
|
||||
val operationParams= iterator.next().split(Regex("""\s+""")).map { it.toInt() }
|
||||
val afterRegs = afterRegex.matchEntire(iterator.next())!!.groupValues.stream().skip(1).map { it.toInt() }.collect(Collectors.toList()).toIntArray()
|
||||
|
||||
val matchingOpcodes = mutableListOf<Opcode>()
|
||||
for (opcode in Opcode.values()) {
|
||||
val opRegs = regs.clone()
|
||||
opcode.operation.invoke(opRegs, operationParams[1], operationParams[2], operationParams[3])
|
||||
if (Arrays.equals(afterRegs, opRegs)) {
|
||||
matchingOpcodes.add(opcode)
|
||||
}
|
||||
}
|
||||
if (matchingOpcodes.size >= 3) {
|
||||
// println(matchingOpcodes)
|
||||
result++
|
||||
}
|
||||
}
|
||||
iterator.next()
|
||||
}
|
||||
println(result)
|
||||
}
|
||||
|
||||
fun puzzle2() {
|
||||
|
||||
val input = lines(DAY16_INPUT).collect(Collectors.toList())
|
||||
val beforeRegex = Regex("""Before:\s+\[(\d+), (\d+), (\d+), (\d+)\]""")
|
||||
val afterRegex = Regex("""After:\s+\[(\d+), (\d+), (\d+), (\d+)\]""")
|
||||
|
||||
var result = 0
|
||||
|
||||
val opcodeIds = (0 until Opcode.values().size).map { Pair(it, Opcode.values().toMutableSet()) }.toMap()
|
||||
|
||||
val iterator = input.iterator()
|
||||
var emptyLineCount = 0
|
||||
while(iterator.hasNext()) {
|
||||
val line = iterator.next()
|
||||
|
||||
if (line.isBlank()) {
|
||||
emptyLineCount++
|
||||
} else {
|
||||
emptyLineCount = 0
|
||||
}
|
||||
|
||||
if (emptyLineCount >= 3) {
|
||||
break
|
||||
}
|
||||
val beforeMatch = beforeRegex.matchEntire(line)
|
||||
if (beforeMatch != null) {
|
||||
val regs = beforeMatch.groupValues.stream().skip(1).map { it.toInt() }.collect(Collectors.toList<Int>()).toIntArray()
|
||||
val instruction= iterator.next().split(Regex("""\s+""")).map { it.toInt() }
|
||||
val afterRegs = afterRegex.matchEntire(iterator.next())!!.groupValues.stream().skip(1).map { it.toInt() }.collect(Collectors.toList()).toIntArray()
|
||||
|
||||
val matchingOpcodes = mutableListOf<Opcode>()
|
||||
for (opcode in Opcode.values()) {
|
||||
val opRegs = regs.clone()
|
||||
opcode.operation.invoke(opRegs, instruction[1], instruction[2], instruction[3])
|
||||
if (Arrays.equals(afterRegs, opRegs)) {
|
||||
matchingOpcodes.add(opcode)
|
||||
}
|
||||
}
|
||||
opcodeIds[instruction[0]]!!.removeAll { !matchingOpcodes.contains(it) }
|
||||
|
||||
}
|
||||
}
|
||||
// println(opcodeIds)
|
||||
|
||||
// At this point, we've excluded many options from the opcode Ids
|
||||
// The next step is to actually assign the opcodeIds, so we find the opcodes for which we have a unique mapping,
|
||||
// and eliminate those from the options, until we have a complete one-to-one mapping
|
||||
var opcodesAssigned = mutableMapOf<Int, Opcode>()
|
||||
while(!opcodesAssigned.values.containsAll(Opcode.values().toList())) {
|
||||
|
||||
val opcodeToAssign = opcodeIds.entries.find { it.value.size == 1 && !opcodesAssigned.containsKey(it.key) }!!;
|
||||
val opcodeTaken = opcodeToAssign.value.first()
|
||||
opcodeIds.values.filter { it.size > 1 }.forEach { it.removeAll { opcode -> opcode == opcodeTaken } }
|
||||
opcodesAssigned.put(opcodeToAssign.key, opcodeToAssign.value.first())
|
||||
// println(opcodeIds)
|
||||
}
|
||||
println(opcodeIds)
|
||||
|
||||
// Now the program (the previous loop only read until the program starts
|
||||
val regs = IntArray(4) {0}
|
||||
while(iterator.hasNext()) {
|
||||
val line = iterator.next()
|
||||
val instruction= line.split(Regex("""\s+""")).map { it.toInt() }
|
||||
// println(line)
|
||||
opcodesAssigned[instruction[0]]!!.operation.invoke(regs, instruction[1], instruction[2], instruction[3])
|
||||
}
|
||||
println(regs.joinToString(" "))
|
||||
|
||||
|
||||
}
|
||||
|
||||
enum class Opcode(val operation: (IntArray, Int, Int, Int) -> Unit) {
|
||||
|
||||
ADDR({regs, a, b, c -> regs[c] = regs[a] + regs[b]}),
|
||||
ADDI({regs, a, b, c -> regs[c] = regs[a] + b}),
|
||||
|
||||
MULR({regs, a, b, c -> regs[c] = regs[a] * regs[b]}),
|
||||
MULI({regs, a, b, c -> regs[c] = regs[a] * b}),
|
||||
|
||||
BANR({regs, a, b, c -> regs[c] = regs[a] and regs[b]}),
|
||||
BANI({regs, a, b, c -> regs[c] = regs[a] and b}),
|
||||
|
||||
BORR({regs, a, b, c -> regs[c] = regs[a] or regs[b]}),
|
||||
BORI({regs, a, b, c -> regs[c] = regs[a] or b}),
|
||||
|
||||
SETR({regs, a, b, c -> regs[c] = regs[a]}),
|
||||
SETI({regs, a, b, c -> regs[c] = a}),
|
||||
|
||||
GTIR({regs, a, b, c -> regs[c] = if (a > regs[b]) 1 else 0}),
|
||||
GTRI({regs, a, b, c -> regs[c] = if (regs[a] > b) 1 else 0}),
|
||||
GTRR({regs, a, b, c -> regs[c] = if (regs[a] > regs[b]) 1 else 0}),
|
||||
|
||||
EQIR({regs, a, b, c -> regs[c] = if (a == regs[b]) 1 else 0}),
|
||||
EQRI({regs, a, b, c -> regs[c] = if (regs[a] == b) 1 else 0}),
|
||||
EQRR({regs, a, b, c -> regs[c] = if (regs[a] == regs[b]) 1 else 0}),
|
||||
}
|
||||
}
|
||||
4
src/main/resources/day/16/example.txt
Normal file
4
src/main/resources/day/16/example.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Before: [3, 2, 1, 1]
|
||||
9 2 1 2
|
||||
After: [3, 2, 2, 1]
|
||||
|
||||
4006
src/main/resources/day/16/input.txt
Normal file
4006
src/main/resources/day/16/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user