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
|
||||||
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
|
defmodule Day18 do
|
||||||
defp read_input do
|
defp read_input do
|
||||||
Path.expand('input', Path.dirname(__ENV__.file))
|
Path.expand('input', Path.dirname(__ENV__.file))
|
||||||
|
|
@ -130,6 +249,7 @@ defmodule Day18 do
|
||||||
|
|
||||||
defp test_input do
|
defp test_input do
|
||||||
"""
|
"""
|
||||||
|
1 + (2 * 3) + (4 * (5 + 6))
|
||||||
2 * 3 + (4 * 5)
|
2 * 3 + (4 * 5)
|
||||||
5 + (8 * 3 + 9 + 3 * 4 * 3)
|
5 + (8 * 3 + 9 + 3 * 4 * 3)
|
||||||
5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))
|
5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))
|
||||||
|
|
@ -143,6 +263,19 @@ defmodule Day18 do
|
||||||
|> Enum.map(&NewMath.evaluate/1)
|
|> Enum.map(&NewMath.evaluate/1)
|
||||||
|> Enum.sum()
|
|> Enum.sum()
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
Day18.part1() |> IO.inspect()
|
Day18.part1() |> IO.inspect()
|
||||||
|
Day18.part2() |> IO.inspect()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue