Day 07
Solution
defmodule D07 do
def parse_input(input), do: Enum.reduce(input, {%{}, [], nil}, &parse_line/2) |> elem(0)
def parse_line("$ cd ..", {dir_sizes, [_curr_dir | path], _state}), do: {dir_sizes, path, nil}
def parse_line("$ ls", {dir_sizes, path, nil}), do: {dir_sizes, path, :ls}
def parse_line(<<"$ cd "::binary, target_dir::binary>>, {dir_sizes, path, _state}),
do: {dir_sizes, [target_dir | path], nil}
def parse_line(<<"dir "::binary, _dir_name::binary>>, {dir_sizes, path, :ls}),
do: {dir_sizes, path, :ls}
def parse_line(file_size_and_name, {dir_sizes, path, :ls}) do
{file_size, ""} = String.split(file_size_and_name) |> hd() |> Integer.parse()
{dir_sizes, []} =
Enum.reduce(
path,
{dir_sizes, path},
fn dir_name, {dir_sizes, [dir_name | rest] = full_path} ->
full_dir_name = Enum.reverse(full_path) |> Enum.join("/") |> String.replace("//", "/")
dir_sizes = Map.update(dir_sizes, full_dir_name, file_size, &(&1 + file_size))
{dir_sizes, rest}
end
)
{dir_sizes, path, :ls}
end
@p1_limit 100_000
def p1(dir_sizes) when is_map(dir_sizes) do
dir_sizes
|> Enum.map(fn {_dir_name, size} -> if size <= @p1_limit, do: size, else: 0 end)
|> Enum.sum()
end
@total_disk_space 70_000_000
@required_free_space 30_000_000
def p2(dir_sizes) when is_map(dir_sizes) do
curr_free_space = @total_disk_space - dir_sizes["/"]
need_to_free = @required_free_space - curr_free_space
dir_sizes
|> Enum.filter(fn {_dir_name, dir_size} -> dir_size >= need_to_free end)
|> Enum.sort_by(fn {_dir_name, dir_size} -> dir_size end, :asc)
|> hd()
|> elem(1)
end
end
Tests
ExUnit.start(autorun: false)
defmodule D07Tests do
use ExUnit.Case, async: true
def get_test_input() do
File.read!("inputs/d07_test") |> String.trim_trailing() |> String.split("\n")
end
def get_input() do
File.read!("inputs/d07") |> String.trim_trailing() |> String.split("\n")
end
test "p1" do
test_dir_sizes = get_test_input() |> D07.parse_input()
assert test_dir_sizes == %{
"/" => 48_381_165,
"/a" => 94853,
"/a/e" => 584,
"/d" => 24_933_642
}
assert D07.p1(test_dir_sizes) == 95437
dir_sizes = get_input() |> D07.parse_input()
assert D07.p1(dir_sizes) == 1_447_046
end
test "p2" do
test_dir_sizes = get_test_input() |> D07.parse_input()
assert D07.p2(test_dir_sizes) == 24_933_642
dir_sizes = get_input() |> D07.parse_input()
assert D07.p2(dir_sizes) == 578_710
end
end
ExUnit.run()