82 lines
1.7 KiB
Elixir
82 lines
1.7 KiB
Elixir
defmodule AOC.Day7 do
|
|
use AOC.Day, day: 7
|
|
|
|
def parse_input(lines) do
|
|
Enum.map(lines, fn
|
|
"$ cd " <> arg ->
|
|
{:cd, arg}
|
|
|
|
"$ ls" ->
|
|
:ls
|
|
|
|
"dir " <> arg ->
|
|
{:dir, arg}
|
|
|
|
line ->
|
|
[size, file] = String.split(line)
|
|
{:file, String.to_integer(size), file}
|
|
end)
|
|
end
|
|
|
|
def part1(input) do
|
|
input
|
|
|> get_file_sizes()
|
|
|> get_directory_sizes()
|
|
|> Enum.map(fn {_, size} -> size end)
|
|
|> Enum.filter(&(&1 <= 100_000))
|
|
|> Enum.sum()
|
|
end
|
|
|
|
def part2(input) do
|
|
file_sizes = get_file_sizes(input)
|
|
|
|
total_size =
|
|
file_sizes
|
|
|> Enum.map(&elem(&1, 1))
|
|
|> Enum.sum()
|
|
|
|
size_needed = total_size - 40_000_000
|
|
|
|
file_sizes
|
|
|> get_directory_sizes()
|
|
|> Enum.map(&elem(&1, 1))
|
|
|> Enum.filter(fn size -> size >= size_needed end)
|
|
|> Enum.min()
|
|
end
|
|
|
|
def get_file_sizes(input) do
|
|
Enum.reduce(input, {[], []}, fn
|
|
{:cd, "/"}, {_, sizes} ->
|
|
{["/"], sizes}
|
|
|
|
{:cd, ".."}, {[_ | path], sizes} ->
|
|
{path, sizes}
|
|
|
|
{:cd, dir}, {path, sizes} ->
|
|
{[dir | path], sizes}
|
|
|
|
{:file, size, file}, {path, sizes} ->
|
|
{path, [{[file | path], size} | sizes]}
|
|
|
|
_, acc ->
|
|
acc
|
|
end)
|
|
|> elem(1)
|
|
end
|
|
|
|
def get_directory_sizes(file_sizes) do
|
|
file_sizes
|
|
|> Enum.reduce(%{}, fn {[_ | path], size}, acc ->
|
|
path = Enum.reverse(path)
|
|
update_directory_size(acc, size, path)
|
|
end)
|
|
end
|
|
|
|
def update_directory_size(sizes, file_size, file_path) do
|
|
Enum.reduce(file_path, {sizes, []}, fn dir, {sizes, cur_path} ->
|
|
cur_path = [dir | cur_path]
|
|
{Map.update(sizes, cur_path, file_size, &(&1 + file_size)), cur_path}
|
|
end)
|
|
|> elem(0)
|
|
end
|
|
end
|