diff --git a/day20/modules_test.go b/day20/modules_test.go new file mode 100644 index 0000000..3d70b6e --- /dev/null +++ b/day20/modules_test.go @@ -0,0 +1,44 @@ +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) + if module.Name != "inv" || slices.Equal(module.OutputNames, []string{"b"}) { + t.Fail() + } +} + +func TestPanic(t *testing.T) { + panic("hehe") +} diff --git a/day20/notes.org b/day20/notes.org new file mode 100644 index 0000000..9dce4b6 --- /dev/null +++ b/day20/notes.org @@ -0,0 +1,35 @@ +#+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 +** TODO Broadcast +** TODO Flip-Flop +** TODO Conjunction +** TODO 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 diff --git a/day20/pulsePropagation.go b/day20/pulsePropagation.go new file mode 100644 index 0000000..c00bfa9 --- /dev/null +++ b/day20/pulsePropagation.go @@ -0,0 +1,92 @@ +package day20 + +import ( + "fmt" + "log" + "regexp" + "strings" +) + +func Run() int { + fmt.Println("hello from dya 20") + + return 0 +} + +type PulseType int + +const ( + HighPulse PulseType = iota + LowPulse +) + +type Signal struct { + To, From string + PulseType PulseType +} + +type Module interface { + receive(s Signal) []Signal +} + +// Modules +type FlipFlop struct { + Name string + OutputNames []string + InOn bool +} + +func IsLineFlipFlop(line string) bool { + return strings.HasPrefix(line, "%") +} + +func ParseFlipFlop(line string) (result FlipFlop) { + re := regexp.MustCompile(`%(?P\D+) -> (?P.+)`) + 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 +} + +func isLineBroadcast(line string) bool { + return strings.HasPrefix(line, "broadcaster") +} + +func ParseBroadcast(line string) (result Broadcast) { + re := regexp.MustCompile(`broadcaster -> (?P.+)`) + matches := re.FindStringSubmatch(line) + + result.OutputNames = strings.Split(matches[1], ", ") + return +} + +type Conjunction struct { + Name string + OutputNames []string + MostRecentPulseFromInputIsHigh map[string]bool +} + +func isLineConjunction(line string) bool { + return strings.HasPrefix(line, "&") +} + +func ParseConjunction(line string) (result Conjunction) { + re := regexp.MustCompile(`&(?P\D+) -> (?P.+)`) + 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 Button struct {} +// process sends single `low pulse` directly to "broadcast" diff --git a/main.go b/main.go index d67c550..9c31f66 100644 --- a/main.go +++ b/main.go @@ -2,25 +2,18 @@ package main import ( "log" + "time" - "sunshine.industries/aoc2023/day19" + "sunshine.industries/aoc2023/day20" ) func main() { + startTime := time.Now() log.Print("> starting run:") - // lnx{m>1548:A,A} - // qqz{s>2770:qs,m<1801:hdj,R} - // kt{m>2215:R,x>3386:A,x<3107:R,R} - testSorter := day19.ReadSorterLine("kt{m>2215:R,x>3386:A,x<3107:R,R}") - 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) + result := day20.Run() + log.Printf("\n\nday20 result: %d\n****\n", result) + endTime := time.Now() + diff := endTime.Sub(startTime) + log.Printf("execution took %s", diff.String()) }