Add solutions for 2022:7 "No Space Left On Device"
tried to solve this one using only incrementing sums, which worked fine for the test input but not the actual puzzle input. By a complete rewrite to actually render the tree as a map, it worked. The spontanious data store is a mess and cost me much time to work around, since I wanted to have a list of tuples with all the sizes for each directory. Took 2 days to figure this one out. Not proud.
This commit is contained in:
parent
67ff3997f1
commit
bb708a5e58
2 changed files with 205 additions and 0 deletions
158
2022-elixir/lib/solutions/day_07.ex
Normal file
158
2022-elixir/lib/solutions/day_07.ex
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
defmodule Aoc.Solution.Day07 do
|
||||||
|
import Aoc.Utils
|
||||||
|
|
||||||
|
@name "Day 7: No Space Left On Device"
|
||||||
|
@behaviour Solution
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def get_name, do: @name
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def present(solution), do: "The small directories sizes sum is #{solution} (1644735)"
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def present_again(solution), do: "The best dir to remove has a size of #{solution}"
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def parse!(raw) do
|
||||||
|
raw |> split_lines()
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve(output) do
|
||||||
|
output
|
||||||
|
|> traverse()
|
||||||
|
|> small_dir_sum()
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_again(output) do
|
||||||
|
output
|
||||||
|
|> traverse()
|
||||||
|
|> removal_dir()
|
||||||
|
end
|
||||||
|
|
||||||
|
def traverse(files) when is_list(files) do
|
||||||
|
Enum.reduce(
|
||||||
|
files,
|
||||||
|
%{
|
||||||
|
pwd: ["/"],
|
||||||
|
tree: %{
|
||||||
|
"/" => %{
|
||||||
|
children: %{},
|
||||||
|
files: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&traverse/2
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def traverse("$ cd /", tree) do
|
||||||
|
%{tree | pwd: ["/"]}
|
||||||
|
end
|
||||||
|
|
||||||
|
def traverse("$ cd ..", tree = %{pwd: path}) do
|
||||||
|
%{tree | pwd: path |> Enum.drop(1)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def traverse("$ cd " <> dirname, tree = %{pwd: path}) do
|
||||||
|
%{tree | pwd: [dirname | path]}
|
||||||
|
end
|
||||||
|
|
||||||
|
def traverse("dir " <> dirname, state = %{pwd: pwd, tree: tree}) do
|
||||||
|
pp = _path(pwd, :children)
|
||||||
|
node = Map.put(get_in(tree, pp), dirname, %{children: %{}, files: []})
|
||||||
|
%{state | tree: put_in(tree, pp, node)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def traverse("$ ls", tree) do
|
||||||
|
tree
|
||||||
|
end
|
||||||
|
|
||||||
|
def traverse(item, %{pwd: pwd, tree: tree}) do
|
||||||
|
[size, _name] = String.split(item)
|
||||||
|
pp = _path(pwd, :files)
|
||||||
|
files = get_in(tree, pp)
|
||||||
|
|
||||||
|
%{
|
||||||
|
pwd: pwd,
|
||||||
|
tree: put_in(tree, pp, [String.to_integer(size) | files])
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def _path(pwd, pos),
|
||||||
|
do:
|
||||||
|
[
|
||||||
|
pos
|
||||||
|
| pwd
|
||||||
|
|> Enum.map(fn s -> [s, :children] end)
|
||||||
|
]
|
||||||
|
|> List.flatten()
|
||||||
|
|> Enum.drop(-1)
|
||||||
|
|> Enum.reverse()
|
||||||
|
|
||||||
|
def small_dir_sum(%{tree: tree}) do
|
||||||
|
tree
|
||||||
|
|> dir_sizes()
|
||||||
|
|> Enum.filter(fn v -> v < 100_000 end)
|
||||||
|
|> Enum.sum()
|
||||||
|
end
|
||||||
|
|
||||||
|
def removal_dir(%{tree: tree}) do
|
||||||
|
needed = 30_000_000
|
||||||
|
disk = 70_000_000
|
||||||
|
|
||||||
|
dirs =
|
||||||
|
tree
|
||||||
|
|> dir_sizes()
|
||||||
|
|
||||||
|
used = Enum.max(dirs)
|
||||||
|
free = disk - used
|
||||||
|
|
||||||
|
dirs
|
||||||
|
|> Enum.filter(fn s -> free + s > needed end)
|
||||||
|
|> Enum.min()
|
||||||
|
end
|
||||||
|
|
||||||
|
def dir_sizes(%{"/" => node}) do
|
||||||
|
dir_sizes("/", node, [])
|
||||||
|
|> Enum.map(fn {_k, v} -> v end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def dir_sizes(_name, children, seen) when is_list(children) do
|
||||||
|
sums =
|
||||||
|
Enum.map(children, fn {name, data} ->
|
||||||
|
dir_sizes(name, data, seen)
|
||||||
|
end)
|
||||||
|
|> List.flatten()
|
||||||
|
|
||||||
|
sums ++ seen
|
||||||
|
end
|
||||||
|
|
||||||
|
def dir_sizes(name, data, seen) do
|
||||||
|
size = dir_size(data)
|
||||||
|
|
||||||
|
seen =
|
||||||
|
case Enum.empty?(Map.get(data, :children)) do
|
||||||
|
true -> seen
|
||||||
|
false -> dir_sizes(name, Map.get(data, :children) |> Map.to_list(), seen)
|
||||||
|
end
|
||||||
|
|
||||||
|
[{name, size} | seen]
|
||||||
|
end
|
||||||
|
|
||||||
|
def dir_size(data) do
|
||||||
|
size = Map.get(data, :files, []) |> Enum.sum()
|
||||||
|
|
||||||
|
child_size =
|
||||||
|
data
|
||||||
|
|> Map.get(:children)
|
||||||
|
|> Enum.map(fn {_n, d} ->
|
||||||
|
dir_size(d)
|
||||||
|
end)
|
||||||
|
|> Enum.sum()
|
||||||
|
|
||||||
|
size + child_size
|
||||||
|
end
|
||||||
|
end
|
||||||
47
2022-elixir/test/solutions/day_07_test.exs
Normal file
47
2022-elixir/test/solutions/day_07_test.exs
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
defmodule Day07Test do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Aoc.Solution.Day07
|
||||||
|
import Aoc.Solution.Day07
|
||||||
|
|
||||||
|
@input ~s(
|
||||||
|
$ 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
|
||||||
|
)
|
||||||
|
|
||||||
|
test "07: No Space Left On Device, part 1" do
|
||||||
|
expected = 95437
|
||||||
|
|
||||||
|
result = @input |> parse!() |> solve()
|
||||||
|
|
||||||
|
assert result == expected
|
||||||
|
end
|
||||||
|
|
||||||
|
test "07: No Space Left On Device, part 2" do
|
||||||
|
expected = 24_933_642
|
||||||
|
|
||||||
|
result = @input |> parse!() |> solve_again()
|
||||||
|
|
||||||
|
assert result == expected
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Reference in a new issue