Skip to content

Commit 1dbbf24

Browse files
committed
2023 day 20, lucianoq
1 parent be797b5 commit 1dbbf24

File tree

10 files changed

+621
-0
lines changed

10 files changed

+621
-0
lines changed

2023/20/Makefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
main1:
2+
go build -o main1 main1.go common.go
3+
4+
main2:
5+
go build -o main2 main2.go common.go
6+
7+
.PHONY: run1 run2 clean
8+
9+
run1: main1
10+
./main1 <input
11+
12+
run2: main2
13+
./main2 <input
14+
15+
clean:
16+
rm -f main1 main2
17+

2023/20/assignment

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
--- Day 20: Pulse Propagation ---
2+
3+
With your help, the Elves manage to find the right parts and fix all of
4+
the machines. Now, they just need to send the command to boot up the
5+
machines and get the sand flowing again.
6+
7+
The machines are far apart and wired together with long cables . The
8+
cables don't connect to the machines directly, but rather to
9+
communication modules attached to the machines that perform various
10+
initialization tasks and also act as communication relays.
11+
12+
Modules communicate using pulses . Each pulse is either a high pulse or
13+
a low pulse . When a module sends a pulse, it sends that type of pulse
14+
to each module in its list of destination modules .
15+
16+
There are several different types of modules:
17+
18+
Flip-flop modules (prefix % ) are either on or off ; they are initially
19+
off . If a flip-flop module receives a high pulse, it is ignored and
20+
nothing happens. However, if a flip-flop module receives a low pulse,
21+
it flips between on and off . If it was off, it turns on and sends a
22+
high pulse. If it was on, it turns off and sends a low pulse.
23+
24+
Conjunction modules (prefix & ) remember the type of the most recent
25+
pulse received from each of their connected input modules; they
26+
initially default to remembering a low pulse for each input. When a
27+
pulse is received, the conjunction module first updates its memory for
28+
that input. Then, if it remembers high pulses for all inputs, it sends
29+
a low pulse ; otherwise, it sends a high pulse .
30+
31+
There is a single broadcast module (named broadcaster ). When it
32+
receives a pulse, it sends the same pulse to all of its destination
33+
modules.
34+
35+
Here at Desert Machine Headquarters, there is a module with a single
36+
button on it called, aptly, the button module . When you push the
37+
button, a single low pulse is sent directly to the broadcaster module.
38+
39+
After pushing the button, you must wait until all pulses have been
40+
delivered and fully handled before pushing it again. Never push the
41+
button if modules are still processing pulses.
42+
43+
Pulses are always processed in the order they are sent . So, if a pulse
44+
is sent to modules a , b , and c , and then module a processes its
45+
pulse and sends more pulses, the pulses sent to modules b and c would
46+
have to be handled first.
47+
48+
The module configuration (your puzzle input) lists each module. The
49+
name of the module is preceded by a symbol identifying its type, if
50+
any. The name is then followed by an arrow and a list of its
51+
destination modules. For example:
52+
53+
broadcaster -> a, b, c
54+
%a -> b
55+
%b -> c
56+
%c -> inv
57+
&inv -> a
58+
59+
In this module configuration, the broadcaster has three destination
60+
modules named a , b , and c . Each of these modules is a flip-flop
61+
module (as indicated by the % prefix). a outputs to b which outputs to
62+
c which outputs to another module named inv . inv is a conjunction
63+
module (as indicated by the & prefix) which, because it has only one
64+
input, acts like an inverter (it sends the opposite of the pulse type
65+
it receives); it outputs to a .
66+
67+
By pushing the button once, the following pulses are sent:
68+
69+
button -low-> broadcaster
70+
broadcaster -low-> a
71+
broadcaster -low-> b
72+
broadcaster -low-> c
73+
a -high-> b
74+
b -high-> c
75+
c -high-> inv
76+
inv -low-> a
77+
a -low-> b
78+
b -low-> c
79+
c -low-> inv
80+
inv -high-> a
81+
82+
After this sequence, the flip-flop modules all end up off , so pushing
83+
the button again repeats the same sequence.
84+
85+
Here's a more interesting example:
86+
87+
broadcaster -> a
88+
%a -> inv, con
89+
&inv -> b
90+
%b -> con
91+
&con -> output
92+
93+
This module configuration includes the broadcaster , two flip-flops
94+
(named a and b ), a single-input conjunction module ( inv ), a
95+
multi-input conjunction module ( con ), and an untyped module named
96+
output (for testing purposes). The multi-input conjunction module con
97+
watches the two flip-flop modules and, if they're both on, sends a low
98+
pulse to the output module.
99+
100+
Here's what happens if you push the button once:
101+
102+
button -low-> broadcaster
103+
broadcaster -low-> a
104+
a -high-> inv
105+
a -high-> con
106+
inv -low-> b
107+
con -high-> output
108+
b -high-> con
109+
con -low-> output
110+
111+
Both flip-flops turn on and a low pulse is sent to output ! However,
112+
now that both flip-flops are on and con remembers a high pulse from
113+
each of its two inputs, pushing the button a second time does something
114+
different:
115+
116+
button -low-> broadcaster
117+
broadcaster -low-> a
118+
a -low-> inv
119+
a -low-> con
120+
inv -high-> b
121+
con -high-> output
122+
123+
Flip-flop a turns off! Now, con remembers a low pulse from module a ,
124+
and so it sends only a high pulse to output .
125+
126+
Push the button a third time:
127+
128+
button -low-> broadcaster
129+
broadcaster -low-> a
130+
a -high-> inv
131+
a -high-> con
132+
inv -low-> b
133+
con -low-> output
134+
b -low-> con
135+
con -high-> output
136+
137+
This time, flip-flop a turns on, then flip-flop b turns off. However,
138+
before b can turn off, the pulse sent to con is handled first, so it
139+
briefly remembers all high pulses for its inputs and sends a low pulse
140+
to output . After that, flip-flop b turns off, which causes con to
141+
update its state and send a high pulse to output .
142+
143+
Finally, with a on and b off, push the button a fourth time:
144+
145+
button -low-> broadcaster
146+
broadcaster -low-> a
147+
a -low-> inv
148+
a -low-> con
149+
inv -high-> b
150+
con -high-> output
151+
152+
This completes the cycle: a turns off, causing con to remember only low
153+
pulses and restoring all modules to their original states.
154+
155+
To get the cables warmed up, the Elves have pushed the button 1000
156+
times. How many pulses got sent as a result (including the pulses sent
157+
by the button itself)?
158+
159+
In the first example, the same thing happens every time the button is
160+
pushed: 8 low pulses and 4 high pulses are sent. So, after pushing the
161+
button 1000 times, 8000 low pulses and 4000 high pulses are sent.
162+
Multiplying these together gives 32000000 .
163+
164+
In the second example, after pushing the button 1000 times, 4250 low
165+
pulses and 2750 high pulses are sent. Multiplying these together gives
166+
11687500 .
167+
168+
Consult your module configuration; determine the number of low pulses
169+
and high pulses that would be sent after pushing the button 1000 times,
170+
waiting for all pulses to be fully handled after each push of the
171+
button. What do you get if you multiply the total number of low pulses
172+
sent by the total number of high pulses sent?
173+
174+
--- Part Two ---
175+
176+
The final machine responsible for moving the sand down to Island Island
177+
has a module attached named rx . The machine turns on when a single low
178+
pulse is sent to rx .
179+
180+
Reset all modules to their default states. Waiting for all pulses to be
181+
fully handled after each button press, what is the fewest number of
182+
button presses required to deliver a single low pulse to the module
183+
named rx ?

2023/20/common.go

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"os"
6+
"strings"
7+
)
8+
9+
// Pulse
10+
11+
type Pulse bool
12+
13+
func (p Pulse) String() string {
14+
if p {
15+
return "high"
16+
}
17+
return "low"
18+
}
19+
20+
const (
21+
HighPulse Pulse = true
22+
LowPulse Pulse = false
23+
)
24+
25+
// Message
26+
27+
type Message struct {
28+
Pulse Pulse
29+
From, To string
30+
}
31+
32+
var Button = Message{LowPulse, "button", "broadcaster"}
33+
34+
type Network map[string]Module
35+
36+
// Modules
37+
38+
type NetworkModule struct {
39+
Name string
40+
Destinations []string
41+
}
42+
43+
type Module interface {
44+
Process(Message) []Message
45+
}
46+
47+
type FlipFlop struct {
48+
NetworkModule
49+
Status bool
50+
}
51+
52+
func (f *FlipFlop) Process(msg Message) []Message {
53+
if msg.Pulse == LowPulse {
54+
f.Status = !f.Status
55+
56+
var q []Message
57+
for _, d := range f.Destinations {
58+
q = append(q, Message{Pulse(f.Status), f.Name, d})
59+
}
60+
return q
61+
}
62+
return nil
63+
}
64+
65+
type Conjunction struct {
66+
NetworkModule
67+
Memory map[string]Pulse
68+
}
69+
70+
func (c *Conjunction) Process(msg Message) []Message {
71+
c.Memory[msg.From] = msg.Pulse
72+
73+
allHigh := true
74+
for _, v := range c.Memory {
75+
if !v {
76+
allHigh = false
77+
}
78+
}
79+
80+
var q []Message
81+
for _, d := range c.Destinations {
82+
if allHigh {
83+
q = append(q, Message{LowPulse, c.Name, d})
84+
} else {
85+
q = append(q, Message{HighPulse, c.Name, d})
86+
}
87+
}
88+
return q
89+
}
90+
91+
type Broadcast struct {
92+
NetworkModule
93+
}
94+
95+
func (b *Broadcast) Process(msg Message) []Message {
96+
var q []Message
97+
for _, d := range b.Destinations {
98+
q = append(q, Message{msg.Pulse, b.Name, d})
99+
}
100+
return q
101+
}
102+
103+
// parse
104+
func parse() Network {
105+
scanner := bufio.NewScanner(os.Stdin)
106+
107+
nw := Network{}
108+
109+
inputs := map[string][]string{}
110+
conjunctions := []string{}
111+
112+
for scanner.Scan() {
113+
line := scanner.Text()
114+
115+
lr := strings.Split(line, " -> ")
116+
117+
name := ""
118+
dest := strings.Split(lr[1], ", ")
119+
120+
var m Module
121+
switch lr[0][0] {
122+
case '%':
123+
name = lr[0][1:]
124+
m = &FlipFlop{
125+
NetworkModule: NetworkModule{
126+
Name: name,
127+
Destinations: dest,
128+
},
129+
Status: false,
130+
}
131+
case '&':
132+
name = lr[0][1:]
133+
m = &Conjunction{
134+
NetworkModule: NetworkModule{
135+
Name: name,
136+
Destinations: dest,
137+
},
138+
Memory: make(map[string]Pulse),
139+
}
140+
conjunctions = append(conjunctions, name)
141+
case 'b':
142+
name = "broadcaster"
143+
m = &Broadcast{
144+
NetworkModule: NetworkModule{
145+
Name: name,
146+
Destinations: dest,
147+
},
148+
}
149+
}
150+
151+
for _, d := range dest {
152+
inputs[d] = append(inputs[d], name)
153+
}
154+
155+
nw[name] = m
156+
}
157+
158+
for _, c := range conjunctions {
159+
for _, in := range inputs[c] {
160+
con := nw[c].(*Conjunction)
161+
con.Memory[in] = false
162+
}
163+
}
164+
165+
return nw
166+
}

0 commit comments

Comments
 (0)