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