143 lines
4.0 KiB
Go
143 lines
4.0 KiB
Go
package day20
|
|
|
|
import (
|
|
"cmp"
|
|
"log"
|
|
"slices"
|
|
)
|
|
|
|
func TransitiveOutputs(from string, allModules map[string]Module, visited map[string]any) map[string]any {
|
|
// log.Printf("looking for transitive children of %s\n", from)
|
|
_, alreadyProcessed := visited[from]
|
|
if alreadyProcessed {
|
|
return visited
|
|
}
|
|
|
|
module, found := allModules[from]
|
|
if !found {
|
|
return visited
|
|
}
|
|
|
|
visited[from] = struct{}{}
|
|
children := module.Outputs()
|
|
for _, output := range children {
|
|
TransitiveOutputs(output, allModules, visited)
|
|
}
|
|
|
|
delete(visited, "th")
|
|
|
|
// for key, _ := range visited {
|
|
// result = append(result, key)
|
|
// }
|
|
|
|
return visited
|
|
}
|
|
|
|
func FindSubGraphLoopLength(subgraph map[string]any, allModules map[string]Module, monitorOutputsOf string) (fromStep, toStep int, monitoredPulses map[int][]PulseType) {
|
|
step := 1
|
|
seenSubgraphStates := make(map[string]int)
|
|
monitoredPulses = make(map[int][]PulseType)
|
|
for {
|
|
monitoredPulsesOfTheStep := PropagateButtonPressWithMonitor(allModules, step, monitorOutputsOf)
|
|
subgraphModules := make(map[string]Module)
|
|
for key, _ := range subgraph {
|
|
subgraphModules[key] = allModules[key]
|
|
}
|
|
subgraphState := ModulesState(subgraphModules)
|
|
// log.Printf("looping %d. state is %s", step, subgraphState)
|
|
|
|
prevSteps, known := seenSubgraphStates[subgraphState]
|
|
if known {
|
|
// log.Printf(">>> searching for loop of %+v", subgraph)
|
|
log.Printf(">>> found loop from %d to %d. of size %d\n", prevSteps, step - 1, step - prevSteps)
|
|
return prevSteps, step, monitoredPulses
|
|
}
|
|
|
|
seenSubgraphStates[subgraphState] = step
|
|
if len(monitoredPulsesOfTheStep) > 0 {
|
|
monitoredPulses[step] = monitoredPulsesOfTheStep
|
|
}
|
|
step++
|
|
}
|
|
panic("")
|
|
}
|
|
|
|
// i see lot's of 'LowPulse'
|
|
// while i want to find steps where all inputs are remembered as High.
|
|
// so i'm interested in steps with "high" pulses and next steps that make it 'low' after
|
|
func FilterMonitoredPulses(requestedPulses map[int][]PulseType) {
|
|
afterHigh := false
|
|
for step, pulses := range requestedPulses {
|
|
processedPulses := make([]PulseType, 0)
|
|
for _, pulse := range pulses {
|
|
if pulse == HighPulse {
|
|
processedPulses = append(processedPulses, pulse)
|
|
afterHigh = true
|
|
continue
|
|
}
|
|
if afterHigh {
|
|
processedPulses = append(processedPulses, pulse)
|
|
afterHigh = false
|
|
}
|
|
}
|
|
if len(processedPulses) > 0 {
|
|
requestedPulses[step] = processedPulses
|
|
} else {
|
|
delete(requestedPulses, step)
|
|
}
|
|
}
|
|
}
|
|
|
|
// loop math
|
|
// 2023/12/20 12:35:08 >>> searching for loop of sr
|
|
// 2023/12/20 12:35:08 >>> found loop from 1 to 4028. of size 4028
|
|
// 2023/12/20 12:35:08 the pulses: +map[4026:[high low]]
|
|
// 2023/12/20 12:35:08 >>> searching for loop of ch
|
|
// 2023/12/20 12:35:08 >>> found loop from 0 to 3923. of size 3924
|
|
// 2023/12/20 12:35:08 the pulses: +map[3817:[high low]]
|
|
// 2023/12/20 12:35:08 >>> searching for loop of hd
|
|
// 2023/12/20 12:35:09 >>> found loop from 0 to 3793. of size 3794
|
|
// 2023/12/20 12:35:09 the pulses: +map[3427:[high low]]
|
|
// 2023/12/20 12:35:09 >>> searching for loop of bx
|
|
// 2023/12/20 12:35:09 >>> found loop from 0 to 3739. of size 3740
|
|
// 2023/12/20 12:35:09 the pulses: +map[3211:[high low]]
|
|
func CalcCommonStep() int {
|
|
type LoopInfo struct {
|
|
loopLength, initialDesiredStep int
|
|
curStep int
|
|
}
|
|
loopA := &LoopInfo{4027, 4026, 4026}
|
|
loopB := &LoopInfo{3923, 3922, 3922}
|
|
loopC := &LoopInfo{3793, 3792, 3792}
|
|
loopD := &LoopInfo{3739, 3211, 3738}
|
|
|
|
|
|
|
|
// nope they can have different amount of own loops.
|
|
// so it's 4 unknowns, 5 unknowns.
|
|
// i could store 4 'steps' and on each iteration increase the smallest one
|
|
// until they are all equal
|
|
|
|
loops := []*LoopInfo{loopA, loopB, loopC, loopD}
|
|
allSameStep := loopA.curStep == loopB.curStep &&
|
|
loopB.curStep == loopC.curStep &&
|
|
loopC.curStep == loopD.curStep
|
|
|
|
i := 0
|
|
|
|
for !allSameStep {
|
|
minLoop := slices.MinFunc(loops, func(a *LoopInfo, b *LoopInfo) int {
|
|
return cmp.Compare(a.curStep, b.curStep)
|
|
})
|
|
minLoop.curStep += minLoop.loopLength
|
|
|
|
if i % 10000000 == 0 {
|
|
log.Printf(">> iterations made: %d, min step is %d", i, minLoop.curStep)
|
|
}
|
|
|
|
i++
|
|
}
|
|
|
|
return loopA.curStep
|
|
}
|