diff options
| author | Mike Vink <mike1994vink@gmail.com> | 2022-12-11 20:10:38 +0100 |
|---|---|---|
| committer | Mike Vink <mike1994vink@gmail.com> | 2022-12-11 20:10:38 +0100 |
| commit | 999c05159c1f67e60e2d287179776d29f070c5da (patch) | |
| tree | d5e9595fc2921e21fc16ab7f7bb9756907f10b66 /day11.go | |
| parent | 76e924fa212f275206730337ebaae5059f3a9d21 (diff) | |
day10 and day11
Diffstat (limited to 'day11.go')
| -rw-r--r-- | day11.go | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/day11.go b/day11.go new file mode 100644 index 0000000..abcba52 --- /dev/null +++ b/day11.go @@ -0,0 +1,212 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" + "regexp" + "strconv" + "strings" +) + +type monkey struct { + items []*item + operation func(item *item) int + test func(item *item) *monkey + by int + inspections int +} + +func NewMonkey(items []int, by int, op func(i *item) int, test func(i *item) *monkey) *monkey { + itemPtrs := make([]*item, len(items)) + for i, worry := range items { + itemPtrs[i] = NewItem(worry) + } + return &monkey{items: itemPtrs, operation: op, test: test, by: by} +} + +func (m *monkey) throw(receiver *monkey) { + throw, leftover := m.items[0], m.items[1:] + m.items = leftover + receiver.items = append(receiver.items, throw) +} + +type item struct { + worry int +} + +func (i *item) operation(m *monkey, r, mod int) { + worry := m.operation(i) + m.inspections += 1 + i.worry = (worry / r) % mod +} + +func (i *item) test(m *monkey) *monkey { + return m.test(i) +} + +func NewItem(worry int) *item { + return &item{ + worry: worry, + } +} + +// Can someone tell me how to do this better? Multiline regex? +func makeMonkeys(monkeyCount int, f *os.File) []*monkey { + startingItemsRegex := regexp.MustCompile(`\s+Starting items: ([0-9 ,]+)`) + operationRegex := regexp.MustCompile(`\s+Operation: new = ([0-9A-Za-z]+) ([+\*]{1}) ([0-9A-Za-z]+)`) + testRegex := regexp.MustCompile(`\s+Test: divisible by (\d+)`) + testConditionRegex := regexp.MustCompile(`\s+If (true|false): throw to monkey (\d+)`) + + monkeys := make([]*monkey, monkeyCount) + makeTest := func(by int, mtrue, mfalse int) func(i *item) *monkey { + return func(i *item) *monkey { + if i.worry%by == 0 { + return monkeys[mtrue] + } else { + return monkeys[mfalse] + } + } + } + makeOp := func(a1, comb, a2 string) func(i *item) int { + b := []string{a1, a2} + var c func(a, b int) int + if comb == "+" { + c = func(a, b int) int { + return a + b + } + } else if comb == "*" { + c = func(a, b int) int { + return a * b + } + } + b0, _ := strconv.Atoi(b[0]) + b1, _ := strconv.Atoi(b[1]) + return func(i *item) int { + switch { + case b[0] == "old" && b[1] == "old": + return c(i.worry, i.worry) + case b[0] == "old": + return c(i.worry, b1) + case b[1] == "old": + return c(b0, i.worry) + default: + return c(b0, b1) + } + } + } + + f.Seek(0, 0) + s := bufio.NewScanner(f) + startingItems := []int{} + testMap := make(map[string]int) + opMap := make(map[string]string) + monkeyPtr := 0 + for { + eof := s.Scan() + + if !eof || len(s.Bytes()) == 0 { + monkeys[monkeyPtr] = NewMonkey( + startingItems, + testMap["by"], + makeOp(opMap["arg1"], opMap["combination"], opMap["arg2"]), + makeTest(testMap["by"], testMap["true"], testMap["false"]), + ) + monkeyPtr += 1 + testMap = make(map[string]int) + opMap = make(map[string]string) + if monkeyPtr >= len(monkeys) { + break + } + } + + m := startingItemsRegex.FindStringSubmatch(s.Text()) + if len(m) == 2 { + itemStr := strings.Split(m[1], ", ") + startingItems = make([]int, len(itemStr)) + for i, strItem := range itemStr { + v, err := strconv.Atoi(strItem) + if err != nil { + log.Fatal("Could not get item worry from string", err) + } + startingItems[i] = v + } + } + m = operationRegex.FindStringSubmatch(s.Text()) + if len(m) == 4 { + opMap["arg1"] = m[1] + opMap["combination"] = m[2] + opMap["arg2"] = m[3] + } + m = testRegex.FindStringSubmatch(s.Text()) + if len(m) == 2 { + by, err := strconv.Atoi(m[1]) + if err != nil { + log.Fatal("Could not convert divisible by", err) + } + testMap["by"] = by + } + m = testConditionRegex.FindStringSubmatch(s.Text()) + if len(m) == 3 { + to, err := strconv.Atoi(m[2]) + if err != nil { + log.Fatal("Could not convert monkey to throw to", err) + } + testMap[m[1]] = to + } + } + return monkeys +} + +func monkeyBusiness(monkeys []*monkey, rounds, worryFactor, mod int) int { + for round := 0; round < rounds; round++ { + for _, m := range monkeys { + for len(m.items) > 0 { + item := m.items[0] + item.operation(m, worryFactor, mod) + to := item.test(m) + m.throw(to) + } + } + } + + monkey, business := 0, 0 + for _, m := range monkeys { + if m.inspections > monkey { + monkey, business = m.inspections, monkey + } else if m.inspections > business { + monkey, business = monkey, m.inspections + } + } + return monkey * business +} + +func main() { + f, err := os.Open("day11.txt") + if err != nil { + log.Fatal("could open input file", err) + } + + monkeyRegex := regexp.MustCompile(`Monkey (\d+)`) + monkeyCount := 0 + s := bufio.NewScanner(f) + for s.Scan() { + m := monkeyRegex.FindStringSubmatch(s.Text()) + if len(m) > 0 { + monkeyCount += 1 + } + } + + monkeys := makeMonkeys(monkeyCount, f) + mod := 1 + for _, m := range monkeys { + mod *= m.by + } + mb := monkeyBusiness(monkeys, 20, 3, mod) + fmt.Println("Part 1:", mb) + + monkeys = makeMonkeys(monkeyCount, f) + mb = monkeyBusiness(monkeys, 10_000, 1, mod) + fmt.Println("Part 2:", mb) +} |
