aoc/22/lib/days/day11.ex

94 lines
2.5 KiB
Elixir
Raw Permalink Normal View History

2023-04-17 18:18:20 +00:00
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