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

Advent of code day 07

2022/livebooks/day-07.livemd

Advent of code day 07

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

Setup input

input = Kino.Input.textarea("Please paste your input file:")
input =
  input
  |> Kino.Input.read()
  |> String.split(["\n"])
defmodule Recursion do
  def put_file_or_dir("dir " <> directory_name, structure, current_path),
    do:
      structure
      |> put_in(Enum.reverse([directory_name | current_path]), %{})

  def put_file_or_dir(file, structure, current_path) do
    [size_str, filename] = String.split(file, " ")
    size = size_str |> String.to_integer()

    structure
    |> put_in(Enum.reverse([filename | current_path]), size)
  end

  def solve(input), do: solve(input, %{}, [])

  def solve([], structure, _), do: structure

  def solve(["$ ls" | tail], structure, current_path) do
    {ls_results, rest_commands} =
      tail
      |> Enum.split_while(&amp;(not String.starts_with?(&amp;1, "$")))

    new_directory =
      ls_results
      |> Enum.reduce(structure, fn command, structure ->
        put_file_or_dir(command, structure, current_path)
      end)

    solve(rest_commands, new_directory, current_path)
  end

  def solve(["$ cd .." | tail], structure, [_ | current_path]),
    do: solve(tail, structure, current_path)

  def solve(["$ cd /" | tail], structure, _current_path), do: solve(tail, structure, [])

  def solve(["$ cd " <> dir | tail], structure, current_path) do
    solve(tail, structure, [dir | current_path])
  end
end
defmodule Sum do
  def sum_dir(%{} = structure, result) do
    {total_size, result} =
      structure
      |> Enum.reduce({0, result}, fn {_folder, value}, {total_size, result} ->
        # aqui estamos fazendo uma busca em profundidade
        {sub_total_size, result} = sum_dir(value, result)
        {total_size + sub_total_size, result}
      end)

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

  def sum_dir(size, result), do: {size, result}

  def find_dir_to_be_deleted(%{} = structure, candidates, amount_of_space) do
    {total_size, candidates} =
      structure
      |> Enum.reduce({0, candidates}, fn {_name, value}, {total_size, candidates} ->
        {sub_total_size, candidates} = find_dir_to_be_deleted(value, candidates, amount_of_space)

        {total_size + sub_total_size, candidates}
      end)

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

  def find_dir_to_be_deleted(structure, candidates, _amount_of_space), do: {structure, candidates}
end

Part 01

structure = Recursion.solve(input)
{total_size, result} = Sum.sum_dir(structure, 0)
result

Part 02

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

{total, candidates} = Sum.find_dir_to_be_deleted(structure, [], needed_to_be_deleted_space)

candidates |> Enum.min()