Day 18 Part 2
This commit is contained in:
parent
beba85f7ef
commit
339fda2f90
1 changed files with 133 additions and 0 deletions
|
|
@ -112,6 +112,125 @@ defmodule NewMath do
|
|||
end
|
||||
end
|
||||
|
||||
defmodule NextMath do
|
||||
defmodule Integer do
|
||||
@enforce_keys [:value]
|
||||
defstruct [:value]
|
||||
end
|
||||
|
||||
defmodule Plus do
|
||||
@enforce_keys [:lexpr, :rexpr]
|
||||
defstruct [:lexpr, :rexpr]
|
||||
end
|
||||
|
||||
defmodule Times do
|
||||
@enforce_keys [:lexpr, :rexpr]
|
||||
defstruct [:lexpr, :rexpr]
|
||||
end
|
||||
|
||||
def tokenize(text) do
|
||||
scan(String.codepoints(text), [])
|
||||
end
|
||||
|
||||
defp scan([], tokens) do
|
||||
Enum.reverse(tokens)
|
||||
end
|
||||
|
||||
defp scan(text = [first | rest], tokens) do
|
||||
case first do
|
||||
"(" ->
|
||||
scan(rest, [:lparen | tokens])
|
||||
|
||||
")" ->
|
||||
scan(rest, [:rparen | tokens])
|
||||
|
||||
"*" ->
|
||||
scan(rest, [:times | tokens])
|
||||
|
||||
"+" ->
|
||||
scan(rest, [:plus | tokens])
|
||||
|
||||
" " ->
|
||||
scan(rest, tokens)
|
||||
|
||||
_ ->
|
||||
{digits, extra} = Enum.split_while(text, fn char -> String.match?(char, ~r/\d/) end)
|
||||
scan(extra, [{:integer, String.to_integer(Enum.join(digits))} | tokens])
|
||||
end
|
||||
end
|
||||
|
||||
# Grammar
|
||||
#
|
||||
# Expr = Product
|
||||
# Atom = '(' Expr ')' | integer
|
||||
# Sum = Atom ( '+' Atom )*
|
||||
# Product = Sum ( '*' Sum )*
|
||||
|
||||
def parse(tokens) do
|
||||
{expr, []} = parse_expr(tokens)
|
||||
expr
|
||||
end
|
||||
|
||||
defp parse_expr(tokens) do
|
||||
parse_product(tokens)
|
||||
end
|
||||
|
||||
defp parse_product(tokens) do
|
||||
{lexpr, remaining} = parse_sum(tokens)
|
||||
parse_product_iter(remaining, lexpr)
|
||||
end
|
||||
|
||||
defp parse_product_iter(tokens, lexpr) do
|
||||
case tokens do
|
||||
[:times | rest] ->
|
||||
{rexpr, leftover} = parse_sum(rest)
|
||||
product = %Times{lexpr: lexpr, rexpr: rexpr}
|
||||
parse_product_iter(leftover, product)
|
||||
|
||||
_ ->
|
||||
{lexpr, tokens}
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_sum(tokens) do
|
||||
{lexpr, remaining} = parse_atom(tokens)
|
||||
parse_sum_iter(remaining, lexpr)
|
||||
end
|
||||
|
||||
defp parse_sum_iter(tokens, lexpr) do
|
||||
case tokens do
|
||||
[:plus | rest] ->
|
||||
{rexpr, leftover} = parse_atom(rest)
|
||||
sum = %Plus{lexpr: lexpr, rexpr: rexpr}
|
||||
parse_sum_iter(leftover, sum)
|
||||
|
||||
_ ->
|
||||
{lexpr, tokens}
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_atom([:lparen | tokens]) do
|
||||
{expr, [:rparen | rest]} = parse_expr(tokens)
|
||||
{expr, rest}
|
||||
end
|
||||
|
||||
defp parse_atom([{:integer, value} | tokens]) do
|
||||
{%Integer{value: value}, tokens}
|
||||
end
|
||||
|
||||
def evaluate(%Plus{lexpr: lexpr, rexpr: rexpr}) do
|
||||
evaluate(lexpr) + evaluate(rexpr)
|
||||
end
|
||||
|
||||
def evaluate(%Times{lexpr: lexpr, rexpr: rexpr}) do
|
||||
evaluate(lexpr) * evaluate(rexpr)
|
||||
end
|
||||
|
||||
def evaluate(%Integer{value: value}) do
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Day18 do
|
||||
defp read_input do
|
||||
Path.expand('input', Path.dirname(__ENV__.file))
|
||||
|
|
@ -130,6 +249,7 @@ defmodule Day18 do
|
|||
|
||||
defp test_input do
|
||||
"""
|
||||
1 + (2 * 3) + (4 * (5 + 6))
|
||||
2 * 3 + (4 * 5)
|
||||
5 + (8 * 3 + 9 + 3 * 4 * 3)
|
||||
5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))
|
||||
|
|
@ -143,6 +263,19 @@ defmodule Day18 do
|
|||
|> Enum.map(&NewMath.evaluate/1)
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
def part2 do
|
||||
read_input()
|
||||
|> String.split("\n", trim: true)
|
||||
|> Enum.map(fn line ->
|
||||
line
|
||||
|> NextMath.tokenize()
|
||||
|> NextMath.parse()
|
||||
end)
|
||||
|> Enum.map(&NextMath.evaluate/1)
|
||||
|> Enum.sum()
|
||||
end
|
||||
end
|
||||
|
||||
Day18.part1() |> IO.inspect()
|
||||
Day18.part2() |> IO.inspect()
|
||||
|
|
|
|||
Loading…
Reference in a new issue