Day 20
Mix.install([
{:kino, "~> 0.11.3"}
])
Section
input = Kino.Input.textarea("Input")
defmodule Sol20 do
def make_module(module_str, dest_modules) do
{type, state} =
case module_str do
"%" <> _ ->
{:flipflop, :off}
"&" <> _ ->
{:conjunction, nil}
"broadcaster" ->
{:broadcaster, nil}
# _ -> {:simple, nil}
end
%{
type: type,
state: state,
src: [],
src_value: [],
dest: dest_modules
}
end
def read_rule(text) do
[module_str, dest_modules_str] =
text
|> String.replace(" ", "")
|> String.split("->")
dest_modules = String.split(dest_modules_str, ",")
module = Sol20.make_module(module_str, dest_modules)
module_name = Regex.replace(~r/[%&]/, module_str, "")
{module_name, module}
end
def update_src(module_name, modules) do
IO.inspect({"update_src", module_name, modules[module_name]})
Enum.reduce(modules[module_name][:dest], modules, fn dest, acc ->
dest_module = modules[dest]
case dest_module do
nil ->
acc
_ ->
update_dest_module = Map.put(dest_module, :src, [module_name | dest_module[:src]])
update_dest_module =
Map.put(update_dest_module, :src_value, [:low | update_dest_module[:src_value]])
Map.put(acc, dest, update_dest_module)
end
end)
end
def read(text) do
modules =
String.split(text, "\n")
|> Enum.map(&Sol20.read_rule(&1))
|> Enum.into(%{})
Map.keys(modules)
|> Enum.reduce(modules, fn module_name, acc -> Sol20.update_src(module_name, acc) end)
end
def simulate(machine, [], high_count, low_count) do
{machine, high_count, low_count}
end
def simulate(
machine,
[{value, module_name, from_module_name} | pulses_tail],
high_count,
low_count
) do
# IO.inspect({from_module_name, value, module_name, high_count, low_count})
new_high_count = high_count + if value == :high, do: 1, else: 0
new_low_count = low_count + if value == :low, do: 1, else: 0
module = machine[module_name]
{new_machine, new_pulses} =
case module[:type] do
nil ->
{machine, []}
:broadcaster ->
{machine, Enum.map(module[:dest], fn x -> {value, x, module_name} end)}
:flipflop ->
case {module[:state], value} do
{_, :high} ->
{machine, []}
{:on, :low} ->
new_machine = Map.put(machine, module_name, Map.put(module, :state, :off))
new_pulses = Enum.map(module[:dest], fn x -> {:low, x, module_name} end)
{new_machine, new_pulses}
{:off, :low} ->
new_machine = Map.put(machine, module_name, Map.put(module, :state, :on))
new_pulses = Enum.map(module[:dest], fn x -> {:high, x, module_name} end)
{new_machine, new_pulses}
end
:conjunction ->
idx = Enum.find_index(module[:src], &(&1 == from_module_name))
new_module =
Map.put(module, :src_value, List.replace_at(module[:src_value], idx, value))
out_signal =
case Enum.all?(new_module[:src_value], fn x -> x == :high end) do
true -> :low
false -> :high
end
new_machine = Map.put(machine, module_name, new_module)
new_pulses = Enum.map(module[:dest], fn x -> {out_signal, x, module_name} end)
{new_machine, new_pulses}
end
Sol20.simulate(new_machine, pulses_tail ++ new_pulses, new_high_count, new_low_count)
end
end
input_data = Kino.Input.read(input)
machine = Sol20.read(input_data)
pulses = [{:low, "broadcaster", "button"}]
# Sol20.simulate(machine, pulses, 0, 0)
{_, high_count, low_count} =
Enum.reduce(1..1000, {machine, 0, 0}, fn _, {mac, high_count, low_count} ->
Sol20.simulate(mac, pulses, high_count, low_count)
end)
high_count * low_count
m = %{a: [1, 2, 3]}
update_in(m, [:a], &(&1 ++ [4]))