Powered by AppSignal & Oban Pro

Day 7: No Space Left On Device

2022/day_07.livemd

Day 7: No Space Left On Device

Mix.install([:kino])

input = Kino.Input.textarea("Please paste your input:")

Part 1

Run in Livebook

https://adventofcode.com/2022/day/7

data =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)

struct_directory = fn
  [command | rest_commands], directory, r_current_path, fun ->
    case command do
      "$ cd /" ->
        fun.(rest_commands, directory, [], fun)

      "$ cd .." ->
        fun.(rest_commands, directory, tl(r_current_path), fun)

      "$ cd " <> directory_name ->
        fun.(rest_commands, directory, [directory_name | r_current_path], fun)

      "$ ls" ->
        {ls_results, rest_commands} =
          rest_commands
          |> Enum.split_while(&(not String.starts_with?(&1, "$")))

        new_directory =
          ls_results
          |> Enum.reduce(directory, fn
            "dir " <> directory_name, directory ->
              directory
              |> put_in(Enum.reverse([directory_name | r_current_path]), %{})

            file, directory ->
              [size_str, filename] = String.split(file, " ")
              size = size_str |> String.to_integer()

              directory
              |> put_in(Enum.reverse([filename | r_current_path]), size)
          end)

        fun.(rest_commands, new_directory, r_current_path, fun)
    end

  [], directory, _r_current_path, _fun ->
    directory
end

directory = struct_directory.(data, %{}, [], struct_directory)

find_small_directory_sizes = fn
  %{} = directory, result, fun ->
    {total_size, result} =
      directory
      |> Enum.reduce({0, result}, fn {_name, value}, {total_size, result} ->
        {sub_total_size, result} = fun.(value, result, fun)

        {total_size + sub_total_size, result}
      end)

    case total_size < 100_000 do
      true -> {total_size, total_size + result}
      false -> {total_size, result}
    end

  size, result, _fun ->
    {size, result}
end

{total_size, result} = find_small_directory_sizes.(directory, 0, find_small_directory_sizes)

_answer1 = result

Part 2

https://adventofcode.com/2022/day/7#part2

total_disk_space = 70_000_000
needed_unused_space = 30_000_000

unused_space = total_disk_space - total_size
needed_to_be_deleted_space = needed_unused_space - unused_space

list_candidate_directories = fn
  %{} = directory, candidates, fun ->
    {total_size, candidates} =
      directory
      |> Enum.reduce({0, candidates}, fn {_name, value}, {total_size, candidates} ->
        {sub_total_size, candidates} = fun.(value, candidates, fun)

        {total_size + sub_total_size, candidates}
      end)

    case total_size >= needed_to_be_deleted_space do
      true -> {total_size, [total_size | candidates]}
      false -> {total_size, candidates}
    end

  size, result, _fun ->
    {size, result}
end

{_, candidates} = list_candidate_directories.(directories, [], list_candidate_directories)

_answer2 =
  candidates
  |> Enum.min()