Day 18 Part 1
This commit is contained in:
parent
39a36e0813
commit
beba85f7ef
1 changed files with 148 additions and 0 deletions
148
2020/day18/day18.ex
Normal file
148
2020/day18/day18.ex
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
defmodule NewMath 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
|
||||
|
||||
defmodule Group do
|
||||
@enforce_keys [:expr]
|
||||
defstruct [:expr]
|
||||
end
|
||||
|
||||
defmodule Expr do
|
||||
@enforce_keys [:expr]
|
||||
defstruct [:expr]
|
||||
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
|
||||
|
||||
def parse(tokens) do
|
||||
[%Expr{expr: expr}] = parse_iter(tokens, [])
|
||||
expr
|
||||
end
|
||||
|
||||
defp parse_iter([], stack) do
|
||||
stack
|
||||
end
|
||||
|
||||
defp parse_iter(tokens, stack) do
|
||||
{rest, new_stack} = shift(tokens, stack)
|
||||
reduced = reduce(new_stack)
|
||||
parse_iter(rest, reduced)
|
||||
end
|
||||
|
||||
defp shift([token | rest], stack) do
|
||||
gram =
|
||||
case token do
|
||||
{:integer, value} -> %Expr{expr: %Integer{value: value}}
|
||||
_ -> token
|
||||
end
|
||||
|
||||
{rest, [gram | stack]}
|
||||
end
|
||||
|
||||
defp reduce(stack) do
|
||||
case stack do
|
||||
[:rparen, %Expr{expr: expr}, :lparen | rest] ->
|
||||
new_expr = %Expr{expr: expr}
|
||||
reduce([new_expr | rest])
|
||||
|
||||
[%Expr{expr: rexpr}, :plus, %Expr{expr: lexpr} | rest] ->
|
||||
new_expr = %Expr{expr: %Plus{lexpr: lexpr, rexpr: rexpr}}
|
||||
reduce([new_expr | rest])
|
||||
|
||||
[%Expr{expr: rexpr}, :times, %Expr{expr: lexpr} | rest] ->
|
||||
new_expr = %Expr{expr: %Times{lexpr: lexpr, rexpr: rexpr}}
|
||||
reduce([new_expr | rest])
|
||||
|
||||
_ ->
|
||||
stack
|
||||
end
|
||||
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))
|
||||
|> File.read!()
|
||||
end
|
||||
|
||||
defp parse_expressions(text) do
|
||||
String.split(text, "\n", trim: true)
|
||||
|> Enum.map(&parse_expression/1)
|
||||
end
|
||||
|
||||
defp parse_expression(line) do
|
||||
NewMath.tokenize(line)
|
||||
|> NewMath.parse()
|
||||
end
|
||||
|
||||
defp test_input do
|
||||
"""
|
||||
2 * 3 + (4 * 5)
|
||||
5 + (8 * 3 + 9 + 3 * 4 * 3)
|
||||
5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))
|
||||
((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2
|
||||
"""
|
||||
end
|
||||
|
||||
def part1 do
|
||||
read_input()
|
||||
|> parse_expressions()
|
||||
|> Enum.map(&NewMath.evaluate/1)
|
||||
|> Enum.sum()
|
||||
end
|
||||
end
|
||||
|
||||
Day18.part1() |> IO.inspect()
|
||||
Loading…
Reference in a new issue