this repo has no description
1<!-- livebook:{"persist_outputs":true} -->
2
3# Day 11
4
5```elixir
6Mix.install([
7 {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"}
8])
9```
10
11<!-- livebook:{"output":true} -->
12
13```
14:ok
15```
16
17## Section
18
19<!-- livebook:{"attrs":{"day":"11","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
20
21```elixir
22{:ok, puzzle_input} =
23 KinoAOC.download_puzzle("2022", "11", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
24```
25
26<!-- livebook:{"output":true} -->
27
28```
29{:ok,
30 "Monkey 0:\n Starting items: 93, 98\n Operation: new = old * 17\n Test: divisible by 19\n If true: throw to monkey 5\n If false: throw to monkey 3\n\nMonkey 1:\n Starting items: 95, 72, 98, 82, 86\n Operation: new = old + 5\n Test: divisible by 13\n If true: throw to monkey 7\n If false: throw to monkey 6\n\nMonkey 2:\n Starting items: 85, 62, 82, 86, 70, 65, 83, 76\n Operation: new = old + 8\n Test: divisible by 5\n If true: throw to monkey 3\n If false: throw to monkey 0\n\nMonkey 3:\n Starting items: 86, 70, 71, 56\n Operation: new = old + 1\n Test: divisible by 7\n If true: throw to monkey 4\n If false: throw to monkey 5\n\nMonkey 4:\n Starting items: 77, 71, 86, 52, 81, 67\n Operation: new = old + 4\n Test: divisible by 17\n If true: throw to monkey 1\n If false: throw to monkey 6\n\nMonkey 5:\n Starting items: 89, 87, 60, 78, 54, 77, 98\n Operation: new = old * 7\n Test: divisible by 2\n If true: throw to monkey 1\n If false: throw to monkey 4\n\nMonkey 6:\n Starting items: 69, 65, 63\n Operation: new = old + 6\n Test: divisible by 3\n If true: throw to monkey 7\n If false: throw to monkey 2\n\nMonkey 7:\n Starting items: 89\n Operation: new = old * old\n Test: divisible by 11\n If true: throw to monkey 0\n If false: throw to monkey 2\n"}
31```
32
33```elixir
34defmodule Monkey do
35 defstruct items: [],
36 operation: &Function.identity/1,
37 test: nil,
38 true: nil,
39 false: nil,
40 passes: 0
41
42 def parse(input) do
43 [
44 _,
45 "Starting items: " <> items,
46 "Operation: new = old " <> operation,
47 "Test: divisible by " <> test,
48 "If true: throw to monkey " <> if_true,
49 "If false: throw to monkey " <> if_false
50 ] =
51 input
52 |> String.split("\n", trim: true)
53 |> Enum.map(&String.trim/1)
54
55 %__MODULE__{
56 items: parse_items(items),
57 operation: parse_operation(operation),
58 test: String.to_integer(test),
59 true: String.to_integer(if_true),
60 false: String.to_integer(if_false)
61 }
62 end
63
64 def run(%__MODULE__{} = monkey, calming, lcm \\ 1) do
65 {true_val, false_val} =
66 monkey.items
67 |> Enum.map(fn item ->
68 item
69 |> then(monkey.operation)
70 |> div(calming)
71 |> rem(lcm)
72 end)
73 |> Enum.split_with(fn item ->
74 rem(item, monkey.test) == 0
75 end)
76
77 {struct(monkey, passes: monkey.passes + length(monkey.items), items: []),
78 {monkey.true, true_val}, {monkey.false, false_val}}
79 end
80
81 def add_items(%__MODULE__{} = monkey, new_items) do
82 struct(monkey, items: monkey.items ++ new_items)
83 end
84
85 defp parse_items(items) do
86 items
87 |> String.split(", ")
88 |> Enum.map(&String.to_integer/1)
89 end
90
91 defp parse_operation("* old"),
92 do: fn old -> old * old end
93
94 defp parse_operation("* " <> num) do
95 num = String.to_integer(num)
96
97 fn old -> old * num end
98 end
99
100 defp parse_operation("+ " <> num) do
101 num = String.to_integer(num)
102
103 fn old -> old + num end
104 end
105end
106```
107
108<!-- livebook:{"output":true} -->
109
110```
111{:module, Monkey, <<70, 79, 82, 49, 0, 0, 24, ...>>, {:parse_operation, 1}}
112```
113
114```elixir
115monkeys =
116 puzzle_input
117 |> String.split("\n\n")
118 |> Enum.map(&Monkey.parse/1)
119```
120
121<!-- livebook:{"output":true} -->
122
123```
124[
125 %Monkey{
126 items: ']b',
127 operation: #Function<3.112681941/1 in Monkey.parse_operation/1>,
128 test: 19,
129 true: 5,
130 false: 3,
131 passes: 0
132 },
133 %Monkey{
134 items: '_HbRV',
135 operation: #Function<1.112681941/1 in Monkey.parse_operation/1>,
136 test: 13,
137 true: 7,
138 false: 6,
139 passes: 0
140 },
141 %Monkey{
142 items: 'U>RVFASL',
143 operation: #Function<1.112681941/1 in Monkey.parse_operation/1>,
144 test: 5,
145 true: 3,
146 false: 0,
147 passes: 0
148 },
149 %Monkey{
150 items: 'VFG8',
151 operation: #Function<1.112681941/1 in Monkey.parse_operation/1>,
152 test: 7,
153 true: 4,
154 false: 5,
155 passes: 0
156 },
157 %Monkey{
158 items: 'MGV4QC',
159 operation: #Function<1.112681941/1 in Monkey.parse_operation/1>,
160 test: 17,
161 true: 1,
162 false: 6,
163 passes: 0
164 },
165 %Monkey{
166 items: 'YW<N6Mb',
167 operation: #Function<3.112681941/1 in Monkey.parse_operation/1>,
168 test: 2,
169 true: 1,
170 false: 4,
171 passes: 0
172 },
173 %Monkey{
174 items: 'EA?',
175 operation: #Function<1.112681941/1 in Monkey.parse_operation/1>,
176 test: 3,
177 true: 7,
178 false: 2,
179 passes: 0
180 },
181 %Monkey{
182 items: 'Y',
183 operation: #Function<2.112681941/1 in Monkey.parse_operation/1>,
184 test: 11,
185 true: 0,
186 false: 2,
187 passes: 0
188 }
189]
190```
191
192```elixir
193defmodule MonkeyBusiness do
194 import Kernel, except: [round: 1]
195
196 defstruct monkeys: [], lcm: nil
197
198 def new(monkeys) do
199 lcm = Enum.reduce(monkeys, 1, &lcm(&1.test, &2))
200
201 %__MODULE__{
202 monkeys: monkeys,
203 lcm: lcm
204 }
205 end
206
207 def run(%__MODULE__{} = mb, rounds, calming) do
208 1..rounds
209 |> Enum.reduce(mb, fn _, mb ->
210 # IO.inspect(r, label: :round)
211 round(mb, calming)
212 end)
213 |> Map.get(:monkeys)
214 |> Enum.map(& &1.passes)
215 |> Enum.sort(:desc)
216 |> Enum.take(2)
217 |> Enum.product()
218 end
219
220 defp round(%__MODULE__{} = mb, calming) do
221 0..(length(mb.monkeys) - 1)
222 |> Enum.reduce(mb, fn idx, mb ->
223 {monkey, {a, a_val}, {b, b_val}} =
224 mb.monkeys
225 |> Enum.at(idx)
226 |> Monkey.run(calming, mb.lcm)
227
228 mb
229 |> put_in([Access.key(:monkeys), Access.at(idx)], monkey)
230 |> update_in([Access.key(:monkeys), Access.at(a)], &Monkey.add_items(&1, a_val))
231 |> update_in([Access.key(:monkeys), Access.at(b)], &Monkey.add_items(&1, b_val))
232 end)
233 end
234
235 defp lcm(a, b), do: div(a * b, Integer.gcd(a, b))
236end
237```
238
239<!-- livebook:{"output":true} -->
240
241```
242{:module, MonkeyBusiness, <<70, 79, 82, 49, 0, 0, 20, ...>>, {:lcm, 2}}
243```
244
245## Task 1
246
247```elixir
248monkeys
249|> MonkeyBusiness.new()
250|> MonkeyBusiness.run(20, 3)
251```
252
253<!-- livebook:{"output":true} -->
254
255```
25678678
257```
258
259## Task 2
260
261```elixir
262monkeys
263|> MonkeyBusiness.new()
264|> MonkeyBusiness.run(10000, 1)
265```
266
267<!-- livebook:{"output":true} -->
268
269```
27015333249714
271```