chess/js/main.js
Christoph Wagner 82479fb8c7
Some checks failed
CI Pipeline / Code Linting (pull_request) Successful in 13s
CI Pipeline / Run Tests (pull_request) Failing after 19s
CI Pipeline / Build Verification (pull_request) Has been skipped
CI Pipeline / Generate Quality Report (pull_request) Failing after 19s
fix: correct DOM element IDs for move history and captured pieces
Fixes #2 and #3 - DOM element ID mismatches causing UI features to fail

Changes:
- Update move history element ID from 'move-list' to 'move-history' (line 185)
- Update white captured pieces ID from 'white-captured' to 'captured-white-pieces' (line 214)
- Update black captured pieces ID from 'black-captured' to 'captured-black-pieces' (line 215)

These changes align JavaScript DOM queries with the actual element IDs
defined in index.html, enabling move history and captured pieces displays
to function correctly.

Impact:
- Move history now displays correctly in the UI sidebar
- Captured pieces now display correctly for both white and black
- No changes to game logic or business rules
- Zero regression risk (simple ID corrections)

Testing:
- ESLint passes with 0 errors (6 warnings pre-existing)
- Changes verified against HTML element IDs in index.html

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-23 15:04:34 +01:00

319 lines
9.3 KiB
JavaScript

/**
* main.js - Application entry point
* Initializes game and connects all components
*/
import { GameController } from './controllers/GameController.js';
import { BoardRenderer } from './views/BoardRenderer.js';
import { DragDropHandler } from './controllers/DragDropHandler.js';
class ChessApp {
constructor() {
// Initialize components
this.game = new GameController({
autoSave: true,
enableTimer: false
});
this.renderer = new BoardRenderer(
document.getElementById('chess-board'),
{
showCoordinates: true,
pieceStyle: 'symbols',
highlightLastMove: true
}
);
this.dragDropHandler = new DragDropHandler(this.game, this.renderer);
// Initialize UI
this.initializeUI();
this.setupEventListeners();
this.setupGameEventListeners();
// Start new game
this.game.newGame();
this.updateDisplay();
}
/**
* Initialize UI components
*/
initializeUI() {
// Render initial board
this.renderer.renderBoard(this.game.board, this.game.gameState);
// Setup drag and drop
this.dragDropHandler.setupEventListeners();
// Update status
this.updateTurnIndicator();
}
/**
* Setup button event listeners
*/
setupEventListeners() {
// New Game
document.getElementById('btn-new-game').addEventListener('click', () => {
if (confirm('Start a new game? Current game will be lost.')) {
this.game.newGame();
this.updateDisplay();
this.showMessage('New game started!');
}
});
// Undo
document.getElementById('btn-undo').addEventListener('click', () => {
if (this.game.undo()) {
this.updateDisplay();
this.showMessage('Move undone');
} else {
this.showMessage('Nothing to undo');
}
});
// Redo
document.getElementById('btn-redo').addEventListener('click', () => {
if (this.game.redo()) {
this.updateDisplay();
this.showMessage('Move redone');
} else {
this.showMessage('Nothing to redo');
}
});
// Offer Draw
document.getElementById('btn-offer-draw').addEventListener('click', () => {
this.game.offerDraw();
this.showMessage('Draw offered to opponent');
});
// Resign
document.getElementById('btn-resign').addEventListener('click', () => {
if (confirm('Are you sure you want to resign?')) {
this.game.resign();
}
});
}
/**
* Setup game event listeners
*/
setupGameEventListeners() {
// Move made
this.game.on('move', (data) => {
this.updateDisplay();
this.playMoveSound();
});
// Check
this.game.on('check', (data) => {
this.showMessage(`Check! ${data.color} king is in check`);
this.playCheckSound();
});
// Checkmate
this.game.on('checkmate', (data) => {
this.showMessage(`Checkmate! ${data.winner} wins!`, 'success');
this.dragDropHandler.disable();
this.playCheckmateSound();
});
// Stalemate
this.game.on('stalemate', () => {
this.showMessage('Stalemate! Game is a draw', 'info');
this.dragDropHandler.disable();
});
// Draw
this.game.on('draw', (data) => {
this.showMessage(`Draw by ${data.reason}`, 'info');
this.dragDropHandler.disable();
});
// Resign
this.game.on('resign', (data) => {
const winner = data.loser === 'white' ? 'Black' : 'White';
this.showMessage(`${data.loser} resigned. ${winner} wins!`, 'success');
this.dragDropHandler.disable();
});
// Promotion
this.game.on('promotion', (data) => {
this.showPromotionDialog(data.pawn, data.position);
});
// New Game
this.game.on('newgame', () => {
this.dragDropHandler.enable();
this.updateDisplay();
});
}
/**
* Update all display elements
*/
updateDisplay() {
// Re-render board
this.renderer.renderBoard(this.game.board, this.game.gameState);
// Update turn indicator
this.updateTurnIndicator();
// Update move history
this.updateMoveHistory();
// Update captured pieces
this.updateCapturedPieces();
}
/**
* Update turn indicator
*/
updateTurnIndicator() {
const indicator = document.getElementById('turn-indicator');
const turn = this.game.currentTurn;
indicator.textContent = `${turn.charAt(0).toUpperCase() + turn.slice(1)} to move`;
indicator.style.color = turn === 'white' ? '#ffffff' : '#333333';
}
/**
* Update move history display
*/
updateMoveHistory() {
const moveList = document.getElementById('move-history');
const history = this.game.gameState.moveHistory;
if (history.length === 0) {
moveList.innerHTML = '<p style="color: #999; font-style: italic;">No moves yet</p>';
return;
}
let html = '';
for (let i = 0; i < history.length; i += 2) {
const moveNumber = Math.floor(i / 2) + 1;
const whiteMove = history[i];
const blackMove = history[i + 1];
html += `<div>${moveNumber}. ${whiteMove.notation}`;
if (blackMove) {
html += ` ${blackMove.notation}`;
}
html += '</div>';
}
moveList.innerHTML = html;
moveList.scrollTop = moveList.scrollHeight;
}
/**
* Update captured pieces display
*/
updateCapturedPieces() {
const whiteCaptured = document.getElementById('captured-white-pieces');
const blackCaptured = document.getElementById('captured-black-pieces');
const captured = this.game.gameState.capturedPieces;
whiteCaptured.innerHTML = captured.black.map(piece =>
`<span class="captured-piece black">${piece.getSymbol()}</span>`
).join('') || '-';
blackCaptured.innerHTML = captured.white.map(piece =>
`<span class="captured-piece white">${piece.getSymbol()}</span>`
).join('') || '-';
}
/**
* Show message to user
* @param {string} message - Message text
* @param {string} type - Message type (info, success, error)
*/
showMessage(message, type = 'info') {
const statusMessage = document.getElementById('status-message');
statusMessage.textContent = message;
statusMessage.style.display = 'block';
// Auto-hide after 3 seconds
setTimeout(() => {
statusMessage.style.display = 'none';
}, 3000);
}
/**
* Show promotion dialog
* @param {Pawn} pawn - Pawn to promote
* @param {Position} position - Pawn position
*/
showPromotionDialog(pawn, position) {
const overlay = document.getElementById('promotion-overlay');
const dialog = document.getElementById('promotion-dialog');
overlay.style.display = 'block';
dialog.style.display = 'block';
// Update symbols for current color
const symbols = pawn.color === 'white' ?
{ queen: '♕', rook: '♖', bishop: '♗', knight: '♘' } :
{ queen: '♛', rook: '♜', bishop: '♝', knight: '♞' };
document.querySelectorAll('.promotion-piece .symbol').forEach(el => {
const type = el.parentElement.dataset.type;
el.textContent = symbols[type];
el.style.color = pawn.color === 'white' ? '#ffffff' : '#000000';
});
// Handle selection
const handleSelection = (e) => {
const pieceType = e.currentTarget.dataset.type;
// Promote pawn
import('./engine/SpecialMoves.js').then(({ SpecialMoves }) => {
SpecialMoves.promote(this.game.board, pawn, pieceType);
this.updateDisplay();
});
// Hide dialog
overlay.style.display = 'none';
dialog.style.display = 'none';
// Remove listeners
document.querySelectorAll('.promotion-piece').forEach(el => {
el.removeEventListener('click', handleSelection);
});
};
document.querySelectorAll('.promotion-piece').forEach(el => {
el.addEventListener('click', handleSelection);
});
}
/**
* Play move sound (optional - can be implemented)
*/
playMoveSound() {
// TODO: Add sound effect
}
/**
* Play check sound (optional - can be implemented)
*/
playCheckSound() {
// TODO: Add sound effect
}
/**
* Play checkmate sound (optional - can be implemented)
*/
playCheckmateSound() {
// TODO: Add sound effect
}
}
// Initialize app when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
window.chessApp = new ChessApp();
console.log('Chess game initialized successfully!');
});