package day20 import ( "fmt" "strings" ) const ( UNTYPED = "?" FLIP_FLOP = "%" BROADCASDTER = "b" CONJUNCTION = "&" LOW = 0 HIGH = 1 ) type Module struct { kind string name string status bool ouputs []string inputs []string inputMem map[string]int } type Pulse struct { kind int src string dst string } func parseModules(lines []string) map[string]*Module { modules := map[string]*Module{} modulesByOrderOfAppearance := []*Module{} for _, line := range lines { kind := string(line[0]) parts := strings.Split(line, " -> ") name := parts[0][1:] outputs := strings.Split(parts[1], ", ") if kind == "b" { name = "b" + name } module := &Module{kind, name, false, outputs, []string{}, map[string]int{}} modules[name] = module modulesByOrderOfAppearance = append(modulesByOrderOfAppearance, module) } // setup inputs for _, module := range modulesByOrderOfAppearance { for _, outputName := range module.ouputs { m, ok := modules[outputName] if !ok { // create ad'hoc untyped module m = &Module{UNTYPED, outputName, false, []string{}, []string{}, map[string]int{}} modules[outputName] = m modulesByOrderOfAppearance = append(modulesByOrderOfAppearance, m) } m.inputs = append(m.inputs, module.name) m.inputMem[module.name] = LOW } } return modules } func runSim(modules map[string]*Module, pulseQueue []*Pulse, count int) (int, int) { countLow := 0 countHigh := 0 for len(pulseQueue) > 0 { pulse := pulseQueue[0] pulseQueue[0] = nil pulseQueue = pulseQueue[1:] module := modules[pulse.dst] switch module.kind { case BROADCASDTER: for _, dst := range module.ouputs { newPulse := &Pulse{pulse.kind, module.name, dst} pulseQueue = append(pulseQueue, newPulse) if newPulse.kind == LOW { countLow++ } else { countHigh++ } } case FLIP_FLOP: if pulse.kind == LOW { var pulseKind int if module.status { pulseKind = LOW } else { pulseKind = HIGH } module.status = !module.status // flip status for _, dst := range module.ouputs { newPulse := &Pulse{pulseKind, module.name, dst} pulseQueue = append(pulseQueue, newPulse) if newPulse.kind == LOW { countLow++ } else { countHigh++ } } } case CONJUNCTION: if pulse.kind == HIGH && module.name == "qn" { fmt.Println("qn from ", pulse.src, " : ", count) } module.inputMem[pulse.src] = pulse.kind allHigh := true for _, v := range module.inputMem { if v == LOW { allHigh = false break } } var pulseKind int if allHigh { pulseKind = LOW } else { pulseKind = HIGH } for _, dst := range module.ouputs { newPulse := &Pulse{pulseKind, module.name, dst} pulseQueue = append(pulseQueue, newPulse) if newPulse.kind == LOW { countLow++ } else { countHigh++ } } case UNTYPED: module.status = pulse.kind == HIGH } } return countLow, countHigh } func Part1(lines []string, pressCount int) (map[string]*Module, int) { modules := parseModules(lines) sumLow := 0 sumHigh := 0 for i := 0; i < pressCount; i++ { queue := []*Pulse{} queue = append(queue, &Pulse{LOW, "button", "broadcaster"}) countLow, countHigh := runSim(modules, queue, i+1) countLow++ sumLow += countLow sumHigh += countHigh } return modules, sumLow * sumHigh } func Part2(lines []string, pressCount int) (map[string]*Module, int) { modules := parseModules(lines) for i := 0; i < pressCount; i++ { queue := []*Pulse{} queue = append(queue, &Pulse{LOW, "button", "broadcaster"}) runSim(modules, queue, i+1) } return modules, 0 }