package day20 import ( "fmt" "log" "os" "strings" ) func Run() int { // fmt.Println("hello from dya 20") filename := "day20/input" // modules := ReadModules(filename) // InitStuffs(modules) // log.Print("got modules:\n", modules) // var low, high int // low, high = Count10000ButtonPresses(modules) // log.Printf("got low %d and high %d\n", low, high) CheckSubgraphsStuff(filename) var result int // result = CalcCommonStep() return result } func CheckSubgraphsStuff(filename string) { // loopStarts := allModules["broadcast"].Outputs() // loop start and loop sink loopItems := map[string]string { "sr": "xn", "ch": "xf", "hd": "qn", "bx": "zl", } for start, end := range loopItems { allModules := ReadModules(filename) InitStuffs(allModules) log.Printf(">>> searching for loop of %s", start) themap := make(map[string]any) loopModules := TransitiveOutputs(start, allModules, themap) // i think my bug is not to reset state of `allModules` _, _, requestedPulses := FindSubGraphLoopLength(loopModules, allModules, end) FilterMonitoredPulses(requestedPulses) log.Printf("the pulses: +%v", requestedPulses) } // yeah. and now all cycles start from 1 (first button press) // and then they emit the [high low] on last step of their cycle // so just LCM of these all } func Count10000ButtonPresses(modules map[string]Module) (lowSignalsCount, highSignalsCount int) { count := 1000 type counts struct { low, high int step int } countsAfterState := make(map[string]counts) // after each button press check if reached already known state - cycle is present. // then calculate amount of signals before the loop - how much was on that previous state. // then diff - how much added after the loop // for now let's just print the info on loop for i := 0; i < count; i++ { if i % 10000 == 0 { log.Println("done button presses: ", i) } stepLow, stepHigh := PropagateButtonPress(modules, i) lowSignalsCount += stepLow highSignalsCount += stepHigh // log.Printf("after step %d low is %d and high is %d", i, lowSignalsCount, highSignalsCount) state := ModulesState(modules) prevCounts, found := countsAfterState[state] if found { loopLen := i - prevCounts.step log.Printf(">>> found loop. from step %d to step %d. of len %d", prevCounts.step, i, loopLen) multiplication := count / loopLen lowCountInCycle := lowSignalsCount - prevCounts.low highCountInCycle := highSignalsCount - prevCounts.high lowSignalsCount = lowCountInCycle * multiplication highSignalsCount = highCountInCycle * multiplication return } countsAfterState[state] = counts{stepLow, stepHigh, i} } return } func PropagateButtonPress(modules map[string]Module, i int) (lowSignalsCount, highSignalsCount int) { signals := []Signal{{From: "button", To: "broadcast", PulseType: LowPulse}} lowSignalsCount += 1 for len(signals) > 0 { curSignal := signals[0] signals = signals[1:] // log.Printf("%s -%s-> %s", curSignal.From, curSignal.PulseType, curSignal.To) receivingModule, found := modules[curSignal.To] if !found { // log.Print(fmt.Sprintf("signal %+v can't find it's recepient\n", curSignal)) if curSignal.To == "rx" && curSignal.PulseType == LowPulse { panic(fmt.Sprintf("getting low signal to rx, on step %d", i)) } continue } newSignals := receivingModule.Receive(curSignal) // all newSignals will have same type newSignalsAmount := len(newSignals) if newSignalsAmount > 0 { signals = append(signals, newSignals...) someNewSignal := newSignals[0] if someNewSignal.PulseType == HighPulse { highSignalsCount += newSignalsAmount } else { lowSignalsCount += newSignalsAmount } } } return } func PropagateButtonPressWithMonitor(modules map[string]Module, i int, monitorAllOutputsOf string) []PulseType { result := make([]PulseType, 0) signals := []Signal{{From: "button", To: "broadcast", PulseType: LowPulse}} for len(signals) > 0 { curSignal := signals[0] signals = signals[1:] if curSignal.From == monitorAllOutputsOf { result = append(result, curSignal.PulseType) } // log.Printf("%s -%s-> %s", curSignal.From, curSignal.PulseType, curSignal.To) receivingModule, found := modules[curSignal.To] if !found { // log.Print(fmt.Sprintf("signal %+v can't find it's recepient\n", curSignal)) if curSignal.To == "rx" && curSignal.PulseType == LowPulse { panic(fmt.Sprintf("getting low signal to rx, on step %d", i)) } continue } newSignals := receivingModule.Receive(curSignal) // all newSignals will have same type newSignalsAmount := len(newSignals) if newSignalsAmount > 0 { signals = append(signals, newSignals...) } } return result } // process sends single `low pulse` directly to "broadcast" func ReadModules(filename string) map[string]Module { result := make(map[string]Module) bytes, err := os.ReadFile(filename) if err != nil { panic(fmt.Sprint("error reading file: ", filename)) } text := strings.TrimSpace(string(bytes)) for _, line := range strings.Split(text, "\n") { switch { case IsLineBroadcast(line): parsed := ParseBroadcast(line) result["broadcast"] = &parsed case IsLineFlipFlop(line): parsed := ParseFlipFlop(line) result[parsed.Name] = &parsed case IsLineConjunction(line): parsed := ParseConjunction(line) result[parsed.Name] = &parsed } // log.Println(line) } buttonModule := Button{} result["button"] = &buttonModule outputModule := Output{} result["output"] = &outputModule return result } func InitStuffs(allModules map[string]Module) { for _, module := range allModules { if conjunction, ok := module.(*Conjunction); ok { conjunction.RegisterInputs(allModules) } } } func ModulesState(modules map[string]Module) string { // relying on printing of map values to be ordered by key // https://stackoverflow.com/a/54524991/2788805 states := make(map[string]string) for name, module := range modules { states[name] = module.StateSnapshot() } return fmt.Sprint(states) } func AllMermaidFlowChard(allModules map[string]Module) (result string) { result = "flowchart TD\n" for _, module := range allModules { result += module.MermaidFlow() } return }