Skip to content

Instantly share code, notes, and snippets.

@sasa1977
Last active December 10, 2017 08:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sasa1977/c580e36a94bb10d63465b3168d14345c to your computer and use it in GitHub Desktop.
Save sasa1977/c580e36a94bb10d63465b3168d14345c to your computer and use it in GitHub Desktop.
defmodule Day9 do
def part1(), do:
score_groups(input())
def part2(), do:
count_garbage(input())
defp input() do
{groups, "\n"} = parse(zero_or_more(group()), File.read!("input.txt"))
groups
end
defp score_groups(groups), do:
score_groups(groups, 1)
defp score_groups(elements, level) when is_list(elements), do:
elements |> Stream.map(&score_groups(&1, level)) |> Enum.sum()
defp score_groups({:group, members}, level), do:
level + score_groups(members, level + 1)
defp score_groups(_other, _level), do: 0
defp count_garbage(elements) when is_list(elements), do:
elements |> Stream.map(&count_garbage/1) |> Enum.sum()
defp count_garbage({:group, members}), do:
count_garbage(members)
defp count_garbage({:garbage, chars}), do:
chars |> Stream.reject(&match?({:ignored, _}, &1)) |> Enum.count()
defp count_garbage(_other), do:
0
defmacrop parser(parser_generator) do
quote do
fn input -> parse(unquote(parser_generator), input) end
end
end
defp group(), do:
parser(
sequence([char(?{), zero_or_more(group_element()), char(?})])
|> map(fn [?{, members, ?}] -> {:group, members} end)
)
defp group_element(), do:
parser(one_of([group(), garbage(), char_except(?})]))
defp garbage(), do:
parser(
sequence([char(?<), zero_or_more(garbage_element()), char(?>)])
|> map(fn [?<, members, ?>] -> {:garbage, members} end)
)
defp garbage_element(), do:
parser(one_of([ignored_char(), char_except(?>)]))
defp ignored_char(), do:
parser(
sequence([char(?!), char()])
|> map(fn [?!, char] -> {:ignored, char} end)
)
defp parse(parser, input), do:
parser.(input)
defp map(parser, mapper) do
fn input ->
with {element, rest} <- parser.(input), do:
{mapper.(element), rest}
end
end
defp sequence(parsers) do
fn input ->
case parsers do
[] -> {[], input}
[parser | others] ->
with \
{element, rest} <- parser.(input),
{other_elements, rest} <- parse(sequence(others), rest),
do: {[element | other_elements], rest}
end
end
end
defp char() do
fn
<<char::utf8, rest::binary>> -> {char, rest}
_other -> nil
end
end
defp char(value) do
fn
<<^value::utf8, rest::binary>> -> {value, rest}
_other -> nil
end
end
defp char_except(value) do
fn
<<^value::utf8, _::binary>> -> nil
<<char::utf8, rest::binary>> -> {char, rest}
end
end
defp zero_or_more(parser) do
fn input ->
case parser.(input) do
{element, rest} ->
{other_elements, rest} = parse(zero_or_more(parser), rest)
{[element | other_elements], rest}
nil -> {[], input}
end
end
end
defp one_of(parsers) do
fn input ->
case parsers do
[] -> nil
[parser | others] -> with nil <- parser.(input), do: parse(one_of(others), input)
end
end
end
end
Day9.part1() |> IO.inspect
Day9.part2() |> IO.inspect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment