What a mess.
Change-Id: I6691ff4ca64b6a2ae6edc38c4e2105130403437a
This commit is contained in:
parent
04dc4d6ba9
commit
158ed23e9e
@ -1,5 +1,6 @@
|
||||
package aoc2023
|
||||
|
||||
import lcm
|
||||
import println
|
||||
import readInput
|
||||
|
||||
@ -99,6 +100,14 @@ broadcaster -> a, b, c
|
||||
%b -> c
|
||||
%c -> inv
|
||||
&inv -> a
|
||||
"""
|
||||
|
||||
val inlineTestInput2 = """
|
||||
broadcaster -> a
|
||||
%a -> inv, con
|
||||
&inv -> b
|
||||
%b -> con
|
||||
&con -> output
|
||||
"""
|
||||
|
||||
data class Node(
|
||||
@ -110,7 +119,9 @@ broadcaster -> a, b, c
|
||||
var stateIdx: Int = 0
|
||||
)
|
||||
|
||||
fun part1(input: List<String>): Long {
|
||||
data class CacheInfo(val lowPulses: Long, val highPulses: Long, val nextState: BooleanArray)
|
||||
|
||||
fun createGraph(input: List<String>): HashMap<String, Node> {
|
||||
val nodes = HashMap<String, Node>()
|
||||
for (i in input) {
|
||||
val (source, targets) = i.split(" -> ")
|
||||
@ -128,51 +139,138 @@ broadcaster -> a, b, c
|
||||
for (node in nodes.values) {
|
||||
node.stateIdx = stateIdx++
|
||||
for (t in node.targets) {
|
||||
nodes[t]!!.inputs.add(node.id)
|
||||
nodes[t]?.inputs?.add(node.id)
|
||||
}
|
||||
}
|
||||
val state = BooleanArray(nodes.size)
|
||||
val queue = ArrayDeque<String>()
|
||||
queue.add("broadcaster")
|
||||
nodes["broadcaster"]!!.signalsIn.add(false)
|
||||
var lowPulses = 0L
|
||||
var highPulses = 0L
|
||||
var cycleCount = 0
|
||||
do {
|
||||
val node = nodes[queue.removeFirst()]!!
|
||||
val signalsIn = node.signalsIn
|
||||
when (node.type) {
|
||||
0 -> state[node.stateIdx] = node.signalsIn.single()
|
||||
1 -> state[node.stateIdx] = state[node.stateIdx] xor (!node.signalsIn.single())
|
||||
|
||||
2 -> {
|
||||
state[node.stateIdx] = !signalsIn.all { it }
|
||||
}
|
||||
}
|
||||
if (state[node.stateIdx]) highPulses += node.targets.size else lowPulses += node.targets.size
|
||||
node.targets.forEach { nodes[it]!!.signalsIn.add(state[node.stateIdx]) }
|
||||
node.signalsIn.clear()
|
||||
queue.addAll(node.targets)
|
||||
node.targets.forEach { println("${node.id} -${state[node.stateIdx]}> $it") }
|
||||
cycleCount++
|
||||
} while (cycleCount < 2 || state.any { it })
|
||||
|
||||
return lowPulses * highPulses
|
||||
return nodes
|
||||
}
|
||||
|
||||
fun part2(input: List<String>): Int {
|
||||
return 0
|
||||
fun part1(input: List<String>): Long {
|
||||
val nodes = createGraph(input)
|
||||
val state = BooleanArray(nodes.size)
|
||||
val cache = HashMap<String, CacheInfo>()
|
||||
var totalLowPulses = 0L
|
||||
var totalHighPulses = 0L
|
||||
for (n in 1..1000) {
|
||||
val stateString = state.joinToString("") { if (it) "1" else "0" }
|
||||
val cached = cache[stateString]
|
||||
if (cached != null) {
|
||||
totalLowPulses += cached.lowPulses
|
||||
totalHighPulses += cached.highPulses
|
||||
cached.nextState.copyInto(state)
|
||||
continue
|
||||
}
|
||||
val queue = LinkedHashSet<String>()
|
||||
queue.add("broadcaster")
|
||||
nodes["broadcaster"]!!.signalsIn.add(false)
|
||||
var lowPulses = 1L
|
||||
var highPulses = 0L
|
||||
do {
|
||||
val id = queue.first()
|
||||
queue.remove(id)
|
||||
val node = nodes[id]
|
||||
if (node != null) {
|
||||
val signalsIn = node.signalsIn
|
||||
for (signalIn in signalsIn) {
|
||||
when (node.type) {
|
||||
0 -> {
|
||||
state[node.stateIdx] = signalIn
|
||||
if (state[node.stateIdx]) highPulses += node.targets.size else lowPulses += node.targets.size
|
||||
node.targets.forEach { nodes[it]?.signalsIn?.add(state[node.stateIdx]) }
|
||||
queue.addAll(node.targets)
|
||||
}
|
||||
|
||||
1 -> if (!signalIn) {
|
||||
state[node.stateIdx] = !state[node.stateIdx]
|
||||
if (state[node.stateIdx]) highPulses += node.targets.size else lowPulses += node.targets.size
|
||||
node.targets.forEach { nodes[it]?.signalsIn?.add(state[node.stateIdx]) }
|
||||
queue.addAll(node.targets)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
state[node.stateIdx] = !node.inputs.all { state[nodes[it]!!.stateIdx] }
|
||||
if (state[node.stateIdx]) highPulses += node.targets.size else lowPulses += node.targets.size
|
||||
node.targets.forEach { nodes[it]?.signalsIn?.add(state[node.stateIdx]) }
|
||||
queue.addAll(node.targets)
|
||||
}
|
||||
}
|
||||
}
|
||||
node.signalsIn.clear()
|
||||
}
|
||||
} while (queue.isNotEmpty())
|
||||
cache[stateString] = CacheInfo(lowPulses, highPulses, state.copyOf())
|
||||
totalLowPulses += lowPulses
|
||||
totalHighPulses += highPulses
|
||||
}
|
||||
return totalLowPulses * totalHighPulses
|
||||
}
|
||||
|
||||
fun part2(input: List<String>): Long {
|
||||
val nodes = createGraph(input)
|
||||
val state = BooleanArray(nodes.size)
|
||||
var buttonCount = 0L
|
||||
val klNode = nodes.values.first { it.targets.contains("rx") }
|
||||
val periods = LongArray(klNode.inputs.size)
|
||||
do {
|
||||
buttonCount++
|
||||
val queue = LinkedHashSet<String>()
|
||||
queue.add("broadcaster")
|
||||
nodes["broadcaster"]!!.signalsIn.add(false)
|
||||
do {
|
||||
val id = queue.first()
|
||||
queue.remove(id)
|
||||
val node = nodes[id]
|
||||
if (node != null) {
|
||||
val signalsIn = node.signalsIn
|
||||
for (signalIn in signalsIn) {
|
||||
when (node.type) {
|
||||
0 -> {
|
||||
state[node.stateIdx] = signalIn
|
||||
node.targets.forEach { nodes[it]?.signalsIn?.add(state[node.stateIdx]) }
|
||||
queue.addAll(node.targets)
|
||||
}
|
||||
|
||||
1 -> if (!signalIn) {
|
||||
state[node.stateIdx] = !state[node.stateIdx]
|
||||
node.targets.forEach { nodes[it]?.signalsIn?.add(state[node.stateIdx]) }
|
||||
queue.addAll(node.targets)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
state[node.stateIdx] = !node.inputs.all { state[nodes[it]!!.stateIdx] }
|
||||
node.targets.forEach { nodes[it]?.signalsIn?.add(state[node.stateIdx]) }
|
||||
queue.addAll(node.targets)
|
||||
}
|
||||
}
|
||||
}
|
||||
node.signalsIn.clear()
|
||||
klNode.inputs.forEachIndexed { index, s ->
|
||||
if (state[nodes[s]!!.stateIdx]) {
|
||||
if (periods[index] == 0L) {
|
||||
periods[index] = buttonCount
|
||||
println("$index $s $buttonCount")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//node.targets.forEach { println("$rxCount: $lowPulses, $highPulses ${node.id} -${state[node.stateIdx]}> $it") }
|
||||
}
|
||||
} while (queue.isNotEmpty())
|
||||
//println("$buttonCount")
|
||||
} while (periods.any { it == 0L })
|
||||
return periods.asIterable().lcm()
|
||||
}
|
||||
|
||||
// test if implementation meets criteria from the description, like:
|
||||
val testInput = inlineTestInput.trim().reader().readLines()
|
||||
val testInput2 = inlineTestInput2.trim().reader().readLines()
|
||||
//val testInput = readInput("aoc2023/Day20_test")
|
||||
val testInputPart1Result = part1(testInput)
|
||||
println("Part 1 Test: $testInputPart1Result")
|
||||
val testInputPart2Result = part2(testInput)
|
||||
println("Part 2 Test: $testInputPart2Result")
|
||||
check(testInputPart1Result == 0L)
|
||||
check(testInputPart2Result == 0)
|
||||
val testInputPart1bResult = part1(testInput2)
|
||||
println("Part 1b Test: $testInputPart1bResult")
|
||||
check(testInputPart1Result == 32000000L)
|
||||
check(testInputPart1bResult == 11687500L)
|
||||
|
||||
val input = readInput("aoc2023/Day20")
|
||||
part1(input).println()
|
||||
|
Loading…
Reference in New Issue
Block a user