94 lines
2.5 KiB
Elixir
94 lines
2.5 KiB
Elixir
|
defmodule AOC.Day11 do
|
||
|
use AOC.Day, day: 11
|
||
|
alias AOC.Day11.{MonkeyRegistry, Monkey}
|
||
|
|
||
|
def parse_input(lines) do
|
||
|
monkeys =
|
||
|
lines
|
||
|
|> Enum.chunk_by(&(&1 == ""))
|
||
|
|> Enum.reject(&(&1 == [""]))
|
||
|
|> Enum.map(&parse_monkey/1)
|
||
|
|
||
|
supermod =
|
||
|
monkeys
|
||
|
|> Enum.map(& &1.modulo)
|
||
|
|> Enum.reduce(&Kernel.*/2)
|
||
|
|
||
|
{:ok, _} = Registry.start_link(keys: :unique, name: MonkeyRegistry)
|
||
|
|
||
|
Enum.each(monkeys, fn %{id: id} = monkey ->
|
||
|
GenServer.start_link(Monkey, Map.put(monkey, :supermod, supermod),
|
||
|
name: {:via, Registry, {MonkeyRegistry, id}}
|
||
|
)
|
||
|
end)
|
||
|
|
||
|
Enum.count(monkeys)
|
||
|
end
|
||
|
|
||
|
def parse_monkey([
|
||
|
"Monkey " <> monkey_id,
|
||
|
"Starting items: " <> items,
|
||
|
"Operation: " <> operation,
|
||
|
"Test: divisible by " <> modulo,
|
||
|
"If true: throw to monkey " <> true_monkey_id,
|
||
|
"If false: throw to monkey " <> false_monkey_id
|
||
|
]) do
|
||
|
%{
|
||
|
id: monkey_id |> String.slice(0..-2) |> String.to_integer(),
|
||
|
items: items |> String.split(", ") |> Enum.map(&String.to_integer/1),
|
||
|
operation: parse_operation(operation),
|
||
|
modulo: String.to_integer(modulo),
|
||
|
true_monkey_id: String.to_integer(true_monkey_id),
|
||
|
false_monkey_id: String.to_integer(false_monkey_id)
|
||
|
}
|
||
|
end
|
||
|
|
||
|
def parse_operation(operation) do
|
||
|
["new", "=", lhs, op, rhs] = String.split(operation)
|
||
|
|
||
|
fn old ->
|
||
|
lhs = if lhs == "old", do: old, else: String.to_integer(lhs)
|
||
|
rhs = if rhs == "old", do: old, else: String.to_integer(rhs)
|
||
|
|
||
|
op =
|
||
|
case op do
|
||
|
"*" -> &Kernel.*/2
|
||
|
"+" -> &Kernel.+/2
|
||
|
end
|
||
|
|
||
|
op.(lhs, rhs)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def part1(monkey_count) do
|
||
|
# monkey_business(monkey_count, 20, false)
|
||
|
end
|
||
|
|
||
|
def part2(monkey_count) do
|
||
|
monkey_business(monkey_count, 10000, true)
|
||
|
end
|
||
|
|
||
|
def monkey_business(monkey_count, rounds, ridiculous) do
|
||
|
execute_rounds(monkey_count, rounds, ridiculous)
|
||
|
|
||
|
Enum.map(0..(monkey_count - 1), fn id ->
|
||
|
[{pid, _}] = Registry.lookup(MonkeyRegistry, id)
|
||
|
Monkey.get_activeness(pid)
|
||
|
end)
|
||
|
|> Enum.sort(:desc)
|
||
|
|> Enum.take(2)
|
||
|
|> Enum.reduce(&Kernel.*/2)
|
||
|
end
|
||
|
|
||
|
def execute_rounds(monkey_count, rounds, ridiculous) do
|
||
|
Enum.each(0..(rounds - 1), fn _ -> execute_round(monkey_count, ridiculous) end)
|
||
|
end
|
||
|
|
||
|
def execute_round(monkey_count, ridiculous) do
|
||
|
Enum.each(0..(monkey_count - 1), fn id ->
|
||
|
[{pid, _}] = Registry.lookup(MonkeyRegistry, id)
|
||
|
Monkey.execute_turn(pid, ridiculous)
|
||
|
end)
|
||
|
end
|
||
|
end
|