package day11 import ( "fmt" "sort" "strconv" "strings" ) type Solver struct { monkeys []*MonkeySpec } type MonkeySpec struct { itemWorryLevels []uint64 advancedItemWorryLevels []ItemWorryLevel opType string opValue uint64 testDivisor uint64 targetMonkeyIfTrue int targetMonkeyIfFalse int numInspections int } type ItemWorryLevel struct { multipliers []uint64 additive uint64 } func (i *ItemWorryLevel) Value() uint64 { v := uint64(1) for _, m := range i.multipliers { v *= m } return v + i.additive } func (i *ItemWorryLevel) Mod(d uint64) uint64 { currentDivisor := uint64(1) for _, m := range i.multipliers { currentDivisor *= m % d } currentDivisor += i.additive currentDivisor %= d return currentDivisor } func (i *ItemWorryLevel) TimesConst(c uint64) *ItemWorryLevel { r := *i r.multipliers = append(r.multipliers, c) r.additive *= c return &r } // func (i *ItemWorryLevel) Squared() *ItemWorryLevel { // r := *i // r.multipliers = append(r.multipliers, (2*i.additive)%allDivisors) // r.multipliers = append(r.multipliers, i.multipliers...) // r.additive *= i.additive // return &r // } func (s *Solver) ParseInput(input []string) { s.monkeys = make([]*MonkeySpec, 1+len(input)/7) for m := 0; m < len(s.monkeys); m++ { offset := 7 * m startingItemsLine := strings.Split(strings.Split(input[offset+1], ": ")[1], ", ") startingItems := make([]uint64, len(startingItemsLine)) advancedStartingItems := make([]ItemWorryLevel, len(startingItemsLine)) for i, item := range startingItemsLine { startingItems[i], _ = strconv.ParseUint(item, 10, 64) advancedStartingItems[i] = ItemWorryLevel{[]uint64{startingItems[i]}, 0} } operationLine := strings.Split(strings.Split(input[offset+2], " old ")[1], " ") opType := operationLine[0] opValue, _ := strconv.ParseUint(operationLine[1], 10, 64) divisor, _ := strconv.ParseUint(strings.Split(input[offset+3], " by ")[1], 10, 64) trueTargetMonkey, _ := strconv.Atoi(strings.Split(input[offset+4], " monkey ")[1]) falseTargetMonkey, _ := strconv.Atoi(strings.Split(input[offset+5], " monkey ")[1]) s.monkeys[m] = &MonkeySpec{ itemWorryLevels: startingItems, advancedItemWorryLevels: advancedStartingItems, opType: opType, opValue: opValue, testDivisor: divisor, targetMonkeyIfTrue: trueTargetMonkey, targetMonkeyIfFalse: falseTargetMonkey, } } } func (s *Solver) SolvePart1() any { return s.solve(20, true) } func (s *Solver) SolvePart2() any { return s.solve(10000, false) } func (s *Solver) solve(numberOfRounds uint64, divideByThree bool) any { allDivisors := uint64(1) for _, d := range s.monkeys { allDivisors *= d.testDivisor } for r := 0; r < int(numberOfRounds); r++ { for _, monkey := range s.monkeys { for _, item := range monkey.itemWorryLevels { monkey.numInspections++ newWorryLevel := item var opValue uint64 if monkey.opValue == 0 { opValue = item } else { opValue = monkey.opValue } switch monkey.opType { case "*": newWorryLevel *= opValue case "+": newWorryLevel += opValue } if divideByThree { newWorryLevel /= 3 } else { newWorryLevel %= allDivisors } var targetMonkey int if newWorryLevel%monkey.testDivisor == 0 { targetMonkey = monkey.targetMonkeyIfTrue } else { targetMonkey = monkey.targetMonkeyIfFalse } s.monkeys[targetMonkey].itemWorryLevels = append(s.monkeys[targetMonkey].itemWorryLevels, newWorryLevel) // fmt.Printf("-> Throwing to monkey: %d\n", targetMonkey) } monkey.itemWorryLevels = []uint64{} } // fmt.Printf("\nround %d:\n", r) // s.printMonkeys() } var numInspections []int for _, m := range s.monkeys { numInspections = append(numInspections, m.numInspections) } sort.Ints(numInspections) return uint64(numInspections[len(numInspections)-1]) * uint64(numInspections[len(numInspections)-2]) } func (s *Solver) printMonkeys() { for _, m := range s.monkeys { fmt.Printf("%+v\n", m) } }