117 lines
2.8 KiB
Julia
117 lines
2.8 KiB
Julia
|
using Pkg
|
||
|
Pkg.add("Match")
|
||
|
using Match
|
||
|
|
||
|
include("utils.jl")
|
||
|
|
||
|
function parse_input(filename)
|
||
|
reverse(collect(collect(non_empty_lines(filename))[1]))
|
||
|
end
|
||
|
|
||
|
mutable struct BinaryReader
|
||
|
input
|
||
|
rest
|
||
|
BinaryReader(input) = new(input, [])
|
||
|
end
|
||
|
|
||
|
function fill_rest(reader)
|
||
|
char = pop!(reader.input)
|
||
|
code = codepoint(char)
|
||
|
number = code < 0x3A ? code - 0x30 : code - (0x41 - 10)
|
||
|
reader.rest = reverse(parse.(Int, collect(string(number, base=2, pad=4))))
|
||
|
end
|
||
|
|
||
|
function read_bits(reader, count)
|
||
|
result = []
|
||
|
while length(result) < count
|
||
|
if length(reader.rest) == 0
|
||
|
fill_rest(reader)
|
||
|
end
|
||
|
push!(result, pop!(reader.rest))
|
||
|
end
|
||
|
result
|
||
|
end
|
||
|
|
||
|
function reader_length(reader)
|
||
|
length(reader.rest) + length(reader.input) * 4
|
||
|
end
|
||
|
|
||
|
function to_int(bits)
|
||
|
parse(Int, reduce(*, string.(bits)), base=2)
|
||
|
end
|
||
|
|
||
|
function parse_literal(reader, version)
|
||
|
result = []
|
||
|
cont = 1
|
||
|
while cont == 1
|
||
|
cont = read_bits(reader, 1)[1]
|
||
|
result = [result; read_bits(reader, 4)]
|
||
|
end
|
||
|
(version, 4, to_int(result))
|
||
|
end
|
||
|
|
||
|
function parse_operator(reader, version, type)
|
||
|
length_type = read_bits(reader, 1)[1]
|
||
|
subpackets = []
|
||
|
if length_type == 0
|
||
|
subpacket_bits = to_int(read_bits(reader, 15))
|
||
|
start_remaining = reader_length(reader)
|
||
|
while reader_length(reader) + subpacket_bits > start_remaining
|
||
|
push!(subpackets, parse_packet(reader))
|
||
|
end
|
||
|
else
|
||
|
subpacket_count = to_int(read_bits(reader, 11))
|
||
|
for _ in 1:subpacket_count
|
||
|
push!(subpackets, parse_packet(reader))
|
||
|
end
|
||
|
end
|
||
|
(version, type, subpackets)
|
||
|
end
|
||
|
|
||
|
function parse_packet(reader)
|
||
|
version = to_int(read_bits(reader, 3))
|
||
|
type = to_int(read_bits(reader, 3))
|
||
|
if type == 4
|
||
|
parse_literal(reader, version)
|
||
|
else
|
||
|
parse_operator(reader, version, type)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function sum_versions(packet)
|
||
|
result = packet[1]
|
||
|
if packet[2] != 4
|
||
|
result += reduce(+, sum_versions.(packet[3]))
|
||
|
end
|
||
|
result
|
||
|
end
|
||
|
|
||
|
function solution16_1()
|
||
|
input = parse_input("16.data")
|
||
|
reader = BinaryReader(input)
|
||
|
packet = parse_packet(reader)
|
||
|
sum_versions(packet)
|
||
|
end
|
||
|
|
||
|
function value(packet)
|
||
|
@match packet[2] begin
|
||
|
0 => reduce(+, value.(packet[3]))
|
||
|
1 => reduce(*, value.(packet[3]))
|
||
|
2 => reduce(min, value.(packet[3]))
|
||
|
3 => reduce(max, value.(packet[3]))
|
||
|
4 => packet[3]
|
||
|
5 => value(packet[3][1]) > value(packet[3][2]) ? 1 : 0
|
||
|
6 => value(packet[3][1]) < value(packet[3][2]) ? 1 : 0
|
||
|
7 => value(packet[3][1]) == value(packet[3][2]) ? 1 : 0
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function solution16_2()
|
||
|
input = parse_input("16.data")
|
||
|
reader = BinaryReader(input)
|
||
|
packet = parse_packet(reader)
|
||
|
value(packet)
|
||
|
end
|
||
|
|
||
|
solution16_2()
|