Powered by AppSignal & Oban Pro

Day 7: No Space Left On Device

day-7-no-space-left-on-device.livemd

Day 7: No Space Left On Device

Mix.install([
  {:kino, "~> 0.7.0"}
])

Input

input = Kino.Input.textarea("Input")

Part 1

Kino.Input.read(input)
|> String.split("\n", trim: true)
|> Enum.map(&String.split(&1, " ", trim: true))
|> Enum.reduce({["root"], []}, fn command, {acc, struct} ->
  case command do
    ["$", "cd", "/"] ->
      {acc, struct}

    ["$", "cd", ".."] ->
      {Enum.take(acc, Enum.count(acc) - 1), struct}

    ["$", "cd", dir] ->
      {acc ++ [dir], struct}

    ["$", "ls"] ->
      {acc, struct}

    ["dir", _dir] ->
      {acc, struct}

    [file_size, _file_name] ->
      {new_struct, _} =
        Enum.reduce(acc, {[], []}, fn folder, {struct, temp} ->
          {struct ++ [{temp ++ [folder], String.to_integer(file_size)}], temp ++ [folder]}
        end)

      {acc, struct ++ [new_struct]}
  end
end)
|> then(fn {_, struct} ->
  struct
  |> List.flatten()
  |> Enum.group_by(fn {dir, _size} -> dir end, fn {_dir, size} -> size end)
  |> Map.values()
  |> Enum.map(&Enum.sum/1)
  |> Enum.filter(fn size -> size <= 100_000 end)
  |> Enum.sum()
end)

Part 2

Kino.Input.read(input)
|> String.split("\n", trim: true)
|> Enum.map(&amp;String.split(&amp;1, " ", trim: true))
|> Enum.reduce({["root"], []}, fn command, {acc, struct} ->
  case command do
    ["$", "cd", "/"] ->
      {acc, struct}

    ["$", "cd", ".."] ->
      {Enum.take(acc, Enum.count(acc) - 1), struct}

    ["$", "cd", dir] ->
      {acc ++ [dir], struct}

    ["$", "ls"] ->
      {acc, struct}

    ["dir", _dir] ->
      {acc, struct}

    [file_size, _file_name] ->
      {new_struct, _} =
        Enum.reduce(acc, {[], []}, fn folder, {struct, temp} ->
          {struct ++ [{temp ++ [folder], String.to_integer(file_size)}], temp ++ [folder]}
        end)

      {acc, struct ++ [new_struct]}
  end
end)
|> then(fn {_, struct} ->
  struct
  |> List.flatten()
  |> Enum.group_by(fn {dir, _size} -> dir end, fn {_dir, size} -> size end)
  |> then(fn x ->
    root = Map.get(x, ["root"]) |> Enum.sum()
    unused_space = 70_000_000 - root
    space_needed = 30_000_000 - unused_space

    Map.values(x)
    |> Enum.map(&amp;Enum.sum/1)
    |> Enum.reject(fn x -> x < space_needed end)
    |> Enum.sort()
    |> List.first()
  end)
end)