Day 10: Syntax Scoring
Mix.install([:kino])
input = Kino.Input.textarea("Please paste your input:")
Setup
inputs =
input
|> Kino.Input.read()
|> String.split("\n", trim: true)
Part 1
https://adventofcode.com/2021/day/10
Solve: Part 1
defmodule Day10.Part1 do
@opens ["(", "[", "{", "<"]
@closes [")", "]", "}", ">"]
@score_map %{
")" => 3,
"]" => 57,
"}" => 1197,
">" => 25137
}
def analyze(line) do
line
|> String.graphemes()
|> Enum.reduce_while([], fn char, stack ->
case char do
char when char in @opens ->
{:cont, [char | stack]}
char when char in @closes ->
[current | rest_stack] = stack
case chunk?(current, char) do
true -> {:cont, rest_stack}
false -> {:halt, {:corrupted, char}}
end
end
end)
|> case do
{:corrupted, first_illigal_character} -> {:corrupted, first_illigal_character}
_ -> :ok
end
end
def get_score(char), do: @score_map[char]
defp chunk?("(", ")"), do: true
defp chunk?("[", "]"), do: true
defp chunk?("{", "}"), do: true
defp chunk?("<", ">"), do: true
defp chunk?(_, _), do: false
end
inputs
|> Enum.map(&Day10.Part1.analyze/1)
|> Enum.filter(fn
{:corrupted, _} -> true
_ -> false
end)
|> Enum.map(fn {:corrupted, first_illegal_character} ->
Day10.Part1.get_score(first_illegal_character)
end)
|> Enum.sum()
Part 2
https://adventofcode.com/2021/day/10#part2
defmodule Day10.Part2 do
@opens ["(", "[", "{", "<"]
@closes [")", "]", "}", ">"]
@score_map %{
"(" => 1,
"[" => 2,
"{" => 3,
"<" => 4
}
def analyze(line) do
line
|> String.graphemes()
|> Enum.reduce_while([], fn char, stack ->
case char do
char when char in @opens ->
{:cont, [char | stack]}
char when char in @closes ->
[current | rest_stack] = stack
case chunk?(current, char) do
true -> {:cont, rest_stack}
false -> {:halt, {:corrupted, char}}
end
end
end)
|> case do
{:corrupted, first_illigal_character} -> {:corrupted, first_illigal_character}
[_ | _] = rest_stack -> {:incompleted, rest_stack}
_ -> :ok
end
end
def get_score(stack) do
stack
|> Enum.reduce(0, fn open, score ->
score * 5 + @score_map[open]
end)
end
defp chunk?("(", ")"), do: true
defp chunk?("[", "]"), do: true
defp chunk?("{", "}"), do: true
defp chunk?("<", ">"), do: true
defp chunk?(_, _), do: false
end
scores =
inputs
|> Enum.map(&Day10.Part2.analyze/1)
|> Enum.filter(fn
{:incompleted, _} -> true
_ -> false
end)
|> Enum.map(fn {:incompleted, rest_stack} -> Day10.Part2.get_score(rest_stack) end)
|> Enum.sort()
middle_score = Enum.at(scores, div(Enum.count(scores) - 1, 2))