Advent of code day 09
Mix.install([
{:kino, "~> 0.5.0"}
])
Setup input
example = Kino.Input.textarea("Please paste your input example:")
input = Kino.Input.textarea("Please paste your real input:")
Part 01
{list, _method, index} =
example
|> Kino.Input.read()
|> String.split("", trim: true)
|> Enum.map(&String.to_integer/1)
|> Enum.reduce({[], true, 0}, fn e, {list, method, index} ->
cond do
e == 0 ->
{list, !method, index}
method == true ->
elements = Enum.map(0..(e - 1), fn _x -> index end)
{elements ++ list, !method, index + 1}
true ->
elements = Enum.map(0..(e - 1), fn _x -> "." end)
{elements ++ list, !method, index}
end
end)
{list_2, index} = {Enum.reverse(list), index}
map_of_memory = Enum.frequencies(list)
list = List.to_tuple(list_2)
j = tuple_size(list) - 1
i = 0
result =
0
|> Stream.iterate(&(&1 + 1))
|> Enum.reduce_while({list, i, j}, fn _, {list, i, j} ->
if i == j do
{:halt, list}
else
cond do
elem(list, i) == "." && elem(list, j) == "." ->
{:cont, {list, i, j - 1}}
elem(list, i) == "." && elem(list, j) != "." ->
list = put_elem(list, i, elem(list, j)) |> put_elem(j, ".")
{:cont, {list, i + 1, j - 1}}
elem(list, i) != "." && elem(list, j) != "." ->
{:cont, {list, i + 1, j}}
elem(list, i) != "." && elem(list, j) == "." ->
{:cont, {list, i + 1, j - 1}}
end
end
end)
Enum.reduce(i..j, {0, result}, fn p, {total, list} ->
if elem(list, p) == "." do
{total, list}
else
{total + elem(list, p) * p, list}
end
end) |> then(fn {t, _ } -> t end)
Part 02
list =
example
|> Kino.Input.read()
|> String.split("", trim: true)
|> Enum.map(&String.to_integer/1)
|> List.to_tuple()
fid = 0
pos = 0
files = %{}
blanks = []
{pos, fid, %{files: files, blanks: blanks}} =
Enum.reduce(
0..(tuple_size(list) - 1),
{pos, fid, %{files: files, blanks: blanks}},
fn i,
{pos, fid,
%{
files: files,
blanks: blanks
} = map} = _acc ->
length = elem(list, i)
if rem(i, 2) == 0 do
files = Map.put(files, fid, {pos, length})
fid = fid + 1
{pos + length, fid, %{map | files: files}}
else
blanks = if length != 0, do: [{pos, length} | blanks] |> Enum.reverse(), else: blanks
{pos + length, fid, %{map | blanks: blanks}}
end
end
)
{_, response, _} =
0
|> Stream.iterate(&(&1 + 1))
|> Enum.reduce_while(
{fid, files, Enum.sort_by(blanks, fn {p, _} -> p end)},
fn _, {fid, files, blanks} ->
if fid == 0 do
{:halt, {fid, files, blanks}}
else
fid = fid - 1
{pos, size} = Map.get(files, fid)
p_blanks =
Enum.filter(Enum.with_index(blanks), fn {{b_pos, b_size}, _index} ->
b_pos <= pos and b_size >= size
end)
case p_blanks do
[{{start, length}, b_index} | _] ->
blanks =
if size == length do
blanks |> List.delete_at(b_index)
else
blanks |> List.replace_at(b_index, {start + size, length - size})
end
files = Map.put(files, fid, {start, size})
{:cont, {fid, files, blanks}}
[] ->
{:cont, {fid, files, blanks}}
end
end
end
)
response
|> Enum.reduce(0, fn {fid, {pos, size}}, total ->
total +
Enum.reduce(pos..(pos + size - 1), 0, fn x, acc ->
acc + fid * x
end)
end)