aoc-2022/day11/solution.go

165 lines
4.1 KiB
Go
Raw Permalink Normal View History

2022-12-11 19:15:08 +00:00
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)
}
}