-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathday11.go
More file actions
202 lines (174 loc) · 6.08 KB
/
day11.go
File metadata and controls
202 lines (174 loc) · 6.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package main
import (
"AdventOfCode-go/advent2022/utils"
"fmt"
"sort"
"strconv"
"strings"
)
type monkeyObj struct {
startingItems []int64
operationSize int64
operationType byte
testDivisor int64
trueMonkey int
falseMonkey int
inspectionCount int
}
func (m monkeyObj) printMonkey(monkey int) {
fmt.Printf("Monkey %d:\n", monkey)
fmt.Printf(" Starting items: ")
for key := range m.startingItems {
fmt.Printf("%d,", m.startingItems[key])
}
fmt.Printf("\n Operation: new = old ")
switch m.operationType {
case '*':
// Note if operationSize is 0 then the operation is old * old
if m.operationSize == 0 {
fmt.Printf("* old\n")
} else {
fmt.Printf("* %d\n", m.operationSize)
}
case '/':
fmt.Printf("/ %d\n", m.operationSize)
case '+':
fmt.Printf("+ %d\n", m.operationSize)
case '-':
fmt.Printf("- %d\n", m.operationSize)
}
fmt.Printf(" Test: divisible by %d\n", m.testDivisor)
fmt.Printf(" If true: throw to monkey %d\n", m.trueMonkey)
fmt.Printf(" If false: throw to monkey %d\n", m.falseMonkey)
fmt.Printf(" Inspection Count: %d\n", m.inspectionCount)
}
func buildArrayOfMonkeys(puzzleInput []string) []monkeyObj {
// Get the number of monkeys so we can build an array of them
var monkeyCount int
for _, i := range puzzleInput {
if len(i) > 5 {
if i[0:6] == "Monkey" {
monkeyCount++
}
}
}
//fmt.Println("Monkeys:", monkeyCount)
monkeyArray := make([]monkeyObj, monkeyCount)
var currentMonkey int
for _, line := range puzzleInput {
var startingItems string
fmt.Sscanf(line, "Monkey %d:\n", ¤tMonkey)
if strings.Contains(line, " Starting items: ") {
startingItems = strings.TrimPrefix(line, " Starting items: ")
startingItemArray := strings.Split(startingItems, ",")
monkeyArray[currentMonkey].startingItems = make([]int64, len(startingItemArray))
for key, i := range startingItemArray {
tmpStartItem, _ := strconv.Atoi(strings.TrimSpace(i))
monkeyArray[currentMonkey].startingItems[key] = int64(tmpStartItem)
}
//fmt.Printf("Monkey %d Starting Items %s\n", currentMonkey, startingItems)
//fmt.Println(startingItemArray)
}
//fmt.Sscanf(line, " Starting items: %100s\n", &startingItems) // How to do multiples here?
fmt.Sscanf(line, " Operation: new = old %c %d\n", &monkeyArray[currentMonkey].operationType, &monkeyArray[currentMonkey].operationSize)
fmt.Sscanf(line, " Test: divisible by %d\n", &monkeyArray[currentMonkey].testDivisor)
fmt.Sscanf(line, " If true: throw to monkey %d\n", &monkeyArray[currentMonkey].trueMonkey)
fmt.Sscanf(line, " If false: throw to monkey %d\n", &monkeyArray[currentMonkey].falseMonkey)
}
return monkeyArray
}
func calcWorryLevel(item int64, operationType byte, operationSize int64) int64 {
var worryLevel int64
switch operationType {
case '*':
// Note if operationSize is 0 then the operation is old * old
if operationSize == 0 {
worryLevel = item * item
} else {
worryLevel = item * operationSize
}
case '/':
worryLevel = item / operationSize
case '+':
worryLevel = item + operationSize
case '-':
worryLevel = item - operationSize
}
return worryLevel
}
func calcMonkeyBusiness(filename string, part byte, debug bool) int {
var primeMod int64 = 1
puzzleInput, _ := utils.ReadFile(filename)
monkeyArray := buildArrayOfMonkeys(puzzleInput)
/*
for key, monkey := range monkeyArray {
monkey.printMonkey(key)
}
*/
var rounds int
if part == 'a' {
rounds = 20
} else {
rounds = 10000
// Loop through the monkeys and extract the divisors. We'll use this later to keep the worry down via mod
for _, monkey := range monkeyArray {
primeMod *= monkey.testDivisor
}
}
// TODO: Mod the worrylevel by the product of the test divisors
// TODO: understand why this works. All the test divisors are prime numbers
// - count the total number of times each monkey inspects an item over 20 rounds
for i := 0; i < rounds; i++ {
// On a single Monkey's turn:
for monkeyNumber, currMonkey := range monkeyArray {
// - inspect each item in turn in the order listed:
for itemKey, item := range currMonkey.startingItems {
if item != 0 {
// - monkey INSPECTS an item in the list
// - worry level is item <operationType> <operationSize> e.g. 79 * 6
worryLevel := calcWorryLevel(item, currMonkey.operationType, currMonkey.operationSize)
// - worry level divides by 3 and rounded DOWN to nearest integer
if part == 'a' {
worryLevel = worryLevel / 3
} else {
worryLevel = worryLevel % primeMod
}
// - TEST the item based on the <testDivisor>
// - throws to the indicated Monkey which adds the item to the END of their list
if worryLevel%currMonkey.testDivisor == 0 {
// - if TRUE, send the current worrylevel for the item to trueMonkey
monkeyArray[currMonkey.trueMonkey].startingItems = append(monkeyArray[currMonkey.trueMonkey].startingItems, worryLevel)
monkeyArray[monkeyNumber].startingItems = monkeyArray[monkeyNumber].startingItems[1:len(monkeyArray[monkeyNumber].startingItems)]
} else {
// - if FALSE, send the current worrylevel for the item to falseMonkey
monkeyArray[currMonkey.falseMonkey].startingItems = append(monkeyArray[currMonkey.falseMonkey].startingItems, worryLevel)
}
currMonkey.startingItems[itemKey] = 0
monkeyArray[monkeyNumber].inspectionCount++
}
}
// - if a monkey starts its turn with no items it's turn ends immediately
}
}
resultArray := make([]int, len(monkeyArray))
for key, monkey := range monkeyArray {
if debug {
monkey.printMonkey(key)
}
resultArray[key] = monkey.inspectionCount
}
sort.Sort(sort.Reverse(sort.IntSlice(resultArray)))
return resultArray[0] * resultArray[1]
}
// Main routine
func main() {
filenamePtr, execPart, debug := utils.CatchUserInput()
switch execPart {
case 'a':
fmt.Printf("Monkey Business: %d\n", calcMonkeyBusiness(filenamePtr, execPart, debug))
case 'b':
fmt.Printf("Monkey Business: %d\n", calcMonkeyBusiness(filenamePtr, execPart, debug))
case 'z':
fmt.Println("Bad part choice. Available choices are 'a' and 'b'")
}
}