— Day 16: Packet Decoder —
Setup
defmodule Setup do
def get_input(prompt) do
case IO.gets(prompt) do
:eof -> ""
line -> line <> get_input(prompt)
end
end
def parse(binary) do
binary
|> String.trim()
|> :binary.decode_hex()
end
end
defmodule Decoder do
def read_packets(bits) do
case read_packet(bits) do
{:eof, _rest} ->
[]
{packet, rest} ->
[packet | read_packets(rest)]
end
end
def read_n_packets(bits, 0), do: {[], bits}
def read_n_packets(bits, n) do
{packet, rest} = read_packet(bits)
{packets, rest} = read_n_packets(rest, n - 1)
{[packet | packets], rest}
end
def read_packet(bits) when bit_size(bits) < 8, do: {:eof, bits}
def read_packet(<>), do: read_literal(rest, v)
def read_packet(<>) do
operants = read_packets(operants)
{{:operator, v, t, operants}, rest}
end
def read_packet(<>) do
{operants, rest} = read_n_packets(rest, l)
{{:operator, v, t, operants}, rest}
end
def read_literal(bits, version, acc \\ <<>>, len \\ 4)
def read_literal(<<1::1, literal::4, rest::bits>>, version, acc, len),
do: read_literal(rest, version, <>, len + 4)
def read_literal(<<0::1, literal::4, rest::bits>>, version, acc, len) do
<> = <>
{{:literal, version, number}, rest}
end
end
defmodule Packets do
def sum_versions(packets) do
packets
|> Enum.reduce(0, fn
{:literal, v, _}, acc ->
acc + v
{:operator, v, _t, operants}, acc ->
acc + v + sum_versions(operants)
end)
end
def opcode(0), do: &Enum.sum/1
def opcode(1), do: &Enum.product/1
def opcode(2), do: &Enum.min/1
def opcode(3), do: &Enum.max/1
def opcode(5), do: fn [l, r] -> if(l > r, do: 1, else: 0) end
def opcode(6), do: fn [l, r] -> if(l < r, do: 1, else: 0) end
def opcode(7), do: fn [l, r] -> if(l == r, do: 1, else: 0) end
def interpret({:literal, _, num}), do: num
def interpret({:operator, _, opcode, operants}) do
Enum.map(operants, &interpret/1) |> opcode(opcode).()
end
end
Part1
Setup.get_input("input")
|> Setup.parse()
|> Decoder.read_packets()
|> Packets.sum_versions()
Part2
Setup.get_input("input")
|> Setup.parse()
|> Decoder.read_packets()
|> List.first()
|> Packets.interpret()