From d122475f59730efe7a9badd74bf4b503e3b6d87b Mon Sep 17 00:00:00 2001 From: alex-ong Date: Sat, 30 Dec 2023 16:09:53 +1100 Subject: [PATCH] docs: day24 --- day24/__init__.py | 1 + day24/day24.py | 10 +++++++++- day24/lib/__init__.py | 1 + day24/lib/classes.py | 8 ++++++++ day24/lib/parsers.py | 15 +++++++++++++++ day24/tests/__init__.py | 1 + day24/tests/test_day24.py | 5 +++++ day24/tests/test_parsers.py | 3 +++ 8 files changed, 43 insertions(+), 1 deletion(-) diff --git a/day24/__init__.py b/day24/__init__.py index e69de29..836e386 100644 --- a/day24/__init__.py +++ b/day24/__init__.py @@ -0,0 +1 @@ +"""Day 24 solution.""" diff --git a/day24/day24.py b/day24/day24.py index 0f3465e..244e338 100644 --- a/day24/day24.py +++ b/day24/day24.py @@ -1,4 +1,4 @@ -"""day24 solution""" +"""day24 solution.""" from typing import Optional import z3 @@ -11,6 +11,7 @@ def get_intersection_2d(left: Hailstone, right: Hailstone) -> Optional[Vector2]: + """Returns intersection of two hailstones.""" pos1 = left.position.xy dir1 = left.velocity.xy pos2 = right.position.xy @@ -33,10 +34,15 @@ def get_intersection_2d(left: Hailstone, right: Hailstone) -> Optional[Vector2]: def within_2d(point: Vector2, min_max: Vector2) -> bool: + """Returns whether a point is inside a given rectangle. + + x and y are both symmetric and defined by min_max. + """ return min_max.x <= point.x <= min_max.y and min_max.x <= point.y <= min_max.y def part1(hailstones: list[Hailstone], valid_range: Vector2) -> int: + """Solve part1: list of hailstones that are within a given rectangle.""" result = 0 print(len(hailstones)) left: Hailstone @@ -55,6 +61,7 @@ def part1(hailstones: list[Hailstone], valid_range: Vector2) -> int: def part2(hailstones: list[Hailstone]) -> int: + """Solve part2: a magic hailstone that passes through all other hailstones.""" x, y, z = z3.Reals("x y z") vx, vy, vz = z3.Reals("vx vy vz") @@ -90,6 +97,7 @@ def part2(hailstones: list[Hailstone]) -> int: def main() -> None: + """Loads input then solves.""" input_data, valid_range = INPUT hailstones: list[Hailstone] = parse_input(input_data) diff --git a/day24/lib/__init__.py b/day24/lib/__init__.py index e69de29..b4731ce 100644 --- a/day24/lib/__init__.py +++ b/day24/lib/__init__.py @@ -0,0 +1 @@ +"""Day24 library modules.""" diff --git a/day24/lib/classes.py b/day24/lib/classes.py index 6660a63..cd88635 100644 --- a/day24/lib/classes.py +++ b/day24/lib/classes.py @@ -1,24 +1,32 @@ +"""Day24 classes.""" from dataclasses import dataclass @dataclass(frozen=True, slots=True) class Vector3: + """Simple 3d vector.""" + x: float y: float z: float @property def xy(self) -> "Vector2": + """Convert to vector2.""" return Vector2(self.x, self.y) @dataclass(frozen=True, slots=True) class Vector2: + """Simple vector2.""" + x: float y: float @dataclass(frozen=True) class Hailstone: + """Hailstone has a 3d vector for pos/velocity.""" + position: Vector3 velocity: Vector3 diff --git a/day24/lib/parsers.py b/day24/lib/parsers.py index e45f9fa..570a383 100644 --- a/day24/lib/parsers.py +++ b/day24/lib/parsers.py @@ -1,13 +1,28 @@ +"""Day23 parsers.""" from day24.lib.classes import Hailstone, Vector3 def parse_vector3(line: str) -> Vector3: + """Parse a vector3. + + E.g. 1,2,3 + """ line = line.strip() x, y, z = line.split(",") return Vector3(int(x), int(y), int(z)) def parse_input(filename: str) -> list[Hailstone]: + r"""Parse input lines. + + Lines in the format ``1,2,3@4,5,6\n``. + + Args: + filename (str): file to open + + Returns: + list[Hailstone]: list of Hailstones + """ result: list[Hailstone] = [] with open(filename, "r", encoding="utf8") as file: for line in file: diff --git a/day24/tests/__init__.py b/day24/tests/__init__.py index e69de29..97059e2 100644 --- a/day24/tests/__init__.py +++ b/day24/tests/__init__.py @@ -0,0 +1 @@ +"""day24 tests.""" diff --git a/day24/tests/test_day24.py b/day24/tests/test_day24.py index 910e0b7..a9e5612 100644 --- a/day24/tests/test_day24.py +++ b/day24/tests/test_day24.py @@ -1,21 +1,25 @@ +"""Test main functions in day24.""" from day24.day24 import INPUT_SMALL, get_intersection_2d, part1, part2, within_2d from day24.lib.classes import Hailstone, Vector2, Vector3 from day24.lib.parsers import parse_input def test_part1() -> None: + """Test ``part1()``.""" file_path, valid_range = INPUT_SMALL hailstones: list[Hailstone] = parse_input(file_path) assert part1(hailstones, valid_range) == 2 def test_part2() -> None: + """Test ``part2()``.""" file_path, valid_range = INPUT_SMALL hailstones: list[Hailstone] = parse_input(file_path) assert part2(hailstones) == 47 def test_get_intersection_2d() -> None: + """Test ``get_intersection_2d()``.""" hailstone_a = Hailstone(Vector3(20, 25, 34), Vector3(-2, -2, -4)) hailstone_b = Hailstone(Vector3(12, 31, 28), Vector3(-1, -2, -1)) @@ -23,6 +27,7 @@ def test_get_intersection_2d() -> None: def test_within_2d() -> None: + """Test ``within_2d()``.""" valid_range = Vector2(7, 27) v1 = Vector2(14 + 1 / 3, 15 + 1 / 3) v2 = Vector2(11 + 6 / 9, 16 + 6 / 9) diff --git a/day24/tests/test_parsers.py b/day24/tests/test_parsers.py index 9e57602..cb64e94 100644 --- a/day24/tests/test_parsers.py +++ b/day24/tests/test_parsers.py @@ -1,9 +1,11 @@ +"""Test parsing functions.""" from day24.day24 import INPUT_SMALL from day24.lib.classes import Hailstone, Vector3 from day24.lib.parsers import parse_input, parse_vector3 def test_vector3() -> None: + """Test ``parse_vector3()``.""" v1: Vector3 = parse_vector3(" 2, 4, 8") assert v1.x == 2 assert v1.y == 4 @@ -16,6 +18,7 @@ def test_vector3() -> None: def test_parser() -> None: + """Test ``parse_input()``.""" file_path, _ = INPUT_SMALL hailstones: list[Hailstone] = parse_input(file_path)