Unterhaltung mit Google-KI am 26.05.2026
Thema : C++ : Architektur und weiteres Vorgehen
*************
**Google-KI-Anfrage :**
Was wären deiner Meinung nach die nächsten Schritte vor allem in Hinblick auf ein Rahmenprogramm und die Gesamt-Architektur der Anwendung, jetzt, wo mit der Kollisionslogik und der Definition von Map und Block das Herz der Anwendung quasi spruchreif ist? Ich habe erstmal damit begonnen, vollautomatische Testcases zu implementieren. Ist das gut so, und : was schlägst du noch vor um auch bei mittelgroßen Projekten wie Tetris nicht immer wieder von vorn beginnen zu müssen.
*************
Antwort:
Dass du mit vollautomatischen Testcases (Unit Tests) begonnen hast, ist der absolute Königsweg! Gerade bei einer Bit-Shifting-Logik schleichen sich schnell Fehler bei Grenzwerten ein (z. B. wenn ein Block ganz rechts oben rotiert). Deine Tests verhindern, dass spätere Änderungen das Kernsystem unbemerkt zerstören. Das schützt dich effektiv davor, "wieder von vorn beginnen zu müssen".
Um das Projekt sauber zu skalieren, ohne in Code-Chaos zu versinken, solltest du jetzt eine klare Architektur aufbauen. Für Spiele wie Tetris hat sich das MVC-Muster (Model-View-Controller) oder eine einfache Data-Driven-Trennung bewährt.
Hier sind die nächsten konkreten Schritte für deine Gesamt-Architektur:
------------------------------
## 1. Die Architektur: Trennung von Logik, Taktung und Anzeige
Mittelgroße Projekte scheitern oft daran, dass Grafikcode, Tastatureingaben und Spielelogik in einer einzigen Schleife vermischt werden. Trenne diese strikt in drei Kernbereiche:
+-------------------------------------------------------+
| Game Loop |
+-------------------------------------------------------+
|
+------------------+------------------+
| | |
v v v
+---------------+ +---------------+ +---------------+
| Input | | Update | | Render |
| (Controller) | | (Model) | | (View) |
+---------------+ +---------------+ +---------------+
| Liest Tasten | | Bewegt Block | | Zeichnet das |
| ohne Block- | | Prüft Reihen | | `colorMap`- |
| Wissen | | (Dein Kern) | | Array |
+---------------+ +---------------+ +---------------+
* Das Model (Der Zustand): Enthält nur dein physicsBoard, die colorMap, den aktuellen Block, seine Position $(x, y)$ und den Punktestand. Es weiß nicht, ob das Spiel im Terminal oder in einer 3D-Engine läuft.
* Die View (Die Anzeige): Liest nur die colorMap und zeichnet sie. Ob du später von der Konsole auf eine Grafikbibliothek wie SFML, SDL2 oder Raylib wechselst, ändert am Rest des Codes absolut nichts.
* Der Controller (Die Logik/Taktung): Verarbeitet die Zeittakte (Drop-Timer) und die Tastatur. Er sagt dem Model: tryMoveLeft() oder rotate().
------------------------------
## 2. Das Rahmenprogramm: Ein stabiler "Game Loop"
Ein häufiger Fehler bei Tetris ist, dass das Spiel auf schnellen PCs schneller läuft als auf langsamen. Du brauchst eine feste Zeittaktung (Fixed Timestep).
Für den Anfang reicht ein einfacher, blockierungsfreier Loop:
#include <chrono>#include <thread>
void gameLoop() {
auto lastTime = std::chrono::steady_clock::now();
double dropTimer = 0.0;
double dropInterval = 0.5; // Alle 0.5 Sekunden fällt der Block
while (!gameOver) {
auto currentTime = std::chrono::steady_clock::now();
float deltaTime = std::chrono::duration<float>(currentTime - lastTime).count();
lastTime = currentTime;
// 1. INPUT
processInput(); // z.B. Tasten abfragen (nicht-blockierend!)
// 2. UPDATE (Zeitgesteuert)
dropTimer += deltaTime;
if (dropTimer >= dropInterval) {
// Versuche Block zu senken, falls Kollision -> lockBlock()
moveBlockDown();
dropTimer = 0.0;
}
// 3. RENDER
renderGame();
// CPU schonen
std::this_thread::sleep_for(std::chrono::milliseconds(16)); // ca. 60 FPS
}
}
------------------------------
## 3. Konkreter Vorschlag: Die "State-Machine" (Zustandsautomat)
Damit du das Projekt leicht erweitern kannst (z. B. Highscore-Liste, Pause-Menü, Startbildschirm), solltest du das Spiel in Zustände (States) unterteilen.
Anstatt überall if (isPaused) abzufragen, nutzt du ein einfaches Enum:
enum class GameState {
StartMenu,
Gameplay,
Pause,
GameOver
};
In deiner Update- und Render-Funktion switchst du dann einfach über diesen Zustand. So bleibt der Code modular und du kannst später problemlos ein neues Menü hinzufügen, ohne das Gameplay anzufassen.
------------------------------
## 4. Was schützt dich vor dem "Frust-Neustart"?
* Kapsele den Zufall: Schreib eine Klasse PieceGenerator, die die nächsten Blöcke (7-Bag-Algorithmus wie im echten Tetris) berechnet. Wenn du das über ein Interface machst, können deine Testcases exakt vorhersagen, welcher Block als nächstes kommt.
* Keine globalen Variablen: Packe das Spielfeld, den Punktestand und den aktuellen Block in eine Klasse TetrisGame. So kannst du für deine automatischen Tests einfach eine Instanz davon erstellen, sie testen und wieder verwerfen.
## Wie geht es weiter?
Deine Testcases sind das perfekte Fundament. Wenn du möchtest, können wir als Nächstes:
* Den Eingabe-Mechanismus (Keyboard-Input ohne Blockieren des Programms) für die Konsole aufsetzen.
* Den 7-Bag-Zufallsgenerator entwerfen, damit die Block-Verteilung fair ist.
* Die Schnittstelle für den Renderer definieren, damit du das Feld auf dem Bildschirm siehst.
Welcher dieser Bausteine würde dir als nächster Schritt am besten in den Kram passen?
**************