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

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
}