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

--- Day 10: Syntax Scoring ---

2021/elixir/day-10/day-10.livemd

— Day 10: Syntax Scoring —

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

test

Takeaway:

  1. work with binaries
  2. the “gotcha” was in putting the opposite symbol back on stack vs using a mapper later

https://adventofcode.com/2021/day/10

test = Kino.Input.textarea("test")
puzzle1 = Kino.Input.textarea("puzzle1")
right_to_left = fn
  "]" -> "["
  ")" -> "("
  "}" -> "{"
  ">" -> "<"
end

left_to_right = fn
  "[" -> "]"
  "(" -> ")"
  "{" -> "}"
  "<" -> ">"
end
cost = fn
  ")" -> 3
  "]" -> 57
  "}" -> 1197
  ">" -> 25137
end

# ): 3 points.
# ]: 57 points.
# }: 1197 points.
# >: 25137 points

cost_last = fn
  ")" -> 1
  "]" -> 2
  "}" -> 3
  ">" -> 4
end

# ): 1 point.
# ]: 2 points.
# }: 3 points.
# >: 4 points

Part 1

# input
input =
  puzzle1
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(
    &amp;(String.split(&amp;1, "", trim: true)
      |> Enum.reduce_while([], fn
        chr, acc when chr in ["[", "(", "{", "<"] ->
          {:cont, [chr | acc]}

        chr, [last | rest] when chr in ["]", ")", "}", ">"] ->
          if right_to_left.(chr) !== last,
            do: {:halt, [{last, chr}]},
            else: {:cont, rest}
      end))
  )
input
|> Enum.filter(&amp;(List.first(&amp;1) |> is_tuple()))
|> List.flatten()
|> Enum.map(&amp;(elem(&amp;1, 1) |> cost.()))
|> Enum.sum()

# 268845

Part 2

list =
  input
  |> Enum.filter(&amp;(List.first(&amp;1) |> is_binary()))
  |> Enum.map(&amp;Enum.map(&amp;1, fn chr -> left_to_right.(chr) end))
  |> Enum.map(
    &amp;Enum.reduce(&amp;1, 0, fn chr, score ->
      score * 5 + cost_last.(chr)
    end)
  )
  |> Enum.sort()

list
|> Enum.drop(div(length(list), 2))
|> List.first()

# 4038824534

José

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

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

  # Closing
  def corrupted(<>, [chr | stack]), do: corrupted(rest, stack)

  # Corrupted
  def corrupted(<>, _stack), do: {:corrupted, chr}

  # Valid
  def corrupted(<<>>, []), do: :ok

  # Incomplete
  def corrupted(<<>>, stack), do: {:incomplete, stack}
end
lines =
  test
  |> Kino.Input.read()
  |> String.split("\n", trim: true)

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

Enum.sum(
  for line <- lines,
      {:corrupted, char} <- [Syntax.corrupted(line)],
      do: Map.fetch!(points, char)
)
points = %{
  ?) => 1,
  ?] => 2,
  ?} => 3,
  ?> => 4
}

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

Enum.at(scores, div(length(scores), 2))