diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..b58b603
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/functional.iml b/.idea/functional.iml
new file mode 100644
index 0000000..c264907
--- /dev/null
+++ b/.idea/functional.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index a40c391..8ed2205 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 8a50d73..bdb4873 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,7 +2,6 @@
-
\ No newline at end of file
diff --git a/game.py b/game.py
new file mode 100644
index 0000000..518702e
--- /dev/null
+++ b/game.py
@@ -0,0 +1,52 @@
+import pygame
+
+class Game:
+
+ def __init__(self, title, fps=60, size=(640, 400)):
+ self.title = title
+ self.fps = fps
+ self.size = size
+ self.clock = pygame.time.Clock()
+ self.dt = 0
+ self.screen = None
+
+ def init_game(self):
+ pygame.init()
+ pygame.display.set_caption(self.title)
+ self.screen = pygame.display.set_mode(self.size)
+
+
+ def game_loop(self):
+ 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):
+ pygame.quit()
+
+ def event_handling(self): # bleibt in der Unterklasse unverändert
+ for event in pygame.event.get():
+ if not self.handle_event(event):
+ return False
+ return True
+
+ def handle_event(self, event): # wird in der Unterklasse überschrieben
+ if event.type == pygame.QUIT:
+ return False
+ return True
+
+ def update_game(self):
+ return True
+
+ def draw_game(self):
+ pygame.display.flip()
+
+ def run(self):
+ self.init_game()
+ self.game_loop()
+ self.exit_game()
\ No newline at end of file
diff --git a/install_dependencies.py b/install_dependencies.py
new file mode 100644
index 0000000..5a20e39
--- /dev/null
+++ b/install_dependencies.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+"""Installiert die Abhängigkeiten aus pyproject.toml in die aktuelle Python-Umgebung.
+
+Ersatz für "Install requirements" aus PyCharm, wenn das Projekt eine pyproject.toml
+statt einer requirements.txt hat. Kein Build, keine besondere Projektstruktur nötig,
+nur Standardbibliothek (Python >= 3.11).
+
+Benutzung:
+ In PyCharm: Rechtsklick auf diese Datei -> Run 'install_dependencies'
+ Im Terminal (venv aktiv): python install_dependencies.py
+
+Ohne Parameter wird ALLES installiert:
+ [project].dependencies + alle [project.optional-dependencies] + alle [dependency-groups]
+
+Abweichendes Verhalten:
+ python install_dependencies.py --extra dev nur Basis + Extra "dev"
+ python install_dependencies.py --group test nur Basis + Gruppe "test"
+ python install_dependencies.py --no-main --group dev
+ python install_dependencies.py --list nur anzeigen, nichts installieren
+ python install_dependencies.py --write requirements.txt schreiben statt installieren
+ python install_dependencies.py --write -o reqs.txt
+"""
+from __future__ import annotations
+
+import sys
+
+if sys.version_info < (3, 11):
+ sys.exit("Dieses Skript braucht Python 3.11 oder neuer (tomllib). "
+ f"Aktuell: {sys.version.split()[0]}")
+
+import argparse
+import subprocess
+import tempfile
+import tomllib
+from pathlib import Path
+
+PROJECT_DIR = Path(__file__).resolve().parent
+
+
+def resolve_group(groups: dict, name: str, seen: set[str] | None = None) -> list[str]:
+ """Löst eine Dependency-Group inkl. {include-group = "..."} rekursiv auf."""
+ seen = set() if seen is None else seen
+ if name in seen:
+ raise ValueError(f"Zyklische include-group: {name}")
+ if name not in groups:
+ raise KeyError(f"Dependency-Group '{name}' nicht gefunden")
+ seen.add(name)
+ result: list[str] = []
+ for entry in groups[name]:
+ if isinstance(entry, str):
+ result.append(entry)
+ elif isinstance(entry, dict) and "include-group" in entry:
+ result.extend(resolve_group(groups, entry["include-group"], seen))
+ return result
+
+
+def collect(data: dict, extras: list[str], groups: list[str], no_main: bool) -> list[str]:
+ project = data.get("project", {})
+ optional = project.get("optional-dependencies", {})
+ dep_groups = data.get("dependency-groups", {})
+ deps: list[str] = []
+
+ if not no_main:
+ deps.extend(project.get("dependencies", []))
+ for extra in extras:
+ if extra not in optional:
+ raise KeyError(f"Optional-Dependency '{extra}' nicht gefunden")
+ deps.extend(optional[extra])
+ for group in groups:
+ deps.extend(resolve_group(dep_groups, group))
+
+ # Duplikate entfernen, Reihenfolge behalten
+ return list(dict.fromkeys(d.strip() for d in deps if d.strip()))
+
+
+def main() -> int:
+ p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
+ p.add_argument("-p", "--pyproject", type=Path, default=PROJECT_DIR / "pyproject.toml",
+ help="Pfad zur pyproject.toml (Standard: neben diesem Skript)")
+ p.add_argument("--extra", action="append", default=None,
+ help="nur diese optional-dependencies (mehrfach möglich)")
+ p.add_argument("--group", action="append", default=None,
+ help="nur diese dependency-groups (mehrfach möglich)")
+ p.add_argument("--no-main", action="store_true", help="[project].dependencies weglassen")
+ p.add_argument("--list", action="store_true", help="Abhängigkeiten nur anzeigen")
+ p.add_argument("--write", action="store_true", help="requirements-Datei schreiben statt installieren")
+ p.add_argument("-o", "--output", type=Path, default=PROJECT_DIR / "requirements.txt",
+ help="Zieldatei für --write")
+ args = p.parse_args()
+
+ if not args.pyproject.exists():
+ print(f"{args.pyproject} nicht gefunden", file=sys.stderr)
+ return 1
+ data = tomllib.loads(args.pyproject.read_text(encoding="utf-8"))
+ all_extras = list(data.get("project", {}).get("optional-dependencies", {}))
+ all_groups = list(data.get("dependency-groups", {}))
+
+ # Ohne --extra/--group: alles. Mit einem davon: nur das Gewählte.
+ selective = args.extra is not None or args.group is not None
+ extras = (args.extra or []) if selective else all_extras
+ groups = (args.group or []) if selective else all_groups
+
+ try:
+ deps = collect(data, extras, groups, args.no_main)
+ except (KeyError, ValueError) as e:
+ print(f"Fehler: {e.args[0]}", file=sys.stderr)
+ print(f" Vorhandene --extra: {', '.join(all_extras) or '(keine)'}", file=sys.stderr)
+ print(f" Vorhandene --group: {', '.join(all_groups) or '(keine)'}", file=sys.stderr)
+ return 1
+
+ parts = ([] if args.no_main else ["Basis"]) + [f"extra:{e}" for e in extras] + [f"group:{g}" for g in groups]
+ print(f"Auswahl: {', '.join(parts) or '(nichts)'}")
+
+ if args.list:
+ print("\n".join(deps) or "(keine Abhängigkeiten)")
+ return 0
+
+ content = f"# Automatisch erzeugt aus {args.pyproject.name} – nicht von Hand bearbeiten\n" + "\n".join(deps) + "\n"
+
+ if args.write:
+ args.output.write_text(content, encoding="utf-8")
+ print(f"{len(deps)} Abhängigkeiten -> {args.output}")
+ return 0
+
+ if not deps:
+ print("Keine Abhängigkeiten gefunden – nichts zu tun.")
+ return 0
+
+ if sys.prefix == sys.base_prefix:
+ print("WARNUNG: Es ist kein virtuelles Environment aktiv – es wird in die globale "
+ f"Python-Installation installiert:\n {sys.prefix}", file=sys.stderr)
+ if sys.stdin.isatty() and input("Trotzdem fortfahren? [j/N] ").strip().lower() not in ("j", "ja", "y", "yes"):
+ return 1
+
+ with tempfile.NamedTemporaryFile("w", suffix=".txt", delete=False, encoding="utf-8") as tmp:
+ tmp.write(content)
+ tmp_path = Path(tmp.name)
+ try:
+ print(f"Installiere {len(deps)} Abhängigkeiten in {sys.prefix}\n")
+ return subprocess.call([sys.executable, "-m", "pip", "install", "-r", str(tmp_path)])
+ finally:
+ tmp_path.unlink(missing_ok=True)
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/src/functional/01_verdopppeln.py b/src/functional/01_verdopppeln.py
new file mode 100644
index 0000000..bb91d6b
--- /dev/null
+++ b/src/functional/01_verdopppeln.py
@@ -0,0 +1,4 @@
+numbers = [1,2,3,4,5]
+
+result = map(lambda x: x * 2, numbers)
+print(list(result))
\ No newline at end of file
diff --git a/src/functional/02_Trump_Style.py b/src/functional/02_Trump_Style.py
new file mode 100644
index 0000000..d4b961e
--- /dev/null
+++ b/src/functional/02_Trump_Style.py
@@ -0,0 +1,4 @@
+words = ["Hofmann", "was", "right", "about", "something"]
+
+result = map(lambda x: x.upper(), words)
+print(list(result))
\ No newline at end of file
diff --git a/src/functional/03_Gerade_Zahlen.py b/src/functional/03_Gerade_Zahlen.py
new file mode 100644
index 0000000..ea5a990
--- /dev/null
+++ b/src/functional/03_Gerade_Zahlen.py
@@ -0,0 +1,4 @@
+numbers = list(range(1, 21))
+
+result = filter(lambda x: x % 2 == 0, numbers)
+print(list(result))
\ No newline at end of file
diff --git a/src/functional/04_K_Länge.py b/src/functional/04_K_Länge.py
new file mode 100644
index 0000000..0f4663a
--- /dev/null
+++ b/src/functional/04_K_Länge.py
@@ -0,0 +1,6 @@
+from functools import reduce
+
+words = ["Apfel", "Banane", "Kirsche", "Kiwi", "Melone"]
+
+result = sum(map(lambda x : len(x) , filter(lambda x : x[0][0] == "K", words)))
+print(result)
diff --git a/src/functional/05_Particle.py b/src/functional/05_Particle.py
new file mode 100644
index 0000000..9a22dc1
--- /dev/null
+++ b/src/functional/05_Particle.py
@@ -0,0 +1,31 @@
+class Particle:
+ def __init__(self, position, velocity=(0, 0), acceleration=(0, 0),old_version=None):
+ self.position = position
+ self.velocity = velocity
+ self.acceleration = acceleration
+ self.old_version = []
+
+ def update(self):
+ self.old_version.append(self)
+
+ new_velocity = (self.velocity[0] + self.acceleration[0],
+ self.velocity[1] + self.acceleration[1])
+ new_position = (self.position[0] + new_velocity[0],
+ self.position[1] + new_velocity[1])
+
+ return Particle(new_position, new_velocity, self.acceleration, self.old_version)
+
+ def undo(self):
+
+ return self.old_version.pop()
+
+
+p = Particle((0, 0), (1, 1), (1,1))
+
+
+new_p = p.update()
+old_p = p.undo()
+newnew_p = new_p.update()
+oldnew_p = new_p.undo()
+
+print(new_p.position, new_p.velocity, new_p.acceleration, new_p.old_version)
diff --git a/src/functional/06_Quadratzahlen.py b/src/functional/06_Quadratzahlen.py
new file mode 100644
index 0000000..e5c3a83
--- /dev/null
+++ b/src/functional/06_Quadratzahlen.py
@@ -0,0 +1,17 @@
+class Squares:
+ def __init__(self, max_value):
+ self.n = 1
+ self.max_value = max_value
+
+ def __next__(self):
+ if self.n >= self.max_value:
+ raise StopIteration
+ self.n +=1
+ return self.n * self.n
+
+ def __iter__(self):
+ return self
+
+s = Squares(5)
+for i in s:
+ print(i)
\ No newline at end of file
diff --git a/src/functional/07_Ungerade_Zahlen.py b/src/functional/07_Ungerade_Zahlen.py
new file mode 100644
index 0000000..a7f1f15
--- /dev/null
+++ b/src/functional/07_Ungerade_Zahlen.py
@@ -0,0 +1,11 @@
+def odd(max : int):
+ n = 0
+ while n < max:
+ n += 1
+ if n % 2 != 0:
+ yield n
+
+
+o = odd(5)
+for i in o:
+ print(i)
diff --git a/src/functional/08_Laufzeit_Messung.py b/src/functional/08_Laufzeit_Messung.py
new file mode 100644
index 0000000..f8ee3eb
--- /dev/null
+++ b/src/functional/08_Laufzeit_Messung.py
@@ -0,0 +1,24 @@
+import functools
+import time
+
+def time_calculation(f):
+ @functools.wraps(f)
+ def wrapper(*args, **kwargs):
+ start = time.perf_counter()
+ f(*args, **kwargs)
+ end = time.perf_counter()
+ print(f"Dauer: {end-start:.4f} Sekunden")
+
+ return wrapper
+
+
+@time_calculation
+def eine_funktion(a=1, b=2, c=3):
+ """Eine funktion"""
+ for i in range(5000):
+ result = (a * b + c) * i
+ print(result)
+
+
+eine_funktion()
+help(eine_funktion)
diff --git a/src/functional/09_Treppenhaus.py b/src/functional/09_Treppenhaus.py
new file mode 100644
index 0000000..bfa7170
--- /dev/null
+++ b/src/functional/09_Treppenhaus.py
@@ -0,0 +1,25 @@
+from functools import lru_cache
+
+import functools
+import time
+
+def time_calculation(f):
+ @functools.wraps(f)
+ def wrapper(*args, **kwargs):
+ start = time.perf_counter()
+ result = f(*args, **kwargs)
+ end = time.perf_counter()
+ print(f"Dauer: {end-start:.4f} Sekunden")
+ return result
+
+ return wrapper
+
+@time_calculation
+@lru_cache(maxsize=None)
+def ways(n):
+ if n <= 2:
+ return n
+ return ways(n-1) + ways(n-2)
+
+print(ways(40))
+
diff --git a/src/functional/10_Münzwechsel.py b/src/functional/10_Münzwechsel.py
new file mode 100644
index 0000000..08ea8e2
--- /dev/null
+++ b/src/functional/10_Münzwechsel.py
@@ -0,0 +1,30 @@
+import time
+import functools
+from functools import lru_cache
+
+def time_calculation(f):
+ @functools.wraps(f)
+ def wrapper(*args, **kwargs):
+ start = time.perf_counter()
+ result = f(*args, **kwargs)
+ end = time.perf_counter()
+ print(f"Dauer: {end-start:.4f} Sekunden")
+ return result
+
+ return wrapper
+
+@lru_cache(maxsize=None)
+def coins(n):
+ if n == 0:
+ return 1
+ if n < 0:
+ return 0
+ return coins(n-1) + coins(n-2) + coins(n-5)
+
+
+@time_calculation
+def calculate(n):
+ return coins(n)
+
+calculate(5)
+calculate(30)
\ No newline at end of file
diff --git a/src/functional/11_run_once.py b/src/functional/11_run_once.py
new file mode 100644
index 0000000..1b94826
--- /dev/null
+++ b/src/functional/11_run_once.py
@@ -0,0 +1,21 @@
+import functools
+
+def run_once(f):
+ already_run = False
+
+ @functools.wraps(f)
+ def wrapper(*args, **kwargs):
+ nonlocal already_run
+
+ if not already_run:
+ already_run = True
+ return f(*args, **kwargs)
+
+ return wrapper
+
+@run_once
+def test():
+ print("Hello World!")
+
+test()
+test()
\ No newline at end of file