diff --git a/.idea/matrixmania.iml b/.idea/matrixmania.iml
index 9497d65..017f321 100644
--- a/.idea/matrixmania.iml
+++ b/.idea/matrixmania.iml
@@ -7,8 +7,4 @@
-
-
-
-
\ No newline at end of file
diff --git a/compute.py b/compute.py
index c5c3845..98d9800 100644
--- a/compute.py
+++ b/compute.py
@@ -1,17 +1,7 @@
-"""Matrix multiplication with explicit dimension checks.
-
-This module provides a pure‑Python implementation that
-- validates input dimensions and structure
-- performs generic matrix multiplication without external libs
-- raises informative ``ValueError`` when inputs are inconsistent.
-
-The implementation is small but fully typed so it can be
-imported into other projects or used as a teaching example.
-"""
-
from __future__ import annotations
from collections.abc import Sequence
+import math
Matrix = Sequence[Sequence[float]]
@@ -67,6 +57,23 @@ def matmul(left: Matrix, right: Matrix) -> list[list[float]]:
# Helper to validate a matrix is non‑empty and rectangular.
+def rot_2D(theta: float) -> list[list[float]]:
+ """Return the 2‑D rotation matrix for a given angle.
+
+ Parameters
+ ----------
+ theta
+ Rotation angle in radians.
+
+ Returns
+ -------
+ list[list[float]]
+ 2×2 rotation matrix ``[[cosθ, -sinθ], [sinθ, cosθ]]``.
+ """
+ c = math.cos(theta)
+ s = math.sin(theta)
+ return [[c, -s], [s, c]]
+
def _validate(matrix: Matrix, name: str) -> None:
"""Check that *matrix* is a non‑empty, rectangular 2D sequence.
@@ -158,55 +165,10 @@ if __name__ == "__main__":
matmul([[1, 2, 3]], [[1, 2]])
except ValueError as error:
print("example 3 passed:", error)
-else:
- raise AssertionError("example 3 failed: no ValueError raised")
-if __name__ == "__main__":
- # Example 1: standard 2x3 * 3x2 multiplication.
- a = [
- [1, 2, 3],
- [4, 5, 6],
- ]
- b = [
- [7, 8],
- [9, 10],
- [11, 12],
- ]
- expected = [
- [58, 64],
- [139, 154],
- ]
- assert matmul(a, b) == expected, f"example 1 failed: {matmul(a, b)}"
- print("example 1 passed:", matmul(a, b))
- # Example 2: multiplication with the identity matrix changes nothing.
- identity = [
- [1, 0, 0],
- [0, 1, 0],
- [0, 0, 1],
- ]
- c = [
- [2, -1, 0],
- [0, 3, 4],
- [5, 6, -2],
- ]
- assert matmul(c, identity) == c, "example 2 failed"
- print("example 2 passed:", matmul(c, identity))
+ # end of main guard
- # Example 3: mismatched dimensions must raise ValueError.
- try:
- matmul([[1, 2, 3]], [[1, 2]])
- except ValueError as error:
- print("example 3 passed:", error)
- else:
- raise AssertionError("example 3 failed: no ValueError raised")
-
- # Example 4: Demonstration of the transpose function.
- example_matrix = [[1, 2, 3], [4, 5, 6]]
- transposed = transpose(example_matrix)
- print("Example 4: transpose([[1,2,3],[4,5,6]]) =", transposed)
- assert transposed == [[1, 4], [2, 5], [3, 6]], "Example 4 failed"
- print("example 4 passed")
diff --git a/game.py b/game.py
new file mode 100644
index 0000000..c3987a2
--- /dev/null
+++ b/game.py
@@ -0,0 +1,37 @@
+
+import pygame
+
+
+class Game:
+ """Basic Pygame game loop.
+
+ Subclasses **must** implement:
+ * ``update_game`` – update state, return ``False`` to quit.
+ * ``draw_game`` – render to the screen.
+ """
+
+ def __init__(self, title: str, fps: int, size: tuple[int, int]):
+ pygame.init()
+ self.screen = pygame.display.set_mode(size)
+ pygame.display.set_caption(title)
+ self.clock = pygame.time.Clock()
+ self.fps = fps
+ self.size = size
+
+ def run(self) -> None:
+ running = True
+ while running:
+ for event in pygame.event.get():
+ if event.type == pygame.QUIT:
+ running = False
+ running = self.update_game()
+ self.draw_game()
+ pygame.display.flip()
+ self.clock.tick(self.fps)
+ pygame.quit()
+
+ def update_game(self) -> bool:
+ raise NotImplementedError
+
+ def draw_game(self) -> None:
+ raise NotImplementedError
diff --git a/moon.py b/moon.py
new file mode 100644
index 0000000..8810f4d
--- /dev/null
+++ b/moon.py
@@ -0,0 +1,69 @@
+"""Moon orbital simulation demo.
+
+This module defines :class:`Moon` which subclasses :class:`game.Game` and
+uses :func:`compute.rot_2D` and :func:`compute.matmul` to animate a moon
+orbiting the Earth.
+
+The original repository contained a fully functional example, but the
+``moon.py`` file was overwritten by another module during a previous
+edit. The following implementation restores the expected behaviour.
+"""
+
+from __future__ import annotations
+
+import pygame
+
+from compute import rot_2D, matmul
+from game import Game
+
+
+EARTH_RADIUS = 30
+MOON_RADIUS = 10
+BLACK = (0, 0, 0)
+WHITE = (255, 255, 255)
+BLUE = (0, 0, 255)
+
+
+class Moon(Game):
+ """Demonstrates a moon orbiting the Earth using matrix rotation."""
+
+ def __init__(self, title: str = "Moon", fps: int = 60, size: Tuple[int, int] = (640, 400)) -> None:
+ super().__init__(title, fps, size)
+ # Earth centre – centre of the window
+ self.center: Tuple[int, int] = (size[0] // 2, size[1] // 2)
+ # Fixed orbit offset from the centre
+ self.offset: Tuple[float, float] = (100.0, 0.0)
+ # Angular speed (radians per frame)
+ self.delta_theta: float = 0.01
+ self.theta: float = 0.0
+ self.rot_moon: list[list[float]] = rot_2D(self.theta)
+
+ def update_game(self) -> bool:
+ # Advance the angle and recompute the rotation matrix
+ self.theta += self.delta_theta
+ self.rot_moon = rot_2D(self.theta)
+ # Rotate the fixed offset vector
+ point = [[self.offset[0]], [self.offset[1]]]
+ result = matmul(self.rot_moon, point)
+ # Translate back to screen coordinates
+ self.position_moon = (
+ self.center[0] + result[0][0],
+ self.center[1] + result[1][0],
+ )
+ return True
+
+ def draw_game(self) -> None:
+ self.screen.fill(BLACK)
+ pygame.draw.circle(self.screen, BLUE, self.center, EARTH_RADIUS)
+ pygame.draw.circle(
+ self.screen,
+ WHITE,
+ (int(self.position_moon[0]), int(self.position_moon[1])),
+ MOON_RADIUS,
+ )
+
+
+if __name__ == "__main__":
+ moon = Moon()
+ moon.run()
+