AOC 2022 - Day 07
Mix.install([
{:kino_aoc, "~> 0.1"}
])
AOC Helper
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2022", "7", System.fetch_env!("LB_AOC_SESSION"))
Part 1
Code
defmodule PartOne do
def process_file(fs, path, file) do
[size, _] = file |> String.trim() |> String.split(" ")
size = String.to_integer(size)
Enum.map(fs, fn {k, v} ->
if String.starts_with?(path, k) do
{k, v + size}
else
{k, v}
end
end)
end
def solve(input) do
IO.puts("--- Part One ---")
IO.puts("Result: #{run(input)}")
end
def run(input) do
input
|> String.split("\n")
|> Enum.reduce({[{"/", 0}], "/"}, fn line, {fs, current_path} ->
case String.trim(line) do
"$ cd /" -> {fs, "/"}
"$ cd " <> path -> {fs, Path.join(current_path, path) |> Path.expand()}
"$ ls" -> {fs, current_path}
"dir " <> dir -> {fs ++ [{Path.join(current_path, dir), 0}], current_path}
file -> {process_file(fs, current_path, file), current_path}
end
end)
|> elem(0)
|> Enum.filter(fn {_path, size} -> size <= 100_000 end)
|> Enum.reduce(0, fn {_path, size}, total -> total + size end)
end
end
Test
ExUnit.start(autorun: false)
defmodule PartOneTest do
use ExUnit.Case, async: true
import PartOne
@input "$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k"
@expected 95437
test "part one" do
actual = run(@input)
assert actual == @expected
end
end
ExUnit.run()
Solution
PartOne.solve(puzzle_input)
Part 2
Code
defmodule PartTwo do
def process_file(fs, path, file) do
[size, _] = file |> String.trim() |> String.split(" ")
size = String.to_integer(size)
Enum.map(fs, fn {k, v} ->
if String.starts_with?(path, k) do
{k, v + size}
else
{k, v}
end
end)
end
def find_dirs(fs) do
total_space = 70_000_000
required_space = 30_000_000
used_space = fs |> Enum.find(&(elem(&1, 0) == "/")) |> elem(1)
available_space = total_space - used_space
delta_space = required_space - available_space
fs
|> Enum.reject(&(elem(&1, 1) < delta_space))
|> Enum.sort_by(&elem(&1, 1))
|> List.first()
|> elem(1)
end
def solve(input) do
IO.puts("--- Part Two ---")
IO.puts("Result: #{run(input)}")
end
def run(input) do
input
|> String.split("\n")
|> Enum.reduce({[{"/", 0}], "/"}, fn line, {fs, current_path} ->
case String.trim(line) do
"$ cd /" -> {fs, "/"}
"$ cd " <> path -> {fs, Path.join(current_path, path) |> Path.expand()}
"$ ls" -> {fs, current_path}
"dir " <> dir -> {fs ++ [{Path.join(current_path, dir), 0}], current_path}
file -> {process_file(fs, current_path, file), current_path}
end
end)
|> elem(0)
|> find_dirs()
end
end
Test
ExUnit.start(autorun: false)
defmodule PartTwoTest do
use ExUnit.Case, async: true
import PartTwo
@input "$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k"
@expected 24_933_642
test "part two" do
actual = run(@input)
assert actual == @expected
end
end
ExUnit.run()
Solution
PartTwo.solve(puzzle_input)