Add 2021-16 in Python

Signed-off-by: AKU <tom@tdpain.net>
This commit is contained in:
akp 2021-12-17 09:39:14 +00:00
parent 47c497080e
commit 736c040328
No known key found for this signature in database
GPG key ID: AA5726202C8879B7
6 changed files with 234 additions and 0 deletions

View file

@ -0,0 +1,15 @@
{
"day": 15,
"dir": "challenges/2021/15-chiton",
"implementations": {
"Python": {
"part.1.avg": 0.05848939180374146,
"part.1.max": 0.22109389305114746,
"part.1.min": 0.03475213050842285,
"part.2.avg": 0.00003055143356323242,
"part.2.max": 0.0002415180206298828,
"part.2.min": 0.000008344650268554688
}
},
"numRuns": 1000
}

View file

@ -0,0 +1,2 @@
# [Day 16: Packet Decoder](https://adventofcode.com/2021/day/16)

View file

@ -0,0 +1,15 @@
{
"day": 16,
"dir": "challenges/2021/16-packetDecoder",
"implementations": {
"Python": {
"part.1.avg": 0.002915963888168335,
"part.1.max": 0.011673688888549805,
"part.1.min": 0.0016696453094482422,
"part.2.avg": 0.0029851856231689453,
"part.2.max": 0.019982337951660156,
"part.2.min": 0.0017099380493164062
}
},
"numRuns": 1000
}

View file

@ -0,0 +1,57 @@
{
"inputFile": "input.txt",
"testCases": {
"one": [
{
"input": "8A004A801A8002F478",
"expected": "16"
},
{
"input": "620080001611562C8802118E34",
"expected": "12"
},
{
"input": "C0015000016115A2E0802F182340",
"expected": "23"
},
{
"input": "A0016C880162017C3686B18A3D4780",
"expected": "31"
}
],
"two": [
{
"input": "C200B40A82",
"expected": "3"
},
{
"input": "04005AC33890",
"expected": "54"
},
{
"input": "880086C3E88112",
"expected": "7"
},
{
"input": "CE00C43D881120",
"expected": "9"
},
{
"input": "D8005AC2A8F0",
"expected": "1"
},
{
"input": "F600BC2D8F",
"expected": "0"
},
{
"input": "9C005AC2F8F0",
"expected": "0"
},
{
"input": "9C0141080250320F1802104A08",
"expected": "1"
}
]
}
}

View file

@ -0,0 +1,144 @@
from dataclasses import dataclass
from typing import Any, List, SupportsIndex
from aocpy import BaseChallenge
class Consumer:
def __init__(self, instr: str):
self.input = instr
self.pointer = 0
def get(self) -> str:
return self.get_n(1)
def get_n(self, n) -> str:
self.pointer += n
if self.pointer > len(self.input):
raise IndexError("index out of bounds")
return self.input[self.pointer-n:self.pointer]
def finished(self) -> bool:
return len(self.input) == self.pointer
@dataclass
class Packet:
version: int
type_indicator: int
content: Any
def hex_to_binary_string(n: str) -> str:
o = ""
for char in n:
o += bin(int(char, base=16))[2:].zfill(4)
return o
def from_binary_string(x: str) -> int:
return int(x, base=2)
def decode_all(input_stream: Consumer) -> List[Packet]:
o = []
while True:
try:
o.append(decode_one(input_stream))
except IndexError:
break
return o
def decode_one(input_stream: Consumer) -> Packet:
version = from_binary_string(input_stream.get_n(3))
packet_type = from_binary_string(input_stream.get_n(3))
if packet_type == 4:
literal_number = 0
while True:
continue_bit = from_binary_string(input_stream.get())
literal_number = (literal_number << 4) | from_binary_string(input_stream.get_n(4))
if continue_bit == 0:
break
return Packet(version, packet_type, literal_number)
else:
length_type = from_binary_string(input_stream.get())
if length_type == 0:
# 15 bit subpackt length indicator
run_length = from_binary_string(input_stream.get_n(15))
content = decode_all(Consumer(input_stream.get_n(run_length)))
return Packet(version, packet_type, content)
else:
# 11 bit subpacket count
subpacket_count = from_binary_string(input_stream.get_n(11))
content = []
for _ in range(subpacket_count):
content.append(decode_one(input_stream))
return Packet(version, packet_type, content)
def parse(instr: str) -> List[Packet]:
return decode_all(Consumer(hex_to_binary_string(instr.strip())))
def sum_version_numbers(packets: List[Packet]) -> int:
sigma = 0
for packet in packets:
sigma += packet.version
if type(packet.content) == list:
sigma += sum_version_numbers(packet.content)
return sigma
def interpet_packet(packet: Packet) -> int:
if packet.type_indicator == 0:
# sum packet
sigma = 0
for subpacket in packet.content:
sigma += interpet_packet(subpacket)
return sigma
elif packet.type_indicator == 1:
# product packet
product = 1
for subpacket in packet.content:
product *= interpet_packet(subpacket)
return product
elif packet.type_indicator == 2:
# min packet
vals = []
for subpacket in packet.content:
vals.append(interpet_packet(subpacket))
return min(vals)
elif packet.type_indicator == 3:
# max packet
vals = []
for subpacket in packet.content:
vals.append(interpet_packet(subpacket))
return max(vals)
elif packet.type_indicator == 4:
return packet.content
elif packet.type_indicator == 5:
# greater than packet
first = interpet_packet(packet.content[0])
second = interpet_packet(packet.content[1])
return 1 if first > second else 0
elif packet.type_indicator == 6:
# less than packet
first = interpet_packet(packet.content[0])
second = interpet_packet(packet.content[1])
return 1 if first < second else 0
elif packet.type_indicator == 7:
# equal to packet
first = interpet_packet(packet.content[0])
second = interpet_packet(packet.content[1])
return 1 if first == second else 0
else:
raise ValueError(f"unknown packet type {packet.type_indicator}")
class Challenge(BaseChallenge):
@staticmethod
def one(instr: str) -> int:
packets = parse(instr)
return sum_version_numbers(packets)
@staticmethod
def two(instr: str) -> int:
packets = parse(instr)
return interpet_packet(packets[0])

View file

@ -27,6 +27,7 @@ Solutions to the [2021 Advent of Code](https://adventofcode.com/2021).
| 13 - Transparent Origami | ★ ★ | [Python](13-transparentOrigami/py), [Nim](13-transparentOrigami/nim) | I got stuck for hours on an intermittent off-by-one error. :( |
| 14 - Extended Polymerization | ★ ★ | [Python](14-extendedPolymerization/py) | Another off-by-one error, but this time it was because of dodgy division. Wonderful. |
| 15 - Chiton | ★ ☆ | [Python](15-chiton/py) | Pathfinding is hard |
| 16 - Packet Decoder | ★ ★ | [Python](16-packetDecoder/py) | Parsing and interpreting stuff is surprisingly enjoyable |
<!-- PARSE END -->