229 lines
5.4 KiB
Go
229 lines
5.4 KiB
Go
package common
|
|
|
|
import (
|
|
"bufio"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
|
|
type Monkey interface {
|
|
Apply() int
|
|
Invert(int) int
|
|
IsHuman() bool
|
|
}
|
|
|
|
|
|
type Human struct {
|
|
name string
|
|
number int
|
|
}
|
|
|
|
func (monkey *Human) Apply() int {
|
|
return monkey.number
|
|
}
|
|
|
|
func (monkey *Human) Invert(total int) int {
|
|
return total
|
|
}
|
|
|
|
func (monkey *Human) IsHuman() bool {
|
|
return true
|
|
}
|
|
|
|
|
|
type NumberMonkey struct {
|
|
name string
|
|
number int
|
|
}
|
|
|
|
func (monkey *NumberMonkey) Apply() int {
|
|
return monkey.number
|
|
}
|
|
|
|
func (monkey *NumberMonkey) Invert(total int) int {
|
|
return total - monkey.number
|
|
}
|
|
|
|
func (monkey *NumberMonkey) IsHuman() bool {
|
|
return false
|
|
}
|
|
|
|
|
|
type PlusMonkey struct {
|
|
name string
|
|
operand1 Monkey
|
|
operand2 Monkey
|
|
}
|
|
|
|
func (monkey *PlusMonkey) Apply() int {
|
|
return monkey.operand1.Apply() + monkey.operand2.Apply()
|
|
}
|
|
|
|
func (monkey *PlusMonkey) Invert(total int) int {
|
|
if monkey.operand1.IsHuman() {
|
|
return monkey.operand1.Invert(total - monkey.operand2.Apply())
|
|
} else {
|
|
return monkey.operand2.Invert(total - monkey.operand1.Apply())
|
|
}
|
|
}
|
|
|
|
func (monkey *PlusMonkey) IsHuman() bool {
|
|
return monkey.operand1.IsHuman() || monkey.operand2.IsHuman()
|
|
}
|
|
|
|
|
|
type MinusMonkey struct {
|
|
name string
|
|
operand1 Monkey
|
|
operand2 Monkey
|
|
}
|
|
|
|
func (monkey *MinusMonkey) Apply() int {
|
|
return monkey.operand1.Apply() - monkey.operand2.Apply()
|
|
}
|
|
|
|
func (monkey *MinusMonkey) Invert(total int) int {
|
|
if monkey.operand1.IsHuman() {
|
|
return monkey.operand1.Invert(total + monkey.operand2.Apply())
|
|
} else {
|
|
return monkey.operand2.Invert(monkey.operand1.Apply() - total)
|
|
}
|
|
}
|
|
|
|
func (monkey *MinusMonkey) IsHuman() bool {
|
|
return monkey.operand1.IsHuman() || monkey.operand2.IsHuman()
|
|
}
|
|
|
|
|
|
type TimesMonkey struct {
|
|
name string
|
|
operand1 Monkey
|
|
operand2 Monkey
|
|
}
|
|
|
|
func (monkey *TimesMonkey) Apply() int {
|
|
return monkey.operand1.Apply() * monkey.operand2.Apply()
|
|
}
|
|
|
|
func (monkey *TimesMonkey) Invert(total int) int {
|
|
if monkey.operand1.IsHuman() {
|
|
return monkey.operand1.Invert(total / monkey.operand2.Apply())
|
|
} else {
|
|
return monkey.operand2.Invert(total / monkey.operand1.Apply())
|
|
}
|
|
}
|
|
|
|
func (monkey *TimesMonkey) IsHuman() bool {
|
|
return monkey.operand1.IsHuman() || monkey.operand2.IsHuman()
|
|
}
|
|
|
|
|
|
type DivisionMonkey struct {
|
|
name string
|
|
operand1 Monkey
|
|
operand2 Monkey
|
|
}
|
|
|
|
func (monkey *DivisionMonkey) Apply() int {
|
|
return monkey.operand1.Apply() / monkey.operand2.Apply()
|
|
}
|
|
|
|
func (monkey *DivisionMonkey) Invert(total int) int {
|
|
if monkey.operand1.IsHuman() {
|
|
return monkey.operand1.Invert(total * monkey.operand2.Apply())
|
|
} else {
|
|
return monkey.operand2.Invert(monkey.operand1.Apply() / total)
|
|
}
|
|
}
|
|
|
|
func (monkey *DivisionMonkey) IsHuman() bool {
|
|
return monkey.operand1.IsHuman() || monkey.operand2.IsHuman()
|
|
}
|
|
|
|
|
|
type EqualityMonkey struct {
|
|
name string
|
|
operand1 Monkey
|
|
operand2 Monkey
|
|
}
|
|
|
|
func (monkey *EqualityMonkey) Apply() int {
|
|
if monkey.operand1.Apply() == monkey.operand2.Apply() {
|
|
return 1
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func (monkey *EqualityMonkey) Invert(total int) int {
|
|
if monkey.operand1.IsHuman() {
|
|
return monkey.operand1.Invert(monkey.operand2.Apply() - total)
|
|
} else {
|
|
return monkey.operand2.Invert(monkey.operand1.Apply() - total)
|
|
}
|
|
}
|
|
|
|
func (monkey *EqualityMonkey) IsHuman() bool {
|
|
return monkey.operand1.IsHuman() || monkey.operand2.IsHuman()
|
|
}
|
|
|
|
|
|
type StringCouple struct {
|
|
left string
|
|
right string
|
|
}
|
|
|
|
|
|
type UnresolvedMonkey struct {
|
|
name string
|
|
symbol string
|
|
}
|
|
|
|
|
|
func Parse(scanner bufio.Scanner, rootIsEquality bool) Monkey {
|
|
unresolvedMonkeys := make(map[StringCouple]UnresolvedMonkey)
|
|
resolvedMonkeys := make(map[string]Monkey)
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
splittedLine := strings.Split(line, " ")
|
|
if len(splittedLine) == 2 {
|
|
number, _ := strconv.Atoi(splittedLine[1])
|
|
if splittedLine[0][:4] == "humn" {
|
|
resolvedMonkeys[splittedLine[0][:4]] = &Human{splittedLine[0][:4], number}
|
|
} else {
|
|
resolvedMonkeys[splittedLine[0][:4]] = &NumberMonkey{splittedLine[0][:4], number}
|
|
}
|
|
} else {
|
|
unresolvedMonkeys[StringCouple{splittedLine[1], splittedLine[3]}] = UnresolvedMonkey{splittedLine[0][:4], splittedLine[2]}
|
|
}
|
|
}
|
|
|
|
for len(unresolvedMonkeys) > 0 {
|
|
for monkeyCouple := range(unresolvedMonkeys) {
|
|
monkey1, ok1 := resolvedMonkeys[monkeyCouple.left]
|
|
monkey2, ok2 := resolvedMonkeys[monkeyCouple.right]
|
|
if ok1 && ok2 {
|
|
if rootIsEquality && unresolvedMonkeys[monkeyCouple].name == "root" {
|
|
resolvedMonkeys[unresolvedMonkeys[monkeyCouple].name] = &EqualityMonkey{unresolvedMonkeys[monkeyCouple].name, monkey1, monkey2}
|
|
} else {
|
|
switch unresolvedMonkeys[monkeyCouple].symbol {
|
|
case "+":
|
|
resolvedMonkeys[unresolvedMonkeys[monkeyCouple].name] = &PlusMonkey{unresolvedMonkeys[monkeyCouple].name, monkey1, monkey2}
|
|
case "-":
|
|
resolvedMonkeys[unresolvedMonkeys[monkeyCouple].name] = &MinusMonkey{unresolvedMonkeys[monkeyCouple].name, monkey1, monkey2}
|
|
case "*":
|
|
resolvedMonkeys[unresolvedMonkeys[monkeyCouple].name] = &TimesMonkey{unresolvedMonkeys[monkeyCouple].name, monkey1, monkey2}
|
|
case "/":
|
|
resolvedMonkeys[unresolvedMonkeys[monkeyCouple].name] = &DivisionMonkey{unresolvedMonkeys[monkeyCouple].name, monkey1, monkey2}
|
|
}
|
|
}
|
|
delete(unresolvedMonkeys, monkeyCouple)
|
|
}
|
|
}
|
|
}
|
|
|
|
return resolvedMonkeys["root"]
|
|
}
|