Files

248 lines
9.6 KiB
JavaScript
Executable File

// McGonagall's Wizard Chess (Zauberschach) Mini-Game
(function() {
const boardEl = document.getElementById('chessBoard');
if (!boardEl) return;
const statusMsg = document.getElementById('chessStatus');
const moveHistoryEl = document.getElementById('moveHistory');
const modalBackdrop = document.getElementById('modalBackdrop');
const modalTitle = document.getElementById('modalTitle');
const modalText = document.getElementById('modalText');
const modalBtn = document.getElementById('modalBtn');
const btnResetChess = document.getElementById('btnResetChess');
// Piece Unicode Symbols
const PIECES = {
'wK': '♔', 'wQ': '♕', 'wR': '♖', 'wB': '♗', 'wN': '♘', 'wP': '♙',
'bK': '♚', 'bQ': '♛', 'bR': '♜', 'bB': '♝', 'bN': '♞', 'bP': '♟'
};
// Initial Board State for "Rons Meisterzug" (Smothered Mate / Zauberschach-Taktik)
// Black to move: Knight on g4 and Queen on h4 attack White's castled King on h1!
let initialPosition = {
'h1': 'wK', 'g2': 'wP', 'h2': 'wP', 'f1': 'wR', 'd2': 'wQ', 'b2': 'wP', 'a1': 'wR',
'g8': 'bK', 'g7': 'bP', 'h7': 'bP', 'f8': 'bR', 'h4': 'bQ', 'g4': 'bN', 'c6': 'bP'
};
let boardState = {};
let selectedSquare = null;
let isSolved = false;
function initBoard() {
boardState = Object.assign({}, initialPosition);
selectedSquare = null;
isSolved = false;
if (statusMsg) {
statusMsg.innerHTML = "🧙‍♂️ <strong>Du führst Schwarz (Rons Springer & Hermines Figuren)!</strong> Finde den vernichtenden Zug gegen den weißen König!";
statusMsg.style.color = "var(--gold)";
}
if (moveHistoryEl) moveHistoryEl.innerHTML = "<li>Partie eröffnet: Schwarz am Zug!</li>";
renderBoard();
}
// Valid moves for Black pieces in this tactical puzzle
function getValidMoves(square) {
const piece = boardState[square];
if (!piece || !piece.startsWith('b')) return [];
const file = square.charCodeAt(0) - 97; // 0 to 7 (a-h)
const rank = parseInt(square[1], 10) - 1; // 0 to 7 (1-8)
const moves = [];
if (piece === 'bN') {
// Knight moves: L-shape
const offsets = [
[-2, -1], [-2, 1], [-1, -2], [-1, 2],
[1, -2], [1, 2], [2, -1], [2, 1]
];
offsets.forEach(([df, dr]) => {
const nf = file + df;
const nr = rank + dr;
if (nf >= 0 && nf < 8 && nr >= 0 && nr < 8) {
const targetSq = String.fromCharCode(97 + nf) + (nr + 1);
const targetPiece = boardState[targetSq];
if (!targetPiece || targetPiece.startsWith('w')) {
moves.push(targetSq);
}
}
});
} else if (piece === 'bQ') {
// Queen moves: orthogonal + diagonal
const directions = [
[0, 1], [0, -1], [1, 0], [-1, 0],
[1, 1], [1, -1], [-1, 1], [-1, -1]
];
directions.forEach(([df, dr]) => {
let step = 1;
while (true) {
const nf = file + df * step;
const nr = rank + dr * step;
if (nf < 0 || nf >= 8 || nr < 0 || nr >= 8) break;
const targetSq = String.fromCharCode(97 + nf) + (nr + 1);
const targetPiece = boardState[targetSq];
if (!targetPiece) {
moves.push(targetSq);
} else {
if (targetPiece.startsWith('w')) moves.push(targetSq);
break;
}
step++;
}
});
}
return moves;
}
function renderBoard() {
boardEl.innerHTML = '';
// 8 ranks (from 8 down to 1), 8 files (a to h)
for (let r = 8; r >= 1; r--) {
for (let f = 0; f < 8; f++) {
const sq = String.fromCharCode(97 + f) + r;
const isLight = (f + r) % 2 !== 0;
const tile = document.createElement('div');
tile.className = `chess-sq ${isLight ? 'light' : 'dark'}`;
tile.dataset.sq = sq;
if (selectedSquare === sq) {
tile.classList.add('selected');
}
const piece = boardState[sq];
if (piece) {
const pSpan = document.createElement('span');
pSpan.className = `chess-piece ${piece.startsWith('w') ? 'white-piece' : 'black-piece'}`;
pSpan.innerText = PIECES[piece] || '';
tile.appendChild(pSpan);
}
// Show valid moves
if (selectedSquare) {
const validMoves = getValidMoves(selectedSquare);
if (validMoves.includes(sq)) {
const dot = document.createElement('div');
dot.className = piece ? 'move-capture-ring' : 'move-dot';
tile.appendChild(dot);
}
}
tile.addEventListener('click', () => onSquareClick(sq));
boardEl.appendChild(tile);
}
}
}
function onSquareClick(sq) {
if (isSolved) return;
const piece = boardState[sq];
if (selectedSquare) {
const validMoves = getValidMoves(selectedSquare);
if (validMoves.includes(sq)) {
// Execute Move!
executeMove(selectedSquare, sq);
selectedSquare = null;
return;
}
}
// Select new piece if black
if (piece && piece.startsWith('b')) {
selectedSquare = sq;
if (window.soundFX) window.soundFX.playStoneSlide();
renderBoard();
} else {
selectedSquare = null;
renderBoard();
}
}
async function executeMove(fromSq, toSq) {
const piece = boardState[fromSq];
const capturedPiece = boardState[toSq];
delete boardState[fromSq];
boardState[toSq] = piece;
if (window.soundFX) {
window.soundFX.playStoneSlide();
if (capturedPiece) {
window.soundFX.playPoisonSizzle(); // Crushing sound
}
}
renderBoard();
// Check if winning move:
// Winning move 1: Knight moves to f2+ (Smothered mate / Royal fork!)
// Winning move 2: Queen captures h2# (Schachmatt!)
if (piece === 'bN' && toSq === 'f2') {
if (moveHistoryEl) {
const li = document.createElement('li');
li.innerHTML = `<strong>1... ♞f2+</strong> (Springer-Schach! Weißer König erstarrt!)`;
moveHistoryEl.appendChild(li);
}
triggerWin("♞f2+", "Rons Springer zerschellt die weiße Verteidigung! Der weiße König hat kein Feld mehr und die weiße Königin muss kapitulieren!");
} else if (piece === 'bQ' && toSq === 'h2') {
if (moveHistoryEl) {
const li = document.createElement('li');
li.innerHTML = `<strong>1... ♛xh2#</strong> (Schachmatt! Die schwarze Dame schlägt zu!)`;
moveHistoryEl.appendChild(li);
}
triggerWin("♛xh2#", "Schachmatt! Mit kaltblütiger Präzision fällt der weiße König in Trümmer!");
} else {
if (moveHistoryEl) {
const li = document.createElement('li');
li.innerHTML = `Zug: ${piece} nach ${toSq}. Weiß pariert den Angriff. Versuche es erneut!`;
moveHistoryEl.appendChild(li);
}
if (statusMsg) {
statusMsg.innerHTML = "⚠️ <em>Kein Schachmatt! Die weißen Figuren schlagen zurück. Drücke auf 'Zurücksetzen' und versuche es erneut!</em>";
statusMsg.style.color = "#e67e22";
}
}
}
async function triggerWin(moveNotation, explanation) {
isSolved = true;
if (window.soundFX) window.soundFX.playMagicSuccess();
if (statusMsg) {
statusMsg.innerHTML = `🏆 <strong>${moveNotation} — SCHACHMATT!</strong> Die gigantischen weißen Steinfiguren senken ihre Schwerter!`;
statusMsg.style.color = "#2ecc71";
}
try {
const res = await fetch('/api/chess/complete', { method: 'POST' });
const data = await res.json();
if (data.new_item && window.notifyNewItem) {
window.notifyNewItem(data.new_item);
}
} catch (e) {
console.error(e);
}
modalTitle.innerText = "♟️ Zauberschach Gemeistert!";
modalText.innerHTML = `
<strong>${moveNotation} — Grandios kombiniert!</strong><br><br>
${explanation}<br><br>
Die weiße Königin wirft ihr Schwert zu Boden. Die Riesen-Schachfiguren weichen zur Seite und die Tür zur <strong>Flammenkammer (Snapes Flaschenrätsel)</strong> steht weit offen!<br><br>
🎒 <em>Ein massiver schwarzer Springer wurde deinem Zauberbeutel hinzugefügt!</em>
`;
modalBtn.innerText = "Weiter zu Snapes Flammenkammer 🧪";
modalBtn.onclick = () => { window.location.href = '/bottles'; };
modalBackdrop.classList.add('show');
}
if (btnResetChess) {
btnResetChess.addEventListener('click', () => {
if (window.soundFX) window.soundFX.playStoneSlide();
initBoard();
});
}
initBoard();
})();