aoc2021/16.jl

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()