Skip to content

Commit b9f29c6

Browse files
committed
adding templates for all remaining days and start implementing day20
1 parent f0ecf89 commit b9f29c6

File tree

18 files changed

+295
-0
lines changed

18 files changed

+295
-0
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package tr.emreone.adventofcode.days
2+
3+
import tr.emreone.kotlin_utils.automation.Day
4+
import tr.emreone.kotlin_utils.math.*
5+
6+
class Day20 : Day(20, 2023, "Pulse Propagation") {
7+
8+
sealed class Module(val name: String, val destinations: List<String>) {
9+
abstract fun process(input: String, pulse: Boolean): List<Pair<String, Boolean>>
10+
abstract fun reset()
11+
12+
class FlipFlop(name: String, destinations: List<String>) : Module(name, destinations) {
13+
private var _state: Boolean = false
14+
val state: Boolean
15+
get() = _state
16+
17+
override fun reset() {
18+
_state = false
19+
}
20+
21+
override fun process(input: String, pulse: Boolean): List<Pair<String, Boolean>> {
22+
return if (pulse) {
23+
emptyList()
24+
} else {
25+
_state = !_state
26+
return destinations.map { it to state }
27+
}
28+
}
29+
}
30+
31+
class Conjunction(name: String, destinations: List<String>) : Module(name, destinations) {
32+
private val _states: MutableMap<String, Boolean> = mutableMapOf()
33+
val states: Map<String, Boolean>
34+
get() = _states
35+
36+
override fun reset() {
37+
for (name in states.keys) {
38+
_states[name] = false
39+
}
40+
}
41+
42+
override fun process(input: String, pulse: Boolean): List<Pair<String, Boolean>> {
43+
require(_states[input] != null)
44+
_states[input] = pulse
45+
val nextPulse = !_states.values.all { it }
46+
return destinations.map { it to nextPulse }
47+
}
48+
49+
fun addInput(name: String) {
50+
_states[name] = false
51+
}
52+
}
53+
54+
class Broadcast(name: String, destinations: List<String>) : Module(name, destinations) {
55+
override fun reset() {
56+
}
57+
58+
override fun process(input: String, pulse: Boolean): List<Pair<String, Boolean>> {
59+
return destinations.map { it to pulse }
60+
}
61+
}
62+
}
63+
64+
val modules = inputAsList.map { line ->
65+
val (input, outputsString) = line.split("->").map { it.trim() }
66+
val outputs = outputsString.split(",").map { it.trim() }
67+
when {
68+
input == "broadcaster" -> Module.Broadcast(input, outputs)
69+
input[0] == '%' -> Module.FlipFlop(input.substring(1), outputs)
70+
input[0] == '&' -> Module.Conjunction(input.substring(1), outputs)
71+
72+
else -> error("Invalid type: $input")
73+
}
74+
}.associateBy { it.name }
75+
76+
init {
77+
// Process inputs for conjunction modules
78+
for ((name, module) in modules) {
79+
for (target in module.destinations) {
80+
val targetModule = modules[target] ?: continue
81+
if (targetModule is Module.Conjunction) {
82+
targetModule.addInput(name)
83+
}
84+
}
85+
}
86+
}
87+
88+
private fun process(onProcess: (Module?, Boolean) -> Unit) {
89+
val pending = ArrayDeque<Triple<String, String, Boolean>>()
90+
pending += Triple("broadcaster", "button", false)
91+
while (pending.isNotEmpty()) {
92+
val (moduleName, input, pulse) = pending.removeFirst()
93+
94+
println("$input -${if (pulse) "high" else "low"}-> $moduleName")
95+
96+
val module = modules[moduleName]
97+
if (module != null) {
98+
for ((nextModule, nextPulse) in module.process(input, pulse)) {
99+
pending += Triple(nextModule, moduleName, nextPulse)
100+
}
101+
}
102+
onProcess.invoke(module, pulse)
103+
}
104+
}
105+
106+
override fun part1(): Long {
107+
modules.values.forEach { it.reset() }
108+
109+
var lowPulses = 0L
110+
var highPulses = 0L
111+
repeat(1000) {
112+
process { _, pulse ->
113+
if (pulse) {
114+
highPulses++
115+
} else {
116+
lowPulses++
117+
}
118+
}
119+
}
120+
return lowPulses * highPulses
121+
}
122+
123+
override fun part2(): Long {
124+
modules.values.forEach { it.reset() }
125+
126+
var iteration = 0L
127+
val targetModule = modules.values.single { it.destinations == listOf("rx") } as Module.Conjunction
128+
val initialIterations = mutableMapOf<String, Long>()
129+
val cycleIterations = mutableMapOf<String, Long>()
130+
while (initialIterations.size != targetModule.states.size || cycleIterations.size != targetModule.states.size) {
131+
iteration++
132+
process { module, _ ->
133+
if (module === targetModule) {
134+
for ((name, pulse) in module.states) {
135+
if (pulse) {
136+
val initialIteration = initialIterations[name]
137+
if (initialIteration == null) {
138+
initialIterations[name] = iteration
139+
} else if (cycleIterations[name] == null && iteration != initialIteration) {
140+
cycleIterations[name] = iteration - initialIteration
141+
}
142+
}
143+
}
144+
}
145+
}
146+
}
147+
148+
return chineseRemainder(
149+
targetModule.states.keys.map { initialIterations[it]!! to cycleIterations[it]!! }
150+
)?.first ?: error("No solution found")
151+
}
152+
153+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package tr.emreone.adventofcode.days
2+
3+
import tr.emreone.kotlin_utils.automation.Day
4+
5+
class Day21 : Day(21, 2023, "") {
6+
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package tr.emreone.adventofcode.days
2+
3+
import tr.emreone.kotlin_utils.automation.Day
4+
5+
class Day22 : Day(22, 2023, "") {
6+
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package tr.emreone.adventofcode.days
2+
3+
import tr.emreone.kotlin_utils.automation.Day
4+
5+
class Day23 : Day(23, 2023, "") {
6+
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package tr.emreone.adventofcode.days
2+
3+
import tr.emreone.kotlin_utils.automation.Day
4+
5+
class Day24 : Day(24, 2023, "") {
6+
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package tr.emreone.adventofcode.days
2+
3+
import tr.emreone.kotlin_utils.automation.Day
4+
5+
class Day25 : Day(25, 2023, "") {
6+
7+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package tr.emreone.adventofcode.days
2+
3+
import org.junit.jupiter.api.Test
4+
import tr.emreone.kotlin_utils.Resources
5+
import tr.emreone.kotlin_utils.automation.solve
6+
7+
internal class Day20Test {
8+
9+
@Test
10+
fun `execute_tests`() {
11+
solve<Day20>(false) {
12+
Resources.resourceAsList("day20_example.txt")
13+
.joinToString("\n") part1 32_000_000
14+
}
15+
}
16+
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package tr.emreone.adventofcode.days
2+
3+
import org.junit.jupiter.api.Test
4+
import tr.emreone.kotlin_utils.Resources
5+
import tr.emreone.kotlin_utils.automation.solve
6+
7+
internal class Day21Test {
8+
9+
@Test
10+
fun `execute_tests`() {
11+
solve<Day21>(false) {
12+
Resources.resourceAsList("day21_example.txt")
13+
.joinToString("\n") part1 0
14+
}
15+
}
16+
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package tr.emreone.adventofcode.days
2+
3+
import org.junit.jupiter.api.Test
4+
import tr.emreone.kotlin_utils.Resources
5+
import tr.emreone.kotlin_utils.automation.solve
6+
7+
internal class Day22Test {
8+
9+
@Test
10+
fun `execute_tests`() {
11+
solve<Day22>(false) {
12+
Resources.resourceAsList("day22_example.txt")
13+
.joinToString("\n") part1 0
14+
}
15+
}
16+
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package tr.emreone.adventofcode.days
2+
3+
import org.junit.jupiter.api.Test
4+
import tr.emreone.kotlin_utils.Resources
5+
import tr.emreone.kotlin_utils.automation.solve
6+
7+
internal class Day23Test {
8+
9+
@Test
10+
fun `execute_tests`() {
11+
solve<Day23>(false) {
12+
Resources.resourceAsList("day23_example.txt")
13+
.joinToString("\n") part1 0
14+
}
15+
}
16+
17+
}

0 commit comments

Comments
 (0)