189 lines
3.6 KiB
Go
189 lines
3.6 KiB
Go
|
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)
|
||
|
}
|