Day16 - BitString+AST
Untitled
data =
"input"
|> IO.getn(1_000_000)
|> String.trim()
|> :binary.decode_hex()
defmodule D16 do
def parse(data) do
{data, %{}}
|> parse_meta(:version)
|> parse_meta(:type)
|> parse_by_type()
end
def parse_meta({<>, meta}, meta_key) do
{rest, Map.put(meta, meta_key, meta_value)}
end
def parse_by_type({data, %{type: 4} = meta}) do
{literal, rest} = parse_literal(data)
{{bits_to_int(literal), rest}, meta}
end
def parse_by_type({data, meta}) do
{parse_operator(data), meta}
end
def parse_literal(<<1::1, n::4, rest::bitstring>>) do
{data, rest} = parse_literal(rest)
{<>, rest}
end
def parse_literal(<<0::1, n::4, rest::bitstring>>) do
{<>, rest}
end
def parse_operator(<<0::1, length::15, rest::bitstring>>) do
<> = rest
{parse_sub(payload), rest}
end
def parse_operator(<<1::1, length::11, rest::bitstring>>) do
{data, [rest]} = Enum.split(parse_sub(rest, length), -1)
{data, rest}
end
def parse_sub(<<>>), do: []
def parse_sub(data) do
{{data, rest}, meta} = parse(data)
[{{data, []}, meta} | parse_sub(rest)]
end
def parse_sub(rest, 0), do: [rest]
def parse_sub(data, n) do
{{data, rest}, meta} = parse(data)
[{{data, []}, meta} | parse_sub(rest, n - 1)]
end
def solve1({{data, _rest}, meta}) when is_list(data) do
meta.version + (data |> Enum.map(&solve1/1) |> Enum.sum())
end
def solve1({{_data, _rest}, meta}) do
meta.version
end
def solve2({{data, _}, %{type: 0}}) do
data |> Enum.map(&solve2/1) |> unroll(:+)
end
def solve2({{data, _}, %{type: 1}}) do
data |> Enum.map(&solve2/1) |> unroll(:*)
end
def solve2({{data, _}, %{type: 2}}) do
data |> Enum.map(&solve2/1) |> unroll(:min)
end
def solve2({{data, _}, %{type: 3}}) do
data |> Enum.map(&solve2/1) |> unroll(:max)
end
def solve2({{data, _}, %{type: 4}}) do
data
end
def solve2({{data, _}, %{type: 5}}) do
data |> Enum.map(&solve2/1) |> branch(:>)
end
def solve2({{data, _}, %{type: 6}}) do
data |> Enum.map(&solve2/1) |> branch(:<)
end
def solve2({{data, _}, %{type: 7}}) do
data |> Enum.map(&solve2/1) |> branch(:==)
end
defp branch([left, right], op) do
{:||, [],
[
{:&&, [],
[
{op, [], [left, right]},
1
]},
0
]}
end
defp unroll([e1, e2], op) do
{op, [], [e1, e2]}
end
defp unroll([e], _op) do
e
end
defp unroll([e | l], op) do
{op, [], [e, unroll(l, op)]}
end
defp bits_to_int(bits) do
s = bit_size(bits)
<> = bits
int
end
end
data
|> D16.parse()
|> D16.solve1()
data
|> D16.parse()
|> D16.solve2()
|> Code.eval_quoted()