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

AoC 2022 - Day 21

2022/day21.livemd

AoC 2022 - Day 21

Mix.install([:kino])

Setup

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

Common

defmodule Day21 do
  @me :humn

  def get_answer_part_1(map, key) do
    do_get_result(map, map[key])
  end

  # humn is ME!
  def get_answer_part_2(map, key) do
    {first, _, second} = map[key]

    left = do_get_answer_part_2(map, first, map[first], "??")
    right = do_get_answer_part_2(map, second, map[second], "??")
    IO.inspect("--------------------")
    IO.inspect(left)
    IO.inspect("should be equals to")
    IO.inspect(Code.eval_string(right))
    IO.inspect("----------------")

    nil
  end

  def process_equation(equation) do
    try do
      String.to_integer(equation)
    rescue
      _ -> process_real_equation(equation)
    end
  end

  # Private methods
  defp get_string(val) when is_integer(val) do
    Integer.to_string(val)
  end

  defp get_string(val) when is_float(val) do
    Float.to_string(val)
  end

  defp get_string(val), do: val

  defp do_get_answer_part_2(_map, key, _val, _val_for_humn) when key == @me, do: ""
  defp do_get_answer_part_2(_map, _key, val, _val_for_humn) when is_number(val), do: val

  defp do_get_answer_part_2(map, _key, {left, :+, right}, val_for_humn) do
    one = do_get_answer_part_2(map, left, map[left], val_for_humn)
    two = do_get_answer_part_2(map, right, map[right], val_for_humn)

    if is_number(one) and is_number(two) do
      one + two
    else
      get_string(one) <> "+" <> get_string(two)
    end
  end

  defp do_get_answer_part_2(map, _key, {left, :-, right}, val_for_humn) do
    one = do_get_answer_part_2(map, left, map[left], val_for_humn)
    two = do_get_answer_part_2(map, right, map[right], val_for_humn)

    if is_number(one) and is_number(two) do
      one - two
    else
      get_string(one) <> "-" <> get_string(two)
    end
  end

  defp do_get_answer_part_2(map, _key, {left, :*, right}, val_for_humn) do
    one = do_get_answer_part_2(map, left, map[left], val_for_humn)
    two = do_get_answer_part_2(map, right, map[right], val_for_humn)

    if is_number(one) and is_number(two) do
      one * two
    else
      "(" <> get_string(one) <> "*" <> get_string(two) <> ")"
    end
  end

  defp do_get_answer_part_2(map, _key, {left, :/, right}, val_for_humn) do
    one = do_get_answer_part_2(map, left, map[left], val_for_humn)
    two = do_get_answer_part_2(map, right, map[right], val_for_humn)

    if is_number(one) and is_number(two) do
      one / two
    else
      "(" <> get_string(one) <> "/" <> get_string(two) <> ")"
    end
  end

  defp do_get_result(_map, val) when is_number(val), do: val

  defp do_get_result(map, {left, :+, right}) do
    do_get_result(map, map[left]) + do_get_result(map, map[right])
  end

  defp do_get_result(map, {left, :-, right}) do
    do_get_result(map, map[left]) - do_get_result(map, map[right])
  end

  defp do_get_result(map, {left, :*, right}) do
    do_get_result(map, map[left]) * do_get_result(map, map[right])
  end

  defp do_get_result(map, {left, :/, right}) do
    do_get_result(map, map[left]) / do_get_result(map, map[right])
  end

  defp process_real_equation(equation) do
    regex = ~r/(?.+) (?.) (?.+)/
    [[_, first, math_op, second]] = Regex.scan(regex, equation)

    {String.to_atom(first), String.to_atom(math_op), String.to_atom(second)}
  end
end

Part 1

monkeys =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(fn line ->
    line
    |> String.split(": ", trim: true)
    |> List.to_tuple()
  end)
  |> Enum.map(fn {id, val} ->
    {String.to_atom(id), Day21.process_equation(val)}
  end)
  |> Map.new()

monkeys
|> Day21.get_answer_part_1(:root)
|> floor()

Part 2

monkeys =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(fn line ->
    line
    |> String.split(": ", trim: true)
    |> List.to_tuple()
  end)
  |> Enum.map(fn {id, val} ->
    {String.to_atom(id), Day21.process_equation(val)}
  end)
  |> Map.new()

monkeys
|> Day21.get_answer_part_2(:root)