-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathday_11.lua
More file actions
153 lines (135 loc) · 4 KB
/
Copy pathday_11.lua
File metadata and controls
153 lines (135 loc) · 4 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
local eio = require "libs.eio"
local profile = require "libs.profile"
local estring = require "libs.estring"
local Deque = require "libs.Deque"
local sequence = require "libs.sequence"
local input = eio.lines
local printf = eio.printf
local split = estring.split
local makeDeque = Deque.new
local sub = string.sub
local floor = math.floor
local tonumber = tonumber
local map = sequence.map
local sort = table.sort
local product = sequence.product
local maxinteger = 2^53
profile.start()
local USE_MODULO = true
local DONT_USE_MODULO = false
local function makeMonkey (items, operation, test, onTrue, onFalse, n)
return {
items = items,
operation = operation,
test = test,
onTrue = onTrue,
onFalse = onFalse,
n = n,
activity = 0
}
end
local ops = {
["+"] = function (b)
return function (a, m)
return (a + b) % m
end
end,
["*"] = function (b)
return function (a, m)
local b = b or a
return (a * b) % m
end
end
}
local function divisibleBy (n)
return function (x)
return x % n == 0
end
end
local function throwItem (monkeys, to)
return function (item)
monkeys[to].items:pushLast(item)
end
end
local function parseInput (useModulo)
local monkeys = {}
local ns = {}
local monkeyId, items, operation, test, onTrue, onFalse, n
for lineIdx = 1, #input() do
local line = input()[lineIdx]
local words = split(line)
if words[1] == "Monkey" then
monkeyId = tonumber(sub(words[2], 1, -2))
elseif words[1] == "Starting" then
items = makeDeque()
for i = 3, #words do
local item = words[i]
if sub(item, -1, -1) == "," then
item = sub(item, 1, -2)
end
items:pushLast(tonumber(item))
end
elseif words[1] == "Operation:" then
operation = ops[words[5]](tonumber(words[6]))
elseif words[1] == "Test:" then
n = tonumber(words[4])
test = divisibleBy(n)
ns[#ns + 1] = n
elseif words[1] == "If" then
if words[2] == "true:" then
onTrue = throwItem(monkeys, tonumber(words[6]) + 1)
else
onFalse = throwItem(monkeys, tonumber(words[6]) + 1)
end
else
monkeys[monkeyId + 1] = makeMonkey(items, operation, test, onTrue, onFalse, n)
end
end
monkeys[monkeyId + 1] = makeMonkey(items, operation, test, onTrue, onFalse, n)
n = useModulo and product(ns) or maxinteger
return monkeys, n
end
local function simulateRound (monkeys, n, useModulo)
for monkeyId = 1, #monkeys do
local monkey = monkeys[monkeyId]
local items = monkey.items
local operation = monkey.operation
local test = monkey.test
local onTrue = monkey.onTrue
local onFalse = monkey.onFalse
while not items:isEmpty() do
monkey.activity = monkey.activity + 1
local item = items:popFirst()
item = operation(item, n)
if not useModulo then
item = floor(item / 3)
end
if test(item) then
onTrue(item)
else
onFalse(item)
end
end
end
end
local function activityFromMonkey (monkey)
return monkey.activity
end
local function monkeyBusiness (monkeys)
local activities = map(activityFromMonkey, monkeys)
sort(activities)
return activities[#activities] * activities[#activities - 1]
end
local monkeys, n = parseInput(DONT_USE_MODULO)
for _ = 1, 20 do
simulateRound(monkeys, n, DONT_USE_MODULO)
end
local answer1 = monkeyBusiness(monkeys)
printf("Part 1: %i\n", answer1)
monkeys, n = parseInput(USE_MODULO)
for _ = 1, 10000 do
simulateRound(monkeys, n, USE_MODULO)
end
local answer2 = monkeyBusiness(monkeys)
printf("Part 2: %i\n", answer2)
return answer1, answer2, profile.finish()