/**
* NIM Spiel - Konkrete Implementierung des GameState-Interfaces.
*
* Dies ist ein VOLLSTÄNDIGES Beispiel für eine neue Spielimplementierung.
* Schüler können dies als Vorlage für ihre eigenen Spiele verwenden.
*
* Spielregeln:
* - 3 Haufen mit je 3 Streichhölzern
* - Spieler nimmt beliebig viele Streichhölzer aus EINEM Haufen
* - Wer den LETZTEN nimmt, gewinnt (Normales Nim)
*
* @fileoverview NIM Game - Implementierungsbeispiel
*/
class NIMGameLogic extends GameState {
/**
* Initialisiert ein neues NIM-Spiel.
*
* @param {Array<number>} [piles] - Optional: Startkonfiguration
*/
constructor(piles = [3, 3, 3]) {
super();
// === Basis-Eigenschaften (geerbt) ===
this.currentPlayer = 1; // Spieler 1 startet
this.winner = 0; // 0 = noch nicht entschieden
this.isGameOver = false; // Spiel läuft noch
// === NIM-spezifische Daten ===
this.piles = [...piles]; // Kopie der Haufen-Konfiguration
// Move-Historie für Debugging (optional)
this.moveHistory = [];
}
/**
* ✅ ERFORDERLICH: getAllValidMoves()
*
* Im NIM gibt es gültige Züge, wenn noch Streichhölzer vorhanden sind.
* Ein Zug: {pile: 0-2, count: 1-n} wobei n die Größe des Haufens
*
* @returns {Array<Object>} Array von {pile, count} Objekten
*/
getAllValidMoves() {
if (this.isGameOver) return [];
const moves = [];
// Iteriere über alle Haufen
for (let pileIdx = 0; pileIdx < this.piles.length; pileIdx++) {
// Für jeden Haufen: kann 1 bis piles[pileIdx] Streichhölzer nehmen
for (let count = 1; count <= this.piles[pileIdx]; count++) {
moves.push({ pile: pileIdx, count });
}
}
return moves;
}
/**
* ✅ ERFORDERLICH: makeMove(move)
*
* Führt einen NIM-Zug aus:
* 1. Validierung
* 2. Piles aktualisieren
* 3. Spielende prüfen
* 4. Spieler wechseln
*
* @param {Object} move - {pile: number, count: number}
* @returns {boolean}
*/
makeMove(move) {
// Typ-Check: NIM akzeptiert Objekte
if (typeof move !== 'object' || move.pile === undefined || move.count === undefined) {
DebugConfig.log(DEBUG_DOMAINS.GAMES_NIM, "warn", "NIM: Ungültiges Move-Format. Erwartet {pile, count}");
return false;
}
const { pile, count } = move;
// === Validierung ===
if (this.isGameOver) {
DebugConfig.log(DEBUG_DOMAINS.GAMES_NIM, "warn", "NIM: Spiel ist bereits vorbei");
return false;
}
if (pile < 0 || pile >= this.piles.length) {
DebugConfig.log(DEBUG_DOMAINS.GAMES_NIM, "warn", `NIM: Ungültiger Haufen ${pile}`);
return false;
}
if (count < 1 || count > this.piles[pile]) {
DebugConfig.log(DEBUG_DOMAINS.GAMES_NIM, "warn", `NIM: Kann nicht ${count} Streichhölzer aus Haufen ${pile} nehmen (hat nur ${this.piles[pile]})`);
return false;
}
// === Zug ausführen ===
this.piles[pile] -= count;
this.moveHistory.push({ pile, count, player: this.currentPlayer, pilesBefore: [...this.piles] });
// === Spielende prüfen ===
this._checkGameEnd();
// === Spieler wechseln ===
if (!this.isGameOver) {
this.currentPlayer = this.currentPlayer === 1 ? 2 : 1;
}
return true;
}
/**
* ✅ ERFORDERLICH: clone()
*
* Erstellt eine exakte Kopie für KI-Simulationen.
*
* @returns {NIMGameLogic}
*/
clone() {
const copy = new NIMGameLogic(this.piles);
copy.currentPlayer = this.currentPlayer;
copy.winner = this.winner;
copy.isGameOver = this.isGameOver;
copy.moveHistory = [...this.moveHistory]; // Flache Kopie reicht
return copy;
}
/**
* ✅ ERFORDERLICH: getStateKey()
*
* Zwei Zustände sind gleich, wenn:
* - Die Haufen identisch sind
* - Der aktuelle Spieler gleich ist
*
* @returns {string}
*/
getStateKey() {
return JSON.stringify({
piles: this.piles,
player: this.currentPlayer
});
}
/**
* Hilfsfunktion: Prüft auf Spielende
*
* Spielende ist erreicht, wenn keine Streichhölzer mehr vorhanden sind.
* Der aktuelle Spieler (der gerade gezogen hat) gewinnt.
*/
_checkGameEnd() {
// Sind alle Haufen leer?
if (this.piles.every(pile => pile === 0)) {
// Der Spieler, der gerade gezogen hat (currentPlayer), gewinnt
this.winner = this.currentPlayer;
this.isGameOver = true;
}
}
/**
* OPTIONAL: Gibt einen lesbar formatierten String des Zustands zurück.
* Nützlich zum Debuggen.
*
* @returns {string}
*/
toString() {
return `NIM [P${this.currentPlayer}]: [${this.piles.join(', ')}] Winner: ${this.winner}`;
}
}
// ============== EXPORT ==============
if (typeof module !== 'undefined' && module.exports) {
module.exports = NIMGameLogic;
}