Day 21: – AoC 22
# there is a comma in citizenstatezip as well
stream =
"./input/21.txt"
|> Path.expand(__DIR__)
|> File.stream!()
|> Stream.map(&String.trim(&1))
test_stream = "root: pppw + sjmn
dbpl: 5
cczh: sllz + lgvd
zczc: 2
ptdq: humn - dvpt
dvpt: 3
lfqf: 4
humn: 5
ljgn: 2
sjmn: drzm * dbpl
sllz: 4
pppw: cczh / lfqf
lgvd: ljgn * ptdq
drzm: hmdt - zczc
hmdt: 32" |> String.trim() |> String.split("\n")
Part One
%{nums: nums, terms: terms} =
Enum.reduce(stream, %{terms: [], nums: %{}}, fn cmd, %{terms: terms, nums: nums} ->
[var, body] = String.split(cmd, ": ")
if String.contains?(body, ["+", "-", "/", "*"]) do
[lhs, op, rhs] = String.split(body, " ")
terms = [%{var: var, lhs: lhs, op: op, rhs: rhs} | terms]
%{terms: terms, nums: nums}
else
nums = Map.put_new(nums, var, String.to_integer(body))
%{terms: terms, nums: nums}
end
end)
iterate = fn terms, nums ->
terms
|> Stream.map(fn term ->
term
|> Map.put(
:rhs,
if(Enum.member?(Map.keys(nums), term.rhs), do: Map.get(nums, term.rhs), else: term.rhs)
)
|> Map.put(
:lhs,
if(Enum.member?(Map.keys(nums), term.lhs), do: Map.get(nums, term.lhs), else: term.lhs)
)
end)
|> Enum.reduce(%{nums: nums, terms: []}, fn term, %{nums: nums, terms: terms} ->
lhs = Map.get(term, :lhs)
rhs = Map.get(term, :rhs)
# after / it can be a float -> number
if is_number(lhs) && is_number(rhs) do
new_value =
case term.op do
"+" -> lhs + rhs
"-" -> lhs - rhs
# prevents floats
"/" -> round(lhs / rhs)
"*" -> lhs * rhs
end
nums = Map.put(nums, term.var, new_value)
%{nums: nums, terms: terms}
else
terms = [term | terms]
%{nums: nums, terms: terms}
end
end)
end
Stream.iterate(1, &(&1 + 1))
|> Enum.reduce_while(%{nums: nums, terms: terms}, fn _x, acc ->
if Enum.count(acc.terms) <= 0 do
{:halt, acc}
else
{:cont, iterate.(acc.terms, acc.nums)}
end
end)
|> Map.get(:nums)
|> Map.get("root")
Part Two
%{nums: nums, terms: terms} =
Enum.reduce(stream, %{terms: [], nums: %{}}, fn cmd, %{terms: terms, nums: nums} ->
[var, body] = String.split(cmd, ": ")
if String.contains?(body, ["+", "-", "/", "*"]) do
[lhs, op, rhs] = String.split(body, " ")
op = if var == "root", do: "=", else: op
terms = [%{var: var, lhs: lhs, op: op, rhs: rhs} | terms]
%{terms: terms, nums: nums}
else
nums = Map.put_new(nums, var, String.to_integer(body))
%{terms: terms, nums: nums}
end
end)
iterate2 = fn terms, nums ->
terms
|> Stream.map(fn term ->
term
|> Map.put(
:rhs,
if(Enum.member?(Map.keys(nums), term.rhs), do: Map.get(nums, term.rhs), else: term.rhs)
)
|> Map.put(
:lhs,
if(Enum.member?(Map.keys(nums), term.lhs), do: Map.get(nums, term.lhs), else: term.lhs)
)
end)
|> Enum.reduce(%{nums: nums, terms: []}, fn term, %{nums: nums, terms: terms} ->
lhs = Map.get(term, :lhs)
rhs = Map.get(term, :rhs)
# after / it can be a float -> number
if is_number(lhs) && is_number(rhs) do
new_value =
case term.op do
"+" -> lhs + rhs
"-" -> lhs - rhs
# prevents floats
"/" -> round(lhs / rhs)
"*" -> lhs * rhs
"=" -> lhs == rhs
end
nums = Map.put(nums, term.var, new_value)
%{nums: nums, terms: terms}
else
terms = [term | terms]
%{nums: nums, terms: terms}
end
end)
end
nums = Map.put(nums, "humn", 0)
Stream.iterate(2240, &(&1 + 1))
|> Enum.reduce_while(nil, fn x, _acc ->
new_nums = Map.put(nums, "humn", Map.get(nums, "humn") + x)
# new_acc = Map.put(acc, :nums, new_nums)
result =
Stream.iterate(1, &(&1 + 1))
|> Enum.reduce_while(%{nums: new_nums, terms: terms}, fn _y, acc ->
cond do
# Enum.count(acc.terms) <= 0 && Map.get(acc.nums, "root") -> {:halt, acc}
# new try
Enum.count(acc.terms) <= 0 -> {:halt, acc}
true -> {:cont, iterate2.(acc.terms, acc.nums)}
end
end)
|> Map.get(:nums)
if Map.get(result, "root") do
{:halt, result}
else
{:cont, nil}
end
end)
|> Map.get("humn")