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

Day 10: Syntax Scoring

2021/elixir/day-10.livemd

Day 10: Syntax Scoring

Setup

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

Input

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

Stack

defmodule Stack do
  defstruct list: []

  def new(list \\ []) do
    %__MODULE__{list: list}
  end

  def pop(%__MODULE__{list: [value | rest]}) do
    {%__MODULE__{list: rest}, value}
  end

  def push(%__MODULE__{list: list}, value) do
    %__MODULE__{list: [value | list]}
  end
end

Part 1

defmodule Bracket do
  def brackets do
    %{
      ?( => ?),
      ?[ => ?],
      ?{ => ?},
      ?< => ?>
    }
  end

  def points do
    %{
      ?) => 3,
      ?] => 57,
      ?} => 1197,
      ?> => 25137
    }
  end

  def feed(chars) do
    Enum.reduce_while(chars, {Stack.new(), nil}, fn char, {stack, _} ->
      acc = feed(stack, char)
      if elem(acc, 1) == nil, do: {:cont, acc}, else: {:halt, acc}
    end)
  end

  def feed(stack, char) do
    if brackets()[char] do
      {Stack.push(stack, char), nil}
    else
      {stack, value} = Stack.pop(stack)
      {stack, if(brackets()[value] == char, do: nil, else: char)}
    end
  end
end

Kino.Input.read(input)
|> String.split("\n", trim: true)
|> Enum.map(&amp;String.to_charlist/1)
|> Enum.map(&amp;Bracket.feed/1)
|> Enum.map(&amp;elem(&amp;1, 1))
|> Enum.filter(&amp; &amp;1)
|> Enum.map(fn char -> Bracket.points()[char] end)
|> Enum.sum()

Part 2

defmodule Score do
  def score(stack) do
    stack.list
    |> Enum.map(fn char ->
      case Bracket.brackets()[char] do
        ?) -> 1
        ?] -> 2
        ?} -> 3
        ?> -> 4
      end
    end)
    |> Enum.reduce(0, fn n, acc -> acc * 5 + n end)
  end
end

Kino.Input.read(input)
|> String.split("\n", trim: true)
|> Enum.map(&amp;String.to_charlist/1)
|> Enum.map(&amp;Bracket.feed/1)
|> Enum.filter(&amp;(!elem(&amp;1, 1)))
|> Enum.map(&amp;elem(&amp;1, 0))
|> Enum.map(&amp;Score.score/1)
|> Enum.sort(:asc)
|> then(fn l ->
  Enum.at(l, div(length(l), 2))
end)