222 lines
5.1 KiB
Go
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)
|
|
}
|