My attempts to work through the 2021 Advent of Code problems.

```commit 56752f87bdf5006fee61ebbaadeb1c2d50b4b42e
parent dbeaa80a09e9536763b9d43aec12634492148d3f
Date:   Thu, 16 Dec 2021 16:10:56 -0500

Solution to day 2, part 2

Diffstat:
Mday16_classes.py | 49++++++++++++++++++++++++++++++++++++++++++++++++-
```
```2 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/day16_classes.py b/day16_classes.py
@@ -1,7 +1,9 @@
"""Class definitions for day 16 problems (and maybe other days, we'll see)"""
# I'm finally breaking down and doing OOP.

-from typing import List, Union
+from typing import List, Union, cast
+from functools import reduce
+from operator import mul

"""BitReader objects facilitate reading bits a few at a time from a stream
@@ -85,3 +87,48 @@ class Packet:
children packets (if there are any)"""
return self.version + \
sum([p.version_sum() for p in self.contents if isinstance(p, Packet)])
+
+    def operation_result(self) -> int:
+        """Perform the operation encoded in the current packet and return its
+        result"""
+        result: int = 0
+
+        if self.type_id == 4:
+            # Literal value packet: return the value
+            result = cast(int, self.contents[0])
+
+        else:
+            # We'll process all of this operator packet's children
+            child_results = [p.operation_result() for p in self.contents \
+                             if isinstance(p, Packet)]
+
+            if self.type_id == 0:
+                # sum Packet: return the sum of all subpackets
+                result = sum(child_results)
+
+            elif self.type_id == 1:
+                # product Packet
+                result = reduce(mul, child_results)
+
+            elif self.type_id == 2:
+                # minimum Packet
+                result = min(child_results)
+
+            elif self.type_id == 3:
+                # maximum Packet
+                result = max(child_results)
+
+            elif self.type_id == 5:
+                # greater than Packet: 1 if the first subpacket is greater than
+                # the second, otherwise 0
+                result = int(child_results[0] > child_results[1])
+
+            elif self.type_id == 6:
+                # less than Packet
+                result = int(child_results[0] < child_results[1])
+
+            else:
+                # equal Packet
+                result = int(child_results[0] == child_results[1])
+
+        return result
diff --git a/day16_part2.py b/day16_part2.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+"""Advent of Code 2021, day 16 (part 2): Packet Decoder
+Processing packets using the Buoyancy Interchange Transmission System (BITS)"""
+
+# Not only am I defining classes for the first time, I'm also allowing myself
+# to change part 1 code in order to complete part 2 (I had a feeling I'd be
+# adding features to my Packet class)
+
+from utils import get_puzzle_input
+
+def solve_puzzle(input_string: str) -> int:
+    """Return the numeric solution to the puzzle"""
+
+def main() -> None:
+    """Run when the file is called as a script"""
+    assert solve_puzzle("C200B40A82") == 3
+    assert solve_puzzle("04005AC33890") == 54
+    assert solve_puzzle("880086C3E88112") == 7
+    assert solve_puzzle("CE00C43D881120") == 9
+    assert solve_puzzle("D8005AC2A8F0") == 1
+    assert solve_puzzle("F600BC2D8F") == 0
+    assert solve_puzzle("9C005AC2F8F0") == 0
+    assert solve_puzzle("9C0141080250320F1802104A08") == 1
+
+    print("Packet expression result:",
+          solve_puzzle(get_puzzle_input(16)))
+
+if __name__ == "__main__":
+    main()
```