forked from technolyceum/g11-m2
862 lines
32 KiB
HTML
862 lines
32 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Learn to Code: Chess Game</title>
|
|
<style>
|
|
:root {
|
|
--board-size: 500px;
|
|
--grid-size: 8;
|
|
--cell-size: calc(var(--board-size) / var(--grid-size));
|
|
--board-shape: square;
|
|
--light-color: #f0d9b5;
|
|
--dark-color: #b58863;
|
|
}
|
|
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
|
|
color: white;
|
|
min-height: 100vh;
|
|
padding: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
header {
|
|
text-align: center;
|
|
margin-bottom: 20px;
|
|
max-width: 800px;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 2.5rem;
|
|
margin-bottom: 10px;
|
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
.description {
|
|
font-size: 1.1rem;
|
|
margin-bottom: 20px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.container {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
gap: 30px;
|
|
max-width: 1200px;
|
|
width: 100%;
|
|
}
|
|
|
|
.controls {
|
|
background: rgba(0, 0, 0, 0.7);
|
|
padding: 20px;
|
|
border-radius: 10px;
|
|
width: 300px;
|
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4);
|
|
}
|
|
|
|
.control-group {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
h2 {
|
|
font-size: 1.5rem;
|
|
margin-bottom: 15px;
|
|
color: #ffcc00;
|
|
}
|
|
|
|
label {
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
select, button {
|
|
width: 100%;
|
|
padding: 10px;
|
|
margin-bottom: 15px;
|
|
border-radius: 5px;
|
|
border: none;
|
|
background: #333;
|
|
color: white;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
button {
|
|
background: #4CAF50;
|
|
cursor: pointer;
|
|
transition: background 0.3s;
|
|
font-weight: bold;
|
|
}
|
|
|
|
button:hover {
|
|
background: #45a049;
|
|
}
|
|
|
|
.game-area {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
/* === STUDENT TASK 1: COMPLETE THE CHESS BOARD CSS === */
|
|
.chess-board {
|
|
/* TODO: Set the width and height to 400px */
|
|
/* YOUR CODE HERE */
|
|
|
|
/* TODO: Use CSS Grid for layout */
|
|
/* YOUR CODE HERE */
|
|
|
|
/* TODO: Add a 3px solid gray border */
|
|
/* YOUR CODE HERE */
|
|
width: 400px;
|
|
height: 400px;
|
|
display: grid;
|
|
border: 3px solid gray;
|
|
grid-template-columns: repeat(var(--grid-size), 1fr);
|
|
grid-template-rows: repeat(var(--grid-size), 1fr);
|
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
|
margin-bottom: 20px;
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
|
|
/* Board shapes */
|
|
.chess-board.square {
|
|
border-radius: 0;
|
|
}
|
|
|
|
.chess-board.circle {
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.chess-board.triangle {
|
|
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
|
|
}
|
|
|
|
.cell {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-size: calc(var(--cell-size) * 0.6);
|
|
position: relative;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.cell.light {
|
|
background-color: var(--light-color);
|
|
}
|
|
|
|
.cell.dark {
|
|
background-color: var(--dark-color);
|
|
}
|
|
|
|
.cell.selected {
|
|
box-shadow: inset 0 0 0 3px #ff0000;
|
|
}
|
|
|
|
.cell.valid-move::after {
|
|
content: "";
|
|
position: absolute;
|
|
width: 30%;
|
|
height: 30%;
|
|
border-radius: 50%;
|
|
background: rgba(0, 255, 0, 0.5);
|
|
}
|
|
|
|
.piece {
|
|
cursor: pointer;
|
|
width: 90%;
|
|
height: 90%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-weight: bold;
|
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.7);
|
|
user-select: none;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.white {
|
|
color: white;
|
|
}
|
|
|
|
.black {
|
|
color: black;
|
|
}
|
|
|
|
.status {
|
|
background: rgba(0, 0, 0, 0.7);
|
|
padding: 15px;
|
|
border-radius: 10px;
|
|
width: var(--board-size);
|
|
text-align: center;
|
|
font-size: 1.2rem;
|
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4);
|
|
}
|
|
|
|
.coordinates {
|
|
position: absolute;
|
|
font-size: calc(var(--cell-size) * 0.15);
|
|
color: rgba(0, 0, 0, 0.7);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.file-coord {
|
|
bottom: 2px;
|
|
right: 4px;
|
|
}
|
|
|
|
.rank-coord {
|
|
top: 2px;
|
|
left: 4px;
|
|
}
|
|
|
|
/* Accessibility features */
|
|
.sr-only {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
padding: 0;
|
|
margin: -1px;
|
|
overflow: hidden;
|
|
clip: rect(0, 0, 0, 0);
|
|
white-space: nowrap;
|
|
border: 0;
|
|
}
|
|
|
|
/* Focus styles for accessibility */
|
|
button:focus, select:focus {
|
|
outline: 2px solid #ffcc00;
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.piece:focus {
|
|
outline: 2px solid #ffcc00;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
/* Responsive design */
|
|
@media (max-width: 768px) {
|
|
.container {
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.controls {
|
|
width: 90%;
|
|
}
|
|
|
|
:root {
|
|
--board-size: 350px;
|
|
}
|
|
|
|
.status {
|
|
width: var(--board-size);
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<h1>Customizable Chess Game</h1>
|
|
<p class="description">Change board size, grid dimensions, shape, and colors to create your perfect chess experience! The grid size option changes the number of squares in each row and column.</p>
|
|
</header>
|
|
|
|
<div class="container">
|
|
<div class="controls">
|
|
<div class="control-group">
|
|
<h2>Board Settings</h2>
|
|
<label for="board-size">Board Size (pixels):</label>
|
|
<select id="board-size">
|
|
<option value="400">Small (400px)</option>
|
|
<option value="500" selected>Medium (500px)</option>
|
|
<option value="600">Large (600px)</option>
|
|
</select>
|
|
|
|
<label for="grid-size">Grid Size (squares per side):</label>
|
|
<select id="grid-size">
|
|
<option value="6">6x6</option>
|
|
<option value="8" selected>8x8 (Standard Chess)</option>
|
|
<option value="10">10x10</option>
|
|
<option value="12">12x12</option>
|
|
</select>
|
|
|
|
<label for="board-shape">Board Shape:</label>
|
|
<select id="board-shape">
|
|
<option value="square" selected>Square</option>
|
|
<option value="circle">Circle</option>
|
|
<option value="triangle">Triangle</option>
|
|
</select>
|
|
|
|
<label for="light-color">Light Square Color:</label>
|
|
<select id="light-color">
|
|
<option value="#f0d9b5" selected>Classic Tan</option>
|
|
<option value="#eaeaea">Light Gray</option>
|
|
<option value="#b5d8f0">Light Blue</option>
|
|
</select>
|
|
|
|
<label for="dark-color">Dark Square Color:</label>
|
|
<select id="dark-color">
|
|
<option value="#b58863" selected>Classic Brown</option>
|
|
<option value="#555555">Dark Gray</option>
|
|
<option value="#1a5fb4">Dark Blue</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="control-group">
|
|
<h2>Game Controls</h2>
|
|
<button id="reset-btn">Reset Game</button>
|
|
<button id="flip-btn">Flip Board</button>
|
|
</div>
|
|
|
|
<div class="control-group">
|
|
<h2>Accessibility</h2>
|
|
<button id="high-contrast-btn">Toggle High Contrast</button>
|
|
<button id="announce-btn">Announce Game State</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="game-area">
|
|
<div id="chess-board" class="chess-board square">
|
|
<!-- Chess board will be generated by JavaScript -->
|
|
</div>
|
|
<div class="status" id="game-status">
|
|
White's turn. Click on a piece to select it.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Game state
|
|
const gameState = {
|
|
board: [],
|
|
selectedPiece: null,
|
|
currentPlayer: 'white',
|
|
gameOver: false,
|
|
flipped: false,
|
|
gridSize: 8
|
|
};
|
|
|
|
// DOM elements
|
|
const chessBoard = document.getElementById('chess-board');
|
|
const gameStatus = document.getElementById('game-status');
|
|
const boardSizeSelect = document.getElementById('board-size');
|
|
const gridSizeSelect = document.getElementById('grid-size');
|
|
const boardShapeSelect = document.getElementById('board-shape');
|
|
const lightColorSelect = document.getElementById('light-color');
|
|
const darkColorSelect = document.getElementById('dark-color');
|
|
const resetBtn = document.getElementById('reset-btn');
|
|
const flipBtn = document.getElementById('flip-btn');
|
|
const highContrastBtn = document.getElementById('high-contrast-btn');
|
|
const announceBtn = document.getElementById('announce-btn');
|
|
|
|
// Initialize the game
|
|
initializeGame();
|
|
|
|
// Event listeners for controls
|
|
boardSizeSelect.addEventListener('change', updateBoardSize);
|
|
gridSizeSelect.addEventListener('change', updateGridSize);
|
|
boardShapeSelect.addEventListener('change', updateBoardShape);
|
|
lightColorSelect.addEventListener('change', updateBoardColors);
|
|
darkColorSelect.addEventListener('change', updateBoardColors);
|
|
resetBtn.addEventListener('click', resetGame);
|
|
flipBtn.addEventListener('click', flipBoard);
|
|
highContrastBtn.addEventListener('click', toggleHighContrast);
|
|
announceBtn.addEventListener('click', announceGameState);
|
|
|
|
// Initialize the chess board
|
|
function createChessBoard() {
|
|
createBoard();
|
|
setupPieces();
|
|
updateGameStatus();
|
|
}
|
|
|
|
/* === STUDENT TASK 2: CREATE THE CHESS BOARD FUNCTION === */
|
|
// TODO: Create the createChessBoard function
|
|
/* YOUR CODE HERE */ {
|
|
const board = document.getElementById('chess-board');
|
|
// Code to create chess squares
|
|
|
|
// Clear any existing board
|
|
board.innerHTML = '';
|
|
|
|
/* === STUDENT TASK 3: CREATE NESTED FOR LOOPS === */
|
|
// TODO: Create nested for loops to make an 8x8 grid
|
|
// Outer loop for rows (0 to 7)
|
|
for (let row = 0; row < 8; row++) {
|
|
for (let col = 0; col < 8; col++) {
|
|
// Inner loop for columns (0 to 7)
|
|
/* YOUR CODE HERE */ {
|
|
|
|
// Create a cell element
|
|
const cell = document.createElement('div');
|
|
cell.className = `cell ${(row + col) % 2 === 0 ? 'light' : 'dark'}`;
|
|
cell.dataset.row = row;
|
|
cell.dataset.col = col;
|
|
|
|
// Add coordinates for accessibility
|
|
const fileCoord = document.createElement('span');
|
|
fileCoord.className = 'coordinates file-coord';
|
|
fileCoord.textContent = String.fromCharCode(97 + col);
|
|
|
|
const rankCoord = document.createElement('span');
|
|
rankCoord.className = 'coordinates rank-coord';
|
|
rankCoord.textContent = 8 - row;
|
|
|
|
cell.appendChild(fileCoord);
|
|
cell.appendChild(rankCoord);
|
|
|
|
cell.addEventListener('click', handleCellClick);
|
|
board.appendChild(cell);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set up the initial chess pieces
|
|
function setupPieces() {
|
|
// Clear any existing pieces
|
|
document.querySelectorAll('.piece').forEach(piece => piece.remove());
|
|
|
|
const gridSize = gameState.gridSize;
|
|
|
|
// Initialize empty board
|
|
gameState.board = Array(gridSize).fill().map(() => Array(gridSize).fill(''));
|
|
|
|
// Set up pieces based on grid size
|
|
setupPiecesForGridSize(gridSize);
|
|
|
|
// Place pieces on the board
|
|
for (let row = 0; row < gridSize; row++) {
|
|
for (let col = 0; col < gridSize; col++) {
|
|
const piece = gameState.board[row][col];
|
|
if (piece) {
|
|
placePiece(row, col, piece);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set up pieces based on grid size
|
|
function setupPiecesForGridSize(gridSize) {
|
|
const board = gameState.board;
|
|
|
|
// Clear the board first
|
|
for (let row = 0; row < gridSize; row++) {
|
|
for (let col = 0; col < gridSize; col++) {
|
|
board[row][col] = '';
|
|
}
|
|
}
|
|
|
|
// Different setups for different grid sizes
|
|
switch(gridSize) {
|
|
case 6:
|
|
setup6x6Board();
|
|
break;
|
|
case 8:
|
|
setup8x8Board();
|
|
break;
|
|
case 10:
|
|
setup10x10Board();
|
|
break;
|
|
case 12:
|
|
setup12x12Board();
|
|
break;
|
|
}
|
|
}
|
|
|
|
function setup6x6Board() {
|
|
const board = gameState.board;
|
|
// Pawns
|
|
for (let col = 0; col < 6; col++) {
|
|
board[1][col] = 'p';
|
|
board[4][col] = 'P';
|
|
}
|
|
// Back rows
|
|
const blackPieces = ['r', 'n', 'b', 'q', 'k', 'b'];
|
|
const whitePieces = ['R', 'N', 'B', 'Q', 'K', 'B'];
|
|
for (let col = 0; col < 6; col++) {
|
|
board[0][col] = blackPieces[col];
|
|
board[5][col] = whitePieces[col];
|
|
}
|
|
}
|
|
|
|
function setup8x8Board() {
|
|
const board = gameState.board;
|
|
// Pawns
|
|
for (let col = 0; col < 8; col++) {
|
|
board[1][col] = 'p';
|
|
board[6][col] = 'P';
|
|
}
|
|
// Back rows
|
|
const blackPieces = ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'];
|
|
const whitePieces = ['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R'];
|
|
for (let col = 0; col < 8; col++) {
|
|
board[0][col] = blackPieces[col];
|
|
board[7][col] = whitePieces[col];
|
|
}
|
|
}
|
|
|
|
function setup10x10Board() {
|
|
const board = gameState.board;
|
|
// Pawns
|
|
for (let col = 0; col < 10; col++) {
|
|
board[1][col] = 'p';
|
|
board[8][col] = 'P';
|
|
}
|
|
// Back rows - extended piece set
|
|
const blackPieces = ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r', 'c', 'a'];
|
|
const whitePieces = ['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R', 'C', 'A'];
|
|
for (let col = 0; col < 10; col++) {
|
|
board[0][col] = blackPieces[col];
|
|
board[9][col] = whitePieces[col];
|
|
}
|
|
}
|
|
|
|
function setup12x12Board() {
|
|
const board = gameState.board;
|
|
// Pawns
|
|
for (let col = 0; col < 12; col++) {
|
|
board[1][col] = 'p';
|
|
board[10][col] = 'P';
|
|
}
|
|
// Back rows - extended piece set with duplicates
|
|
const blackPieces = ['r', 'r', 'n', 'n', 'b', 'b', 'q', 'k', 'b', 'b', 'n', 'n'];
|
|
const whitePieces = ['R', 'R', 'N', 'N', 'B', 'B', 'Q', 'K', 'B', 'B', 'N', 'N'];
|
|
for (let col = 0; col < 12; col++) {
|
|
board[0][col] = blackPieces[col];
|
|
board[11][col] = whitePieces[col];
|
|
}
|
|
}
|
|
|
|
// Place a piece on the board
|
|
function placePiece(row, col, piece) {
|
|
const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
|
|
if (!cell) return;
|
|
|
|
const pieceElement = document.createElement('div');
|
|
pieceElement.className = `piece ${piece === piece.toUpperCase() ? 'white' : 'black'}`;
|
|
pieceElement.textContent = getPieceSymbol(piece);
|
|
pieceElement.dataset.piece = piece;
|
|
pieceElement.dataset.row = row;
|
|
pieceElement.dataset.col = col;
|
|
pieceElement.setAttribute('tabindex', '0');
|
|
pieceElement.addEventListener('click', handlePieceClick);
|
|
pieceElement.addEventListener('keydown', handlePieceKeyPress);
|
|
|
|
cell.appendChild(pieceElement);
|
|
}
|
|
|
|
// Get Unicode symbol for chess piece
|
|
function getPieceSymbol(piece) {
|
|
const symbols = {
|
|
'K': '♔', 'Q': '♕', 'R': '♖', 'B': '♗', 'N': '♘', 'P': '♙',
|
|
'k': '♚', 'q': '♛', 'r': '♜', 'b': '♝', 'n': '♞', 'p': '♟',
|
|
'C': '♔', 'A': '♕', 'c': '♚', 'a': '♛' // Extra pieces for larger boards
|
|
};
|
|
return symbols[piece] || '?';
|
|
}
|
|
|
|
// Handle piece selection
|
|
function handlePieceClick(e) {
|
|
e.stopPropagation();
|
|
const piece = e.target.closest('.piece');
|
|
if (!piece) return;
|
|
|
|
const row = parseInt(piece.dataset.row);
|
|
const col = parseInt(piece.dataset.col);
|
|
const pieceType = piece.dataset.piece;
|
|
|
|
// Check if it's the current player's piece
|
|
const isWhitePiece = pieceType === pieceType.toUpperCase();
|
|
if ((isWhitePiece && gameState.currentPlayer !== 'white') ||
|
|
(!isWhitePiece && gameState.currentPlayer !== 'black')) {
|
|
return;
|
|
}
|
|
|
|
// Select the piece
|
|
selectPiece(row, col);
|
|
}
|
|
|
|
// Handle piece selection with keyboard
|
|
function handlePieceKeyPress(e) {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
e.preventDefault();
|
|
const piece = e.target;
|
|
const row = parseInt(piece.dataset.row);
|
|
const col = parseInt(piece.dataset.col);
|
|
selectPiece(row, col);
|
|
}
|
|
}
|
|
|
|
// Select a piece and show valid moves
|
|
function selectPiece(row, col) {
|
|
// Clear previous selection
|
|
clearSelection();
|
|
|
|
// Select the new piece
|
|
gameState.selectedPiece = { row, col };
|
|
const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
|
|
cell.classList.add('selected');
|
|
|
|
// Show valid moves
|
|
showValidMoves(row, col);
|
|
|
|
// Update status
|
|
const pieceSymbol = getPieceSymbol(gameState.board[row][col]);
|
|
gameStatus.textContent = `Selected ${gameState.currentPlayer} piece ${pieceSymbol}. Click on a highlighted square to move.`;
|
|
}
|
|
|
|
// Show valid moves for the selected piece
|
|
function showValidMoves(row, col) {
|
|
const piece = gameState.board[row][col];
|
|
const gridSize = gameState.gridSize;
|
|
|
|
// Simple movement patterns based on piece type
|
|
const pieceType = piece.toLowerCase();
|
|
let directions = [];
|
|
|
|
switch(pieceType) {
|
|
case 'p': // Pawn
|
|
directions = piece === 'P' ? [[-1, 0]] : [[1, 0]];
|
|
break;
|
|
case 'r': // Rook
|
|
directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
|
|
break;
|
|
case 'n': // Knight
|
|
directions = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]];
|
|
break;
|
|
case 'b': // Bishop
|
|
directions = [[-1, -1], [-1, 1], [1, -1], [1, 1]];
|
|
break;
|
|
case 'q': // Queen
|
|
directions = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [-1, 1], [1, -1], [1, 1]];
|
|
break;
|
|
case 'k': // King
|
|
directions = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]];
|
|
break;
|
|
default:
|
|
directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
|
|
}
|
|
|
|
directions.forEach(([dr, dc]) => {
|
|
const newRow = row + dr;
|
|
const newCol = col + dc;
|
|
|
|
if (newRow >= 0 && newRow < gridSize && newCol >= 0 && newCol < gridSize) {
|
|
const targetCell = document.querySelector(`.cell[data-row="${newRow}"][data-col="${newCol}"]`);
|
|
const targetPiece = gameState.board[newRow][newCol];
|
|
|
|
// Show as valid move if empty or contains opponent's piece
|
|
if (!targetPiece || (targetPiece === targetPiece.toUpperCase()) !== (piece === piece.toUpperCase())) {
|
|
targetCell.classList.add('valid-move');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Handle cell click for moving pieces
|
|
function handleCellClick(e) {
|
|
if (gameState.gameOver) return;
|
|
|
|
const cell = e.target.closest('.cell');
|
|
if (!cell) return;
|
|
|
|
const row = parseInt(cell.dataset.row);
|
|
const col = parseInt(cell.dataset.col);
|
|
|
|
// If a piece is selected, try to move it
|
|
if (gameState.selectedPiece) {
|
|
movePiece(gameState.selectedPiece.row, gameState.selectedPiece.col, row, col);
|
|
}
|
|
}
|
|
|
|
// Move a piece from one position to another
|
|
function movePiece(fromRow, fromCol, toRow, toCol) {
|
|
// Check if the move is valid
|
|
if (!isValidMove(fromRow, fromCol, toRow, toCol)) {
|
|
gameStatus.textContent = "Invalid move! Try again.";
|
|
clearSelection();
|
|
return;
|
|
}
|
|
|
|
// Perform the move
|
|
const piece = gameState.board[fromRow][fromCol];
|
|
const targetPiece = gameState.board[toRow][toCol];
|
|
|
|
// Check if capturing a piece
|
|
if (targetPiece) {
|
|
gameStatus.textContent = `${gameState.currentPlayer} captures ${targetPiece === targetPiece.toUpperCase() ? 'white' : 'black'} ${getPieceSymbol(targetPiece)}!`;
|
|
}
|
|
|
|
gameState.board[toRow][toCol] = piece;
|
|
gameState.board[fromRow][fromCol] = '';
|
|
|
|
// Update the board visually
|
|
const fromCell = document.querySelector(`.cell[data-row="${fromRow}"][data-col="${fromCol}"]`);
|
|
const toCell = document.querySelector(`.cell[data-row="${toRow}"][data-col="${toCol}"]`);
|
|
|
|
// Remove any existing piece in the target cell
|
|
toCell.querySelectorAll('.piece').forEach(p => p.remove());
|
|
|
|
// Move the piece
|
|
const pieceElement = fromCell.querySelector('.piece');
|
|
if (pieceElement) {
|
|
toCell.appendChild(pieceElement);
|
|
pieceElement.dataset.row = toRow;
|
|
pieceElement.dataset.col = toCol;
|
|
}
|
|
|
|
// Switch players
|
|
gameState.currentPlayer = gameState.currentPlayer === 'white' ? 'black' : 'white';
|
|
|
|
// Clear selection
|
|
clearSelection();
|
|
|
|
// Update game status
|
|
updateGameStatus();
|
|
}
|
|
|
|
// Simplified move validation
|
|
function isValidMove(fromRow, fromCol, toRow, toCol) {
|
|
// Check if target cell is marked as valid move
|
|
const targetCell = document.querySelector(`.cell[data-row="${toRow}"][data-col="${toCol}"]`);
|
|
return targetCell.classList.contains('valid-move');
|
|
}
|
|
|
|
// Clear selection and valid move indicators
|
|
function clearSelection() {
|
|
document.querySelectorAll('.cell.selected').forEach(cell => {
|
|
cell.classList.remove('selected');
|
|
});
|
|
document.querySelectorAll('.cell.valid-move').forEach(cell => {
|
|
cell.classList.remove('valid-move');
|
|
});
|
|
gameState.selectedPiece = null;
|
|
}
|
|
|
|
// Update game status display
|
|
function updateGameStatus() {
|
|
if (gameState.gameOver) {
|
|
gameStatus.textContent = "Game Over!";
|
|
} else {
|
|
gameStatus.textContent = `${gameState.currentPlayer.charAt(0).toUpperCase() + gameState.currentPlayer.slice(1)}'s turn. Click on a piece to select it.`;
|
|
}
|
|
}
|
|
|
|
// Update board size based on user selection
|
|
function updateBoardSize() {
|
|
const size = boardSizeSelect.value;
|
|
document.documentElement.style.setProperty('--board-size', `${size}px`);
|
|
}
|
|
|
|
// Update grid size based on user selection
|
|
function updateGridSize() {
|
|
const newGridSize = parseInt(gridSizeSelect.value);
|
|
gameState.gridSize = newGridSize;
|
|
resetGame();
|
|
}
|
|
|
|
// Update board shape based on user selection
|
|
function updateBoardShape() {
|
|
const shape = boardShapeSelect.value;
|
|
chessBoard.className = `chess-board ${shape}`;
|
|
}
|
|
|
|
// Update board colors based on user selection
|
|
function updateBoardColors() {
|
|
const lightColor = lightColorSelect.value;
|
|
const darkColor = darkColorSelect.value;
|
|
document.documentElement.style.setProperty('--light-color', lightColor);
|
|
document.documentElement.style.setProperty('--dark-color', darkColor);
|
|
}
|
|
|
|
// Reset the game to initial state
|
|
function resetGame() {
|
|
gameState.selectedPiece = null;
|
|
gameState.currentPlayer = 'white';
|
|
gameState.gameOver = false;
|
|
clearSelection();
|
|
createBoard();
|
|
setupPieces();
|
|
updateGameStatus();
|
|
gameStatus.textContent = `Game reset! ${gameState.gridSize}x${gameState.gridSize} board. White's turn.`;
|
|
}
|
|
|
|
// Flip the board perspective
|
|
function flipBoard() {
|
|
gameState.flipped = !gameState.flipped;
|
|
const gridSize = gameState.gridSize;
|
|
const cells = document.querySelectorAll('.cell');
|
|
|
|
cells.forEach(cell => {
|
|
const row = parseInt(cell.dataset.row);
|
|
const col = parseInt(cell.dataset.col);
|
|
|
|
// Update coordinates display
|
|
const fileCoord = cell.querySelector('.file-coord');
|
|
const rankCoord = cell.querySelector('.rank-coord');
|
|
|
|
if (gameState.flipped) {
|
|
fileCoord.textContent = String.fromCharCode(97 + (gridSize - 1 - col));
|
|
rankCoord.textContent = row + 1;
|
|
} else {
|
|
fileCoord.textContent = String.fromCharCode(97 + col);
|
|
rankCoord.textContent = gridSize - row;
|
|
}
|
|
});
|
|
|
|
gameStatus.textContent = `Board ${gameState.flipped ? 'flipped' : 'normal'}. ${gameState.currentPlayer}'s turn.`;
|
|
}
|
|
|
|
// Toggle high contrast mode
|
|
function toggleHighContrast() {
|
|
document.body.classList.toggle('high-contrast');
|
|
|
|
if (document.body.classList.contains('high-contrast')) {
|
|
document.documentElement.style.setProperty('--light-color', '#ffffff');
|
|
document.documentElement.style.setProperty('--dark-color', '#000000');
|
|
gameStatus.textContent = "High contrast mode enabled.";
|
|
} else {
|
|
// Restore original colors
|
|
updateBoardColors();
|
|
gameStatus.textContent = "High contrast mode disabled.";
|
|
}
|
|
}
|
|
|
|
// Announce game state for accessibility
|
|
function announceGameState() {
|
|
const status = gameState.gameOver ?
|
|
"Game over." :
|
|
`It is ${gameState.currentPlayer}'s turn on a ${gameState.gridSize} by ${gameState.gridSize} board.`;
|
|
|
|
gameStatus.textContent = status + " " + gameStatus.textContent;
|
|
|
|
// Create a temporary element for screen readers
|
|
const announcement = document.createElement('div');
|
|
announcement.setAttribute('aria-live', 'polite');
|
|
announcement.className = 'sr-only';
|
|
announcement.textContent = status;
|
|
document.body.appendChild(announcement);
|
|
|
|
// Remove the element after it's been announced
|
|
setTimeout(() => {
|
|
document.body.removeChild(announcement);
|
|
}, 1000);
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |