day20: more reading
This commit is contained in:
		
							parent
							
								
									9dbc2ca205
								
							
						
					
					
						commit
						4974127cef
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
/.direnv/
 | 
			
		||||
/.go
 | 
			
		||||
example
 | 
			
		||||
/day19/input
 | 
			
		||||
input
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								day19/example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								day19/example
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										5
									
								
								day20/example1
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
broadcaster -> a, b, c
 | 
			
		||||
%a -> b
 | 
			
		||||
%b -> c
 | 
			
		||||
%c -> inv
 | 
			
		||||
&inv -> a
 | 
			
		||||
							
								
								
									
										5
									
								
								day20/example2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								day20/example2
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
broadcaster -> a
 | 
			
		||||
%a -> inv, con
 | 
			
		||||
&inv -> b
 | 
			
		||||
%b -> con
 | 
			
		||||
&con -> output
 | 
			
		||||
							
								
								
									
										127
									
								
								day20/modules.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								day20/modules.go
									
									
									
									
									
										Normal 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]"
 | 
			
		||||
}
 | 
			
		||||
@ -16,7 +16,7 @@ func TestParseFlipFlop(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestParseBroadcast(t *testing.T) {
 | 
			
		||||
	broadcastLine := "broadcaster -> a, b, c"
 | 
			
		||||
	if !isLineBroadcast(broadcastLine) {
 | 
			
		||||
	if !IsLineBroadcast(broadcastLine) {
 | 
			
		||||
		t.Error("expected line to pass broadcast check")
 | 
			
		||||
	}
 | 
			
		||||
	module := ParseBroadcast(broadcastLine)
 | 
			
		||||
@ -29,16 +29,24 @@ func TestParseBroadcast(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestParseConjunction(t *testing.T) {
 | 
			
		||||
	conjunctionLine := "&inv -> b"
 | 
			
		||||
	if !isLineConjunction(conjunctionLine) {
 | 
			
		||||
	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"}) {
 | 
			
		||||
	moduleAsExpected := module.Name != "inv" || slices.Equal(module.OutputNames, []string{"b"})
 | 
			
		||||
	if !moduleAsExpected {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestPanic(t *testing.T) {
 | 
			
		||||
	panic("hehe")
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ package day20
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -12,81 +12,37 @@ func Run() int {
 | 
			
		||||
 | 
			
		||||
	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"
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user