— Day 10: Syntax Scoring —
Mix.install([{:kino, "~> 0.9.4"}])
test
Takeaway:
- work with binaries
- 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(
&(String.split(&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(&(List.first(&1) |> is_tuple()))
|> List.flatten()
|> Enum.map(&(elem(&1, 1) |> cost.()))
|> Enum.sum()
# 268845
Part 2
list =
input
|> Enum.filter(&(List.first(&1) |> is_binary()))
|> Enum.map(&Enum.map(&1, fn chr -> left_to_right.(chr) end))
|> Enum.map(
&Enum.reduce(&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))