Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Advent 2022 - Day 7

day7.livemd

Advent 2022 - Day 7

Mix.install([
  {:kino, github: "livebook-dev/kino"}
])
:ok

Setup

input = Kino.Input.textarea("Please paste your input file:")
raw_session =
  input
  |> Kino.Input.read()
  |> String.split("$")
  |> tl
  |> Enum.map(&String.trim/1)
  |> Enum.map(&String.split(&1, "\n"))
[
  ["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"]
]
session =
  raw_session
  |> Enum.map(fn raw_command ->
    case length(raw_command) do
      1 -> {:cd, raw_command |> Enum.at(0) |> String.split(" ") |> Enum.at(1)}
      _ -> {:ls, raw_command |> Enum.drop(1) |> Enum.map(&String.split(&1, " "))}
    end
  end)
[
  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"]]
]

Utils

defmodule DeviceFS do
  def dir_to_string(dir), do: "/#{dir |> Enum.reverse() |> tl |> Enum.join("/")}"

  def expand_contents(dir, contents) do
    Enum.map(contents, fn content ->
      case content do
        ["dir", name] -> ["dir", dir_to_string([name | dir])]
        _ -> content
      end
    end)
  end

  def generate_fs(fs, curdir, [{:cd, ".."} | session]) do
    generate_fs(fs, Enum.drop(curdir, 1), session)
  end

  def generate_fs(fs, curdir, [{:cd, dir} | [{:ls, contents} | session]]) do
    dir = [dir | curdir]
    fs = Map.put(fs, dir_to_string(dir), expand_contents(dir, contents))
    generate_fs(fs, dir, session)
  end

  def generate_fs(fs, _curdir, []), do: fs

  def generate_fs(session), do: generate_fs(%{}, [], session)
end
{:module, DeviceFS, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:generate_fs, 1}}
fs = DeviceFS.generate_fs(session)
%{
  "/" => [["dir", "/a"], ["14848514", "b.txt"], ["8504156", "c.dat"], ["dir", "/d"]],
  "/a" => [["dir", "/a/e"], ["29116", "f"], ["2557", "g"], ["62596", "h.lst"]],
  "/a/e" => [["584", "i"]],
  "/d" => [["4060174", "j"], ["8033020", "d.log"], ["5626152", "d.ext"], ["7214296", "k"]]
}
defmodule DeviceFSUtils do
  def get_size_of_dir(fs, dir) do
    dir = Map.get(fs, dir)

    sizes =
      for item <- dir do
        case item do
          ["dir", name] -> get_size_of_dir(fs, name)
          [number, _name] -> String.to_integer(number)
        end
      end

    Enum.sum(sizes)
  end

  def get_sizes_of_dirs(fs) do
    Map.keys(fs) |> Enum.map(&amp;get_size_of_dir(fs, &amp;1))
  end
end
{:module, DeviceFSUtils, <<70, 79, 82, 49, 0, 0, 9, ...>>, {:get_sizes_of_dirs, 1}}

Part 1

DeviceFSUtils.get_sizes_of_dirs(fs)
|> Enum.filter(&amp;(&amp;1 <= 100_000))
|> Enum.sum()
95437

Part 2

total_size_of_fs = 70_000_000
space_needed_to_update = 30_000_000

size_of_root_dir = DeviceFSUtils.get_size_of_dir(fs, "/")
48381165
space_to_free_up = size_of_root_dir + space_needed_to_update - total_size_of_fs
8381165
DeviceFSUtils.get_sizes_of_dirs(fs)
|> Enum.filter(&amp;(&amp;1 >= space_to_free_up))
|> Enum.min()
24933642