main.go (4903B)
1 package main 2 3 import ( 4 "bufio" 5 "fmt" 6 "log" 7 "os" 8 "sort" 9 "strconv" 10 "strings" 11 ) 12 13 type Monkey struct { 14 items []uint64 15 orig []uint64 16 operation func(val uint64) uint64 17 test uint64 // divisible by 18 ifTrue, ifFalse int // pass to monkeys 19 count uint64 // how many times monkey inspected items 20 } 21 22 func (m *Monkey) Reset() { 23 m.items = nil 24 m.items = append(m.items, m.orig...) 25 m.count = 0 26 } 27 func (m *Monkey) parseItems(in string) { 28 items := strings.Split(in, ",") 29 for _, i := range items { 30 item, err := strconv.Atoi(strings.TrimSpace(i)) 31 if err != nil { 32 log.Fatal(err) 33 } 34 m.items = append(m.items, uint64(item)) 35 m.orig = append(m.orig, uint64(item)) 36 } 37 } 38 func (m *Monkey) parseOperation(in string) { 39 var v, op string 40 _, err := fmt.Sscanf(in, "new = old %s %s", &op, &v) 41 if err != nil { 42 log.Fatal(err) 43 } 44 m.operation = func(val uint64) uint64 { 45 if op == "*" { 46 if v == "old" { 47 return val * val 48 } else { 49 num, err := strconv.Atoi(v) 50 if err != nil { 51 log.Fatal(err) 52 } 53 return val * uint64(num) 54 } 55 } else if op == "+" { 56 if v == "old" { 57 return val + val 58 } else { 59 num, err := strconv.Atoi(v) 60 if err != nil { 61 log.Fatal(err) 62 } 63 return val + uint64(num) 64 } 65 } else { 66 log.Fatal("invalid operation", op) 67 } 68 return val 69 } 70 } 71 func (m *Monkey) parseTest(in string) { 72 _, err := fmt.Sscanf(in, "divisible by %d", &m.test) 73 if err != nil { 74 log.Fatal(err) 75 } 76 } 77 func (m *Monkey) parseIfTrue(in string) { 78 _, err := fmt.Sscanf(in, "throw to monkey %d", &m.ifTrue) 79 if err != nil { 80 log.Fatal(err) 81 } 82 } 83 func (m *Monkey) parseIfFalse(in string) { 84 _, err := fmt.Sscanf(in, "throw to monkey %d", &m.ifFalse) 85 if err != nil { 86 log.Fatal(err) 87 } 88 } 89 func (m *Monkey) processItem1(i int) int { 90 if i >= len(m.items) { 91 log.Fatal("invalid item id") 92 } 93 m.items[i] = m.operation(m.items[i]) 94 m.items[i] /= 3 95 m.count++ 96 if m.items[i]%m.test == 0 { 97 return m.ifTrue 98 } else { 99 return m.ifFalse 100 } 101 } 102 func (m *Monkey) processItem2(i int) int { 103 if i >= len(m.items) { 104 log.Fatal("invalid item id") 105 } 106 m.items[i] = m.operation(m.items[i]) 107 m.count++ 108 if m.items[i]%m.test == 0 { 109 return m.ifTrue 110 } else { 111 return m.ifFalse 112 } 113 } 114 115 type Monkeys []*Monkey 116 117 func (m *Monkeys) Reset() { 118 for _, monkey := range *m { 119 monkey.Reset() 120 } 121 } 122 func (m Monkeys) Len() int { return len(m) } 123 func (m Monkeys) Swap(i, j int) { 124 m[i], m[j] = m[j], m[i] 125 } 126 func (m Monkeys) Less(i, j int) bool { 127 return m[i].count > m[j].count 128 } 129 func (monkeys Monkeys) GetCommon() uint64 { 130 var common uint64 = 1 131 for _, m := range monkeys { 132 common *= m.test 133 } 134 return common 135 } 136 func (monkeys Monkeys) DoTurn1() { 137 for _, m := range monkeys { 138 for n, _ := range m.items { 139 t := m.processItem1(n) 140 target := monkeys[t] 141 target.items = append(target.items, m.items[n]) 142 } 143 m.items = nil 144 } 145 } 146 func (monkeys Monkeys) DoTurn2(common uint64) { 147 for _, m := range monkeys { 148 for n, _ := range m.items { 149 m.items[n] %= common 150 t := m.processItem2(n) 151 target := monkeys[t] 152 target.items = append(target.items, m.items[n]) 153 } 154 m.items = nil 155 } 156 } 157 func (monkeys Monkeys) GetCounts() []uint64 { 158 var counts []uint64 159 for _, m := range monkeys { 160 counts = append(counts, m.count) 161 } 162 return counts 163 } 164 165 func main() { 166 if len(os.Args) > 1 { 167 day11(os.Args[1]) 168 } else if len(os.Args) == 1 { 169 fmt.Printf("usage: %s inputfile.txt\n", os.Args[0]) 170 } else { 171 fmt.Println("No input data") 172 } 173 } 174 175 func day11(input_file string) { 176 fmt.Printf("day 11 input filename: %s\n", input_file) 177 input, err := os.Open(input_file) 178 if err != nil { 179 log.Fatal(err) 180 } 181 defer input.Close() 182 scanner := bufio.NewScanner(input) 183 var monkeys Monkeys 184 current := -1 185 for scanner.Scan() { 186 in := scanner.Text() 187 if in == "" { 188 continue 189 } 190 field, val, _ := strings.Cut(in, ":") 191 field = strings.TrimSpace(field) 192 val = strings.TrimSpace(val) 193 switch field { 194 case "Starting items": 195 monkeys[current].parseItems(val) 196 case "Operation": 197 monkeys[current].parseOperation(val) 198 case "Test": 199 monkeys[current].parseTest(val) 200 case "If true": 201 monkeys[current].parseIfTrue(val) 202 case "If false": 203 monkeys[current].parseIfFalse(val) 204 default: 205 if n, err := fmt.Sscanf(in, "Monkey %d", ¤t); n != 1 || err != nil { 206 log.Fatal("Invalid input", in, err) 207 } else { 208 // new monkey 209 monkeys = append(monkeys, &Monkey{}) 210 } 211 } 212 } 213 if err = scanner.Err(); err != nil { 214 log.Fatal(err) 215 } 216 217 var monkeys2 Monkeys 218 monkeys2 = append(monkeys2, monkeys...) 219 for i := 0; i < 20; i++ { 220 monkeys.DoTurn1() 221 } 222 sort.Sort(monkeys) 223 fmt.Println("Monkey business 1:", monkeys[0].count*monkeys[1].count) 224 225 monkeys2.Reset() 226 common := monkeys2.GetCommon() 227 for i := 0; i < 10000; i++ { 228 monkeys2.DoTurn2(common) 229 } 230 sort.Sort(monkeys2) 231 fmt.Println("Monkey business 2:", monkeys2[0].count*monkeys2[1].count) 232 }