Files
4Gewinnt/TECHNISCHE_SPEZIFIKATION.md

1353 lines
41 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Technische Spezifikation 4Gewinnt
## 1. Projektübersicht
### Name der Anwendung
**4Gewinnt** (Vier-Gewinnt als lokaler und online Multiplayer).
### Ziel der Anwendung
Bereitstellung eines browserbasierten Vier-Gewinnt-Spiels mit zwei Betriebsarten:
- **Lokaler Modus** (zwei lokale Spieler, optional Bot-Spieler)
- **Online-Modus** (zwei entfernte Spieler über Spielcode und SignalR)
### Problem, das gelöst wird
Die Anwendung löst die technische Herausforderung, ein rundenbasiertes Rasterspiel gleichzeitig:
- mit **reaktiver Benutzeroberfläche**,
- mit **serverautoritärer Validierung der Spielzüge**,
- mit **Echtzeit-Event-Übertragung**,
- und mit **einfacher Lobby-Logik über 6-stellige Codes**
zu betreiben.
### Zielgruppe
- Spieler:innen, die im Browser schnell ein Vier-Gewinnt-Spiel starten wollen
- Entwickler:innen/Lernende für ein Referenzprojekt zu Vue 3 + SignalR + ASP.NET Core
### Hauptfunktionen
1. Spiel erstellen mit variabler Feldgröße
2. Spiel beitreten über sechsstelligen Code
3. Echtzeit-Synchronisation von Spielzustand und Spielende
4. Gewinn-/Unentschieden-Erkennung serverseitig
5. Lokales Spiel (ohne externen Gegenspieler)
6. Wiederholungsrunde (Replay-Code) nach Spielende
---
## 2. Systemarchitektur
### Beschreibung der Gesamtarchitektur
Das Projekt ist als **zweiteilige Client-Server-Architektur** umgesetzt:
- **Frontend (GUI)**: Vue 3 SPA, Rendert UI und delegiert Spiellogik-Kommandos an SignalR-Verbindung
- **Backend (API)**: ASP.NET Core Web API + SignalR Hub, verwaltet Spielinstanzen in Memory
### Frontend-/Backend-Struktur
- **Frontend** enthält:
- Routing und Seitenzustände
- UI-Komponenten für Menüs, Spielfeld und Spielende
- Client-seitige Orchestrierung (`OnlineGame`, `LocalGame`)
- Transport-Layer (`GameConnection`) für SignalR
- **Backend** enthält:
- Hub-Endpunkte als Eintrittspunkt für Spieloperationen
- Game-Manager als fachliche Orchestrierung
- Repository als In-Memory-Persistenz
- Domain-Modelle (Spiel, Feld, Spieler, DTOs)
### Verwendete Technologien
- Vue 3 + TypeScript + Vuetify + Vite
- ASP.NET Core 9 + SignalR + Swagger/OpenAPI
### Datenfluss zwischen Frontend und Backend
1. Frontend öffnet SignalR-Verbindung zu `/api/gamehub`.
2. Frontend ruft Hub-Methoden (`CreateGame`, `JoinGame`, `Drop`, ...).
3. Hub delegiert an `IGameManager`.
4. `GameManager` liest/schreibt via `IGameRepository`.
5. `GameManager` sendet Events an einzelne Clients oder Gruppen.
6. Frontend aktualisiert lokalen State über Event-Callbacks.
### Wichtige Designentscheidungen
- **Serverautorität**: Züge werden im Backend validiert.
- **In-Memory-Repository**: schnell, aber nicht persistent.
- **Gruppenkommunikation**: SignalR-Gruppen nach `game.Id`.
- **DTO-Transformation**: 2D-Array im Backend wird in jagged array (`int[][]`) für Frontend gewandelt.
- **Zeitgesteuerte Aufräumlogik**: Spiele werden nach Endbedingungen entfernt.
---
## 3. Technologie-Stack
| Kategorie | Technologie | Rolle |
| --- | --- | --- |
| Frontend Framework | Vue 3 | Komponenten, Reaktivität, SPA |
| Frontend Sprache | TypeScript | Typsicherheit in UI- und Spiel-Logik |
| UI-Bibliothek | Vuetify 3 | Material Design Komponenten |
| Frontend Routing | Vue Router | Seitenwechsel (`/`, `/localMode`, `/onlineMode`) |
| Echtzeitkommunikation (Client) | `@microsoft/signalr` | Verbindungsaufbau, Invoke, Event-Handling |
| Build Tool Frontend | Vite | Dev-Server, Build, Alias-Auflösung |
| Backend Framework | ASP.NET Core 9 | Hosting, DI, HTTP-Pipeline, SignalR |
| Echtzeitkommunikation (Server) | ASP.NET SignalR | Hub-Methoden, Gruppen- und Client-Events |
| API-Dokumentation | OpenAPI + Swagger | Test/Inspektion im Development |
| Persistenz | In-Memory (`GameRepository`) | Laufzeitverwaltung von Spielen |
| Lösung/Build | .NET SDK + npm | Backend/Frontend Build und Start |
---
## 4. Projektstruktur
```text
/
├── API/ # Backend (.NET 9)
│ ├── Controllers/ # Status-Controller + SignalR Hub
│ ├── Models/
│ │ ├── DataClasses/ # Value Objects (z. B. SixDigitInt)
│ │ └── Game/ # Domänenmodelle, DTOs, Spielfeldlogik
│ ├── Repository/GameRepo/ # Spielspeicher (Interface + In-Memory-Impl.)
│ ├── Services/GameManager/ # Use-Case- und Ablaufsteuerung
│ ├── Program.cs # App-Konfiguration und DI
│ └── appsettings*.json # Konfiguration
├── GUI/ # Frontend (Vue 3 + TS)
│ ├── public/ # Statische Assets (Sprites, Hintergrund, Icons)
│ ├── src/
│ │ ├── components/ # Wiederverwendbare UI-Komponenten
│ │ │ └── game/ # Spielfeld-/Info-Komponenten
│ │ ├── routes/ # View-Komponenten pro Route
│ │ ├── router/ # Router-Konfiguration
│ │ ├── scripts/
│ │ │ ├── interfaces/ # TS-Typdefinitionen
│ │ │ ├── logic/ # Anwendungslogik (lokal/online/signalR)
│ │ │ └── utils/ # Hilfsfunktionen
│ │ ├── Layout.vue # App-Shell
│ │ ├── Home.vue # Startseite
│ │ ├── NotFound.vue # 404-Fallback
│ │ └── main.ts # Bootstrapping
│ ├── vite.config.ts # Build-/Alias-Konfiguration
│ └── package.json # npm Scripts + Abhängigkeiten
├── 4Gewinnt.sln # .NET Lösung
└── TECHNISCHE_SPEZIFIKATION.md # Diese Spezifikation
```
---
## 5. Backend-Architektur
### Überblick
Das Backend besteht aus vier Schichten:
1. **Controller/Hub-Schicht**: externer Zugriff
2. **Service-Schicht**: Geschäftsabläufe
3. **Repository-Schicht**: Speicherung und Lookup
4. **Model-Schicht**: Domänenobjekte und Algorithmen
### Klassen- und Typdokumentation (Backend)
## Program (Program.cs)
### Zweck
Konfiguriert Dependency Injection, Middleware und Endpunkte der Anwendung.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `builder` | `WebApplicationBuilder` | Aufbau des DI-Containers und Hostings |
| `app` | `WebApplication` | Laufende ASP.NET Anwendung |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| Top-Level Setup | - | - | Registriert Controller, SignalR, Swagger, Repositories und Services; mappt Endpunkte |
### Beziehungen
- Verwendet `IGameManager`/`GameManager` und `IGameRepository`/`GameRepository` via DI.
- Mappt `GameHubSocket` als SignalR-Hub unter `/api/gamehub`.
---
## StatusController
### Zweck
Einfacher Healthcheck-Endpunkt (`GET /api/status`) zur Verfügbarkeitsprüfung.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| - | - | Keine eigenen Felder |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `Get` | - | `IActionResult` | Gibt `200 OK` mit `"Running"` zurück |
### Beziehungen
- Keine Abhängigkeiten zu Domain-Services.
---
## GameHubSocket
### Zweck
SignalR-Hub als Eintrittspunkt für Spiel-Kommandos aus Clients.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `_gameManager` | `IGameManager` | Service für Spielfunktionen |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `CreateGame` | `playerName: string`, `gFs: Coordinates` | `Task` | Validiert Feldgröße, erstellt Spiel, fügt Client zur Spielgruppe hinzu, sendet `GameCreated` |
| `JoinGame` | `playerName: string`, `gameCode: int` | `Task` | Lässt Client einem Spiel beitreten, sendet `GameJoined` oder `Error` |
| `RequestGameInformation` | `gameId: string` | `Task` | Delegiert an Manager für aktuellen Spielzustand |
| `Drop` | `gameId: string`, `column: int` | `Task` | Delegiert Zugausführung an Manager |
| `OnDisconnectedAsync` | `exception?: Exception` | `Task` | Meldet Disconnection und ruft Basisverhalten auf |
### Beziehungen
- Ruft `IGameManager`-Methoden auf.
- Sendet Events über `Clients` und verwaltet Gruppenmitgliedschaft.
---
## IGameManager (Interface)
### Zweck
Definiert die fachlichen Operationen für Spiele.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| - | - | Interface ohne Felder |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `CreateGame` | `gFs: Coordinates`, `player: Player` | `(string, int)` | Erstellt neues Spiel und gibt `(gameId, gameCode)` |
| `JoinGame` | `player: Player`, `gameCode: int` | `Task<string?>` | Versucht Beitritt; liefert `gameId` oder `null` |
| `RequestGameInformation` | `gameId: string`, `playerConnectionId: string` | `Task` | Liefert Spielzustand an anfragenden Client |
| `Drop` | `gameCode: string`, `column: int`, `playerConnectionId: string` | `Task` | Führt Spielzug aus |
| `DisconnectedPlayer` | `playerConnectionId: string` | `Task` | Beendet Spiel bei Verbindungsabbruch |
### Beziehungen
- Implementiert durch `GameManager`.
---
## GameManager
### Zweck
Orchestriert Kern-Use-Cases: Spielstart, Beitritt, Zuglogik, Endbedingungen und Aufräumen.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `gameRepository` | `IGameRepository` | Zugriff auf Spielinstanzen |
| `hubContext` | `IHubContext<GameHubSocket>` | Serverseitiges Senden von SignalR-Events |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `CreateGame` | `gFs: Coordinates`, `player: Player` | `(string, int)` | Legt Spiel an, fügt Ersteller hinzu, liefert Kennungen |
| `JoinGame` | `player: Player`, `gameCode: int` | `Task<string?>` | Prüft Lobbyzustand/Platz, fügt Gruppe hinzu, sendet bei 2 Spielern `GameStarted` |
| `RequestGameInformation` | `gameId: string`, `playerConnectionId: string` | `Task` | Baut DTO und sendet `GameInformation` an den Client |
| `Drop` | `gameCode: string`, `column: int`, `playerConnectionId: string` | `Task` | Prüft Zugrecht/Zustand, lässt Stein fallen, sendet `FieldUpdated`, prüft Win/Draw, sendet `GameEnded` |
| `DisconnectedPlayer` | `playerConnectionId: string` | `Task` | Entfernt Spieler aus Spiel, beendet Spiel, sendet `GameEnded` mit `PlayerDisconnected` |
| `ConvertField` *(privat, statisch)* | `field: int[,]?` | `int[][]` | Transformiert 2D-Array in jagged array für DTO |
| `ScheduleGameDeletion` *(privat)* | `gameId: string`, `delay: TimeSpan` | `void` | Verzögerte Löschung in Hintergrund-Task und Versand `GameDestroyed` |
### Beziehungen
- Verwendet `IGameRepository`, `Game`, `GameField`, `GameInformationDto`.
- Ruft SignalR-Clients/Gruppen auf (`GameStarted`, `FieldUpdated`, `GameEnded`, `GameInformation`, `GameDestroyed`).
---
## IGameRepository (Interface)
### Zweck
Abstraktion der Spielpersistenz.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| - | - | Interface ohne Felder |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `GetAll` | - | `List<Game>` | Liefert alle Spiele |
| `GetOne` | `id: string` | `Game?` | Sucht Spiel per ID |
| `GetOne` | `gameCode: SixDigitInt` | `Game?` | Sucht Spiel per Spielcode |
| `GetOneByConnectionId` | `connectionId: string` | `Game?` | Sucht Spiel, in dem ein Spieler verbunden ist |
| `Create` | `gameFieldSize: Coordinates` | `Game` | Erstellt neues Spiel |
| `Destroy` | `id: string` | `void` | Entfernt Spiel aus Speicher |
### Beziehungen
- Implementiert durch `GameRepository`.
---
## GameRepository
### Zweck
In-Memory-Implementierung für Spielverwaltung inklusive Codegenerierung.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `_games` | `List<Game>` | Aktive Spiele im Arbeitsspeicher |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `GetAll` | - | `List<Game>` | Gibt interne Liste zurück |
| `GetOne` | `id: string` | `Game?` | Lookup über `Game.Id` |
| `GetOne` | `gameCode: SixDigitInt` | `Game?` | Lookup über `Game.GameCode` |
| `GetOneByConnectionId` | `connectionId: string` | `Game?` | Spielsuche nach enthaltenem Spieler |
| `Create` | `gameFieldSize: Coordinates` | `Game` | Erzeugt `Game` mit einzigartigem Code, fügt zur Liste hinzu |
| `Destroy` | `id: string` | `void` | Entfernt Spiele mit ID |
| `GenerateGameCode` *(privat)* | - | `SixDigitInt` | Erzeugt kryptografisch zufälligen 6-stelligen, einzigartigen Code |
### Beziehungen
- Instanziiert `Game` und `SixDigitInt`.
- Wird von `GameManager` genutzt.
---
## SixDigitInt (record struct)
### Zweck
Value Object für sechsstellige Spielcodes mit Wertebereichsvalidierung.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `Value` | `int` | Interner numerischer Wert (0999999) |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| Konstruktor | `value: int` | - | Validiert Bereich und setzt `Value` |
| `ToString` | - | `string` | Gibt Code links mit Nullen aufgefüllt (`D6`) zurück |
| `implicit operator int` | `v: SixDigitInt` | `int` | Ermöglicht implizite Konvertierung nach `int` |
### Beziehungen
- Wird in `Game` und Repository als Spielcode verwendet.
---
## Coordinates (readonly struct)
### Zweck
Datenstruktur für Felddimensionen oder Koordinaten.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `X` | `int` | Breite / X-Koordinate |
| `Y` | `int` | Höhe / Y-Koordinate |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| - | - | - | Keine Methoden |
### Beziehungen
- Wird von `Game`, `GameField` und Hub-Aufrufen genutzt.
---
## GameState (enum)
### Zweck
Statusautomat eines Spiels.
### Werte
| Wert | Beschreibung |
| --- | --- |
| `Lobby` | Spiel erstellt, wartet auf zweiten Spieler |
| `Running` | Spiel aktiv |
| `Ended` | Spiel beendet |
---
## Player
### Zweck
Spielerobjekt mit Name, Connection-ID und Spielerrolle (1 oder 2).
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `Name` | `string` | Anzeigename |
| `ConnectionId` | `string` | SignalR-Verbindungs-ID |
| `PlayerTag` | `int` | Rolle/Steinfarbe (`1` oder `2`) |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| Konstruktor | `name: string`, `connectionId: string` | - | Initialisiert Spieler |
### Beziehungen
- Bestandteil von `Game.Players`.
---
## Game
### Zweck
Aggregate Root für einen kompletten Matchzustand.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `Id` | `string` | Eindeutige Spiel-ID (GUID) |
| `GameCode` | `SixDigitInt` | Human-readable Join-Code |
| `Players` | `List<Player>` | Teilnehmer (max. 2) |
| `CurrentTurn` | `int` | Aktuelle Spielerrolle (1/2) |
| `State` | `GameState` | Lobby/Running/Ended |
| `Field` | `GameField` | Spielfeldinstanz |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| Konstruktor | `gFs: Coordinates`, `gameCode: SixDigitInt` | - | Erstellt neues Spiel mit Feld |
| `AddPlayer` | `player: Player` | `bool` | Fügt Spieler hinzu, weist `PlayerTag` zu, startet Spiel bei 2 Spielern |
| `RemovePlayer` | `playerConnectionId: string` | `void` | Entfernt Spieler anhand Connection-ID |
| `GetPlayerByConnectionId` | `playerConnectionId: string` | `Player?` | Spielersuche nach Connection-ID |
| `GetPlayerByTag` | `playerTag: int` | `Player?` | Spielersuche nach Rolle |
| `StartGame` | - | `void` | Setzt Status auf `Running` |
| `EndGame` | - | `void` | Setzt Status auf `Ended` |
### Beziehungen
- Enthält `GameField` und `Player`.
- Wird über `GameManager` gesteuert.
---
## DropResult (enum)
### Zweck
Ergebniscode für Zugversuche im Spielfeld.
### Werte
| Wert | Beschreibung |
| --- | --- |
| `OutOfGameField` | Spalte außerhalb gültigen Bereichs |
| `NotAllowedPlayer` | Ungültiger Spielerwert |
| `ColumnFull` | Spalte ist voll |
| `InvalidFieldValue` | Feld enthält ungültige Werte |
| `Placed` | Stein erfolgreich platziert |
---
## FieldState (enum)
### Zweck
Status eines einzelnen Feldpunktes.
### Werte
| Wert | Beschreibung |
| --- | --- |
| `OutOfGameField` | Koordinate außerhalb |
| `Empty` | Feld leer |
| `OccupiedRed` | Belegt durch Spieler 1 |
| `OccupiedYellow` | Belegt durch Spieler 2 |
| `InvalidFieldValue` | Unerwarteter Wert |
---
## GameField
### Zweck
Kapselt Feldzustand und Algorithmen für Einwurf, Vollprüfung und Gewinnerkennung.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `GFs` | `Coordinates` | Spielfeldgröße |
| `CurrentField` | `int[,]` | Aktuelles Feldraster (0 leer, 1/2 Spieler) |
| `BackupField` | `int[,]` | Sicherung für Rücksetzen bei Fehlern |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| Konstruktor | `gFs: Coordinates` | - | Erzeugt Raster und Backup |
| `Drop` | `column: int`, `player: int` | `DropResult` | Lässt Stein in Spalte fallen; nutzt Backup vor Änderung |
| `CheckField` | `coordinates: Coordinates` | `FieldState` | Liefert Status eines Feldpunktes |
| `IsFull` | - | `bool` | Prüft, ob kein Leerfeld mehr existiert |
| `CountInDirection` *(privat)* | `startX,startY,dx,dy,player` | `int` | Zählt zusammenhängende Steine in Richtung |
| `CheckLine` *(privat)* | `startX,startY,dx,dy,player` | `bool` | Prüft 4er-Linie über beide Richtungen |
| `CheckForWin` | - | `int` | Durchsucht Feld nach Gewinner (0/1/2) |
| `ResetToLastSave` | - | `void` | Stellt Feld aus Backup wieder her |
| `CreateSave` | - | `void` | Kopiert `CurrentField` nach `BackupField` |
### Beziehungen
- Wird von `Game` gehalten.
- Von `GameManager.Drop` aufgerufen.
---
## GameInformationDto
### Zweck
Transportobjekt für Frontend-Synchronisation.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `Id` | `string` | Spiel-ID |
| `Players` | `List<Player>` | Spielerliste |
| `State` | `GameState?` | Spielstatus |
| `CurrentField` | `int[][]` | Feldzustand in serialisierbarer Struktur |
| `CurrentTurn` | `int` | Nächster Spieler |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| - | - | - | Reines DTO ohne Logik |
### Beziehungen
- Wird vom `GameManager` erzeugt und über Hub-Ereignisse versendet.
---
## 6. Frontend-Architektur
### Seiten / Views
- `/``Home.vue` (Moduswahl)
- `/localMode``LocalMode.vue` (lokales Spiel)
- `/onlineMode``OnlineMode.vue` (Lobbyauswahl + Online-Spiel)
- Fallback → `NotFound.vue`
### Komponenten
- **Layout**: App-Shell mit Header und Router-View
- **CreateOrJoinMenu**: Auswahl „Erstellen“/„Beitreten“
- **GameCreationMenu**: Spieler-/Feldeinstellungen
- **GameJoinMenu**: Name + 6-stelliger Join-Code
- **GameEndedMenu**: Endstand + Restart
- **Field**: Spielfelddarstellung + Spaltenauswahl
- **InfoField**: Textstatus aktueller Spielerzug
- **Slider**: Wiederverwendbarer numerischer Slider
### State Management
Kein zentrales Store-Framework; Zustand wird komponentenlokal mit Vue `ref`/`computed` gehalten.
- Spielzustand fließt über Callback-Events aus den Logikklassen (`OnlineGame`, `LocalGame`).
### API-Kommunikation
- Keine klassische REST-Spiel-API.
- Vollständig ereignisgesteuert via SignalR (`GameConnection`).
- REST nur für Healthcheck (`/api/status`).
### Routing
Router in `router/index.ts` mit `createWebHistory`.
### Klassen- und Komponentendokumentation (Frontend)
## main.ts
### Zweck
Bootstrapping von Vue-App, Vuetify, Router und globalen Styles.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `vuetify` | Vuetify-Instanz | Dark Theme, Komponenten/Directives |
| `app` | Vue App | Root-App mit `Layout.vue` |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| Top-Level Setup | - | - | Initialisiert App, bindet Plugins, mountet `#app` |
### Beziehungen
- Nutzt `Layout.vue` und Router.
---
## Router (router/index.ts)
### Zweck
Definiert Navigationsstruktur der SPA.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `router` | Router | Routentabelle und History-Strategie |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `createRouter(...)` | Konfigurationsobjekt | `Router` | Baut Router mit vier Routen |
### Beziehungen
- Verknüpft Views `Home`, `LocalMode`, `OnlineMode`, `NotFound`.
---
## Layout.vue (Komponente)
### Zweck
Stellt globale App-Hülle (AppBar + Inhalt) bereit.
### Props
Keine.
### State / reactive Daten
Keine.
### Methoden
Keine.
### Events
- Klick auf Titel navigiert zur Startseite.
### API Calls
Keine.
---
## Home.vue (Komponente)
### Zweck
Startseite zur Auswahl des Spielmodus.
### Props
Keine.
### State / reactive Daten
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `buttons` | Array | Konfiguration der zwei Modus-Buttons |
### Methoden
Keine expliziten Methoden.
### Events
- Navigationsereignisse über `:to` auf Button.
### API Calls
Keine.
---
## OnlineMode.vue (Komponente)
### Zweck
Steuert gesamten Online-Flow von Auswahl bis laufendem Spiel.
### Props
Keine.
### State / reactive Daten
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `settings` | `Ref<GameSettings>` | Einstellungen zum Erstellen |
| `joiningModel` | `Ref<JoinGameObject>` | Daten für Join-Flow |
| `currentState` | `Ref<CurrentState>` | UI-State-Maschine |
| `game` | `Ref<OnlineGame>` | Online-Spielorchestrator |
| `gameField` | `Ref<number[][]>` | Feld für Anzeige |
| `currentSelectionIndex` | `Ref<number \| null>` | Hover-/Klickspalte |
| `gameEndedInformation` | `Ref<GameEnded \| null>` | Endscreen-Daten |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `createGame` | - | `Promise<void>` | Delegiert an `OnlineGame.createGame` |
| `tryToJoin` | - | `Promise<void>` | Delegiert an `OnlineGame.joinGame` |
| `restartGame` | - | `Promise<void>` | Startet neue Runde via Replay-Code |
| `onUnmounted` Hook | - | - | Trennt SignalR-Verbindung |
### Events
- Child-Events: `createGame`, `join`, `restart-game`, `click-on-game-field`.
- Interne Callbacks: `onGameStateChanged`, `onGameEnded`, `onGameCreated`, `onGameStarted`, `onGameJoinedFailed`.
### API Calls
Indirekt über `OnlineGame``GameConnection` (`CreateGame`, `JoinGame`, `Drop`).
---
## LocalMode.vue (Komponente)
### Zweck
Steuert lokalen Spielmodus inkl. optionalem Bot.
### Props
Keine.
### State / reactive Daten
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `settings` | `Ref<GameSettings>` | Lokale Spieleinstellungen |
| `currentState` | `Ref<CurrentState>` | UI-State (Create/Game/End) |
| `game` | `Ref<LocalGame>` | Lokaler Spielorchestrator |
| `gameField` | `Ref<number[][]>` | Angezeigter Feldzustand |
| `currentSelectionIndex` | `Ref<number \| null>` | Ausgewählte Spalte |
| `gameEndedInformation` | `Ref<GameEnded \| null>` | Endinformationen |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `startGame` | - | `Promise<void>` | Verbindet beide lokale Clients und erstellt Spiel |
| `restart` | - | `Promise<void>` | Trennt beide Clients und startet neu |
### Events
- Child-Events: `create-game`, `restart-game`, `click-on-game-field`.
### API Calls
Indirekt über `LocalGame` → 2× `GameConnection`.
---
## NotFound.vue (Komponente)
### Zweck
Fallback-Anzeige für unbekannte Routen.
### Props / State / Methoden / Events / API Calls
Keine fachliche Logik.
---
## CreateOrJoinMenu.vue (Komponente)
### Zweck
Zwischenschritt im Online-Modus zur Auswahl zwischen Erstellen und Beitreten.
### Props
Keine.
### State / reactive Daten
Keine.
### Methoden
Keine.
### Events
| Event | Beschreibung |
| --- | --- |
| `createGame` | Wechselt in Erstellungsflow |
| `joinGame` | Wechselt in Join-Flow |
### API Calls
Keine.
---
## GameCreationMenu.vue (Komponente)
### Zweck
Eingabe von Namen, Feldgröße und optional Bot-Konfiguration.
### Props
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `settings` (Model) | `GameSettings` | Zweiwegegebundene Einstellungen |
### State / reactive Daten
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `settingsProp` | `ModelRef<GameSettings>` | Reaktiver Zugriff auf Einstellungen |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `gameFieldPreset` | `x: number`, `y: number` | `void` | Setzt vordefinierte Spielfeldgröße |
### Events
| Event | Beschreibung |
| --- | --- |
| `createGame` | Startet Spiel-/Lobby-Erzeugung |
### API Calls
Keine direkten.
---
## GameJoinMenu.vue (Komponente)
### Zweck
Erfasst Spielername und sechsstelligen Beitrittscode.
### Props
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `joinGameObject` (Model) | `JoinGameObject` | Daten inklusive Fehlerzustand |
### State / reactive Daten
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `joiningModel` | `ModelRef<JoinGameObject>` | Lokaler Zugriff auf Join-Modell |
### Methoden
Keine.
### Events
| Event | Beschreibung |
| --- | --- |
| `join` | Löst Join-Operation aus |
### API Calls
Keine direkten.
---
## GameEndedMenu.vue (Komponente)
### Zweck
Anzeige des Endzustands (Sieg/Draw/Disconnect) und Neustartaktion.
### Props
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `gameEndedInformation` | `GameEnded \| null` | Endereignis-Payload |
### State / reactive Daten
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `restarted` | `Ref<boolean>` | Verhindert Mehrfachklick auf Neustart |
| `message` | `ComputedRef<string>` | Aufbereiteter Endtext |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `restartClicked` | - | `void` | Emitet Neustart und setzt Sperrflag |
### Events
| Event | Beschreibung |
| --- | --- |
| `restartGame` | Triggert neues Spiel |
### API Calls
Keine direkten.
---
## Slider.vue (Komponente)
### Zweck
Generischer Slider mit numerischer Anzeige.
### Props
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `label` | `string` | Beschriftung |
| `min` | `number` | Untergrenze |
| `max` | `number` | Obergrenze |
| `step` | `number` | Schrittweite |
| `width` | `string \| number` | Breite Inputfeld |
| `disabled` | `boolean` | Deaktivierung |
| `readonlyValue` | `boolean` | Schreibschutz Input |
### State / reactive Daten
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `model` | `ModelRef<number>` | Aktueller Wert |
| `inputWidth` | `ComputedRef<string>` | CSS-Breite des Append-Inputs |
### Methoden
Keine separaten Methoden.
### Events
Standard `v-model`-Update.
### API Calls
Keine.
---
## Field.vue (Komponente)
### Zweck
Visuelle Darstellung des Spielfeldes inkl. Hover-/Auswahlspalte.
### Props
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `gameState` | `number[][]` | Feldzustand |
| `currentSelectionIndex` (Model) | `number \| null` | aktuell gewählte Spalte |
### State / reactive Daten
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `gameFieldSize` | `ComputedRef<FieldSize>` | abgeleitete Feldgröße |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| `translateNumberToImage` | `num: number` | `string` | Mapt Feldwert auf Sprite-Pfad |
| `selectionUpdate` | `index: number`, `active: boolean` | `void` | Setzt/entfernt Spaltenauswahl |
### Events
| Event | Beschreibung |
| --- | --- |
| `clickOnGameField` | Anwender klickt auf Spielfeld, Parent löst `drop` aus |
### API Calls
Keine direkten.
---
## InfoField.vue (Komponente)
### Zweck
Zeigt Status- oder Hinweistext zum aktuellen Zug.
### Props
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `msg` | `string` | Meldung |
| `currenlyWaiting?` | `boolean` | Optionales Ausblend-Flag |
### State / Methoden / Events / API Calls
Keine.
---
## FieldSize (Interface)
### Zweck
Typsichere Feldgrößenbeschreibung.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `x` | `number` | Breite |
| `y` | `number` | Höhe |
---
## GameSettings (Interface)
### Zweck
Konfigurationsmodell für Spielanlage.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `fieldSize` | `FieldSize` | Spielfeldgröße |
| `playerName1` | `string` | Spieler 1 |
| `playerName2?` | `string \| null` | Spieler 2 (lokal/optional) |
| `botPlayer2?` | `boolean \| null` | Bot-Flag für Spieler 2 |
| `message?` | `string \| null` | UI-Nachricht nach Erstellung |
---
## JoinGameObject (Interface)
### Zweck
Eingabemodell für Beitritt zu bestehendem Spiel.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `failed` | `boolean` | Fehlerstatus (UI) |
| `playerName` | `string` | Anzeigename |
| `gameCode?` | `string` | Eingetippter 6-stelliger Code |
---
## GameConnection (Klasse)
### Zweck
SignalR-Transportabstraktion für Hub-Aufrufe und Eventbindung.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `connection` | `signalR.HubConnection` | Physische SignalR-Verbindung |
| `playerName` | `string` | Lokaler Name für Hub-Aufrufe |
| Callback-Felder | optionale Funktionen | Reaktion auf Hub-Events (`onGameCreated`, `onError`, ... ) |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| Konstruktor | - | - | Baut HubConnection (`/api/gamehub`) und registriert Event-Listener |
| `connect` | `playerName: string` | `Promise<void>` | Startet Verbindung |
| `disconnect` | - | `Promise<void>` | Stoppt Verbindung |
| `createGame` | `gFs: FieldSize` | `Promise<void>` | Hub-Invoke `CreateGame` |
| `joinGame` | `gameCode: number` | `Promise<void>` | Hub-Invoke `JoinGame` |
| `requestGameInformation` | `gameId: string` | `Promise<void>` | Hub-Invoke `RequestGameInformation` |
| `drop` | `gameId: string`, `column: number` | `Promise<void>` | Hub-Invoke `Drop` |
### Beziehungen
- Wird von `OnlineGame` und `LocalGame` verwendet.
- Spiegelt Server-Eventmodell 1:1.
---
## OnlineGame (Klasse)
### Zweck
Use-Case-Orchestrierung für Online-Spiel aus Sicht eines einzelnen Clients.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `player` | `GameConnection` | SignalR-Clientinstanz |
| `currentDescription` | `string` | Text zur aktuellen Runde |
| `gameId` | `string` | Serverseitige Spiel-ID |
| `gameState` | `GameInformationDto \| undefined` | Lokaler Snapshot |
| Callback-Felder | optionale Funktionen | Hooks für UI (`onGameCreated`, `onGameEnded`, ...) |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| Konstruktor | - | - | Verkabelt alle Transport-Events auf UI-Callbacks |
| `createGame` | `settings: GameSettings` | `Promise<void>` | Verbindet Spieler und erstellt Lobby |
| `joinGame` | `joinObject: JoinGameObject` | `Promise<void>` | Validiert Codeformat, verbindet, tritt Spiel bei |
| `updateState` | `newState: GameInformationDto` | `Promise<void>` | Aktualisiert lokalen Zustand und Callback |
| `drop` | `index: number` | `Promise<void>` | Führt Zug im aktuellen Spiel aus |
| `changePlaceDescription` | - | `void` | Setzt zufällige Zugmeldung anhand `currentTurn` |
| `restartGame` | `replayGameCode: any` | `Promise<void>` | Trennt Verbindung und joint Replay-Code |
### Beziehungen
- Nutzt `GameConnection` und Utility `getRandomMovePhrase`.
---
## LocalGame (Klasse)
### Zweck
Orchestriert lokalen Modus durch zwei parallele `GameConnection`-Instanzen.
### Eigenschaften
| Name | Typ | Beschreibung |
| --- | --- | --- |
| `player1` | `GameConnection` | Lokaler Client 1 |
| `player2` | `GameConnection` | Lokaler Client 2/Bot |
| `currentDescription` | `string` | UI-Text aktueller Spieler |
| `gameId` | `string` | Aktuelle Spiel-ID |
| `botGame` | `boolean` | Bot-Modus für Spieler 2 |
| `gameState` | `GameInformationDto \| undefined` | Spielsnapshot |
| Callback-Felder | optionale Funktionen | UI-Hooks für State-Änderung und Spielende |
### Methoden
| Methode | Parameter | Rückgabewert | Beschreibung |
| --- | --- | --- | --- |
| Konstruktor | - | - | Verdrahtet Events beider Player-Verbindungen |
| `start` | `settings: GameSettings` | `Promise<void>` | Verbindet beide Spieler und erstellt neues Spiel |
| `updateState` | `newState: GameInformationDto` | `Promise<void>` | Aktualisiert lokalen Zustand |
| `drop` | `index: number` | `Promise<void>` | Führt Zug durch aktuellen Spieler aus; Bot setzt random verzögert |
| `changePlaceDescription` | - | `void` | Erzeugt zufällige Zugmeldung |
| `disconnectAll` | - | `Promise<void>` | Trennt beide SignalR-Verbindungen |
### Beziehungen
- Nutzt 2× `GameConnection`, optional Bot-Zug per Zufall.
---
## buildFieldArray (Funktion)
### Zweck
Erzeugt initiales `number[][]`-Spielfeld in gewünschter Größe.
### Signatur
`buildFieldArray(fieldSize: FieldSize): number[][]`
### Verhalten
- Erstellt `y` Zeilen, jede Zeile enthält `x` Nullen.
---
## getRandomMovePhrase (Funktion)
### Zweck
Erzeugt abwechslungsreiche Statusmeldung für die UI.
### Signatur
`getRandomMovePhrase(playerName: string): string`
### Verhalten
- Wählt zufällig eine Phrase aus `movePhrases`.
- Ersetzt Platzhalter `{playerName}`.
---
## 7. Datenmodelle
## Backend-Datenmodelle
### Game
- `id`: string
- `gameCode`: SixDigitInt
- `players`: List<Player>
- `currentTurn`: int (1 oder 2)
- `state`: GameState
- `field`: GameField
Beziehungen:
- 1 Game besitzt 1 GameField
- 1 Game besitzt 0..2 Player
### Player
- `name`: string
- `connectionId`: string
- `playerTag`: int
### GameField
- `gFs`: Coordinates
- `currentField`: int[,]
- `backupField`: int[,]
### GameInformationDto
- `id`: string
- `players`: List<Player>
- `state`: GameState?
- `currentField`: int[][]
- `currentTurn`: int
### Coordinates
- `x`: int
- `y`: int
### SixDigitInt
- `value`: int
## Frontend-Datenmodelle
### GameInformationDto (TS)
- `id: string | null`
- `players: Player[]`
- `state: number`
- `currentField: number[][]`
- `currentTurn: number`
### Player (TS)
- `name: string`
- `connectionId: string`
- `playerTag: number`
### GameEnded (TS)
- `method: string`
- `player?: Player | null`
- `replayGameCode?: number | null`
### GameIdentifier (TS)
- `gameId: string`
- `gameCode: number`
### GameSettings (TS)
- siehe Abschnitt 6
### JoinGameObject (TS)
- siehe Abschnitt 6
---
## 8. Spiel- / Geschäftslogik
### Spiel erstellen
1. Client verbindet SignalR (`connect`).
2. Client ruft `CreateGame(playerName, fieldSize)`.
3. Server erstellt `Game`, setzt Spieler 1, vergibt GameCode.
4. Server fügt Client zur Gruppe `game.Id` hinzu.
5. Server sendet `GameCreated` an Ersteller.
### Spiel beitreten
1. Client validiert 6-stelligen Code lokal.
2. Client ruft `JoinGame(playerName, gameCode)`.
3. Server prüft Spiel vorhanden + `Lobby` + Platz frei.
4. Server fügt Spieler 2 hinzu, setzt ggf. Spiel auf `Running`.
5. Server fügt Client zur Gruppe `game.Id` hinzu.
6. Server sendet `GameStarted` an Gruppe.
### Spiel starten
- Start erfolgt implizit beim zweiten Spieler (`AddPlayer`/`JoinGame`).
### Spielzüge
1. Aktiver Spieler sendet `Drop(gameId, column)`.
2. Server prüft Verbindung zu Spiel + Turn-Recht + Zustand `Running`.
3. `GameField.Drop` setzt Stein in unterste freie Zelle.
4. Server toggelt `CurrentTurn`.
5. Server sendet `FieldUpdated` an Spielgruppe.
### Spielende
- **Gewinn**: `CheckForWin() != 0`, dann `GameEnded(Method=Win)` + Replay-Code.
- **Unentschieden**: `IsFull() == true`, dann `GameEnded(Method=Draw)` + Replay-Code.
- **Disconnect**: `DisconnectedPlayer`, dann `GameEnded(Method=PlayerDisconnected)`.
---
## 9. Datenfluss
### Ablauf „Spiel erstellen“
1. Frontend (`OnlineGame.createGame`) sendet `CreateGame`.
2. `GameHubSocket.CreateGame` erstellt `Player` und delegiert.
3. `GameManager.CreateGame` ruft Repository `Create`.
4. Hub fügt Verbindung zur SignalR-Gruppe hinzu.
5. Hub sendet `GameCreated` an Caller.
6. Frontend zeigt Join-Code in `GameCreationMenu`.
### Ablauf „Spielzug“
1. Nutzer klickt Spalte in `Field.vue`.
2. Route ruft `game.drop(index)`.
3. `GameConnection.drop` invokt Hub-Methode.
4. `GameManager.Drop` validiert und setzt Stein.
5. `FieldUpdated` wird an Gruppe gesendet.
6. Clients aktualisieren `gameField` und Statusnachricht.
### Ablauf „Spielende + Replay“
1. Nach Win/Draw erstellt Server ein neues Spiel mit gleicher Feldgröße.
2. Server sendet `GameEnded` inkl. `ReplayGameCode`.
3. Frontend zeigt `GameEndedMenu`.
4. Beim Neustart joint Client per Replay-Code.
---
## 10. Wichtige Algorithmen
### Spielzug validieren
- Prüfungen in Reihenfolge:
1. Spiel existiert
2. Spieler gehört zum Spiel
3. Spielzustand ist `Running`
4. `CurrentTurn == player.PlayerTag`
5. Spalte in Bounds
6. Spalte nicht voll
7. Feldwerte konsistent (nur 0/1/2)
### Gewinner erkennen
- Für jede Zelle mit Spielerwert 1/2 werden vier Richtungen geprüft:
- Horizontal `(1,0)`
- Vertikal `(0,1)`
- Diagonal rechts-unten `(1,1)`
- Diagonal links-unten `(-1,1)`
- Der Algorithmus zählt zusammenhängende Steine in beide Richtungen und addiert die Startzelle.
- `>= 4` ergibt Sieg.
### Spielstatus berechnen
- `Lobby` → weniger als 2 Spieler.
- `Running` → 2 Spieler und laufendes Spiel.
- `Ended` → bei Win/Draw/Disconnect.
---
## 11. API-Dokumentation
### HTTP-Endpunkte
| Endpoint | Methode | Beschreibung |
| --- | --- | --- |
| `/api/status` | `GET` | Healthcheck (`Running`) |
### SignalR Hub-Endpunkt
| Endpoint | Methode | Beschreibung |
| --- | --- | --- |
| `/api/gamehub` | SignalR | Echtzeitkommunikation für Spiellogik |
### Hub-Methoden
| Hub-Methode | Parameter | Beschreibung |
| --- | --- | --- |
| `CreateGame` | `playerName: string`, `gFs: Coordinates` | Erstellt neues Spiel |
| `JoinGame` | `playerName: string`, `gameCode: int` | Tritt bestehendem Spiel bei |
| `RequestGameInformation` | `gameId: string` | Liefert aktuellen Zustand |
| `Drop` | `gameId: string`, `column: int` | Führt Zug aus |
---
## 12. Ereignisse / Echtzeitkommunikation
| Event | Sender | Empfänger | Beschreibung |
| --- | --- | --- | --- |
| `GameCreated` | Server | Caller | Enthält `gameId`, `gameCode` nach Erstellung |
| `GameJoined` | Server | Caller | Bestätigt Beitritt |
| `GameStarted` | Server | Gruppe `game.Id` | Initialer Spielzustand nach 2. Spieler |
| `GameInformation` | Server | Einzelclient | Zustandsabfrage-Antwort |
| `FieldUpdated` | Server | Gruppe `game.Id` | Feld/Turn nach gültigem Zug |
| `GameEnded` | Server | Gruppe `game.Id` | Endgrund: Win/Draw/Disconnect + optionale Daten |
| `GameDestroyed` | Server | Gruppe `game.Id` | Hinweis nach geplanter Löschung |
| `Error` | Server | Caller/Client | Fehlertext (z. B. ungültiger Zug / Spiel nicht gefunden) |
---
## 13. Benutzeroberfläche
### Screens
1. **Startseite**: Moduswahl lokal/online
2. **Online: Auswahlseite**: Erstellen oder Beitreten
3. **Spielerstellung**: Namen, Feldgröße, Presets
4. **Join-Seite**: Name + OTP-Feld für Spielcode
5. **Spielansicht**: Spielfeld + Zugstatus
6. **Endscreen**: Ergebnis + Neustartoption
### UI-Ablauf
- Nutzer startet auf Home und navigiert über Buttons.
- In Spielansicht zeigt `Field` den Rasterzustand mit Hover-Pfeil.
- `InfoField` zeigt dynamische Spielzugtexte.
- Endzustand sperrt Spiel und bietet Neustart/Abbruch.
### Benutzeraktionen
- Namen eingeben
- Feldgröße per Slider/Presets auswählen
- Beitrittscode eingeben
- Spalte durch Hover/Klick auswählen
- Neustart auslösen
---
## 14. Anwendungsabläufe (User-Flows)
### Flow A: Online-Spiel erstellen
1. Home → Online Multiplayer.
2. Auswahl „Erstellen“.
3. Name/Feldgröße setzen, Spiel starten.
4. Code wird angezeigt.
5. Warten bis zweiter Spieler beitritt.
6. Spiel startet automatisch.
### Flow B: Online-Spiel beitreten
1. Home → Online Multiplayer.
2. Auswahl „Beitreten“.
3. Namen + 6-stelligen Code eingeben.
4. Bei Erfolg Übergang in Spielansicht.
5. Bei Fehler (`failed=true`) visuelles Feedback.
### Flow C: Lokal spielen
1. Home → Lokaler Multiplayer.
2. Namen/Feldgröße/Bot-Option setzen.
3. Spiel starten.
4. Spieler wechseln ab (oder Bot setzt random).
5. Endscreen erscheint bei Win/Draw.
### Flow D: Spiel erneut starten
1. Endscreen „Spiel Neustarten“.
2. Online: Join auf vom Server gelieferten Replay-Code.
3. Lokal: Verbindungen schließen und neu initialisieren.
---
## 15. Annahmen und Einschränkungen
1. **Keine persistente Speicherung**: Alle Spiele gehen bei Serverneustart verloren.
2. **Maximal 2 Spieler pro Spiel**.
3. **Keine Authentifizierung/Autorisierung** für Spielzugriffe.
4. **Disconnect-Handling simpel**: Ein Disconnect beendet das Spiel.
5. **Fehlertoleranz begrenzt**: Teilweise nur Logging/Events, keine Retry-Strategie.
6. **Lokaler Modus nutzt trotzdem Server/SignalR** (zwei Verbindungen im selben Client-Kontext).
7. **Skalierung**: In-Memory-Liste ist nicht für Multi-Instance-Betrieb ausgelegt.
---
## 16. Erweiterungsmöglichkeiten
1. Persistentes Repository (SQL/NoSQL) inkl. Match-Historie
2. Benutzerkonten, Auth und Freundeslisten
3. Elo-/Ranking-System
4. Beobachtermodus (Spectator)
5. Chat pro Spielgruppe
6. Zugtimer und automatische Aufgabe
7. Mehrsprachigkeit (i18n)
8. KI mit heuristischer oder minimax-basierter Strategie
9. Reconnect-Mechanismus mit Session-Tokens
10. Horizontale Skalierung mit verteiltem Backplane/Cache für SignalR
11. REST-API für Match-Archiv und Statistiken
12. Erweiterte Telemetrie und strukturiertes Logging
---
## Ableitbarkeit für Folgeartefakte
Diese Spezifikation enthält alle notwendigen Informationen, um automatisiert folgende Artefakte abzuleiten:
- **Pflichtenheft**: Kapitel 1, 2, 8, 14, 15
- **Meilensteinplanung**: Kapitel 3, 4, 5, 6, 16
- **UML-Klassendiagramm**: Kapitel 5, 6, 7
- **Ablaufplan / Flowchart**: Kapitel 8, 9, 14
- **Benutzerdokumentation**: Kapitel 13, 14