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

Advent 2021 - Day 10

day10.livemd

Advent 2021 - Day 10

Setup

Mix.install([
  {:kino, github: "livebook-dev/kino"}
])
input = Kino.Input.textarea("Please paste your input file:")
input =
  input
  |> Kino.Input.read()
  |> String.trim()
  |> String.split("\n")
  |> Enum.map(&String.graphemes(&1))

Utils

defmodule Utils do
  def validate(input) do
    returned =
      Enum.reduce_while(input, [], fn char, stack ->
        push = fn -> {:cont, [char | stack]} end

        pop = fn expected ->
          [head | tail] = stack

          case head do
            ^expected -> {:cont, tail}
            _ -> {:halt, char}
          end
        end

        case char do
          "(" -> push.()
          "[" -> push.()
          "{" -> push.()
          "<" -> push.()
          ")" -> pop.("(")
          "]" -> pop.("[")
          "}" -> pop.("{")
          ">" -> pop.("<")
        end
      end)

    if is_list(returned), do: {:ok, returned}, else: {:error, returned}
  end
end

Part 1

point_lookup = %{
  ")" => 3,
  "]" => 57,
  "}" => 1197,
  ">" => 25137
}

input
|> Enum.map(&amp;Utils.validate(&amp;1))
|> Enum.filter(fn {status, _} -> status == :error end)
|> Enum.map(fn {_, char} -> point_lookup[char] end)
|> Enum.sum()

Part 2

point_lookup = %{
  "(" => 1,
  "[" => 2,
  "{" => 3,
  "<" => 4
}

scores =
  input
  |> Enum.map(&amp;Utils.validate(&amp;1))
  |> Enum.filter(fn {status, _} -> status == :ok end)
  |> Enum.map(fn {_, remaining_stack} ->
    Enum.reduce(remaining_stack, 0, fn char, acc ->
      acc * 5 + point_lookup[char]
    end)
  end)
  |> Enum.sort()

scores
|> Enum.at(length(scores) |> div(2))