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

Advent of Code 2021 day 10

2021/priv/day-10.livemd

Advent of Code 2021 day 10

Setup

Mix.install([
  {:kino, "~> 0.4.1"}
])
input = Kino.Input.textarea("Please paste your input:")
lines =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)

Part 1

defmodule Day10 do
  @pair %{
    ?] => ?[,
    ?} => ?{,
    ?> => ?<,
    ?) => ?(
  }
  @points %{
    ?) => 3,
    ?] => 57,
    ?} => 1197,
    ?> => 25137
  }
  def parse(line) do
    Enum.reduce_while(line, [], fn next, opens ->
      cond do
        next in Map.values(@pair) ->
          {:cont, [next | opens]}

        next in Map.keys(@pair) ->
          [prev | rest] = opens

          if prev == Map.get(@pair, next) do
            {:cont, rest}
          else
            {:halt, {prev, next}}
          end
      end
    end)
  end

  def point(char) do
    Map.get(@points, char)
  end
end

lines
|> Enum.map(&amp;String.to_charlist/1)
|> Enum.map(&amp;Day10.parse/1)
|> Enum.filter(&amp;is_tuple/1)
|> Enum.map(&amp;elem(&amp;1, 1))
|> Enum.map(&amp;Day10.point/1)
|> Enum.sum()

Part 2

defmodule Day10Part2 do
  @points %{
    ?( => 1,
    ?[ => 2,
    ?{ => 3,
    ?< => 4
  }

  def calc(line) do
    Enum.reduce(line, 0, &amp;next/2)
  end

  defp next(char, score) do
    score * 5 + Map.get(@points, char)
  end
end

incompletes =
  lines
  |> Enum.map(&amp;String.to_charlist/1)
  |> Enum.map(&amp;Day10.parse/1)
  |> Enum.filter(&amp;is_list/1)

incompletes
|> Enum.map(&amp;Day10Part2.calc/1)
|> Enum.sort()
|> Enum.at(incompletes |> length |> then(&amp;div(&amp;1, 2)))

José’s parser

defmodule Syntax do
  def parse(line), do: parse(line, [])

  # opening
  def parse(<rest::binary>, stack), do: parse(rest, [?) | stack])
  def parse(<rest::binary>, stack), do: parse(rest, [?] | stack])
  def parse(<rest::binary>, stack), do: parse(rest, [?} | stack])
  def parse(<rest::binary>, stack), do: parse(rest, [?> | stack])

  # Closing (correctly)
  def parse(<>, [char | stack]), do: parse(rest, stack)

  # Base/error cases
  def parse(<>, _stack), do: {:corrupted, char}
  def parse(<<>>, []), do: :ok
  def parse(<<>>, stack), do: {:incomplete, stack}
end

Part 1

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

for line <- lines,
    {:corrupted, char} <- [Syntax.parse(line)] do
  Map.fetch!(points, char)
end
|> Enum.sum()

Part 2

points = %{
  ?) => 1,
  ?] => 2,
  ?} => 3,
  ?> => 4
}

scores =
  for line <- lines,
      {:incomplete, chars} <- [Syntax.parse(line)] do
    Enum.reduce(chars, 0, fn char, acc -> acc * 5 + Map.fetch!(points, char) end)
  end
  |> Enum.sort()

scores
|> Enum.fetch!(scores |> length |> then(&amp;div(&amp;1, 2)))