You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.0 KiB
Elixir

defmodule Day24 do
def run do
{wires, gates} = parse_input("data.txt")
# part1
part1 = run_loop(wires, gates) |> wire_value("z") |> b_to_d()
dbg(part1)
# part2
x = wire_value(wires, "x") |> b_to_d()
y = wire_value(wires, "y") |> b_to_d()
target = (x + y) |> d_to_b()
dbg(target)
dbg(b_to_d(target))
end
defp b_to_d(bin) do
:erlang.binary_to_integer(Integer.to_string(bin), 2)
end
defp d_to_b(dec) do
Integer.to_string(dec, 2) |> String.to_integer()
end
defp wire_value(wires, char) do
wires
|> Enum.filter(fn {k, _} -> String.starts_with?(k, char) end)
|> Enum.sort()
|> Enum.reduce([], fn {_, v}, acc -> [v | acc] end)
|> Integer.undigits()
end
defp run_loop(wires, gates) do
new_wires = run(wires, gates)
if map_size(new_wires) == map_size(wires) do
wires
else
run_loop(new_wires, gates)
end
end
defp run(wires, gates) do
Enum.reduce(gates, wires, fn %{left: left, right: right, output: output, op: op}, acc ->
l = Map.get(wires, left, nil)
r = Map.get(wires, right, nil)
if !is_nil(l) and !is_nil(r) do
Map.put(acc, output, op.(l, r))
else
acc
end
end)
end
defp parse_input(file) do
[wires, gates] =
File.read!(file)
|> String.trim()
|> String.split("\n\n")
|> Enum.map(&String.split(&1, "\n"))
wires =
Enum.reduce(wires, %{}, fn el, map ->
[wire, value] = String.split(el, ": ")
Map.put(map, wire, String.to_integer(value))
end)
gates =
Enum.reduce(gates, [], fn el, map ->
[logic, output] = String.split(el, " -> ")
[left, op, right] = String.split(logic, " ")
op =
case op do
"AND" -> &Bitwise.band/2
"OR" -> &Bitwise.bor/2
"XOR" -> &Bitwise.bxor/2
end
[%{left: left, right: right, op: op, output: output} | map]
end)
{wires, gates}
end
end
Day24.run()