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

Day 10

day10/index.livemd

Day 10

Setup

input =
  File.read!("aoc2021/day10/input.txt")
  |> String.split("\n", trim: true)
  |> Enum.map(&String.to_charlist/1)

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

symbol_pairs =
  '[]{}()<>'
  |> to_charlist()
  |> Enum.chunk_every(2)
  |> Enum.map(fn row ->
    {Enum.at(row, 0), Enum.at(row, 1)}
  end)
[{91, 93}, {123, 125}, {40, 41}, {60, 62}]
defmodule Recursion do
  def is_expected_symbol(symbol_list, index, symbol_pairs, stack)
      when length(symbol_list) > index do
    symbol = Enum.at(symbol_list, index)

    {start, pend} =
      Enum.find(symbol_pairs, nil, fn pair ->
        {start, pend} = pair
        start == symbol or pend == symbol
      end)

    cond do
      start == symbol ->
        Recursion.is_expected_symbol(symbol_list, index + 1, symbol_pairs, stack ++ [symbol])

      pend == symbol and start == Enum.at(stack, length(stack) - 1) ->
        {_, newstack} = List.pop_at(stack, -1)
        Recursion.is_expected_symbol(symbol_list, index + 1, symbol_pairs, newstack)

      true ->
        {:corrupted, symbol_list, stack, symbol}
    end
  end

  def is_expected_symbol(symbol_list, index, _, stack) when length(symbol_list) <= index do
    {:incomplete, symbol_list, stack, nil}
  end
end
{:module, Recursion, <<70, 79, 82, 49, 0, 0, 10, ...>>, {:is_expected_symbol, 4}}

Part 1

# take to_char
# if start then push
# if end then check if last push was start
#   if last push was not the start we want then return the this symbol as bad
#   
walked_symbols =
  input
  |> Enum.map(fn symbol_list ->
    Recursion.is_expected_symbol(symbol_list, 0, symbol_pairs, [])
  end)

walked_symbols
|> Enum.filter(fn result ->
  case result do
    {:corrupted, _, _, _} -> true
    _ -> false
  end
end)
|> Enum.reduce(0, fn result, acc ->
  {_, _, _, inval_char} = result
  acc + lookup_table[inval_char]
end)
311895

Part 2

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

completed_score =
  walked_symbols
  |> Enum.filter(fn result ->
    case result do
      {:incomplete, _, _, _} -> true
      _ -> false
    end
  end)
  |> Enum.map(fn row ->
    {_, _, symbol_list, _} = row
    symbol_list
  end)
  |> Enum.map(fn symbol_list ->
    Enum.map(symbol_list, fn symbol ->
      pair =
        Enum.find(symbol_pairs, nil, fn {start, _} ->
          start == symbol
        end)

      {_, pend} = pair
      pend
    end)
    |> Enum.reverse()
  end)
  |> Enum.map(fn symbol_list ->
    Enum.reduce(symbol_list, 0, fn symbol, acc ->
      acc * 5 + points_lookup[symbol]
    end)
  end)
  |> Enum.sort()

Enum.at(completed_score, length(completed_score) |> div(2))
2904180541