227 lines
5.7 KiB
Go
227 lines
5.7 KiB
Go
package day11
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Operation int
|
|
|
|
const (
|
|
Times Operation = iota
|
|
Plus
|
|
Square
|
|
)
|
|
|
|
type Monkey struct {
|
|
items []int
|
|
operation Operation
|
|
operation_by int
|
|
divisible_by int
|
|
if_true int
|
|
if_false int
|
|
}
|
|
|
|
func printMonkeys(monkeys []*Monkey) {
|
|
for monkey_no, monkey := range monkeys {
|
|
if monkey != nil {
|
|
fmt.Printf("Monkey #%d: ", monkey_no)
|
|
var items []int = (*monkey).items
|
|
for idx, item := range items {
|
|
fmt.Printf("%d", item)
|
|
if idx != len(items)-1 {
|
|
fmt.Printf(", ")
|
|
}
|
|
}
|
|
fmt.Println()
|
|
}
|
|
}
|
|
}
|
|
|
|
func lcm(items []int) int {
|
|
worstCase := 1
|
|
smallest := items[0]
|
|
for _, val := range items {
|
|
worstCase *= val
|
|
if val < smallest {
|
|
smallest = val
|
|
}
|
|
}
|
|
|
|
retval := worstCase
|
|
for candidate := worstCase; candidate > 2; candidate -= smallest {
|
|
works := true
|
|
for _, val := range items {
|
|
works = works && (candidate%val == 0)
|
|
}
|
|
if works {
|
|
retval = candidate
|
|
}
|
|
}
|
|
|
|
return retval
|
|
}
|
|
|
|
func runRound(monkeys *[]*Monkey, counts *[]int, ceiling int) {
|
|
//three := big.NewInt(3)
|
|
for monkey_no, monkey := range *monkeys {
|
|
if monkey == nil {
|
|
break
|
|
}
|
|
//fmt.Printf("Monkey %d:\n", monkey_no)
|
|
items := (*monkey).items
|
|
(*monkey).items = []int{}
|
|
for _, item := range items {
|
|
(*counts)[monkey_no] += 1
|
|
//fmt.Printf(" Monkey inspects an item with a worry level of %d.\n", item)
|
|
var result int = item
|
|
switch monkey.operation {
|
|
case Times:
|
|
result = item * monkey.operation_by
|
|
//fmt.Printf(" Worry level is multiplied by %d to %d.\n", monkey.operation_by, result)
|
|
case Square:
|
|
result = item * item
|
|
//fmt.Printf(" Worry level is squared to %d.\n", result)
|
|
case Plus:
|
|
result = item + monkey.operation_by
|
|
//fmt.Printf(" Worry level is increased by %d to %d.\n", monkey.operation_by, result)
|
|
default:
|
|
//fmt.Printf("PANIC: Don't understand operation\n", monkey.operation_by)
|
|
return
|
|
}
|
|
result %= ceiling
|
|
//result = result.Div(result, three)
|
|
//fmt.Printf(" Monkey gets bored with item. Worry level is divided by 3 to %d.\n", result)
|
|
var targetMonkey int
|
|
|
|
if result%monkey.divisible_by == 0 {
|
|
//fmt.Printf(" Current worry level is divisible by %d.\n", monkey.divisible_by)
|
|
targetMonkey = monkey.if_true
|
|
} else {
|
|
//fmt.Printf(" Current worry level is not divisible by %d.\n", monkey.divisible_by)
|
|
targetMonkey = monkey.if_false
|
|
}
|
|
//fmt.Printf(" Item with worry level %d is thrown to monkey %d.\n", result, targetMonkey)
|
|
(*monkeys)[targetMonkey].items = append((*monkeys)[targetMonkey].items, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
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 := []*Monkey{nil, nil, nil, nil, nil, nil, nil, nil}
|
|
inspectionCounts := []int{0, 0, 0, 0, 0, 0, 0, 0}
|
|
divisors := []int{}
|
|
var currentMonkey *Monkey = nil
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
|
|
if strings.HasPrefix(line, "Monkey ") {
|
|
number, err := strconv.Atoi(line[7 : len(line)-1])
|
|
if err != nil {
|
|
fmt.Println("Error parsing monkey number", line[7:len(line)-1])
|
|
return
|
|
}
|
|
|
|
newMonkey := Monkey{[]int{}, Times, 0, 0, 0, 0}
|
|
monkeys[number] = &newMonkey
|
|
currentMonkey = &newMonkey
|
|
} else if strings.HasPrefix(line, " Starting items: ") {
|
|
list := line[18:]
|
|
splits := strings.Split(list, ", ")
|
|
if currentMonkey == nil {
|
|
fmt.Println("Item list with no monkey")
|
|
return
|
|
}
|
|
for _, split := range splits {
|
|
splitInt, err := strconv.Atoi(split)
|
|
if err != nil {
|
|
fmt.Println("Error parsing monkey's item", split)
|
|
return
|
|
}
|
|
(*currentMonkey).items = append((*¤tMonkey).items, splitInt)
|
|
}
|
|
} else if strings.HasPrefix(line, " Operation: new = old * ") {
|
|
amtString := line[25:]
|
|
if amtString == "old" {
|
|
(*currentMonkey).operation = Square
|
|
} else {
|
|
amt, err := strconv.Atoi(amtString)
|
|
if err != nil {
|
|
fmt.Println("Error parsing operation number", amtString)
|
|
return
|
|
}
|
|
(*¤tMonkey).operation = Times
|
|
(*¤tMonkey).operation_by = amt
|
|
}
|
|
} else if strings.HasPrefix(line, " Operation: new = old + ") {
|
|
amtString := line[25:]
|
|
amt, err := strconv.Atoi(amtString)
|
|
if err != nil {
|
|
fmt.Println("Error parsing plus operation number", amtString)
|
|
return
|
|
}
|
|
(*¤tMonkey).operation = Plus
|
|
(*¤tMonkey).operation_by = amt
|
|
} else if strings.HasPrefix(line, " Test: divisible by ") {
|
|
amtString := line[21:]
|
|
amt, err := strconv.Atoi(amtString)
|
|
if err != nil {
|
|
fmt.Println("Error parsing divisible by number", amtString)
|
|
return
|
|
}
|
|
(*¤tMonkey).divisible_by = amt
|
|
divisors = append(divisors, amt)
|
|
} else if strings.HasPrefix(line, " If true: throw to monkey ") {
|
|
amtString := line[29:]
|
|
amt, err := strconv.Atoi(amtString)
|
|
if err != nil {
|
|
fmt.Println("Error parsing if true number", amtString)
|
|
return
|
|
}
|
|
(*¤tMonkey).if_true = amt
|
|
} else if strings.HasPrefix(line, " If false: throw to monkey ") {
|
|
amtString := line[30:]
|
|
amt, err := strconv.Atoi(amtString)
|
|
if err != nil {
|
|
fmt.Println("Error parsing if false number", amtString)
|
|
return
|
|
}
|
|
(*¤tMonkey).if_false = amt
|
|
} else if len(line) == 0 {
|
|
} else {
|
|
fmt.Printf("Invalid line: '%s'\n", line)
|
|
return
|
|
}
|
|
}
|
|
|
|
ceiling := lcm(divisors)
|
|
|
|
printMonkeys(monkeys)
|
|
for i := 0; i < 10000; i++ {
|
|
if i%100 == 0 {
|
|
fmt.Println("Running round", i)
|
|
}
|
|
runRound(&monkeys, &inspectionCounts, ceiling)
|
|
//printMonkeys(monkeys)
|
|
}
|
|
for monkey_no, count := range inspectionCounts {
|
|
fmt.Printf("Monkey %d inspected items %d times\n", monkey_no, count)
|
|
}
|
|
|
|
file.Close()
|
|
}
|