diff --git a/2023/20/Makefile b/2023/20/Makefile new file mode 100644 index 0000000..27dfdc0 --- /dev/null +++ b/2023/20/Makefile @@ -0,0 +1,17 @@ +main1: + go build -o main1 main1.go common.go + +main2: + go build -o main2 main2.go common.go + +.PHONY: run1 run2 clean + +run1: main1 + ./main1 a, b, c + %a -> b + %b -> c + %c -> inv + &inv -> a + + In this module configuration, the broadcaster has three destination + modules named a , b , and c . Each of these modules is a flip-flop + module (as indicated by the % prefix). a outputs to b which outputs to + c which outputs to another module named inv . inv is a conjunction + module (as indicated by the & prefix) which, because it has only one + input, acts like an inverter (it sends the opposite of the pulse type + it receives); it outputs to a . + + By pushing the button once, the following pulses are sent: + + button -low-> broadcaster + broadcaster -low-> a + broadcaster -low-> b + broadcaster -low-> c + a -high-> b + b -high-> c + c -high-> inv + inv -low-> a + a -low-> b + b -low-> c + c -low-> inv + inv -high-> a + + After this sequence, the flip-flop modules all end up off , so pushing + the button again repeats the same sequence. + + Here's a more interesting example: + + broadcaster -> a + %a -> inv, con + &inv -> b + %b -> con + &con -> output + + This module configuration includes the broadcaster , two flip-flops + (named a and b ), a single-input conjunction module ( inv ), a + multi-input conjunction module ( con ), and an untyped module named + output (for testing purposes). The multi-input conjunction module con + watches the two flip-flop modules and, if they're both on, sends a low + pulse to the output module. + + Here's what happens if you push the button once: + + button -low-> broadcaster + broadcaster -low-> a + a -high-> inv + a -high-> con + inv -low-> b + con -high-> output + b -high-> con + con -low-> output + + Both flip-flops turn on and a low pulse is sent to output ! However, + now that both flip-flops are on and con remembers a high pulse from + each of its two inputs, pushing the button a second time does something + different: + + button -low-> broadcaster + broadcaster -low-> a + a -low-> inv + a -low-> con + inv -high-> b + con -high-> output + + Flip-flop a turns off! Now, con remembers a low pulse from module a , + and so it sends only a high pulse to output . + + Push the button a third time: + + button -low-> broadcaster + broadcaster -low-> a + a -high-> inv + a -high-> con + inv -low-> b + con -low-> output + b -low-> con + con -high-> output + + This time, flip-flop a turns on, then flip-flop b turns off. However, + before b can turn off, the pulse sent to con is handled first, so it + briefly remembers all high pulses for its inputs and sends a low pulse + to output . After that, flip-flop b turns off, which causes con to + update its state and send a high pulse to output . + + Finally, with a on and b off, push the button a fourth time: + + button -low-> broadcaster + broadcaster -low-> a + a -low-> inv + a -low-> con + inv -high-> b + con -high-> output + + This completes the cycle: a turns off, causing con to remember only low + pulses and restoring all modules to their original states. + + To get the cables warmed up, the Elves have pushed the button 1000 + times. How many pulses got sent as a result (including the pulses sent + by the button itself)? + + In the first example, the same thing happens every time the button is + pushed: 8 low pulses and 4 high pulses are sent. So, after pushing the + button 1000 times, 8000 low pulses and 4000 high pulses are sent. + Multiplying these together gives 32000000 . + + In the second example, after pushing the button 1000 times, 4250 low + pulses and 2750 high pulses are sent. Multiplying these together gives + 11687500 . + + Consult your module configuration; determine the number of low pulses + and high pulses that would be sent after pushing the button 1000 times, + waiting for all pulses to be fully handled after each push of the + button. What do you get if you multiply the total number of low pulses + sent by the total number of high pulses sent? + +--- Part Two --- + + The final machine responsible for moving the sand down to Island Island + has a module attached named rx . The machine turns on when a single low + pulse is sent to rx . + + Reset all modules to their default states. Waiting for all pulses to be + fully handled after each button press, what is the fewest number of + button presses required to deliver a single low pulse to the module + named rx ? diff --git a/2023/20/common.go b/2023/20/common.go new file mode 100644 index 0000000..e484100 --- /dev/null +++ b/2023/20/common.go @@ -0,0 +1,166 @@ +package main + +import ( + "bufio" + "os" + "strings" +) + +// Pulse + +type Pulse bool + +func (p Pulse) String() string { + if p { + return "high" + } + return "low" +} + +const ( + HighPulse Pulse = true + LowPulse Pulse = false +) + +// Message + +type Message struct { + Pulse Pulse + From, To string +} + +var Button = Message{LowPulse, "button", "broadcaster"} + +type Network map[string]Module + +// Modules + +type NetworkModule struct { + Name string + Destinations []string +} + +type Module interface { + Process(Message) []Message +} + +type FlipFlop struct { + NetworkModule + Status bool +} + +func (f *FlipFlop) Process(msg Message) []Message { + if msg.Pulse == LowPulse { + f.Status = !f.Status + + var q []Message + for _, d := range f.Destinations { + q = append(q, Message{Pulse(f.Status), f.Name, d}) + } + return q + } + return nil +} + +type Conjunction struct { + NetworkModule + Memory map[string]Pulse +} + +func (c *Conjunction) Process(msg Message) []Message { + c.Memory[msg.From] = msg.Pulse + + allHigh := true + for _, v := range c.Memory { + if !v { + allHigh = false + } + } + + var q []Message + for _, d := range c.Destinations { + if allHigh { + q = append(q, Message{LowPulse, c.Name, d}) + } else { + q = append(q, Message{HighPulse, c.Name, d}) + } + } + return q +} + +type Broadcast struct { + NetworkModule +} + +func (b *Broadcast) Process(msg Message) []Message { + var q []Message + for _, d := range b.Destinations { + q = append(q, Message{msg.Pulse, b.Name, d}) + } + return q +} + +// parse +func parse() Network { + scanner := bufio.NewScanner(os.Stdin) + + nw := Network{} + + inputs := map[string][]string{} + conjunctions := []string{} + + for scanner.Scan() { + line := scanner.Text() + + lr := strings.Split(line, " -> ") + + name := "" + dest := strings.Split(lr[1], ", ") + + var m Module + switch lr[0][0] { + case '%': + name = lr[0][1:] + m = &FlipFlop{ + NetworkModule: NetworkModule{ + Name: name, + Destinations: dest, + }, + Status: false, + } + case '&': + name = lr[0][1:] + m = &Conjunction{ + NetworkModule: NetworkModule{ + Name: name, + Destinations: dest, + }, + Memory: make(map[string]Pulse), + } + conjunctions = append(conjunctions, name) + case 'b': + name = "broadcaster" + m = &Broadcast{ + NetworkModule: NetworkModule{ + Name: name, + Destinations: dest, + }, + } + } + + for _, d := range dest { + inputs[d] = append(inputs[d], name) + } + + nw[name] = m + } + + for _, c := range conjunctions { + for _, in := range inputs[c] { + con := nw[c].(*Conjunction) + con.Memory[in] = false + } + } + + return nw +} diff --git a/2023/20/graph.dot b/2023/20/graph.dot new file mode 100644 index 0000000..a584cd8 --- /dev/null +++ b/2023/20/graph.dot @@ -0,0 +1,62 @@ +digraph { + broadcaster [color=blue] + rx [color=red] +dx -> {fb jm} +ss -> {lp} +broadcaster -> {km xt pk vk} +pk -> {gp cb} +bk -> {dg jn} +pd -> {cf fb} +gp -> {vm cb bd qm xf pk} +kg -> {fb} +vm -> {bf} +vk -> {cg fb} +dt -> {xv gp} +lm -> {bh} +cb -> {bd} +mp -> {xn} +jn -> {hs lp hm hn ql xt ss} +bf -> {fx gp} +rn -> {bk jn} +hn -> {xn} +fb -> {hb vk fz kl cg} +js -> {zb jl} +ql -> {hs} +rs -> {fb rt} +jf -> {jn kz} +jm -> {hv fb} +ms -> {bg} +hv -> {kg fb} +lp -> {hm} +kl -> {rs} +kz -> {ss jn} +jv -> {rn jn} +rt -> {fb hb} +fz -> {xn} +bd -> {dt} +bh -> {jl ms} +jl -> {km lm ms mp lr zb bg} +dg -> {jn} +rr -> {vm gp} +xv -> {mv gp} +jt -> {hx jl} +pt -> {jt jl} +qd -> {jl} +km -> {jl lm} +mv -> {gp qm} +lr -> {pt} +hb -> {pd} +cf -> {dx fb} +xt -> {jn jf} +hs -> {jv} +zb -> {lr} +dp -> {gp} +cg -> {kl} +hx -> {qd jl} +qm -> {rr} +fx -> {gp dp} +hm -> {ql} +xn -> {rx} +bg -> {js} +xf -> {xn} +} diff --git a/2023/20/graph.png b/2023/20/graph.png new file mode 100644 index 0000000..89a05ce Binary files /dev/null and b/2023/20/graph.png differ diff --git a/2023/20/input b/2023/20/input new file mode 100644 index 0000000..da95431 --- /dev/null +++ b/2023/20/input @@ -0,0 +1,58 @@ +%jv -> rn, jn +&fb -> hb, vk, fz, kl, cg +%rr -> vm, gp +&gp -> vm, cb, bd, qm, xf, pk +%hm -> ql +%cf -> dx, fb +%cg -> kl +%hv -> kg, fb +%hs -> jv +%bd -> dt +%xv -> mv, gp +%js -> zb, jl +%rn -> bk, jn +%lp -> hm +%dx -> fb, jm +%ss -> lp +&hn -> xn +%bh -> jl, ms +%km -> jl, lm +%mv -> gp, qm +&jl -> km, lm, ms, mp, lr, zb, bg +%pt -> jt, jl +%cb -> bd +%xt -> jn, jf +%kg -> fb +%dg -> jn +%rt -> fb, hb +broadcaster -> km, xt, pk, vk +%lr -> pt +%vm -> bf +%hx -> qd, jl +&mp -> xn +%hb -> pd +%vk -> cg, fb +%kl -> rs +%pk -> gp, cb +%jt -> hx, jl +&jn -> hs, lp, hm, hn, ql, xt, ss +%bg -> js +%kz -> ss, jn +%bf -> fx, gp +%bk -> dg, jn +%qm -> rr +%fx -> gp, dp +%dp -> gp +%jf -> jn, kz +%jm -> hv, fb +%ql -> hs +%ms -> bg +%zb -> lr +%rs -> fb, rt +%dt -> xv, gp +%lm -> bh +&xf -> xn +%pd -> cf, fb +%qd -> jl +&xn -> rx +&fz -> xn diff --git a/2023/20/main1.go b/2023/20/main1.go new file mode 100644 index 0000000..7fb4184 --- /dev/null +++ b/2023/20/main1.go @@ -0,0 +1,33 @@ +package main + +import "fmt" + +func main() { + network := parse() + var queue []Message + + lowSent, highSent := 0, 0 + count := func(msg Message) { + if msg.Pulse == LowPulse { + lowSent++ + } else { + highSent++ + } + } + + for i := 0; i < 1000; i++ { + queue = append(queue, Button) + + var msg Message + for len(queue) > 0 { + msg, queue = queue[0], queue[1:] + count(msg) + + if network[msg.To] != nil { + queue = append(queue, network[msg.To].Process(msg)...) + } + } + } + + fmt.Println(lowSent * highSent) +} diff --git a/2023/20/main2.go b/2023/20/main2.go new file mode 100644 index 0000000..5848b31 --- /dev/null +++ b/2023/20/main2.go @@ -0,0 +1,100 @@ +package main + +import ( + "fmt" + "strings" +) + +func main() { + network := parse() + + //graphviz(network) + + // 4 high pulses from these 4 to `xn` means 1 low pulse + // from `xn` to `rx`, our goal + firstOccurrence := map[string]int{ + "fz": 0, + "hn": 0, + "xf": 0, + "mp": 0, + } + count := len(firstOccurrence) + + var queue []Message + + for i := 1; ; i++ { + queue = append(queue, Button) + + var msg Message + for len(queue) > 0 { + msg, queue = queue[0], queue[1:] + + // real goal + if msg.To == "rx" && msg.Pulse == LowPulse { + return + } + + first, exists := firstOccurrence[msg.From] + if exists && msg.Pulse == HighPulse && first == 0 { + firstOccurrence[msg.From] = i + count-- + } + + if count == 0 { + var values []int + for _, v := range firstOccurrence { + values = append(values, v) + } + fmt.Println(lcmm(values)) + return + } + + if network[msg.To] != nil { + queue = append(queue, network[msg.To].Process(msg)...) + } + } + } +} + +func lcmm(xs []int) int { + lcm := func(a, b int) int { return a * b / gcd(a, b) } + + result := 1 + for _, n := range xs { + result = lcm(result, n) + } + return result +} + +func gcd(a, b int) int { + for b != 0 { + t := b + b = a % b + a = t + } + return a +} + +func graphviz(network Network) { + fmt.Println("digraph {") + fmt.Println(" broadcaster [color=blue]") + fmt.Println(" rx [color=red]") + + for k, v := range network { + fmt.Print(k) + fmt.Print(" -> {") + + switch m := v.(type) { + case *Conjunction: + fmt.Print(strings.Join(m.Destinations, " ")) + case *FlipFlop: + fmt.Print(strings.Join(m.Destinations, " ")) + case *Broadcast: + fmt.Print(strings.Join(m.Destinations, " ")) + } + + fmt.Println("}") + } + + fmt.Println("}") +} diff --git a/2023/20/output1 b/2023/20/output1 new file mode 100644 index 0000000..e3e9144 --- /dev/null +++ b/2023/20/output1 @@ -0,0 +1 @@ +806332748 diff --git a/2023/20/output2 b/2023/20/output2 new file mode 100644 index 0000000..30d76ad --- /dev/null +++ b/2023/20/output2 @@ -0,0 +1 @@ +228060006554227