What a mess! 18-20, no Part 2 solve. Oh well!

This commit is contained in:
🐙PiperYxzzy
2023-12-21 07:26:06 +02:00
parent 9e2c2637e8
commit bcda89984d
13 changed files with 2172 additions and 90 deletions

243
2023/20/code.go Normal file
View 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
}