day20: more reading

This commit is contained in:
efim 2023-12-20 08:10:10 +00:00
parent 9dbc2ca205
commit 4974127cef
7 changed files with 202 additions and 85 deletions

3
.gitignore vendored
View File

@ -1,4 +1,3 @@
/.direnv/ /.direnv/
/.go /.go
example input
/day19/input

17
day19/example Normal file
View File

@ -0,0 +1,17 @@
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}

5
day20/example1 Normal file
View File

@ -0,0 +1,5 @@
broadcaster -> a, b, c
%a -> b
%b -> c
%c -> inv
&inv -> a

5
day20/example2 Normal file
View File

@ -0,0 +1,5 @@
broadcaster -> a
%a -> inv, con
&inv -> b
%b -> con
&con -> output

127
day20/modules.go Normal file
View File

@ -0,0 +1,127 @@
package day20
import (
"fmt"
"log"
"regexp"
"strings"
)
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 (ff *FlipFlop)Receive(s Signal) []Signal {
return []Signal{}
}
func (ff *FlipFlop)String() string {
return fmt.Sprintf("[flip-flop '%s' (on: %t) -> %s]", ff.Name, ff.InOn, ff.OutputNames)
}
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
}
func (b *Broadcast)Receive(s Signal) []Signal {
return []Signal{}
}
func (b *Broadcast)String() string {
return fmt.Sprintf("[broadcast -> %+v]", b.OutputNames)
}
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
}
func (c *Conjunction)Receive(s Signal) []Signal {
return []Signal{}
}
func (c *Conjunction)String() string {
return fmt.Sprintf("[conjunction '%s' -> %+v]", c.Name, c.OutputNames)
}
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], ", ")
return
}
type Button struct {}
func (b *Button)Receive(s Signal) []Signal {
return []Signal{}
}
func (b *Button)String() string {
return "[button]"
}
type Output struct {}
func (o *Output)Receive(s Signal) []Signal {
return []Signal{}
}
func (o *Output)String() string {
return "[output]"
}

View File

@ -16,7 +16,7 @@ func TestParseFlipFlop(t *testing.T) {
func TestParseBroadcast(t *testing.T) { func TestParseBroadcast(t *testing.T) {
broadcastLine := "broadcaster -> a, b, c" broadcastLine := "broadcaster -> a, b, c"
if !isLineBroadcast(broadcastLine) { if !IsLineBroadcast(broadcastLine) {
t.Error("expected line to pass broadcast check") t.Error("expected line to pass broadcast check")
} }
module := ParseBroadcast(broadcastLine) module := ParseBroadcast(broadcastLine)
@ -29,16 +29,24 @@ func TestParseBroadcast(t *testing.T) {
func TestParseConjunction(t *testing.T) { func TestParseConjunction(t *testing.T) {
conjunctionLine := "&inv -> b" conjunctionLine := "&inv -> b"
if !isLineConjunction(conjunctionLine) { if !IsLineConjunction(conjunctionLine) {
t.Errorf("line '%s' should be flip flop\n", conjunctionLine) t.Errorf("line '%s' should be flip flop\n", conjunctionLine)
} }
module := ParseConjunction(conjunctionLine) module := ParseConjunction(conjunctionLine)
t.Logf("got module %+v\n", module) t.Logf("got module %+v\n", module)
if module.Name != "inv" || slices.Equal(module.OutputNames, []string{"b"}) { moduleAsExpected := module.Name != "inv" || slices.Equal(module.OutputNames, []string{"b"})
if !moduleAsExpected {
t.Fail() t.Fail()
} }
} }
func TestPanic(t *testing.T) { func TestReadManyModules(t *testing.T) {
panic("hehe") filename := "example1"
modules := ReadModules(filename)
t.Logf("> read example1:\n%+v", modules)
filename2 := "example2"
modules2 := ReadModules(filename2)
t.Logf("> read example2:\n%+v", modules2)
} }

View File

@ -3,7 +3,7 @@ package day20
import ( import (
"fmt" "fmt"
"log" "log"
"regexp" "os"
"strings" "strings"
) )
@ -12,81 +12,37 @@ func Run() int {
return 0 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<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
}
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
}
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], ", ")
return
}
type Button struct {}
// process sends single `low pulse` directly to "broadcast" // 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
}