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() }