From 9487b4012775caa78ec0bb591aa4681d904d822b Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 28 Oct 2025 15:22:53 +0100 Subject: [PATCH] ha1 znd ue --- Hausaufgaben/ha1/.env | 20 +++++++ Hausaufgaben/ha1/1. Apollo.py | 41 +++++++++++++ Hausaufgaben/ha1/compute.py | 69 ++++++++++++++++++++++ Hausaufgaben/ha1/config.py | 105 ++++++++++++++++++++++++++++++++++ Hausaufgaben/ha1/game.py | 32 +++++++++++ Hausaufgaben/ha1/moon.py | 65 +++++++++++++++++++++ Übungen/compute.py | 69 ++++++++++++++++++++++ Übungen/game.py | 32 +++++++++++ Übungen/moon.py | 98 +++++++++++++++++++++++++++++++ Übungen/product.py | 23 ++++++++ Übungen/substr.py | 19 ++++++ 11 files changed, 573 insertions(+) create mode 100644 Hausaufgaben/ha1/.env create mode 100644 Hausaufgaben/ha1/1. Apollo.py create mode 100644 Hausaufgaben/ha1/compute.py create mode 100644 Hausaufgaben/ha1/config.py create mode 100644 Hausaufgaben/ha1/game.py create mode 100644 Hausaufgaben/ha1/moon.py create mode 100644 Übungen/compute.py create mode 100644 Übungen/game.py create mode 100644 Übungen/moon.py create mode 100644 Übungen/product.py create mode 100644 Übungen/substr.py diff --git a/Hausaufgaben/ha1/.env b/Hausaufgaben/ha1/.env new file mode 100644 index 0000000..c8249df --- /dev/null +++ b/Hausaufgaben/ha1/.env @@ -0,0 +1,20 @@ +# Anzeige +WIDTH=800 +HEIGHT=600 +FPS=60 +BG_COLOR=#0a0a14 + +# Erde +EARTH_COLOR=#2878ff +EARTH_RADIUS=30 + +# Mond +MOON_COLOR=#f0f0f0 +MOON_RADIUS=10 +MOON_ORBIT_RADIUS=160 +MOON_ANGULAR_SPEED_DEG=45 # Grad/Sekunde + +# Apollo (optional, nur falls apollo.py genutzt wird) +APOLLO_COLOR=#dc3232 +APOLLO_RADIUS=7 +APOLLO_ORBIT_RADIUS=40 diff --git a/Hausaufgaben/ha1/1. Apollo.py b/Hausaufgaben/ha1/1. Apollo.py new file mode 100644 index 0000000..106b8f8 --- /dev/null +++ b/Hausaufgaben/ha1/1. Apollo.py @@ -0,0 +1,41 @@ +from __future__ import annotations +import math +from typing import Tuple, List +import pygame # type: ignore + +from moon import Moon +import compute + + +class Apollo(Moon): + """Fügt die Apollo-Kapsel hinzu; liest alle Werte aus Settings (env).""" + + def get_apollo_angle(self) -> float: + # doppelte Winkelgeschwindigkeit, entgegengesetzte Richtung + return -2.0 * self.get_moon_angle() + + def get_apollo_position(self) -> Tuple[int, int]: + theta = self.get_apollo_angle() + r = float(self.settings.apollo_orbit_radius) + rot: List[List[float]] = [ + [math.cos(theta), -math.sin(theta)], + [math.sin(theta), math.cos(theta)], + ] + vec: List[List[float]] = [[r], [0.0]] + res = compute.matmul(rot, vec) + mx, my = self.get_moon_position() + return int(mx + res[0][0]), int(my + res[1][0]) + + def draw(self, surface: pygame.Surface) -> None: + super().draw(surface) + # kleine Orbit-Linie um den Mond (optional) + pygame.draw.circle( + surface, (90, 50, 50), self.get_moon_position(), self.settings.apollo_orbit_radius, width=1 + ) + ax, ay = self.get_apollo_position() + pygame.draw.circle(surface, self.settings.apollo_color, (ax, ay), self.settings.apollo_radius) + + +if __name__ == "__main__": + Apollo().run() + diff --git a/Hausaufgaben/ha1/compute.py b/Hausaufgaben/ha1/compute.py new file mode 100644 index 0000000..f0e8dcb --- /dev/null +++ b/Hausaufgaben/ha1/compute.py @@ -0,0 +1,69 @@ +from typing import List + +def matmul(A: List[List[float]], B: List[List[float]]) -> List[List[float]]: + """ + Multiplies two matrices A and B (nested Python lists). + + Requirements: + - A has shape (m x n), B has shape (n x p). + - All rows in A and B must have equal length. + - Elements are numeric (float/int). + + Args: + A: Left matrix, list of rows (m x n). + B: Right matrix, list of rows (n x p). + + Returns: + New matrix C = A * B with shape (m x p). + + Raises: + ValueError: If matrices are empty, ragged, + or shapes are incompatible. + + """ + if not A or not B: + raise ValueError("Empty matrices are not supported.") + if not A[0] or not B[0]: + raise ValueError("Matrices must have at least one column.") + + a_cols = len(A[0]) + + for row in A: + if len(row) != a_cols: + raise ValueError("Left matrix has inconsistent row lengths.") + b_cols = len(B[0]) + for row in B: + if len(row) != b_cols: + raise ValueError("Right matrix has inconsistent row lengths.") + + if a_cols != len(B): + raise ValueError( + f"Incompatible shapes: A is {len(A)}x{a_cols}, " + f"B is {len(B)}x{b_cols}; need cols(A) == rows(B)." + ) + + m, n, p = len(A), a_cols, b_cols + C: List[List[float]] = [[0 for _ in range(p)] for _ in range(m)] + + for i in range(m): + for k in range(n): + a_ik = A[i][k] + for j in range(p): + C[i][j] += a_ik * B[k][j] + + return C + + +if __name__ == "__main__": + matrix_a = [[3, 4, -1, 4], + [-2, 2, 5, 1]] + matrix_b = [[1, 3, -2], + [2, 5, 1], + [-1, 4, -4], + [2, 3, 6]] + matrix_c = matmul(matrix_a, matrix_b) + print("Ergebnis C = A * B:") + for row in matrix_c: + print(row) + + diff --git a/Hausaufgaben/ha1/config.py b/Hausaufgaben/ha1/config.py new file mode 100644 index 0000000..839cf52 --- /dev/null +++ b/Hausaufgaben/ha1/config.py @@ -0,0 +1,105 @@ +"""Konfigurations-Loader für das Moon/Apollo-Projekt. + +Lädt Werte aus .env in Umgebungsvariablen und stellt sie typisiert bereit. +Verwendet python-dotenv. Enthält Validierung & sinnvolle Defaults. +""" + +from __future__ import annotations + +import os +import re +from dataclasses import dataclass +from typing import Tuple + +from dotenv import load_dotenv + +# .env → os.environ laden +load_dotenv(override=False) + + +def _get_env(name: str, default: str) -> str: + val = os.getenv(name) + return val if val is not None and val != "" else default + + +def _parse_int(name: str, default: int, min_val: int | None = None) -> int: + raw = _get_env(name, str(default)) + try: + v = int(raw) + if min_val is not None and v < min_val: + raise ValueError + return v + except Exception as _: + return default + + +def _parse_float(name: str, default: float, min_val: float | None = None) -> float: + raw = _get_env(name, str(default)) + try: + v = float(raw) + if min_val is not None and v < min_val: + raise ValueError + return v + except Exception as _: + return default + + +_HEX = re.compile(r"^#?([0-9a-fA-F]{6})$") + + +def _parse_rgb(name: str, default_hex: str) -> Tuple[int, int, int]: + """Erlaubt '#rrggbb' oder 'rrggbb'. Fällt auf default zurück, wenn ungültig.""" + raw = _get_env(name, default_hex) + m = _HEX.match(raw) + hx = m.group(1) if m else default_hex.lstrip("#") + r = int(hx[0:2], 16) + g = int(hx[2:4], 16) + b = int(hx[4:6], 16) + return (r, g, b) + + +@dataclass(frozen=True) +class Settings: + # Anzeige + width: int + height: int + fps: int + bg_color: Tuple[int, int, int] + + # Erde + earth_color: Tuple[int, int, int] + earth_radius: int + + # Mond + moon_color: Tuple[int, int, int] + moon_radius: int + moon_orbit_radius: int + moon_angular_speed_deg: float # Grad/Sekunde + + # Apollo (optional) + apollo_color: Tuple[int, int, int] + apollo_radius: int + apollo_orbit_radius: int + + +def get_settings() -> Settings: + """Erzeugt Settings aus Umgebungsvariablen oder Defaults.""" + return Settings( + # Anzeige + width=_parse_int("WIDTH", 800, min_val=100), + height=_parse_int("HEIGHT", 600, min_val=100), + fps=_parse_int("FPS", 60, min_val=1), + bg_color=_parse_rgb("BG_COLOR", "#0a0a14"), + # Erde + earth_color=_parse_rgb("EARTH_COLOR", "#2878ff"), + earth_radius=_parse_int("EARTH_RADIUS", 30, min_val=1), + # Mond + moon_color=_parse_rgb("MOON_COLOR", "#f0f0f0"), + moon_radius=_parse_int("MOON_RADIUS", 10, min_val=1), + moon_orbit_radius=_parse_int("MOON_ORBIT_RADIUS", 160, min_val=10), + moon_angular_speed_deg=_parse_float("MOON_ANGULAR_SPEED_DEG", 45.0, min_val=0.1), + # Apollo + apollo_color=_parse_rgb("APOLLO_COLOR", "#dc3232"), + apollo_radius=_parse_int("APOLLO_RADIUS", 7, min_val=1), + apollo_orbit_radius=_parse_int("APOLLO_ORBIT_RADIUS", 40, min_val=5), + ) diff --git a/Hausaufgaben/ha1/game.py b/Hausaufgaben/ha1/game.py new file mode 100644 index 0000000..5ff21f3 --- /dev/null +++ b/Hausaufgaben/ha1/game.py @@ -0,0 +1,32 @@ +import pygame + +class Game: + def __init__(self, width=800, height=600, fps=60, title="Game"): + pygame.init() + self.width = width + self.height = height + self.fps = fps + self.title = title + self.screen = pygame.display.set_mode((width, height)) + pygame.display.set_caption(title) + self.clock = pygame.time.Clock() + self.running = True + + def run(self): + """Startet die Hauptschleife.""" + while self.running: + dt = self.clock.tick(self.fps) / 1000 # Zeit seit letztem Frame + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + self.update(dt) + self.draw(self.screen) + pygame.display.flip() + pygame.quit() + + + def update(self, dt: float): + pass + + def draw(self, surface: pygame.Surface): + pass diff --git a/Hausaufgaben/ha1/moon.py b/Hausaufgaben/ha1/moon.py new file mode 100644 index 0000000..df7bf85 --- /dev/null +++ b/Hausaufgaben/ha1/moon.py @@ -0,0 +1,65 @@ +from __future__ import annotations +import math +from typing import Tuple, List +import pygame # type: ignore + +from game import Game +import compute +from config import get_settings + + +class Moon(Game): + """Unterklasse von Game: Animation Mond-um-Erde mit .env-Konfiguration.""" + + def __init__(self) -> None: + self.settings = get_settings() + super().__init__( + width=self.settings.width, + height=self.settings.height, + fps=self.settings.fps, + title="Moon Orbit (env-configured)", + ) + self._theta: float = 0.0 + self._center: Tuple[float, float] = (self.width / 2, self.height / 2) + + # Hooks + def get_earth_center(self) -> Tuple[float, float]: + return self._center + + def get_moon_angle(self) -> float: + return self._theta + + def get_moon_orbit_radius(self) -> int: + return self.settings.moon_orbit_radius + + def get_moon_position(self) -> Tuple[int, int]: + theta = self.get_moon_angle() + r = float(self.get_moon_orbit_radius()) + rot: List[List[float]] = [ + [math.cos(theta), -math.sin(theta)], + [math.sin(theta), math.cos(theta)], + ] + vec: List[List[float]] = [[r], [0.0]] + res = compute.matmul(rot, vec) + cx, cy = self.get_earth_center() + return int(cx + res[0][0]), int(cy + res[1][0]) + + def update(self, dt: float) -> None: + omega = math.radians(self.settings.moon_angular_speed_deg) + self._theta = (self._theta + omega * dt) % (2.0 * math.pi) + + def draw(self, surface: pygame.Surface) -> None: + s = self.settings + surface.fill(s.bg_color) + + ex, ey = self.get_earth_center() + pygame.draw.circle(surface, s.earth_color, (int(ex), int(ey)), s.earth_radius) + + pygame.draw.circle(surface, (60, 60, 80), (int(ex), int(ey)), s.moon_orbit_radius, width=1) + + mx, my = self.get_moon_position() + pygame.draw.circle(surface, s.moon_color, (mx, my), s.moon_radius) + + +if __name__ == "__main__": + Moon().run() diff --git a/Übungen/compute.py b/Übungen/compute.py new file mode 100644 index 0000000..f0e8dcb --- /dev/null +++ b/Übungen/compute.py @@ -0,0 +1,69 @@ +from typing import List + +def matmul(A: List[List[float]], B: List[List[float]]) -> List[List[float]]: + """ + Multiplies two matrices A and B (nested Python lists). + + Requirements: + - A has shape (m x n), B has shape (n x p). + - All rows in A and B must have equal length. + - Elements are numeric (float/int). + + Args: + A: Left matrix, list of rows (m x n). + B: Right matrix, list of rows (n x p). + + Returns: + New matrix C = A * B with shape (m x p). + + Raises: + ValueError: If matrices are empty, ragged, + or shapes are incompatible. + + """ + if not A or not B: + raise ValueError("Empty matrices are not supported.") + if not A[0] or not B[0]: + raise ValueError("Matrices must have at least one column.") + + a_cols = len(A[0]) + + for row in A: + if len(row) != a_cols: + raise ValueError("Left matrix has inconsistent row lengths.") + b_cols = len(B[0]) + for row in B: + if len(row) != b_cols: + raise ValueError("Right matrix has inconsistent row lengths.") + + if a_cols != len(B): + raise ValueError( + f"Incompatible shapes: A is {len(A)}x{a_cols}, " + f"B is {len(B)}x{b_cols}; need cols(A) == rows(B)." + ) + + m, n, p = len(A), a_cols, b_cols + C: List[List[float]] = [[0 for _ in range(p)] for _ in range(m)] + + for i in range(m): + for k in range(n): + a_ik = A[i][k] + for j in range(p): + C[i][j] += a_ik * B[k][j] + + return C + + +if __name__ == "__main__": + matrix_a = [[3, 4, -1, 4], + [-2, 2, 5, 1]] + matrix_b = [[1, 3, -2], + [2, 5, 1], + [-1, 4, -4], + [2, 3, 6]] + matrix_c = matmul(matrix_a, matrix_b) + print("Ergebnis C = A * B:") + for row in matrix_c: + print(row) + + diff --git a/Übungen/game.py b/Übungen/game.py new file mode 100644 index 0000000..425c340 --- /dev/null +++ b/Übungen/game.py @@ -0,0 +1,32 @@ +import pygame + +class Game: + def __init__(self, width=800, height=600, fps=60, title="Game"): + pygame.init() + self.width = width + self.height = height + self.fps = fps + self.title = title + self.screen = pygame.display.set_mode((width, height)) + pygame.display.set_caption(title) + self.clock = pygame.time.Clock() + self.running = True + + def run(self): + """Startet die Hauptschleife.""" + while self.running: + dt = self.clock.tick(self.fps) / 1000 # Zeit seit letztem Frame + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + self.update(dt) + self.draw(self.screen) + pygame.display.flip() + pygame.quit() + + # Diese beiden Methoden überschreibst du in Unterklassen: + def update(self, dt: float): + pass + + def draw(self, surface: pygame.Surface): + pass diff --git a/Übungen/moon.py b/Übungen/moon.py new file mode 100644 index 0000000..a668273 --- /dev/null +++ b/Übungen/moon.py @@ -0,0 +1,98 @@ +""" +Mond-Animation mit pygame. + +Die Klasse Moon erbt von Game und zeigt: +- blaue Erde im Zentrum +- weißer Mond, der die Erde umkreist + +Mathematische Operationen (Rotationsmatrix * Vektor) +werden über compute.matmul() erledigt (Separation of Concerns). +""" + +from __future__ import annotations + +import math +from typing import Tuple, List +import pygame # type: ignore +from game import Game +import compute + + +class Moon(Game): + """Unterklasse von Game: Animation Mond-um-Erde.""" + + # --- Konfiguration (leicht anpassbar / erweiterbar) --- + WIDTH: int = 800 + HEIGHT: int = 600 + FPS: int = 60 + + EARTH_COLOR: Tuple[int, int, int] = (40, 120, 255) # Blau + MOON_COLOR: Tuple[int, int, int] = (240, 240, 240) # Weiß + BG_COLOR: Tuple[int, int, int] = (10, 10, 20) # Dunkel + ORBIT_COLOR: Tuple[int, int, int] = (60, 60, 80) # dezente Orbit-Linie + + EARTH_RADIUS: int = 30 + MOON_RADIUS: int = 10 + MOON_ORBIT_RADIUS: int = 160 + + # Winkelgeschwindigkeit des Mondes (rad/s) + MOON_ANGULAR_SPEED: float = math.radians(45.0) + + def __init__(self) -> None: + """Initialisiert Fenster, Farben und Startwerte.""" + super().__init__(width=self.WIDTH, height=self.HEIGHT, fps=self.FPS, title="Moon Orbit") + self._theta: float = 0.0 + self._center: Tuple[float, float] = (self.width / 2, self.height / 2) + + # --- Hooks: erleichtern Erweiterungen (OCP) --- + def get_earth_center(self) -> Tuple[float, float]: + """Zentrum der Erde (kann von Subklassen überschrieben werden).""" + return self._center + + def get_moon_angle(self) -> float: + """Aktueller Mond-Winkel in Radiant (kann überschrieben werden).""" + return self._theta + + def get_moon_orbit_radius(self) -> int: + """Orbit-Radius des Mondes um die Erde (Pixel).""" + return self.MOON_ORBIT_RADIUS + + def get_moon_position(self) -> Tuple[int, int]: + """Berechnet die aktuelle Mondposition (Bildschirmkoordinaten).""" + theta = self.get_moon_angle() + r = float(self.get_moon_orbit_radius()) + # Rotierter Vektor (r, 0) mit Winkel theta per compute.matmul (2x2 @ 2x1) + rot: List[List[float]] = [ + [math.cos(theta), -math.sin(theta)], + [math.sin(theta), math.cos(theta)], + ] + vec: List[List[float]] = [[r], [0.0]] + res = compute.matmul(rot, vec) # 2x1 + cx, cy = self.get_earth_center() + return int(cx + res[0][0]), int(cy + res[1][0]) + + # --- Game-Hooks --- + def update(self, dt: float) -> None: + """Aktualisiert den Winkel für die Mondrotation.""" + self._theta = (self._theta + self.MOON_ANGULAR_SPEED * dt) % (2.0 * math.pi) + + def draw(self, surface: pygame.Surface) -> None: + """Zeichnet Erde, Orbit und Mond.""" + surface.fill(self.BG_COLOR) + + # Erde + ex, ey = self.get_earth_center() + pygame.draw.circle(surface, self.EARTH_COLOR, (int(ex), int(ey)), self.EARTH_RADIUS) + + # Orbit (visuelle Hilfe) + pygame.draw.circle( + surface, self.ORBIT_COLOR, (int(ex), int(ey)), self.get_moon_orbit_radius(), width=1 + ) + + # Mond + mx, my = self.get_moon_position() + pygame.draw.circle(surface, self.MOON_COLOR, (mx, my), self.MOON_RADIUS) + + +if __name__ == "__main__": + Moon().run() diff --git a/Übungen/product.py b/Übungen/product.py new file mode 100644 index 0000000..1303da4 --- /dev/null +++ b/Übungen/product.py @@ -0,0 +1,23 @@ +from typing import List + +def product(numbers: List[float]) -> float: + """Berechnet das Produkt aller Zahlen in einer Liste. + + Args: + numbers (List[float]): Liste mit Zahlen. + + Returns: + float: Das Produkt aller Zahlen. + """ + if not numbers: + raise ValueError("Liste darf nicht leer sein") + + result = 1.0 + for n in numbers: + result *= n + return result + + +# Beispieltests +print(product([1, 2, 3, 4])) # 24.0 +print(product([2.5, 2, 2])) # 10.0 diff --git a/Übungen/substr.py b/Übungen/substr.py new file mode 100644 index 0000000..77c3536 --- /dev/null +++ b/Übungen/substr.py @@ -0,0 +1,19 @@ +def substr(string: str, start: int, length: int | None = None) -> str: + + """ + Find Substring of a original String. + :param string: Original String. + :param start: Start of Substring. + :param length: Length of Substring. + :return: Substring of original String. + """ + + if length is not None and (length < 0 or length > len(string)): + raise ValueError("invalid Param") + if length is None: + return string [start:] + else: + return string[start:start+length] + +print(substr("GEEKSFORGEEKS", 0,5)) +print(substr("GEEKSFORGEEKS", 4, 2)) \ No newline at end of file