Moon Aufgabe

This commit is contained in:
Kata committed 2026-11-12 14:26:07 +01:00
1 parent a9c95dfc03
commit 0c59c96407
3 files changed
+210

No files matched your search

+23
View File
@@ -59,6 +59,29 @@ def matmul(matrix_a: Matrix, matrix_b: Matrix) -> Matrix:
import math
def matvec(a: Matrix, v: list[float]) -> list[float]:
"""Return the product of a matrix and a column vector.
Parameters
----------
a: list[list[float]]
Matrix of shape ``(m, n)``.
v: list[float]
Column vector of shape ``(n,)``.
Returns
-------
list[float]
Resulting vector of shape ``(m,)``.
"""
if not isinstance(a, list) or not isinstance(v, list):
raise TypeError("Matrix and vector must be lists of numbers.")
if not a or not a[0] or not v:
raise ValueError("Matrix and vector must be non-empty.")
if any(len(row) != len(v) for row in a):
raise ValueError(f"Inner dimensions mismatch: vector has {len(v)} entries.")
return [sum(x * y for x, y in zip(row, v)) for row in a]
def rot_2D(theta: float) -> Matrix:
"""Return a 2×2 rotation matrix for the given angle ``theta``.
+110
View File
@@ -0,0 +1,110 @@
"""Basisklasse ``Game`` für einfache pygame-Anwendungen."""
import pygame
class Game:
"""Basisklasse für pygame-Spiele.
Unterklassen passen das Verhalten durch Überschreiben von
:meth:`handle_event`, :meth:`update_game` und :meth:`draw_game` an.
"""
def __init__(
self,
title: str,
fps: int = 60,
size: tuple[int, int] = (640, 400),
) -> None:
"""Legt Fenstertitel, Bildrate und Fenstergröße fest.
Args:
title: Titel des Fensters.
fps: Maximale Bilder pro Sekunde.
size: Fenstergröße als (Breite, Höhe) in Pixeln.
"""
self.title: str = title
self.fps: int = fps
self.size: tuple[int, int] = size
self.clock: pygame.time.Clock = pygame.time.Clock()
self.dt: float = 0
self.screen: pygame.Surface | None = None
def init_game(self) -> None:
"""Initialisiert pygame und erzeugt das Fenster."""
pygame.init()
pygame.display.set_caption(self.title)
self.screen = pygame.display.set_mode(self.size)
def game_loop(self) -> None:
"""Führt die Hauptschleife aus, bis Events oder Update ``False`` liefern."""
while True:
# Berechnung der Zeitdifferenz seit dem letzten Frame
self.dt = self.clock.tick(self.fps) / 1000
if self.event_handling() == False:
break
if self.update_game() == False:
break
self.draw_game()
def exit_game(self) -> None:
"""Beendet pygame."""
pygame.quit()
def clear(self, color: tuple[int, int, int] = (0, 0, 0)) -> None:
"""Füllt den Bildschirm mit einer Hintergrundfarbe.
Args:
color: Hintergrundfarbe als (R, G, B).
"""
self.screen.fill(color)
def display(self) -> None:
"""Bringt den gezeichneten Frame zur Anzeige."""
pygame.display.flip()
def event_handling(self) -> bool:
"""Verteilt alle anstehenden Events an :meth:`handle_event`.
Bleibt in der Unterklasse unverändert.
Returns:
``False``, sobald ein Event das Spiel beenden soll, sonst ``True``.
"""
for event in pygame.event.get():
if not self.handle_event(event):
return False
return True
def handle_event(self, event: pygame.event.Event) -> bool:
"""Verarbeitet ein einzelnes Event.
Wird in der Unterklasse überschrieben.
Args:
event: Das zu verarbeitende pygame-Event.
Returns:
``False`` bei ``pygame.QUIT``, sonst ``True``.
"""
if event.type == pygame.QUIT:
return False
return True
def update_game(self) -> bool:
"""Aktualisiert den Spielzustand um einen Frame.
Returns:
``False``, wenn das Spiel beendet werden soll, sonst ``True``.
"""
return True
def draw_game(self) -> None:
"""Zeichnet den aktuellen Frame und bringt ihn zur Anzeige."""
pygame.display.flip()
def run(self) -> None:
"""Startet das Spiel: Initialisierung, Hauptschleife, Beenden."""
self.init_game()
self.game_loop()
self.exit_game()
+77
View File
@@ -0,0 +1,77 @@
"""Der Mond kreist um die Erde."""
import pygame
from compute import matvec, rot_2D
from game import Game
EARTH_RADIUS = 30
MOON_RADIUS = 10
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
MOON_DIST = 120 # Abstand Erde -> Mond
ANGLE = 0.02 # Drehwinkel pro Bild
class Moon(Game):
"""Der Mond kreist um die Erde."""
def __init__(
self,
title: str = "Moon",
fps: int = 60,
size: tuple[int, int] = (640, 400),
) -> None:
"""Legt Startposition, Drehwinkel und Rotationsmatrix fest."""
super().__init__(title, fps, size)
self.center = (size[0] / 2, size[1] / 2) # Erdposition
self.angle = self.drehwinkel() # Drehwinkel pro Bild
self.pos = self.startposition() # Vektor relativ zur Erde
def drehwinkel(self) -> float:
"""Winkel, um den pro Bild weitergedreht wird (Hook für Apollo)."""
return ANGLE
def startposition(self) -> list[float]:
"""Startposition als Vektor relativ zum Mittelpunkt."""
return [MOON_DIST, 0.0]
def update_game(self) -> bool:
"""Dreht den Mond ein Stück weiter."""
self.pos = self.drehe(self.pos)
return True
def drehe(self, vektor: list[float]) -> list[float]:
"""Dreht einen Vektor mit der Rotationsmatrix weiter."""
return matvec(rot_2D(self.angle), vektor)
def absolut(self, vektor: list[float]) -> tuple[float, float]:
"""Rechnet einen relativen Vektor in Bildschirmkoordinaten um."""
return (self.center[0] + vektor[0], self.center[1] + vektor[1])
def draw_game(self) -> None:
"""Zeichnet Erde und Mond."""
self.draw_space()
self.display()
def draw_space(self):
self.clear()
self.draw_earth()
self.draw_body(self.absolut(self.pos), MOON_RADIUS, WHITE)
def draw_earth(self) -> None:
"""Zeichnet die Erde ins Zentrum."""
pygame.draw.circle(self.screen, BLUE, self.center, EARTH_RADIUS)
def draw_body(
self, pos: tuple[float, float],
radius: int, farbe: tuple[int, int, int],
) -> None:
"""Zeichnet einen Himmelskörper an einer Position."""
pygame.draw.circle(self.screen, farbe, pos, radius)
if __name__ == "__main__":
moon = Moon()
moon.run()