Skip to content

Instantly share code, notes, and snippets.

@al2o3cr
Created December 21, 2022 21:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save al2o3cr/3cdfe9259f5bf7937579d2959d4019a4 to your computer and use it in GitHub Desktop.
Save al2o3cr/3cdfe9259f5bf7937579d2959d4019a4 to your computer and use it in GitHub Desktop.
2022 AOC Day 11
defmodule Monkey do
defstruct [:id, :touched, :held, :operation, :test, :true_target, :false_target]
def examine_item(level, monkey) do
new_level = monkey.operation.(level)
relieved_level = div(new_level, 3)
if monkey.test.(relieved_level) do
{:throw, monkey.true_target, relieved_level}
else
{:throw, monkey.false_target, relieved_level}
end
end
def take_turn(monkey) do
throws = Enum.map(monkey.held, &examine_item(&1, monkey))
{%{monkey | held: [], touched: (monkey.touched || 0) + length(throws)}, throws}
end
def catch_object(monkey, level) do
%{monkey | held: monkey.held ++ [level]}
end
end
defmodule MonkeyGame do
def step(monkeys, turn_order) do
turn_order
|> Enum.reduce(monkeys, fn active_id, monkeys ->
active_monkey = Map.fetch!(monkeys, active_id)
{updated_monkey, throws} = Monkey.take_turn(active_monkey)
monkeys = Map.replace!(monkeys, active_id, updated_monkey)
Enum.reduce(throws, monkeys, fn throw, monkeys ->
exec(throw, monkeys)
end)
end)
end
defp exec({:throw, target, level}, monkeys) do
Map.update!(monkeys, target, &Monkey.catch_object(&1, level))
end
def touched(monkeys) do
Map.new(monkeys, fn {id, monkey} -> {id, monkey.touched} end)
end
def monkey_business(totals) do
totals
|> Map.values()
|> Enum.sort(:desc)
|> Enum.take(2)
|> then(fn [a, b] -> a * b end)
end
end
defmodule ExampleMonkeys do
def setup do
[
%Monkey{
id: 0,
held: [79, 98],
operation: &(&1 * 19),
test: &(rem(&1, 23) == 0),
true_target: 2,
false_target: 3
},
%Monkey{
id: 1,
held: [54, 65, 75, 74],
operation: &(&1 + 6),
test: &(rem(&1, 19) == 0),
true_target: 2,
false_target: 0
},
%Monkey{
id: 2,
held: [79, 60, 97],
operation: &(&1 * &1),
test: &(rem(&1, 13) == 0),
true_target: 1,
false_target: 3
},
%Monkey{
id: 3,
held: [74],
operation: &(&1 + 3),
test: &(rem(&1, 17) == 0),
true_target: 0,
false_target: 1
}
]
|> Map.new(&{&1.id, %{&1 | touched: 0}})
end
def turn_order, do: [0, 1, 2, 3]
end
defmodule InputMonkeys do
def setup do
[
%Monkey{
id: 0,
held: [83, 88, 96, 79, 86, 88, 70],
operation: &(&1 * 5),
test: &(rem(&1, 11) == 0),
true_target: 2,
false_target: 3
},
%Monkey{
id: 1,
held: [59, 63, 98, 85, 68, 72],
operation: &(&1 * 11),
test: &(rem(&1, 5) == 0),
true_target: 4,
false_target: 0
},
%Monkey{
id: 2,
held: [90, 79, 97, 52, 90, 94, 71, 70],
operation: &(&1 + 2),
test: &(rem(&1, 19) == 0),
true_target: 5,
false_target: 6
},
%Monkey{
id: 3,
held: [97, 55, 62],
operation: &(&1 + 5),
test: &(rem(&1, 13) == 0),
true_target: 2,
false_target: 6
},
%Monkey{
id: 4,
held: [74, 54, 94, 76],
operation: &(&1 * &1),
test: &(rem(&1, 7) == 0),
true_target: 0,
false_target: 3
},
%Monkey{
id: 5,
held: [58],
operation: &(&1 + 4),
test: &(rem(&1, 17) == 0),
true_target: 7,
false_target: 1
},
%Monkey{
id: 6,
held: [66, 63],
operation: &(&1 + 6),
test: &(rem(&1, 2) == 0),
true_target: 7,
false_target: 5
},
%Monkey{
id: 7,
held: [56, 56, 90, 96, 68],
operation: &(&1 + 7),
test: &(rem(&1, 3) == 0),
true_target: 4,
false_target: 1
}
]
|> Map.new(&{&1.id, %{&1 | touched: 0}})
end
def turn_order, do: [0, 1, 2, 3, 4, 5, 6, 7]
end
# monkeys = ExampleMonkeys.setup()
# turns = ExampleMonkeys.turn_order()
monkeys = InputMonkeys.setup()
turns = InputMonkeys.turn_order()
monkeys
|> Stream.iterate(&MonkeyGame.step(&1, turns))
|> Stream.map(&MonkeyGame.touched/1)
|> Stream.map(&MonkeyGame.monkey_business/1)
|> Stream.drop(20)
|> Enum.take(1)
|> hd()
|> IO.inspect()
defmodule Monkey do
defstruct [:id, :touched, :held, :operation, :test, :true_target, :false_target]
def examine_item(level, monkey) do
new_level = monkey.operation.(level)
relieved_level = new_level
if monkey.test.(relieved_level) do
{:throw, monkey.true_target, relieved_level}
else
{:throw, monkey.false_target, relieved_level}
end
end
def take_turn(monkey) do
throws = Enum.map(monkey.held, &examine_item(&1, monkey))
{%{monkey | held: [], touched: (monkey.touched || 0) + length(throws)}, throws}
end
def catch_object(monkey, level) do
%{monkey | held: monkey.held ++ [level]}
end
end
defmodule MonkeyGame do
def step(monkeys, turn_order) do
turn_order
|> Enum.reduce(monkeys, fn active_id, monkeys ->
active_monkey = Map.fetch!(monkeys, active_id)
{updated_monkey, throws} = Monkey.take_turn(active_monkey)
monkeys = Map.replace!(monkeys, active_id, updated_monkey)
Enum.reduce(throws, monkeys, fn throw, monkeys ->
exec(throw, monkeys)
end)
end)
end
defp exec({:throw, target, level}, monkeys) do
Map.update!(monkeys, target, &Monkey.catch_object(&1, level))
end
def touched(monkeys) do
Map.new(monkeys, fn {id, monkey} -> {id, monkey.touched} end)
end
def monkey_business(totals) do
totals
|> Map.values()
|> Enum.sort(:desc)
|> Enum.take(2)
|> then(fn [a, b] -> a * b end)
end
end
defmodule Residue do
def to_residue(n, moduli) do
Map.new(moduli, fn m -> {m, rem(n, m)} end)
end
def add_n(r, n) do
Map.new(r, fn {m, r_m} -> {m, rem(r_m + n, m)} end)
end
def mul_n(r, n) do
Map.new(r, fn {m, r_m} -> {m, rem(r_m * n, m)} end)
end
def mul(r1, r2) do
Map.new(r1, fn {m, r1_m} -> {m, rem(r1_m * r2[m], m)} end)
end
def multiple(r, m) do
r[m] == 0
end
end
defmodule ExampleMonkeys do
import Residue
@moduli [23, 19, 13, 17]
defp r(ns), do: Enum.map(ns, &to_residue(&1, @moduli))
def setup do
[
%Monkey{
id: 0,
held: r([79, 98]),
operation: &mul_n(&1, 19),
test: &multiple(&1, 23),
true_target: 2,
false_target: 3
},
%Monkey{
id: 1,
held: r([54, 65, 75, 74]),
operation: &add_n(&1, 6),
test: &multiple(&1, 19),
true_target: 2,
false_target: 0
},
%Monkey{
id: 2,
held: r([79, 60, 97]),
operation: &mul(&1, &1),
test: &multiple(&1, 13),
true_target: 1,
false_target: 3
},
%Monkey{
id: 3,
held: r([74]),
operation: &add_n(&1, 3),
test: &multiple(&1, 17),
true_target: 0,
false_target: 1
}
]
|> Map.new(&{&1.id, %{&1 | touched: 0}})
end
def turn_order, do: [0, 1, 2, 3]
end
defmodule InputMonkeys do
import Residue
@moduli [11, 5, 19, 13, 7, 17, 2, 3]
defp r(ns), do: Enum.map(ns, &to_residue(&1, @moduli))
def setup do
[
%Monkey{
id: 0,
held: r([83, 88, 96, 79, 86, 88, 70]),
operation: &mul_n(&1, 5),
test: &multiple(&1, 11),
true_target: 2,
false_target: 3
},
%Monkey{
id: 1,
held: r([59, 63, 98, 85, 68, 72]),
operation: &mul_n(&1, 11),
test: &multiple(&1, 5),
true_target: 4,
false_target: 0
},
%Monkey{
id: 2,
held: r([90, 79, 97, 52, 90, 94, 71, 70]),
operation: &add_n(&1, 2),
test: &multiple(&1, 19),
true_target: 5,
false_target: 6
},
%Monkey{
id: 3,
held: r([97, 55, 62]),
operation: &add_n(&1, 5),
test: &multiple(&1, 13),
true_target: 2,
false_target: 6
},
%Monkey{
id: 4,
held: r([74, 54, 94, 76]),
operation: &mul(&1, &1),
test: &multiple(&1, 7),
true_target: 0,
false_target: 3
},
%Monkey{
id: 5,
held: r([58]),
operation: &add_n(&1, 4),
test: &multiple(&1, 17),
true_target: 7,
false_target: 1
},
%Monkey{
id: 6,
held: r([66, 63]),
operation: &add_n(&1, 6),
test: &multiple(&1, 2),
true_target: 7,
false_target: 5
},
%Monkey{
id: 7,
held: r([56, 56, 90, 96, 68]),
operation: &add_n(&1, 7),
test: &multiple(&1, 3),
true_target: 4,
false_target: 1
}
]
|> Map.new(&{&1.id, %{&1 | touched: 0}})
end
def turn_order, do: [0, 1, 2, 3, 4, 5, 6, 7]
end
# monkeys = ExampleMonkeys.setup()
# turns = ExampleMonkeys.turn_order()
monkeys = InputMonkeys.setup()
turns = InputMonkeys.turn_order()
monkeys
|> Stream.iterate(&MonkeyGame.step(&1, turns))
|> Stream.map(&MonkeyGame.touched/1)
|> Stream.map(&MonkeyGame.monkey_business/1)
|> Stream.drop(10_000)
|> Enum.take(1)
|> hd()
|> IO.inspect()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment