Day 16
This commit is contained in:
@@ -3,6 +3,7 @@ package com.basdado.adventofcode
|
|||||||
import java.util.Arrays.stream
|
import java.util.Arrays.stream
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
import java.util.stream.Collectors
|
import java.util.stream.Collectors
|
||||||
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
const val DAY15_INPUT = "/day/15/input.txt"
|
const val DAY15_INPUT = "/day/15/input.txt"
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ fun main() {
|
|||||||
|
|
||||||
val day = Day15()
|
val day = Day15()
|
||||||
day.puzzle1()
|
day.puzzle1()
|
||||||
day.puzzle2()
|
println("Puzzle 2: " + measureTimeMillis { day.puzzle2() } + " ms")
|
||||||
}
|
}
|
||||||
|
|
||||||
class Day15 {
|
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