From e02b552da35d58c48bdb339d175c7d0fd2f9f9d8 Mon Sep 17 00:00:00 2001 From: Anna Date: Thu, 22 Oct 2026 12:55:07 +0200 Subject: [PATCH] =?UTF-8?q?mond=20l=C3=A4uft?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/matrixmania.iml | 4 --- compute.py | 76 +++++++++++-------------------------------- game.py | 37 +++++++++++++++++++++ moon.py | 69 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 61 deletions(-) create mode 100644 game.py create mode 100644 moon.py 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() +