AOC 2022 Day 07
Section
Mix.install([
{:kino, "~> 0.7.0"}
])
Inputs
input = Kino.Input.textarea("Input")
test_input = Kino.Input.textarea("Input")
Structs that ended up being useless and are now a shell of what they were when I originally built them out
defmodule Dir do
defstruct contents: []
end
defmodule F do
defstruct [:name, size: 0]
end
The main functions
defmodule Terminal do
def build(lines, current \\ nil, filesystem \\ %{})
def build([], _, filesystem), do: filesystem
def build([line | rest], current, filesystem) do
{current, filesystem} =
case line do
["$", cmd, dir] -> command(cmd, current, dir, filesystem)
["$", "ls"] -> {current, filesystem}
["dir", name] -> add_dir(name, current, filesystem)
[size, name] -> add_file(String.to_integer(size), name, current, filesystem)
end
build(rest, current, filesystem)
end
defp command("cd", current, to, filesystem) do
case to do
"/" ->
if filesystem[to] do
{to, filesystem}
else
fs = filesystem |> Map.put(to, %Dir{})
{to, fs}
end
_ ->
path = Path.expand(to, current)
if filesystem[path] do
{path, filesystem}
else
fs = filesystem |> Map.put(path, %Dir{})
{path, fs}
end
end
end
defp add_dir(name, current, filesystem) do
curr = filesystem[current]
path = Path.expand(name, current)
content = [path | curr.contents]
fs = %{filesystem | current => %{curr | contents: content}}
{current, fs}
end
defp add_file(size, name, current, filesystem) do
curr = filesystem[current]
f = %F{name: name, size: size}
new_content = [f | curr.contents]
fs = %{filesystem | current => %{curr | contents: new_content}}
{current, fs}
end
def get_size(fs, name) do
fs[name].contents
|> Enum.map(fn x ->
case x do
%F{} -> x.size
_ -> get_size(fs, x)
end
end)
|> Enum.sum()
end
end
Get the data and build the file tree
data =
Kino.Input.read(input)
|> String.split("\n", trim: true)
|> Enum.map(&String.split(&1, " "))
filesystem = data |> Terminal.build()
Get all the sizes
sizes =
filesystem
|> Enum.map(fn {k, _} ->
Terminal.get_size(filesystem, k)
end)
Part 1
sizes
|> Enum.reduce(0, fn num, acc ->
if num > 100_000, do: acc, else: acc + num
end)
Part 2
max_space = 70_000_000
needed_space = 30_000_000
[top | sorted] =
sizes
|> Enum.sort(:desc)
free_space = max_space - top
sizes
|> Enum.filter(fn x ->
x + free_space >= needed_space
end)
|> Enum.min()