1
+ package adventofcode2023
2
+
3
+ import java.io.File
4
+ import java.util.LinkedList
5
+
6
+ object Day20 {
7
+ private const val BROADCASTER = " broadcaster"
8
+ private const val RX_OUTPUT = " rx"
9
+
10
+ private val inputs = File (" resources/adventofcode2023/Day20.txt" )
11
+ .readLines()
12
+ .map { line ->
13
+ val split = line.split(" -> " )
14
+ Pair (split[0 ], split[1 ].split(" , " ))
15
+ }
16
+
17
+ private val modules: Map <String , Module > = inputs.associate { line ->
18
+ val name = line.first.removePrefix(" %" ).removePrefix(" &" )
19
+ val module =
20
+ when (line.first.first()) {
21
+ ' %' -> FlipFlopModule (line.second)
22
+ ' &' -> ConjunctionModule (line.second, inputs.filter { it.second.contains(name) }.map {
23
+ it.first.removePrefix(" %" ).removePrefix(" &" )
24
+ })
25
+ else -> BroadcastModule (line.second)
26
+ }
27
+ name to module
28
+ }
29
+
30
+ private sealed class Module (val outputs : List <String >) {
31
+ abstract fun send (pulse : Boolean , input : String ): Map <String , Boolean >
32
+
33
+ open fun reset () {}
34
+ }
35
+
36
+ private class BroadcastModule (outputs : List <String >) : Module(outputs) {
37
+ override fun send (pulse : Boolean , input : String ): Map <String , Boolean > =
38
+ outputs.associateWith { pulse }
39
+ }
40
+
41
+ private class FlipFlopModule (outputs : List <String >) : Module(outputs) {
42
+ var enabled = false
43
+
44
+ override fun send (pulse : Boolean , input : String ): Map <String , Boolean > =
45
+ if (pulse) emptyMap()
46
+ else {
47
+ enabled = ! enabled
48
+ outputs.associateWith { enabled }
49
+ }
50
+
51
+ override fun reset () { enabled = false }
52
+ }
53
+
54
+ private class ConjunctionModule (outputs : List <String >, val inputs : List <String >) : Module(outputs) {
55
+ var lastPulses = inputs.associateWith { false }.toMutableMap()
56
+
57
+ override fun send (pulse : Boolean , input : String ): Map <String , Boolean > {
58
+ lastPulses[input] = pulse
59
+ return outputs.associateWith { ! lastPulses.values.all { it } }
60
+ }
61
+
62
+ override fun reset () { lastPulses = inputs.associateWith { false }.toMutableMap() }
63
+ }
64
+
65
+ private fun pushButton (onEveryPulse : (String , Boolean , String ) -> Unit ) {
66
+ val queue = LinkedList (listOf (Triple (BROADCASTER , false , " " )))
67
+
68
+ while (queue.isNotEmpty()) {
69
+ val (destination, pulse, from) = queue.removeFirst()
70
+ val module = modules[destination]
71
+
72
+ onEveryPulse(destination, pulse, from)
73
+
74
+ module?.send(pulse, from)?.forEach {
75
+ queue.add(Triple (it.key, it.value, destination))
76
+ }
77
+ }
78
+ }
79
+
80
+ private fun highLowPulsesCounts (times : Int ): Map <Boolean , Long > {
81
+ val pulseCount = mutableMapOf (true to 0L , false to 0L )
82
+
83
+ for (i in 1 .. times) {
84
+ pushButton { _, pulse, _ ->
85
+ pulseCount[pulse] = pulseCount[pulse]!! .plus(1 )
86
+ }
87
+ }
88
+
89
+ return pulseCount
90
+ }
91
+
92
+ private fun pushesToGetRx (): Long {
93
+ val beforeRxName = modules.filter { it.value.outputs.contains(RX_OUTPUT ) }.map { it.key }.single()
94
+ val beforeRxInputsCounts = modules.filter { it.value.outputs.contains(beforeRxName) }.mapValues { 0L }.toMutableMap()
95
+ var pushCount = 0L
96
+
97
+ while (beforeRxInputsCounts.any { it.value == 0L }) {
98
+ pushCount++
99
+
100
+ pushButton { destination, pulse, from ->
101
+ if (destination == beforeRxName && pulse) {
102
+ beforeRxInputsCounts[from] = pushCount
103
+ }
104
+ }
105
+ }
106
+
107
+ return beforeRxInputsCounts.values.reduce { acc, i -> lcm(acc, i) }
108
+ }
109
+
110
+ private fun gcd (a : Long , b : Long ): Long = if (b == 0L ) a else gcd(b, a % b)
111
+
112
+ private fun lcm (a : Long , b : Long ): Long = a * b / gcd(a, b)
113
+
114
+ fun resetModules () = modules.forEach { it.value.reset() }
115
+
116
+ fun part1 () = println (highLowPulsesCounts(1000 ).values.reduce { acc, i -> acc * i })
117
+
118
+ fun part2 () = println (pushesToGetRx())
119
+ }
120
+
121
+ fun main () {
122
+ Day20 .part1()
123
+ Day20 .resetModules()
124
+ Day20 .part2()
125
+ }
0 commit comments