Files
advent2022/solutions/day21/day21.go
2022-12-23 19:45:56 -08:00

222 lines
5.1 KiB
Go

package day21
import (
"bufio"
"fmt"
"os"
"strconv"
)
const (
OpAdd int = iota
OpMul
OpSub
OpDiv
OpTarget
)
func opString(v int) string {
switch v {
case OpAdd:
return "+"
case OpMul:
return "*"
case OpSub:
return "-"
case OpDiv:
return "/"
case OpTarget:
return "=="
default:
return "???????"
}
}
type MonkeyState struct {
valueSet bool
value int
operation int
left string
right string
}
func step(monkeys map[string]MonkeyState) bool {
changedSomething := false
for monkey, state := range monkeys {
if !state.valueSet && monkeys[state.left].valueSet && monkeys[state.right].valueSet {
switch state.operation {
case OpAdd:
state.value = monkeys[state.left].value + monkeys[state.right].value
case OpSub:
state.value = monkeys[state.left].value - monkeys[state.right].value
case OpMul:
state.value = monkeys[state.left].value * monkeys[state.right].value
case OpDiv:
state.value = monkeys[state.left].value / monkeys[state.right].value
}
state.valueSet = true
monkeys[monkey] = state
changedSomething = true
}
}
return changedSomething
}
func contains(ls []string, x string) bool {
for _, tester := range ls {
if tester == x {
return true
}
}
return false
}
func Run(filename string) {
file, err := os.Open(filename)
if err != nil {
fmt.Println("Error opening file:", err)
return
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
monkeys := map[string]MonkeyState{}
for scanner.Scan() {
line := scanner.Text()
monkey := line[0:4]
data := line[6:]
value, err := strconv.Atoi(data)
if err == nil {
monkeys[monkey] = MonkeyState{true, value, 0, "", ""}
} else {
left := data[0:4]
right := data[7:]
switch data[5] {
case '+':
monkeys[monkey] = MonkeyState{false, 0, OpAdd, left, right}
case '-':
monkeys[monkey] = MonkeyState{false, 0, OpSub, left, right}
case '*':
monkeys[monkey] = MonkeyState{false, 0, OpMul, left, right}
case '/':
monkeys[monkey] = MonkeyState{false, 0, OpDiv, left, right}
default:
fmt.Println("Bad operation", string(data[5]))
return
}
}
}
file.Close()
for !monkeys["root"].valueSet {
step(monkeys)
}
fmt.Println("Root monkey value, part 1:", monkeys["root"].value)
humn := monkeys["humn"]
humn.valueSet = false
humn.operation = OpTarget
monkeys["humn"] = humn
unwoundMonkeys := []string{"humn"}
updatedSomething := true
for updatedSomething {
updatedSomething = false
for monkey, state := range monkeys {
if contains(unwoundMonkeys, state.left) || contains(unwoundMonkeys, state.right) {
if state.valueSet {
state.valueSet = false
monkeys[monkey] = state
unwoundMonkeys = append(unwoundMonkeys, monkey)
updatedSomething = true
}
}
}
}
fmt.Println("monkeys now", monkeys)
var targetValue int
var nextNode string
if monkeys[monkeys["root"].left].valueSet {
targetValue = monkeys[monkeys["root"].left].value
nextNode = monkeys["root"].right
fmt.Println("Root's right is the unknown one", nextNode)
} else {
targetValue = monkeys[monkeys["root"].right].value
nextNode = monkeys["root"].left
fmt.Println("Root's left is the unknown one", nextNode)
}
for !monkeys["humn"].valueSet {
nextState := monkeys[nextNode]
if nextState.valueSet {
fmt.Println("PANIC: Grounded in a node with the value set")
return
} else if nextState.operation == OpTarget {
nextState.value = targetValue
nextState.valueSet = true
monkeys[nextNode] = nextState
} else if monkeys[nextState.left].valueSet {
nextState.value = targetValue
nextState.valueSet = true
monkeys[nextNode] = nextState
switch nextState.operation {
case OpAdd:
// T = V + X
// T - V = X
targetValue = targetValue - monkeys[nextState.left].value
case OpMul:
// T = V * X
// T / V = X
targetValue = targetValue / monkeys[nextState.left].value
case OpSub:
// T = V - X
// T + X = V
// X = V - T
targetValue = monkeys[nextState.left].value - targetValue
case OpDiv:
// T = V / X
// TX = V
// X = V / T
targetValue = monkeys[nextState.left].value / targetValue
default:
fmt.Println("PANIC: Bad operation in back compute")
}
nextNode = nextState.right
} else if monkeys[nextState.right].valueSet {
nextState.value = targetValue
nextState.valueSet = true
monkeys[nextNode] = nextState
switch nextState.operation {
case OpAdd:
// T = X + V
// T - V = X
targetValue = targetValue - monkeys[nextState.right].value
case OpMul:
// T = X * V
targetValue = targetValue / monkeys[nextState.right].value
case OpSub:
// T = X - V
// T + V = X
targetValue = targetValue + monkeys[nextState.right].value
case OpDiv:
// T = X / V
// TV = X
targetValue = targetValue * monkeys[nextState.right].value
default:
fmt.Println("PANIC: Bad operation in back compute")
}
nextNode = nextState.left
} else {
fmt.Println("PANIC: Trouble with a double split in search")
return
}
}
fmt.Println("Actually, my value should be", monkeys["humn"].value)
}