You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
3.6 KiB
Go
185 lines
3.6 KiB
Go
package day20
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
UNTYPED = "?"
|
|
FLIP_FLOP = "%"
|
|
BROADCASDTER = "b"
|
|
CONJUNCTION = "&"
|
|
LOW = 0
|
|
HIGH = 1
|
|
)
|
|
|
|
type Module struct {
|
|
kind string
|
|
name string
|
|
status bool
|
|
ouputs []string
|
|
inputs []string
|
|
inputMem map[string]int
|
|
}
|
|
|
|
type Pulse struct {
|
|
kind int
|
|
src string
|
|
dst string
|
|
}
|
|
|
|
func parseModules(lines []string) map[string]*Module {
|
|
modules := map[string]*Module{}
|
|
modulesByOrderOfAppearance := []*Module{}
|
|
|
|
for _, line := range lines {
|
|
kind := string(line[0])
|
|
parts := strings.Split(line, " -> ")
|
|
name := parts[0][1:]
|
|
outputs := strings.Split(parts[1], ", ")
|
|
|
|
if kind == "b" {
|
|
name = "b" + name
|
|
}
|
|
|
|
module := &Module{kind, name, false, outputs, []string{}, map[string]int{}}
|
|
modules[name] = module
|
|
modulesByOrderOfAppearance = append(modulesByOrderOfAppearance, module)
|
|
}
|
|
|
|
// setup inputs
|
|
for _, module := range modulesByOrderOfAppearance {
|
|
for _, outputName := range module.ouputs {
|
|
m, ok := modules[outputName]
|
|
|
|
if !ok {
|
|
// create ad'hoc untyped module
|
|
m = &Module{UNTYPED, outputName, false, []string{}, []string{}, map[string]int{}}
|
|
modules[outputName] = m
|
|
modulesByOrderOfAppearance = append(modulesByOrderOfAppearance, m)
|
|
}
|
|
|
|
m.inputs = append(m.inputs, module.name)
|
|
m.inputMem[module.name] = LOW
|
|
}
|
|
}
|
|
|
|
return modules
|
|
}
|
|
|
|
func runSim(modules map[string]*Module, pulseQueue []*Pulse, count int) (int, int) {
|
|
countLow := 0
|
|
countHigh := 0
|
|
|
|
for len(pulseQueue) > 0 {
|
|
|
|
pulse := pulseQueue[0]
|
|
pulseQueue[0] = nil
|
|
pulseQueue = pulseQueue[1:]
|
|
|
|
module := modules[pulse.dst]
|
|
|
|
switch module.kind {
|
|
case BROADCASDTER:
|
|
for _, dst := range module.ouputs {
|
|
newPulse := &Pulse{pulse.kind, module.name, dst}
|
|
pulseQueue = append(pulseQueue, newPulse)
|
|
if newPulse.kind == LOW {
|
|
countLow++
|
|
} else {
|
|
countHigh++
|
|
}
|
|
}
|
|
|
|
case FLIP_FLOP:
|
|
if pulse.kind == LOW {
|
|
var pulseKind int
|
|
if module.status {
|
|
pulseKind = LOW
|
|
} else {
|
|
pulseKind = HIGH
|
|
}
|
|
module.status = !module.status // flip status
|
|
|
|
for _, dst := range module.ouputs {
|
|
newPulse := &Pulse{pulseKind, module.name, dst}
|
|
pulseQueue = append(pulseQueue, newPulse)
|
|
if newPulse.kind == LOW {
|
|
countLow++
|
|
} else {
|
|
countHigh++
|
|
}
|
|
}
|
|
}
|
|
|
|
case CONJUNCTION:
|
|
if pulse.kind == HIGH && module.name == "qn" {
|
|
fmt.Println("qn from ", pulse.src, " : ", count)
|
|
}
|
|
module.inputMem[pulse.src] = pulse.kind
|
|
allHigh := true
|
|
for _, v := range module.inputMem {
|
|
if v == LOW {
|
|
allHigh = false
|
|
break
|
|
}
|
|
}
|
|
|
|
var pulseKind int
|
|
if allHigh {
|
|
pulseKind = LOW
|
|
} else {
|
|
pulseKind = HIGH
|
|
}
|
|
|
|
for _, dst := range module.ouputs {
|
|
newPulse := &Pulse{pulseKind, module.name, dst}
|
|
pulseQueue = append(pulseQueue, newPulse)
|
|
if newPulse.kind == LOW {
|
|
countLow++
|
|
} else {
|
|
countHigh++
|
|
}
|
|
}
|
|
|
|
case UNTYPED:
|
|
module.status = pulse.kind == HIGH
|
|
}
|
|
|
|
}
|
|
|
|
return countLow, countHigh
|
|
}
|
|
|
|
func Part1(lines []string, pressCount int) (map[string]*Module, int) {
|
|
modules := parseModules(lines)
|
|
|
|
sumLow := 0
|
|
sumHigh := 0
|
|
|
|
for i := 0; i < pressCount; i++ {
|
|
queue := []*Pulse{}
|
|
queue = append(queue, &Pulse{LOW, "button", "broadcaster"})
|
|
countLow, countHigh := runSim(modules, queue, i+1)
|
|
countLow++
|
|
|
|
sumLow += countLow
|
|
sumHigh += countHigh
|
|
}
|
|
|
|
return modules, sumLow * sumHigh
|
|
}
|
|
|
|
func Part2(lines []string, pressCount int) (map[string]*Module, int) {
|
|
modules := parseModules(lines)
|
|
|
|
for i := 0; i < pressCount; i++ {
|
|
queue := []*Pulse{}
|
|
queue = append(queue, &Pulse{LOW, "button", "broadcaster"})
|
|
runSim(modules, queue, i+1)
|
|
}
|
|
|
|
return modules, 0
|
|
}
|