What a mess! 18-20, no Part 2 solve. Oh well!
This commit is contained in:
243
2023/20/code.go
Normal file
243
2023/20/code.go
Normal file
@@ -0,0 +1,243 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/jpillora/puzzler/harness/aoc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
aoc.Harness(run)
|
||||
}
|
||||
|
||||
// on code change, run will be executed 4 times:
|
||||
// 1. with: false (part1), and example input
|
||||
// 2. with: true (part2), and example input
|
||||
// 3. with: false (part1), and user input
|
||||
// 4. with: true (part2), and user input
|
||||
// the return value of each run is printed to stdout
|
||||
|
||||
type Module struct {
|
||||
Name string
|
||||
Prefix rune
|
||||
|
||||
OutputsStr []string
|
||||
Outputs []*Module
|
||||
|
||||
// For %
|
||||
On bool
|
||||
|
||||
// For &
|
||||
ConjMap map[*Module]bool
|
||||
}
|
||||
|
||||
type Pulse struct {
|
||||
From *Module
|
||||
Destination *Module
|
||||
High bool
|
||||
}
|
||||
|
||||
func (m *Module) LowPulse(from *Module) []Pulse {
|
||||
if m.Name == "rx" {
|
||||
panic("WE GOT HERE")
|
||||
}
|
||||
|
||||
next := make([]Pulse, 0)
|
||||
|
||||
if m.Prefix == '%' {
|
||||
m.On = !m.On
|
||||
for _, n := range m.Outputs {
|
||||
next = append(next, Pulse{m, n, m.On})
|
||||
}
|
||||
} else if m.Prefix == '&' {
|
||||
m.ConjMap[from] = false
|
||||
|
||||
for _, n := range m.Outputs {
|
||||
next = append(next, Pulse{m, n, true})
|
||||
}
|
||||
} else if m.Prefix == 'b' {
|
||||
for _, n := range m.Outputs {
|
||||
next = append(next, Pulse{m, n, false})
|
||||
}
|
||||
} else if m.Prefix == '.' {
|
||||
// Output, do nothing
|
||||
} else {
|
||||
panic("bad prefix")
|
||||
}
|
||||
|
||||
return next
|
||||
}
|
||||
|
||||
func (m *Module) HiPulse(from *Module) []Pulse {
|
||||
next := make([]Pulse, 0)
|
||||
|
||||
if m.Prefix == '%' {
|
||||
// Ignore
|
||||
} else if m.Prefix == '&' {
|
||||
m.ConjMap[from] = true
|
||||
|
||||
anyLow := false
|
||||
for _, val := range m.ConjMap {
|
||||
if !val {
|
||||
anyLow = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, n := range m.Outputs {
|
||||
next = append(next, Pulse{m, n, anyLow})
|
||||
}
|
||||
} else if m.Prefix == 'b' {
|
||||
for _, n := range m.Outputs {
|
||||
next = append(next, Pulse{m, n, true})
|
||||
}
|
||||
} else if m.Prefix == '.' {
|
||||
// Output, do nothing
|
||||
} else {
|
||||
panic("bad prefix")
|
||||
}
|
||||
|
||||
return next
|
||||
|
||||
}
|
||||
|
||||
func (p *Pulse) Pulse(tally *Tally) ([]Pulse, bool) {
|
||||
//fmt.Printf("Pulsing %v from %v to %v [L:%v H:%v] \n", p.High, p.From, p.Destination, tally.Lo, tally.Hi)
|
||||
if p.High {
|
||||
tally.Hi += 1
|
||||
return p.Destination.HiPulse(p.From), false
|
||||
}
|
||||
|
||||
if p.Destination.Name == "rx" {
|
||||
fmt.Printf("Rx! Terminating!")
|
||||
return nil, true
|
||||
}
|
||||
|
||||
tally.Lo += 1
|
||||
return p.Destination.LowPulse(p.From), false
|
||||
}
|
||||
|
||||
type Tally struct {
|
||||
Hi int
|
||||
Lo int
|
||||
}
|
||||
|
||||
func run(part2 bool, input string) any {
|
||||
var broadcaster Module
|
||||
|
||||
mods := make(map[string]*Module)
|
||||
|
||||
for _, l := range strings.Split(input, "\n") {
|
||||
if l == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
spl := strings.Split(l, " -> ")
|
||||
|
||||
dests := strings.Split(spl[1], ", ")
|
||||
|
||||
if spl[0] == "broadcaster" {
|
||||
broadcaster = Module{
|
||||
"broadcaster",
|
||||
'b',
|
||||
dests,
|
||||
make([]*Module, 0),
|
||||
false,
|
||||
make(map[*Module]bool),
|
||||
}
|
||||
|
||||
mods["broadcaster"] = &broadcaster
|
||||
} else {
|
||||
mod := Module{
|
||||
spl[0][1:],
|
||||
rune(spl[0][0]),
|
||||
dests,
|
||||
make([]*Module, 0),
|
||||
false,
|
||||
make(map[*Module]bool),
|
||||
}
|
||||
mods[mod.Name] = &mod
|
||||
}
|
||||
}
|
||||
|
||||
// Now, configure
|
||||
toProcess := []*Module{&broadcaster}
|
||||
processed := make(map[string]bool)
|
||||
for len(toProcess) > 0 {
|
||||
m := toProcess[0]
|
||||
toProcess = toProcess[1:]
|
||||
|
||||
if _, ok := processed[m.Name]; ok {
|
||||
continue
|
||||
}
|
||||
processed[m.Name] = true
|
||||
|
||||
//fmt.Printf("Preprocessing %v\n", m.Name)
|
||||
|
||||
for _, d := range m.OutputsStr {
|
||||
dest, ok := mods[d]
|
||||
if !ok {
|
||||
dest = &Module{
|
||||
d,
|
||||
'.',
|
||||
make([]string, 0),
|
||||
make([]*Module, 0),
|
||||
false,
|
||||
make(map[*Module]bool),
|
||||
}
|
||||
}
|
||||
m.Outputs = append(m.Outputs, dest)
|
||||
dest.ConjMap[m] = false
|
||||
}
|
||||
toProcess = append(toProcess, m.Outputs...)
|
||||
}
|
||||
|
||||
// Print mappings:
|
||||
modPrint := []*Module{&broadcaster}
|
||||
processed = make(map[string]bool)
|
||||
for len(modPrint) > 0 {
|
||||
mp := modPrint[0]
|
||||
modPrint = modPrint[1:]
|
||||
if _, ok := processed[mp.Name]; ok {
|
||||
continue
|
||||
}
|
||||
processed[mp.Name] = true
|
||||
|
||||
modPrint = append(modPrint, mp.Outputs...)
|
||||
|
||||
//fmt.Printf("%v (%v): %v (%v) [%v]\n", mp.Name, mp.Prefix, mp.OutputsStr, mp.Outputs, &mp)
|
||||
}
|
||||
|
||||
tally := Tally{0, 0}
|
||||
|
||||
limit := 1000
|
||||
if part2 {
|
||||
limit = math.MaxInt
|
||||
}
|
||||
|
||||
for i := 0; i < limit; i++ {
|
||||
if i%1000000 == 0 {
|
||||
fmt.Printf("Sent %v pulses\n", i)
|
||||
}
|
||||
pulsesToSend := []Pulse{{nil, &broadcaster, false}}
|
||||
for len(pulsesToSend) > 0 {
|
||||
pulse := pulsesToSend[0]
|
||||
pulsesToSend = pulsesToSend[1:]
|
||||
|
||||
newPulses, rxLow := pulse.Pulse(&tally)
|
||||
|
||||
if rxLow && part2 {
|
||||
return tally.Lo
|
||||
}
|
||||
|
||||
//fmt.Printf("New pulses: %v\n", newPulses)
|
||||
|
||||
pulsesToSend = append(pulsesToSend, newPulses...)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Lo: %v ; Hi: %v\n", tally.Lo, tally.Hi)
|
||||
|
||||
return tally.Lo * tally.Hi
|
||||
}
|
||||
Reference in New Issue
Block a user