aoc2021/day16.py
2021-12-16 09:05:38 +01:00

126 lines
3.9 KiB
Python

from math import prod
from tools.aoc import AOCDay
from typing import Any, List
def get_packet(bit_rep: str) -> (int, int, str, int): # version, type, packet, packet_length
msg_version = int(bit_rep[:3], 2)
msg_type = int(bit_rep[3:6], 2)
pkg_msg = ""
index = 6
if msg_type == 4:
while bit_rep[index] == "1":
pkg_msg += bit_rep[index+1:index+5]
index += 5
pkg_msg += bit_rep[index:index + 5]
index += 5
else:
op_type = bit_rep[index]
index += 1
if op_type == "0":
sub_pkg_len = int(bit_rep[index:index+15], 2)
index += 15 + sub_pkg_len
else:
sub_pkg_count = int(bit_rep[index:index+11], 2)
index += 11
for x in range(sub_pkg_count):
_, _, _, sub_pkg_len = get_packet(bit_rep[index:])
index += sub_pkg_len
return msg_version, msg_type, bit_rep[:index], index
def get_subpackages(packet: str) -> List[str]:
ptype = int(packet[3:6], 2)
if ptype == 4:
return [packet]
else:
plist = []
op_type = packet[6]
if op_type == "0":
sub_pkg_len = int(packet[7:22], 2)
sub_packages = packet[22:22+sub_pkg_len]
while "1" in sub_packages:
_, _, sub_packet, sub_pkg_len = get_packet(sub_packages)
sub_packages = sub_packages[sub_pkg_len:]
plist.append(sub_packet)
else:
sub_pkg_count = int(packet[7:18], 2)
index = 18
for x in range(sub_pkg_count):
_, _, sub_packet, sub_pkg_len = get_packet(packet[index:])
index += sub_pkg_len
plist.append(sub_packet)
return plist
def get_versions(packet: str) -> int:
version = int(packet[0:3], 2)
ptype = int(packet[3:6], 2)
if ptype == 4:
return version
else:
for p in get_subpackages(packet):
version += get_versions(p)
return version
def get_value(packet: str) -> int:
while "1" in packet:
pkg_version, pkg_type, this_packet, pkg_len = get_packet(packet)
packet = packet[pkg_len:]
if pkg_type == 0:
return sum(get_value(p) for p in get_subpackages(this_packet))
elif pkg_type == 1:
return prod(get_value(p) for p in get_subpackages(this_packet))
elif pkg_type == 2:
return min(get_value(p) for p in get_subpackages(this_packet))
elif pkg_type == 3:
return max(get_value(p) for p in get_subpackages(this_packet))
elif pkg_type == 4:
index = 6
pkg_bits = ""
while this_packet[index] == "1":
pkg_bits += this_packet[index + 1:index + 5]
index += 5
pkg_bits += this_packet[index + 1:index + 5]
return int(pkg_bits, 2)
elif pkg_type == 5:
sub_pkg = get_subpackages(this_packet)
return get_value(sub_pkg[0]) > get_value(sub_pkg[1])
elif pkg_type == 6:
sub_pkg = get_subpackages(this_packet)
return get_value(sub_pkg[0]) < get_value(sub_pkg[1])
elif pkg_type == 7:
sub_pkg = get_subpackages(this_packet)
return get_value(sub_pkg[0]) == get_value(sub_pkg[1])
class Day(AOCDay):
test_solutions_p1 = [16, 12, 23, 31, 1007]
test_solutions_p2 = [3, 54, 7, 9, 1, 0, 0, 1, 834151779165]
def part1(self) -> Any:
bit_rep = ""
for c in self.getInput():
bit_rep += "{0:04b}".format(int(c, 16))
version_sum = 0
while "1" in bit_rep:
pkg_version, pkg_type, packet, pkg_len = get_packet(bit_rep)
bit_rep = bit_rep[pkg_len:]
version_sum += get_versions(packet)
return version_sum
def part2(self) -> Any:
bit_rep = ""
for c in self.getInput():
bit_rep += "{0:04b}".format(int(c, 16))
return get_value(bit_rep)