-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathy23day20part2.kt
85 lines (84 loc) · 3.29 KB
/
y23day20part2.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import java.util.*
import kotlin.collections.ArrayDeque
import kotlin.collections.List
import kotlin.collections.MutableSet
import kotlin.collections.buildMap
import kotlin.collections.buildSet
import kotlin.collections.forEach
import kotlin.collections.getOrPut
import kotlin.collections.indexOf
import kotlin.collections.mutableSetOf
import kotlin.collections.plusAssign
import kotlin.time.measureTime
fun main() {
data class Signal(val pulse: Boolean, val source: String, val destination: String)
open class Module(val name: String, val destinations: List<String>) {
fun process(input: Signal, output: (Signal) -> Unit) {
modulate(input)?.let { pulse ->
destinations.forEach { output(Signal(pulse, name, it)) }
}
}
open fun modulate(input: Signal): Boolean? = input.pulse
}
class FlipFlop(name: String, destinations: List<String>) : Module(name, destinations) {
var on = false
override fun modulate(input: Signal) =
if (!input.pulse) {
on = !on
on
} else null
}
class Conjunction(name: String, destinations: List<String>) : Module(name, destinations) {
val inputs = mutableSetOf<String>()
val states = BitSet()
override fun modulate(input: Signal) =
states.apply {
set(inputs.indexOf(input.source), input.pulse)
}.run { cardinality() != inputs.size }
}
val modules = generateSequence { readlnOrNull() }.map { line ->
line.splitToSequence(" -> ", ", ").let { tokens ->
val it = tokens.iterator()
val name = it.next()
val destinations = it.asSequence().toList()
when (name[0]) {
'%' -> FlipFlop(name.substring(1), destinations)
'&' -> Conjunction(name.substring(1), destinations)
else -> Module(name, destinations)
}
}
}.associateBy { it.name }
val sources = buildMap<String, MutableSet<String>> {
modules.values.forEach { module ->
module.destinations.forEach { dest ->
(modules[dest] as? Conjunction)?.apply { inputs += module.name }
getOrPut(dest) { mutableSetOf() } += module.name
}
}
}
val perspectiveModules = buildSet {
val marcReachable = DeepRecursiveFunction<String, Unit> { dest ->
add(dest)
sources[dest]?.forEach { if (it !in this@buildSet) callRecursive(it) }
}
marcReachable("rx")
}
println("Total Modules: ${modules.keys.size}")
println("Reachable Modules: ${perspectiveModules.size}")
measureTime {
generateSequence(1L) { it + 1 }.first {
var rxLoCount = 0
val queue = ArrayDeque<Signal>()
fun send(signal: Signal) {
if (signal.destination in perspectiveModules) queue.add(signal)
}
send(Signal(false, "button", "broadcaster"))
while (true) {
val signal = queue.removeFirstOrNull() ?: break
if (signal.destination == "rx" && !signal.pulse) ++rxLoCount
modules[signal.destination]?.process(signal, ::send)
}
rxLoCount == 1
}.let(::println)
}.let(::println)
}