306 lines
7.7 KiB
Go
306 lines
7.7 KiB
Go
package common
|
|
|
|
import (
|
|
"bufio"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
|
|
type WorryLevel interface {
|
|
Plus(int) WorryLevel
|
|
Times(int) WorryLevel
|
|
Power(int) WorryLevel
|
|
Relief() WorryLevel
|
|
Modulo(int) int
|
|
}
|
|
|
|
|
|
type WorryLevelWithRelief struct {
|
|
level int
|
|
}
|
|
|
|
func (worryLevel WorryLevelWithRelief) Plus(operand int) WorryLevel {
|
|
return WorryLevelWithRelief{worryLevel.level + operand}
|
|
}
|
|
|
|
func (worryLevel WorryLevelWithRelief) Times(operand int) WorryLevel {
|
|
return WorryLevelWithRelief{worryLevel.level * operand}
|
|
}
|
|
|
|
func (worryLevel WorryLevelWithRelief) Power(operand int) WorryLevel {
|
|
result := 1
|
|
for i := 0; i < operand; i++ {
|
|
result *= worryLevel.level
|
|
}
|
|
return WorryLevelWithRelief{result}
|
|
}
|
|
|
|
func (worryLevel WorryLevelWithRelief) Relief() WorryLevel {
|
|
return WorryLevelWithRelief{worryLevel.level / 3}
|
|
}
|
|
|
|
func (worryLevel WorryLevelWithRelief) Modulo(operand int) int {
|
|
return worryLevel.level % operand
|
|
}
|
|
|
|
|
|
type WorryLevelWithoutReliefBase struct {
|
|
level int
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefBase) Plus(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefPlus{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefBase) Times(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefTimes{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefBase) Power(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefPower{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefBase) Relief() WorryLevel {
|
|
return worryLevel
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefBase) Modulo(operand int) int {
|
|
return worryLevel.level % operand
|
|
}
|
|
|
|
|
|
type WorryLevelWithoutReliefPlus struct {
|
|
worryLevel WorryLevel
|
|
operand int
|
|
modulos map[int]int
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefPlus) Plus(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefPlus{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefPlus) Times(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefTimes{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefPlus) Power(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefPower{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefPlus) Relief() WorryLevel {
|
|
return worryLevel
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefPlus) Modulo(operand int) int {
|
|
if val, ok := worryLevel.modulos[operand]; ok {
|
|
return val
|
|
} else {
|
|
val = (worryLevel.worryLevel.Modulo(operand) + worryLevel.operand % operand) % operand
|
|
worryLevel.modulos[operand] = val
|
|
return val
|
|
}
|
|
}
|
|
|
|
|
|
type WorryLevelWithoutReliefTimes struct {
|
|
worryLevel WorryLevel
|
|
operand int
|
|
modulos map[int]int
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefTimes) Plus(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefPlus{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefTimes) Times(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefTimes{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefTimes) Power(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefPower{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefTimes) Relief() WorryLevel {
|
|
return worryLevel
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefTimes) Modulo(operand int) int {
|
|
if val, ok := worryLevel.modulos[operand]; ok {
|
|
return val
|
|
} else {
|
|
val = (worryLevel.worryLevel.Modulo(operand) * (worryLevel.operand % operand)) % operand
|
|
worryLevel.modulos[operand] = val
|
|
return val
|
|
}
|
|
}
|
|
|
|
|
|
type WorryLevelWithoutReliefPower struct {
|
|
worryLevel WorryLevel
|
|
operand int
|
|
modulos map[int]int
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefPower) Plus(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefPlus{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefPower) Times(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefTimes{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefPower) Power(operand int) WorryLevel {
|
|
return &WorryLevelWithoutReliefPower{worryLevel, operand, make(map[int]int)}
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefPower) Relief() WorryLevel {
|
|
return worryLevel
|
|
}
|
|
|
|
func (worryLevel *WorryLevelWithoutReliefPower) Modulo(operand int) int {
|
|
if val, ok := worryLevel.modulos[operand]; ok {
|
|
return val
|
|
} else {
|
|
mod := worryLevel.worryLevel.Modulo(operand)
|
|
result := 1
|
|
for i := 0; i < worryLevel.operand; i++ {
|
|
result *= mod
|
|
}
|
|
val = result % operand
|
|
worryLevel.modulos[operand] = val
|
|
return val
|
|
}
|
|
}
|
|
|
|
|
|
type Item struct {
|
|
worryLevel WorryLevel
|
|
}
|
|
|
|
func NewItem(worryLevel WorryLevel) *Item {
|
|
return &Item{worryLevel}
|
|
}
|
|
|
|
|
|
type Operation interface {
|
|
Apply(WorryLevel) WorryLevel
|
|
}
|
|
|
|
|
|
type Addition struct {
|
|
operand int
|
|
}
|
|
|
|
func (operation Addition) Apply(operand WorryLevel) WorryLevel {
|
|
return operand.Plus(operation.operand)
|
|
}
|
|
|
|
|
|
type Multiplication struct {
|
|
operand int
|
|
}
|
|
|
|
func (operation Multiplication) Apply(operand WorryLevel) WorryLevel {
|
|
return operand.Times(operation.operand)
|
|
}
|
|
|
|
|
|
type Power struct {
|
|
operand int
|
|
}
|
|
|
|
func (operation Power) Apply(operand WorryLevel) WorryLevel {
|
|
return operand.Power(operation.operand)
|
|
}
|
|
|
|
|
|
type Test struct {
|
|
divisible int
|
|
targets map[bool]*Monkey
|
|
}
|
|
|
|
|
|
type Monkey struct {
|
|
heldItems []Item
|
|
operation Operation
|
|
test Test
|
|
nInspections int
|
|
}
|
|
|
|
func (monkey *Monkey) ReceiveItem(item Item) {
|
|
monkey.heldItems = append(monkey.heldItems, item)
|
|
}
|
|
|
|
func (monkey *Monkey) GetNumberOfInspections() int {
|
|
return monkey.nInspections
|
|
}
|
|
|
|
func (monkey *Monkey) NextRound() {
|
|
for len(monkey.heldItems) > 0 {
|
|
monkey.nInspections++
|
|
item := monkey.heldItems[0]
|
|
monkey.heldItems = monkey.heldItems[1:]
|
|
worryLevel := item.worryLevel
|
|
worryLevel = monkey.operation.Apply(worryLevel)
|
|
worryLevel = worryLevel.Relief()
|
|
monkey.test.targets[worryLevel.Modulo(monkey.test.divisible) == 0].ReceiveItem(Item{worryLevel})
|
|
}
|
|
}
|
|
|
|
|
|
func Parse(scanner bufio.Scanner, relief bool) []Monkey {
|
|
monkeys := []Monkey{}
|
|
targets := make(map[int]map[bool]int)
|
|
var monkey Monkey
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
|
|
if line == "" {
|
|
monkeys = append(monkeys, monkey)
|
|
} else if line[:6] == "Monkey" {
|
|
monkey = Monkey{}
|
|
} else if line[:16] == " Starting items" {
|
|
items := strings.Split(line[18:], ", ")
|
|
for _, item := range(items) {
|
|
itemInt, _ := strconv.Atoi(item)
|
|
if (relief) {
|
|
monkey.heldItems = append(monkey.heldItems, *NewItem(WorryLevelWithRelief{itemInt}))
|
|
} else {
|
|
monkey.heldItems = append(monkey.heldItems, *NewItem(&WorryLevelWithoutReliefBase{itemInt}))
|
|
}
|
|
}
|
|
} else if line[:11] == " Operation" {
|
|
if line[23] == '+' {
|
|
operand, _ := strconv.Atoi(line[25:])
|
|
monkey.operation = Addition{operand}
|
|
} else if line[23] == '*' {
|
|
operand, err := strconv.Atoi(line[25:])
|
|
if err == nil {
|
|
monkey.operation = Multiplication{operand}
|
|
} else {
|
|
monkey.operation = Power{2}
|
|
}
|
|
}
|
|
} else if line[:6] == " Test" {
|
|
divisible, _ := strconv.Atoi(line[21:])
|
|
monkey.test.divisible = divisible
|
|
targets[len(monkeys)] = make(map[bool]int)
|
|
} else if line[:11] == " If true" {
|
|
targets[len(monkeys)][true] = int(line[29] - '0')
|
|
} else if line[:12] == " If false" {
|
|
targets[len(monkeys)][false] = int(line[30] - '0')
|
|
}
|
|
}
|
|
monkeys = append(monkeys, monkey)
|
|
|
|
for i, target := range targets {
|
|
monkeys[i].test.targets = make(map[bool]*Monkey)
|
|
monkeys[i].test.targets[true] = &monkeys[target[true]]
|
|
monkeys[i].test.targets[false] = &monkeys[target[false]]
|
|
}
|
|
|
|
return monkeys
|
|
}
|