package main import ( "fmt" "log" "strings" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) func main() { inp := h.StdinToStringSlice() part1(inp) part2(inp) } func part1(inp []string) { monkeys := BuildMonkeys(inp, 1) for i := 0; i < 20; i++ { for _, m := range monkeys.monkeys { m.Do(monkeys) } } fmt.Println("# Part 1") fmt.Println("Monkey Business:", monkeys.Business()) } func part2(inp []string) { monkeys := BuildMonkeys(inp, 2) mod := uint64(1) for _, m := range monkeys.monkeys { mod = mod * m.Div } for i := 0; i < 10000; i++ { for _, m := range monkeys.monkeys { for len(m.Items) > 0 { m.Inspected++ var v uint64 v, m.Items = m.Items[len(m.Items)-1], m.Items[:len(m.Items)-1] v = m.Op(v) % mod if v%m.Div == 0 { monkeys.Find(m.TrueTo).Catch(v) } else { monkeys.Find(m.FalseTo).Catch(v) } } } } fmt.Println("# Part 2") fmt.Println("Monkey Business:", monkeys.Business()) } type AllMonkeys struct { monkeys []*Monkey Part uint64 } func BuildMonkeys(inp []string, part uint64) *AllMonkeys { var ret []*Monkey for i := range inp { if strings.HasPrefix(inp[i], "Monkey") { ret = append(ret, NewMonkey(inp[i:])) } } return &AllMonkeys{ monkeys: ret, Part: part, } } func (a *AllMonkeys) Find(id int) *Monkey { for i := range a.monkeys { if a.monkeys[i].Id == id { return a.monkeys[i] } } return nil } func (a *AllMonkeys) Business() uint64 { // Find the 2 most active monkeys, multiply their inspections together var top1, top2 *Monkey for _, m := range a.monkeys { if top1 == nil { top1 = m } else if m.Inspected > top1.Inspected { top1, top2 = m, top1 } else if top2 == nil || m.Inspected > top2.Inspected { top2 = m } } fmt.Println("Top Two") fmt.Println(top1) fmt.Println(top2) return top1.Inspected * top2.Inspected } type Monkey struct { Id int Items []uint64 Inspected uint64 Op func(uint64) uint64 Value uint64 TrueTo int FalseTo int Div uint64 } func NewMonkey(inp []string) *Monkey { monkey := &Monkey{} fmt.Sscanf(inp[0], "Monkey %d:", &monkey.Id) pts := strings.Fields(inp[1]) for i := 2; i < len(pts); i++ { wrk := strings.TrimSuffix(pts[i], ",") monkey.Items = append(monkey.Items, h.Atoui(wrk)) } // Parse out this Monkey's Operation Function pts = strings.Fields(inp[2]) var p1, p2 uint64 p1S := pts[3] if p1S != "old" { p1 = h.Atoui(p1S) } p2S := pts[5] if p2S != "old" { p2 = h.Atoui(p2S) } op := pts[4] // And the Test monkey.Div = h.Atoui(inp[3][21:]) switch op { case "*": monkey.Op = func(v uint64) uint64 { first, second := v, v if p1S != "old" { first = p1 } if p2S != "old" { second = p2 } return first * second } case "+": monkey.Op = func(v uint64) uint64 { first, second := v, v if p1S != "old" { first = p1 } if p2S != "old" { second = p2 } return first + second } } monkey.TrueTo = h.Atoi(inp[4][29:]) monkey.FalseTo = h.Atoi(inp[5][30:]) return monkey } func (m *Monkey) Do(all *AllMonkeys) { for i := range m.Items { item := m.Items[i] pre := item item = m.Op(item) if item < pre { log.Fatalf("%s; Was %d; Now: %d\n", m, pre, item) } if all.Part == 1 { item = item / 3 } if item%m.Div == 0 { all.Find(m.TrueTo).Catch(item) } else { all.Find(m.FalseTo).Catch(item) } m.Inspected++ } m.Items = []uint64{} } func (m *Monkey) Catch(item uint64) { m.Items = append(m.Items, item) } func (m Monkey) String() string { return fmt.Sprintf("Monkey %d; Inspected %d; Items: %v", m.Id, m.Inspected, m.Items) }