Compare commits
No commits in common. "98206fe6d4d8b41c81b006ebba6b5f92d46df80a" and "e771ac9d9bc8626d01c8b7dde21a2a7cc7926b73" have entirely different histories.
98206fe6d4
...
e771ac9d9b
|
@ -1,3 +1,4 @@
|
||||||
/.direnv/
|
/.direnv/
|
||||||
/.go
|
/.go
|
||||||
input
|
example
|
||||||
|
/day19/input
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
px{a<2006:qkq,m>2090:A,rfg}
|
|
||||||
pv{a>1716:R,A}
|
|
||||||
lnx{m>1548:A,A}
|
|
||||||
rfg{s<537:gd,x>2440:R,A}
|
|
||||||
qs{s>3448:A,lnx}
|
|
||||||
qkq{x<1416:A,crn}
|
|
||||||
crn{x>2662:A,R}
|
|
||||||
in{s<1351:px,qqz}
|
|
||||||
qqz{s>2770:qs,m<1801:hdj,R}
|
|
||||||
gd{a>3333:R,R}
|
|
||||||
hdj{m>838:A,pv}
|
|
||||||
|
|
||||||
{x=787,m=2655,a=1222,s=2876}
|
|
||||||
{x=1679,m=44,a=2067,s=496}
|
|
||||||
{x=2036,m=264,a=79,s=2244}
|
|
||||||
{x=2461,m=1339,a=466,s=291}
|
|
||||||
{x=2127,m=1623,a=2188,s=1013}
|
|
|
@ -1,5 +0,0 @@
|
||||||
broadcaster -> a, b, c
|
|
||||||
%a -> b
|
|
||||||
%b -> c
|
|
||||||
%c -> inv
|
|
||||||
&inv -> a
|
|
|
@ -1,5 +0,0 @@
|
||||||
broadcaster -> a
|
|
||||||
%a -> inv, con
|
|
||||||
&inv -> b
|
|
||||||
%b -> con
|
|
||||||
&con -> output
|
|
142
day20/looping.go
142
day20/looping.go
|
@ -1,142 +0,0 @@
|
||||||
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 {
|
|
||||||
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
|
|
||||||
monitoredPulsesOfTheStep := PropagateButtonPressWithMonitor(allModules, step, monitorOutputsOf)
|
|
||||||
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
|
|
||||||
}
|
|
276
day20/modules.go
276
day20/modules.go
|
@ -1,276 +0,0 @@
|
||||||
package day20
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"slices"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PulseType int
|
|
||||||
func (pt PulseType)String() string {
|
|
||||||
types := []string{"high", "low"}
|
|
||||||
return types[pt]
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
HighPulse PulseType = iota
|
|
||||||
LowPulse
|
|
||||||
)
|
|
||||||
|
|
||||||
type Signal struct {
|
|
||||||
To, From string
|
|
||||||
PulseType PulseType
|
|
||||||
}
|
|
||||||
|
|
||||||
type Module interface {
|
|
||||||
Receive(s Signal) []Signal
|
|
||||||
Outputs() []string
|
|
||||||
StateSnapshot() string
|
|
||||||
MermaidFlow() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modules
|
|
||||||
type FlipFlop struct {
|
|
||||||
Name string
|
|
||||||
OutputNames []string
|
|
||||||
IsOn bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignores HighPulse
|
|
||||||
// on LowPulse - toggle state and send signal
|
|
||||||
func (ff *FlipFlop)Receive(s Signal) []Signal {
|
|
||||||
if s.PulseType == HighPulse {
|
|
||||||
return []Signal{}
|
|
||||||
}
|
|
||||||
|
|
||||||
ff.IsOn = !ff.IsOn
|
|
||||||
outTemplate := Signal{
|
|
||||||
From: ff.Name,
|
|
||||||
}
|
|
||||||
if ff.IsOn {
|
|
||||||
outTemplate.PulseType = HighPulse
|
|
||||||
} else {
|
|
||||||
outTemplate.PulseType = LowPulse
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make([]Signal, len(ff.OutputNames))
|
|
||||||
for i, outName := range ff.OutputNames {
|
|
||||||
out := outTemplate
|
|
||||||
out.To = outName
|
|
||||||
result[i] = out
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ff *FlipFlop)Outputs() []string {
|
|
||||||
return ff.OutputNames
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ff *FlipFlop)String() string {
|
|
||||||
return fmt.Sprintf("[flip-flop '%s' (on: %t) -> %s]", ff.Name, ff.IsOn, ff.OutputNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ff *FlipFlop)StateSnapshot() string {
|
|
||||||
return ff.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ff *FlipFlop)MermaidFlow() string {
|
|
||||||
result := "\n"
|
|
||||||
for _, toName := range ff.OutputNames {
|
|
||||||
result += fmt.Sprintf("%s --> %s\n", ff.Name, toName)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsLineFlipFlop(line string) bool {
|
|
||||||
return strings.HasPrefix(line, "%")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseFlipFlop(line string) (result FlipFlop) {
|
|
||||||
re := regexp.MustCompile(`%(?P<NAME>\D+) -> (?P<OUTPUTS>.+)`)
|
|
||||||
matches := re.FindStringSubmatch(line)
|
|
||||||
|
|
||||||
// log.Printf("matching %s getting '%s' and '%s'\n", line, matches[1], matches[2])
|
|
||||||
result.Name = matches[1]
|
|
||||||
result.OutputNames = strings.Split(matches[2], ", ")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type Broadcast struct {
|
|
||||||
OutputNames []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// send same pulse to all outputs
|
|
||||||
func (b *Broadcast)Receive(s Signal) (result []Signal) {
|
|
||||||
signalTemplate := Signal{From: "broadcast", PulseType: s.PulseType}
|
|
||||||
for _, out := range b.OutputNames {
|
|
||||||
outSignal := signalTemplate
|
|
||||||
outSignal.To = out
|
|
||||||
result = append(result, outSignal)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Broadcast)Outputs() []string {
|
|
||||||
return b.OutputNames
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Broadcast)String() string {
|
|
||||||
return fmt.Sprintf("[broadcast -> %+v]", b.OutputNames)
|
|
||||||
}
|
|
||||||
func (b *Broadcast)StateSnapshot() string {
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Broadcast)MermaidFlow() string {
|
|
||||||
result := "\n"
|
|
||||||
for _, toName := range b.OutputNames {
|
|
||||||
result += fmt.Sprintf("%s --> %s\n", "broadcast", toName)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsLineBroadcast(line string) bool {
|
|
||||||
return strings.HasPrefix(line, "broadcaster")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseBroadcast(line string) (result Broadcast) {
|
|
||||||
re := regexp.MustCompile(`broadcaster -> (?P<OUTPUTS>.+)`)
|
|
||||||
matches := re.FindStringSubmatch(line)
|
|
||||||
|
|
||||||
result.OutputNames = strings.Split(matches[1], ", ")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type Conjunction struct {
|
|
||||||
Name string
|
|
||||||
OutputNames []string
|
|
||||||
MostRecentPulseFromInputIsHigh map[string]bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// remembers last signal type from all inputs (initial default is Low)
|
|
||||||
// when receiving pulse, first update memory for that input
|
|
||||||
// then if for all inputs remembered is high - send LowPulse
|
|
||||||
// otherwise if some remembers are low - send HighPulse
|
|
||||||
func (c *Conjunction)Receive(s Signal) (result []Signal) {
|
|
||||||
c.MostRecentPulseFromInputIsHigh[s.From] = s.PulseType == HighPulse
|
|
||||||
|
|
||||||
allHigh := true
|
|
||||||
for _, latestImpulseHight := range c.MostRecentPulseFromInputIsHigh {
|
|
||||||
if !latestImpulseHight {
|
|
||||||
allHigh = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outTemplate := Signal{From: c.Name}
|
|
||||||
if allHigh {
|
|
||||||
outTemplate.PulseType = LowPulse
|
|
||||||
} else {
|
|
||||||
outTemplate.PulseType = HighPulse
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, outName := range c.OutputNames {
|
|
||||||
outSignal := outTemplate
|
|
||||||
outSignal.To = outName
|
|
||||||
result = append(result, outSignal)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conjunction)Outputs() []string {
|
|
||||||
return c.OutputNames
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conjunction)RegisterInputs(allModules map[string]Module) {
|
|
||||||
for name, module := range allModules {
|
|
||||||
if slices.Contains( module.Outputs(), c.Name) {
|
|
||||||
c.MostRecentPulseFromInputIsHigh[name] = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conjunction)String() string {
|
|
||||||
return fmt.Sprintf("[conjunction '%s' -> %+v]", c.Name, c.OutputNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conjunction)StateSnapshot() string {
|
|
||||||
return fmt.Sprintf("[conjunction '%s' -> %+v]", c.Name, c.MostRecentPulseFromInputIsHigh)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conjunction)MermaidFlow() string {
|
|
||||||
result := "\n"
|
|
||||||
for _, toName := range c.OutputNames {
|
|
||||||
result += fmt.Sprintf("%s --> %s\n", c.Name, toName)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsLineConjunction(line string) bool {
|
|
||||||
return strings.HasPrefix(line, "&")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseConjunction(line string) (result Conjunction) {
|
|
||||||
re := regexp.MustCompile(`&(?P<NAME>\D+) -> (?P<OUTPUTS>.+)`)
|
|
||||||
matches := re.FindStringSubmatch(line)
|
|
||||||
|
|
||||||
// log.Printf("matching %s getting '%s' and '%s'\n", line, matches[1], matches[2])
|
|
||||||
result.Name = matches[1]
|
|
||||||
result.OutputNames = strings.Split(matches[2], ", ")
|
|
||||||
|
|
||||||
result.MostRecentPulseFromInputIsHigh = map[string]bool{}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type Button struct {}
|
|
||||||
|
|
||||||
func (b *Button)Receive(s Signal) []Signal {
|
|
||||||
return []Signal{
|
|
||||||
{ To: "broadcast", From: "button", PulseType: LowPulse },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Button)Outputs() []string {
|
|
||||||
return []string{"broadcast"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Button)String() string {
|
|
||||||
return "[button]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Button)StateSnapshot() string {
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Button)MermaidFlow() string {
|
|
||||||
return "button --> broadcast\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
type Output struct {}
|
|
||||||
|
|
||||||
func (o *Output)Receive(s Signal) []Signal {
|
|
||||||
// log.Print("Outut received signal: ", s)
|
|
||||||
return []Signal{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Output)Outputs() []string {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Output)String() string {
|
|
||||||
return "[output]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Output)StateSnapshot() string {
|
|
||||||
return o.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Output)MermaidFlow() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
package day20
|
|
||||||
|
|
||||||
import (
|
|
||||||
"slices"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParseFlipFlop(t *testing.T) {
|
|
||||||
flipFlopLine := "%a -> inv, con"
|
|
||||||
if !IsLineFlipFlop(flipFlopLine) {
|
|
||||||
t.Errorf("line '%s' should be flip flop\n", flipFlopLine)
|
|
||||||
}
|
|
||||||
module := ParseFlipFlop(flipFlopLine)
|
|
||||||
t.Logf("got module %+v\n", module)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseBroadcast(t *testing.T) {
|
|
||||||
broadcastLine := "broadcaster -> a, b, c"
|
|
||||||
if !IsLineBroadcast(broadcastLine) {
|
|
||||||
t.Error("expected line to pass broadcast check")
|
|
||||||
}
|
|
||||||
module := ParseBroadcast(broadcastLine)
|
|
||||||
t.Logf("got module %+v\n", module)
|
|
||||||
|
|
||||||
if !slices.Equal(module.OutputNames, []string{"a", "b", "c"}) {
|
|
||||||
t.Errorf("got unexpected outputs: %+v\n", module.OutputNames)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseConjunction(t *testing.T) {
|
|
||||||
conjunctionLine := "&inv -> b"
|
|
||||||
if !IsLineConjunction(conjunctionLine) {
|
|
||||||
t.Errorf("line '%s' should be flip flop\n", conjunctionLine)
|
|
||||||
}
|
|
||||||
module := ParseConjunction(conjunctionLine)
|
|
||||||
t.Logf("got module %+v\n", module)
|
|
||||||
moduleAsExpected := module.Name != "inv" || slices.Equal(module.OutputNames, []string{"b"})
|
|
||||||
if !moduleAsExpected {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReadManyModules(t *testing.T) {
|
|
||||||
filename := "example1"
|
|
||||||
modules := ReadModules(filename)
|
|
||||||
t.Logf("> read example1:\n%+v", modules)
|
|
||||||
|
|
||||||
filename2 := "example2"
|
|
||||||
modules2 := ReadModules(filename2)
|
|
||||||
t.Logf("> read example2:\n%+v", modules2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConjunctionRegisterInputs(t *testing.T) {
|
|
||||||
filename := "example2"
|
|
||||||
modules := ReadModules(filename)
|
|
||||||
|
|
||||||
conjunctionInv := modules["inv"].(*Conjunction)
|
|
||||||
conjunctionInv.RegisterInputs(modules)
|
|
||||||
|
|
||||||
t.Logf("after registering inputs on $inv : %+v", conjunctionInv.MostRecentPulseFromInputIsHigh)
|
|
||||||
}
|
|
|
@ -1,170 +0,0 @@
|
||||||
flowchart LR
|
|
||||||
|
|
||||||
zd --> ln
|
|
||||||
zd --> gf
|
|
||||||
|
|
||||||
vz --> cr
|
|
||||||
vz --> vc
|
|
||||||
|
|
||||||
ch --> db
|
|
||||||
ch --> mc
|
|
||||||
|
|
||||||
qm --> gm
|
|
||||||
|
|
||||||
cc --> nn
|
|
||||||
|
|
||||||
qk --> vc
|
|
||||||
|
|
||||||
sr --> gf
|
|
||||||
sr --> vl
|
|
||||||
|
|
||||||
lr --> sb
|
|
||||||
|
|
||||||
hv --> lr
|
|
||||||
|
|
||||||
cl --> qx
|
|
||||||
cl --> bf
|
|
||||||
|
|
||||||
xm --> db
|
|
||||||
|
|
||||||
sf --> bp
|
|
||||||
|
|
||||||
tj --> lc
|
|
||||||
tj --> gf
|
|
||||||
|
|
||||||
rz --> qx
|
|
||||||
rz --> cv
|
|
||||||
|
|
||||||
vc --> lr
|
|
||||||
vc --> hd
|
|
||||||
vc --> ks
|
|
||||||
vc --> qn
|
|
||||||
vc --> gx
|
|
||||||
vc --> nh
|
|
||||||
vc --> hv
|
|
||||||
|
|
||||||
bf --> qx
|
|
||||||
bf --> pf
|
|
||||||
|
|
||||||
jd --> qx
|
|
||||||
jd --> vm
|
|
||||||
|
|
||||||
ds --> cc
|
|
||||||
|
|
||||||
vm --> cl
|
|
||||||
|
|
||||||
ff --> pl
|
|
||||||
|
|
||||||
th --> rx
|
|
||||||
|
|
||||||
gm --> tj
|
|
||||||
gm --> gf
|
|
||||||
|
|
||||||
fj --> zd
|
|
||||||
|
|
||||||
mc --> ds
|
|
||||||
mc --> db
|
|
||||||
|
|
||||||
ks --> vz
|
|
||||||
button --> broadcast
|
|
||||||
|
|
||||||
cv --> xz
|
|
||||||
|
|
||||||
kt --> qx
|
|
||||||
kt --> rz
|
|
||||||
|
|
||||||
qj --> xm
|
|
||||||
qj --> db
|
|
||||||
|
|
||||||
bx --> qx
|
|
||||||
bx --> qp
|
|
||||||
|
|
||||||
fn --> pr
|
|
||||||
fn --> gf
|
|
||||||
|
|
||||||
qp --> cb
|
|
||||||
qp --> qx
|
|
||||||
|
|
||||||
cd --> pm
|
|
||||||
cd --> vc
|
|
||||||
|
|
||||||
nh --> hv
|
|
||||||
|
|
||||||
pl --> sf
|
|
||||||
pl --> db
|
|
||||||
|
|
||||||
qq --> qm
|
|
||||||
qq --> gf
|
|
||||||
|
|
||||||
xf --> th
|
|
||||||
|
|
||||||
zl --> th
|
|
||||||
|
|
||||||
pf --> qx
|
|
||||||
|
|
||||||
qn --> th
|
|
||||||
|
|
||||||
jz --> qj
|
|
||||||
jz --> db
|
|
||||||
|
|
||||||
pr --> gf
|
|
||||||
|
|
||||||
vl --> gf
|
|
||||||
vl --> fj
|
|
||||||
|
|
||||||
sb --> ks
|
|
||||||
sb --> vc
|
|
||||||
|
|
||||||
cr --> gx
|
|
||||||
cr --> vc
|
|
||||||
|
|
||||||
lc --> gf
|
|
||||||
lc --> fn
|
|
||||||
|
|
||||||
xn --> th
|
|
||||||
|
|
||||||
nn --> ff
|
|
||||||
nn --> db
|
|
||||||
|
|
||||||
ln --> gf
|
|
||||||
ln --> qq
|
|
||||||
|
|
||||||
pm --> vc
|
|
||||||
pm --> qk
|
|
||||||
|
|
||||||
xz --> jd
|
|
||||||
|
|
||||||
gx --> cd
|
|
||||||
|
|
||||||
broadcast --> sr
|
|
||||||
broadcast --> ch
|
|
||||||
broadcast --> hd
|
|
||||||
broadcast --> bx
|
|
||||||
|
|
||||||
qx --> cb
|
|
||||||
qx --> cv
|
|
||||||
qx --> bx
|
|
||||||
qx --> xz
|
|
||||||
qx --> vm
|
|
||||||
qx --> zl
|
|
||||||
|
|
||||||
db --> ff
|
|
||||||
db --> ds
|
|
||||||
db --> sf
|
|
||||||
db --> ch
|
|
||||||
db --> cc
|
|
||||||
db --> xf
|
|
||||||
|
|
||||||
cb --> kt
|
|
||||||
|
|
||||||
bp --> db
|
|
||||||
bp --> jz
|
|
||||||
|
|
||||||
gf --> fj
|
|
||||||
gf --> qm
|
|
||||||
gf --> xn
|
|
||||||
gf --> sr
|
|
||||||
|
|
||||||
hd --> vc
|
|
||||||
hd --> nh
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 134 KiB |
174
day20/notes.org
174
day20/notes.org
|
@ -1,174 +0,0 @@
|
||||||
#+title: Notes
|
|
||||||
* ok. only thought i had was to simulate the thing
|
|
||||||
|
|
||||||
have single executor, that takes head of the queue,
|
|
||||||
signals would be (to, from, type)
|
|
||||||
|
|
||||||
take 'to' out of the map, call it's 'process(from, type)'
|
|
||||||
|
|
||||||
and different types of executors would implement this differently.
|
|
||||||
and return a slice of new signals in order, to be appended.
|
|
||||||
|
|
||||||
if queue is empty - the single button press is propagated and all is well.
|
|
||||||
|
|
||||||
we will take snapshot of state, String() repr of all executors should be enough,
|
|
||||||
and save amount of signals sent so far
|
|
||||||
* also, i suppose i'd want to have entry points for fiddling with single executors to be test cases.
|
|
||||||
* modules to implement
|
|
||||||
** DONE Broadcast
|
|
||||||
** DONE Flip-Flop
|
|
||||||
** DONE Conjunction
|
|
||||||
** DONE Button
|
|
||||||
* i guess each module could test if string is it's a representation of this type
|
|
||||||
and would be able to parse it? into it's own struct?
|
|
||||||
well, those are just functions, since only methods are associated, so ok
|
|
||||||
* how do i run single tests?
|
|
||||||
** running tests from the module
|
|
||||||
#+begin_src bash
|
|
||||||
go test sunshine.industries/aoc2023/day20 -v
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
have file with `_test.go` and `func Test...(t *testing.T) {}` name
|
|
||||||
** running single test
|
|
||||||
#+begin_src bash
|
|
||||||
go test sunshine.industries/aoc2023/day20 -v -run TestParseFlipFlop
|
|
||||||
#+end_src
|
|
||||||
* yikes. if i don't know the 'inputs' to the conjunction, don't know how to check for 'all high'
|
|
||||||
let's add registering after the map is read.
|
|
||||||
* well. for part 2 brute force doesn't work.
|
|
||||||
how could i examine inputs to the 'rx' to see when it will receive 'low'?
|
|
||||||
|
|
||||||
i suppose inputs could be on prime cycles, which would align to all required values only on a very big step?
|
|
||||||
|
|
||||||
let's do some kind of visualiztion?
|
|
||||||
|
|
||||||
how would i do graphql or mermaidjs?
|
|
||||||
|
|
||||||
flowchard in mermaid should be it
|
|
||||||
|
|
||||||
go run . > day20/my-mermaid.mmd
|
|
||||||
* so, looking at the thingy.
|
|
||||||
rx is produced by &th
|
|
||||||
which has inputs of
|
|
||||||
11:&xn -> th
|
|
||||||
14:&qn -> th
|
|
||||||
16:&xf -> th
|
|
||||||
32:&zl -> th
|
|
||||||
|
|
||||||
|
|
||||||
for rx to receive a low pulse.
|
|
||||||
&th should receive High Pulse, while all other inputs alse remembered as high.
|
|
||||||
|
|
||||||
this is not too easy.
|
|
||||||
but first let's check if loops over
|
|
||||||
- xn
|
|
||||||
- qn
|
|
||||||
- xh
|
|
||||||
- zl
|
|
||||||
|
|
||||||
are manageable.
|
|
||||||
|
|
||||||
well.
|
|
||||||
i'll need to what?
|
|
||||||
not only track the inputs of the th.
|
|
||||||
but state of the 'subloop'
|
|
||||||
and they are separate
|
|
||||||
|
|
||||||
is there an easy way to collect the names from each subloop?
|
|
||||||
i guess i could write a collect.
|
|
||||||
|
|
||||||
from each of outputs of 'broadcast'
|
|
||||||
|
|
||||||
then have a funciton that checks loop size of each subgraphs
|
|
||||||
|
|
||||||
but i will also need to figure out on which steps output of the loop is remembered as High \ Low
|
|
||||||
|
|
||||||
let's start with loop size? and modify things if need be
|
|
||||||
** starting points of loops:
|
|
||||||
children of the broadcast:
|
|
||||||
broadcaster -> sr, ch, hd, bx
|
|
||||||
|
|
||||||
sr, ch, hd, bx
|
|
||||||
** ok. some data here
|
|
||||||
2023/12/20 12:05:06 >>> searching for loop of sr
|
|
||||||
2023/12/20 12:05:06 >>> found loop from 1 to 4028. of size 4028
|
|
||||||
2023/12/20 12:05:06 >>> searching for loop of ch
|
|
||||||
2023/12/20 12:05:06 >>> found loop from 0 to 3923. of size 3924
|
|
||||||
2023/12/20 12:05:06 >>> searching for loop of hd
|
|
||||||
2023/12/20 12:05:06 >>> found loop from 0 to 3793. of size 3794
|
|
||||||
2023/12/20 12:05:06 >>> searching for loop of bx
|
|
||||||
2023/12/20 12:05:07 >>> found loop from 0 to 3739. of size 3740
|
|
||||||
|
|
||||||
one of these guys starts from 1, not from 0.
|
|
||||||
this is unusual, but OK
|
|
||||||
|
|
||||||
now, i want to figure out what are steps where output for the each cycle is 'considered as saved as 1'
|
|
||||||
|
|
||||||
i guess i could just directly probe the
|
|
||||||
`th`
|
|
||||||
|
|
||||||
on each step up to 4028
|
|
||||||
|
|
||||||
but also, if the signallings from those are rare - would be eaiser to collect steps of each signal.
|
|
||||||
** ok. i collected 'monitored pulses' and i see lots of 'Low'
|
|
||||||
what i want is all "high" and first low after those.
|
|
||||||
** oh wow, this crap
|
|
||||||
2023/12/20 12:30:05 >>> searching for loop of ch
|
|
||||||
2023/12/20 12:30:05 >>> found loop from 1 to 3924. of size 3924
|
|
||||||
2023/12/20 12:30:05 the pulses
|
|
||||||
+map[3922:[high low]]
|
|
||||||
2023/12/20 12:30:05 >>> searching for loop of hd
|
|
||||||
2023/12/20 12:30:05 >>> found loop from 0 to 3793. of size 3794
|
|
||||||
2023/12/20 12:30:05 the pulses
|
|
||||||
+map[3661:[high low]]
|
|
||||||
2023/12/20 12:30:05 >>> searching for loop of bx
|
|
||||||
2023/12/20 12:30:05 >>> found loop from 0 to 3739. of size 3740
|
|
||||||
2023/12/20 12:30:05 the pulses
|
|
||||||
+map[3499:[high low]]
|
|
||||||
2023/12/20 12:30:05 >>> searching for loop of sr
|
|
||||||
2023/12/20 12:30:05 >>> found loop from 0 to 4027. of size 4028
|
|
||||||
2023/12/20 12:30:05 the pulses
|
|
||||||
+map[624:[high low]]
|
|
||||||
*** but at least these 'high low' are all on same step.
|
|
||||||
now with info on loop start, place of pulse in the loop and length of loops,
|
|
||||||
what is the step so that those [high low] occur on same step num?
|
|
||||||
*** math should be:
|
|
||||||
3922 + LOOP_N * (LOOP_LEN)
|
|
||||||
** wait i now get different output?
|
|
||||||
2023/12/20 12:57:50 >>> searching for loop of bx
|
|
||||||
2023/12/20 12:57:50 >>> found loop from 1 to 3739. of size 3739
|
|
||||||
2023/12/20 12:57:50 the pulses: +map[3738:[high low]]
|
|
||||||
2023/12/20 12:57:50 >>> searching for loop of sr
|
|
||||||
2023/12/20 12:57:50 >>> found loop from 0 to 4026. of size 4027
|
|
||||||
2023/12/20 12:57:50 the pulses: +map[286:[high low]]
|
|
||||||
2023/12/20 12:57:50 >>> searching for loop of ch
|
|
||||||
2023/12/20 12:57:50 >>> found loop from 0 to 3922. of size 3923
|
|
||||||
2023/12/20 12:57:50 the pulses: +map[78:[high low]]
|
|
||||||
2023/12/20 12:57:50 >>> searching for loop of hd
|
|
||||||
2023/12/20 12:57:51 >>> found loop from 0 to 3792. of size 3793
|
|
||||||
2023/12/20 12:57:51 the pulses: +map[3481:[high low]]
|
|
||||||
** why is my filtering unstable?
|
|
||||||
** let's check for single loop?
|
|
||||||
** yikes. but maybe
|
|
||||||
2023/12/20 13:08:52 >>> searching for loop of sr
|
|
||||||
2023/12/20 13:08:52 >>> found loop from 2 to 4028. of size 4027
|
|
||||||
2023/12/20 13:08:52 the pulses: +map[4027:[high low]]
|
|
||||||
|
|
||||||
2023/12/20 13:09:23 >>> searching for loop of ch
|
|
||||||
2023/12/20 13:09:23 >>> found loop from 2 to 3924. of size 3923
|
|
||||||
2023/12/20 13:09:23 the pulses: +map[3923:[high low]]
|
|
||||||
|
|
||||||
2023/12/20 13:09:37 >>> searching for loop of hd
|
|
||||||
2023/12/20 13:09:37 >>> found loop from 2 to 3794. of size 3793
|
|
||||||
2023/12/20 13:09:37 the pulses: +map[3793:[high low]]
|
|
||||||
|
|
||||||
2023/12/20 13:09:49 >>> searching for loop of bx
|
|
||||||
2023/12/20 13:09:49 >>> found loop from 2 to 3740. of size 3739
|
|
||||||
2023/12/20 13:09:49 the pulses: +map[3739:[high low]]
|
|
||||||
|
|
||||||
all loops start from same plase.
|
|
||||||
i could just do 1 press. then the loop starts. and all of them have [high low] on last place.
|
|
||||||
so it's going to be 1 + least common ...
|
|
||||||
** aaand, i just did least common multiple of the cycle lenghts.
|
|
||||||
and i didn't even added 1. which is strange. i guess i did have 'off-by-one'
|
|
||||||
crap
|
|
|
@ -1,105 +0,0 @@
|
||||||
package day20
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPropagateButtonPressExample1(t *testing.T) {
|
|
||||||
filename := "example1"
|
|
||||||
modules := ReadModules(filename)
|
|
||||||
t.Log("got modules:\n", modules)
|
|
||||||
|
|
||||||
low, high := PropagateButtonPress(modules, 0)
|
|
||||||
t.Logf("got low %d and high %d\n", low, high)
|
|
||||||
t.Log("modules after single button press:\n", modules)
|
|
||||||
|
|
||||||
success := low == 8 && high == 4
|
|
||||||
if !success {
|
|
||||||
t.Errorf("expected low 8 got %d, high 4 got %d", low, high)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPropagateButtonPressExample2(t *testing.T) {
|
|
||||||
filename := "example2"
|
|
||||||
modules := ReadModules(filename)
|
|
||||||
t.Log("got modules:\n", modules)
|
|
||||||
InitStuffs(modules)
|
|
||||||
|
|
||||||
low, high := PropagateButtonPress(modules, 0)
|
|
||||||
t.Logf("got low %d and high %d\n", low, high)
|
|
||||||
t.Log("modules after single button press:\n", modules)
|
|
||||||
|
|
||||||
success := low == 4 && high == 4
|
|
||||||
if !success {
|
|
||||||
t.Errorf("expected low 4 got %d, high 4 got %d", low, high)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPropagateButtonPressExample2FourSteps(t *testing.T) {
|
|
||||||
filename := "example2"
|
|
||||||
modules := ReadModules(filename)
|
|
||||||
t.Log("got modules:\n", modules)
|
|
||||||
InitStuffs(modules)
|
|
||||||
|
|
||||||
initialModulesState := ModulesState(modules)
|
|
||||||
|
|
||||||
low, high := PropagateButtonPress(modules, 0)
|
|
||||||
t.Logf("got low %d and high %d\n", low, high)
|
|
||||||
t.Log("#1 button press:\n", modules)
|
|
||||||
success := low == 4 && high == 4
|
|
||||||
if !success {
|
|
||||||
t.Errorf("expected low 4 got %d, high 4 got %d", low, high)
|
|
||||||
}
|
|
||||||
|
|
||||||
low, high = PropagateButtonPress(modules, 0)
|
|
||||||
t.Logf("got low %d and high %d\n", low, high)
|
|
||||||
t.Log("#2 button press:\n", modules)
|
|
||||||
success = low == 4 && high == 2
|
|
||||||
if !success {
|
|
||||||
t.Errorf("expected low 4 got %d, high 2 got %d", low, high)
|
|
||||||
}
|
|
||||||
secondState := ModulesState(modules)
|
|
||||||
if initialModulesState == secondState {
|
|
||||||
t.Error("initial state should be different from second")
|
|
||||||
}
|
|
||||||
|
|
||||||
low, high = PropagateButtonPress(modules, 0)
|
|
||||||
t.Logf("got low %d and high %d\n", low, high)
|
|
||||||
t.Log("#3 button press:\n", modules)
|
|
||||||
success = low == 5 && high == 3
|
|
||||||
if !success {
|
|
||||||
t.Errorf("expected low 5 got %d, high 3 got %d", low, high)
|
|
||||||
}
|
|
||||||
thirdState := ModulesState(modules)
|
|
||||||
if initialModulesState == thirdState {
|
|
||||||
t.Error("initial state should be different from third")
|
|
||||||
}
|
|
||||||
|
|
||||||
low, high = PropagateButtonPress(modules, 0)
|
|
||||||
t.Logf("got low %d and high %d\n", low, high)
|
|
||||||
t.Log("#4 button press:\n", modules)
|
|
||||||
success = low == 4 && high == 2
|
|
||||||
if !success {
|
|
||||||
t.Errorf("expected low 4 got %d, high 2 got %d", low, high)
|
|
||||||
}
|
|
||||||
|
|
||||||
lastState := ModulesState(modules)
|
|
||||||
|
|
||||||
log.Print("initial modules state:\n", initialModulesState)
|
|
||||||
log.Print("after 4 steps modules state:\n", lastState)
|
|
||||||
if initialModulesState != lastState {
|
|
||||||
t.Error("expected state to be same after 4 steps for example 2")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExample1TheQuestion(t *testing.T) {
|
|
||||||
filename := "example1"
|
|
||||||
modules := ReadModules(filename)
|
|
||||||
InitStuffs(modules)
|
|
||||||
|
|
||||||
low, high := Count10000ButtonPresses(modules)
|
|
||||||
t.Log("got low and high: ", low, high)
|
|
||||||
t.Log("response is: ", low * high)
|
|
||||||
}
|
|
|
@ -1,232 +0,0 @@
|
||||||
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(modules)
|
|
||||||
|
|
||||||
var result int
|
|
||||||
// result = CalcCommonStep()
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckSubgraphsStuff(allModules map[string]Module) {
|
|
||||||
// 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 {
|
|
||||||
log.Printf(">>> searching for loop of %s", start)
|
|
||||||
themap := make(map[string]any)
|
|
||||||
loopModules := TransitiveOutputs(start, allModules, themap)
|
|
||||||
_, _, requestedPulses := FindSubGraphLoopLength(loopModules, allModules, end)
|
|
||||||
FilterMonitoredPulses(requestedPulses)
|
|
||||||
log.Printf("the pulses: +%v", requestedPulses)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
23
main.go
23
main.go
|
@ -2,18 +2,25 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
|
||||||
|
|
||||||
"sunshine.industries/aoc2023/day20"
|
"sunshine.industries/aoc2023/day19"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
startTime := time.Now()
|
|
||||||
log.Print("> starting run:")
|
log.Print("> starting run:")
|
||||||
|
|
||||||
result := day20.Run()
|
// lnx{m>1548:A,A}
|
||||||
log.Printf("\n\nday20 result: %d\n****\n", result)
|
// qqz{s>2770:qs,m<1801:hdj,R}
|
||||||
endTime := time.Now()
|
// kt{m>2215:R,x>3386:A,x<3107:R,R}
|
||||||
diff := endTime.Sub(startTime)
|
testSorter := day19.ReadSorterLine("kt{m>2215:R,x>3386:A,x<3107:R,R}")
|
||||||
log.Printf("execution took %s", diff.String())
|
log.Printf("my test sorter is %+v", testSorter)
|
||||||
|
|
||||||
|
simplified := day19.SimplifyOperation(testSorter)
|
||||||
|
log.Printf("> simplivied %+v", simplified)
|
||||||
|
|
||||||
|
detail := day19.ReadDetailLine("{x=787,m=2655,a=1222,s=2876}")
|
||||||
|
log.Printf("> detail %+v", detail)
|
||||||
|
|
||||||
|
result := day19.Run()
|
||||||
|
log.Printf("\n\nday19 result: %d\n****\n", result)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue