Skip to content

Commit efe17ae

Browse files
authored
Merge pull request #26 from palinkiewicz/2023_d20
2023 Day 20
2 parents 9ef757b + f5cb1d1 commit efe17ae

File tree

3 files changed

+184
-0
lines changed

3 files changed

+184
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ I started taking part in the event in 2023 but may also consider doing tasks fro
2626
| [Day 17: Clumsy Crucible](https://adventofcode.com/2023/day/17) | [Solution](/adventofcode2023/Day17.kt) | [Inputs](/resources/adventofcode2023/Day17.txt) |
2727
| [Day 18: Lavaduct Lagoon](https://adventofcode.com/2023/day/18) | [Solution](/adventofcode2023/Day18.kt) | [Inputs](/resources/adventofcode2023/Day18.txt) |
2828
| [Day 19: Aplenty](https://adventofcode.com/2023/day/19) | [Solution](/adventofcode2023/Day19.kt) | [Inputs](/resources/adventofcode2023/Day19.txt) |
29+
| [Day 20: Pulse Propagation](https://adventofcode.com/2023/day/20) | [Solution](/adventofcode2023/Day20.kt) | [Inputs](/resources/adventofcode2023/Day20.txt) |

adventofcode2023/Day20.kt

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
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+
}

resources/adventofcode2023/Day20.txt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
%rp -> gq, sd
2+
&kh -> cs
3+
%jz -> pl, jb
4+
%dx -> tx
5+
%dh -> bm, sd
6+
&zv -> ns, dx, hl, hn, fm
7+
%xb -> ds, sk
8+
%hv -> sk, kr
9+
%db -> zv, zz
10+
&sk -> rg, hh, hv, kr, kh, zl, zn
11+
%tc -> jz
12+
%dj -> ts, pl
13+
%jk -> sd, vh
14+
%fm -> dx, zv
15+
%dp -> sd, cc
16+
%vh -> sd
17+
&lz -> cs
18+
%kr -> rg
19+
%jb -> bf, pl
20+
%kz -> sk
21+
%ts -> pl, bs
22+
%gr -> ns, zv
23+
%kc -> sd, kf
24+
%jd -> zv
25+
%bs -> vg
26+
%zk -> rp
27+
%vf -> zk
28+
%mm -> ms, sk
29+
%qc -> pl, dj
30+
%fk -> qc
31+
%bm -> vf, sd
32+
%ds -> kz, sk
33+
%sn -> zv, jd
34+
%zn -> mm
35+
%ct -> fk
36+
%np -> sk, xb
37+
&tg -> cs
38+
%tx -> cm, zv
39+
%zl -> hh
40+
%zz -> px, zv
41+
%ms -> zl, sk
42+
%ns -> db
43+
%px -> zv, sn
44+
broadcaster -> fm, hv, kc, bv
45+
&hn -> cs
46+
%hh -> np
47+
%kf -> dh
48+
%vg -> pl, tc
49+
%bv -> ct, pl
50+
&pl -> bv, fk, ct, bs, tg, tc
51+
%cm -> zv, hl
52+
%cc -> sd, jk
53+
%bf -> pl
54+
%hl -> gr
55+
&cs -> rx
56+
%gq -> dp
57+
%rg -> zn
58+
&sd -> zk, kf, gq, lz, kc, vf

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy