undefined / index.html
Sasanou's picture
I don’t see paws ! Did you use css icons ?
43fdbce verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ChessMaster Pro</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<style>
.chess-square {
position: relative;
width: 100%;
padding-bottom: 100%;
}
.chess-piece {
position: absolute;
width: 80%;
height: 80%;
top: 10%;
left: 10%;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
transition: transform 0.2s ease;
z-index: 10;
}
.chess-piece.dragging {
z-index: 20;
transform: scale(1.1);
}
.legal-move {
position: absolute;
width: 30%;
height: 30%;
border-radius: 50%;
background-color: rgba(0, 255, 0, 0.3);
top: 35%;
left: 35%;
z-index: 5;
}
.selected {
background-color: rgba(255, 215, 0, 0.3) !important;
}
.check {
background-color: rgba(255, 0, 0, 0.3) !important;
}
.captured-piece {
width: 30px;
height: 30px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
margin: 2px;
}
@media (max-width: 768px) {
.captured-piece {
width: 20px;
height: 20px;
}
}
.promotion-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
z-index: 100;
justify-content: center;
align-items: center;
}
.promotion-options {
display: flex;
background-color: #2d3748;
padding: 20px;
border-radius: 10px;
}
.promotion-piece {
width: 60px;
height: 60px;
margin: 10px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
transition: transform 0.2s;
}
.promotion-piece:hover {
transform: scale(1.1);
}
</style>
</head>
<body class="bg-gray-900 text-white min-h-screen flex flex-col">
<header class="bg-indigo-900 py-4 px-6 shadow-lg">
<div class="container mx-auto flex justify-between items-center">
<h1 class="text-2xl md:text-3xl font-bold flex items-center">
<i data-feather="shield" class="mr-2"></i> ChessMaster Pro
</h1>
<div class="flex space-x-4">
<button id="resetBtn" class="bg-red-600 hover:bg-red-700 px-4 py-2 rounded-lg flex items-center">
<i data-feather="refresh-cw" class="mr-2"></i> Reset
</button>
<button id="undoBtn" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
<i data-feather="corner-up-left" class="mr-2"></i> Undo
</button>
</div>
</div>
</header>
<main class="flex-grow container mx-auto px-4 py-8 flex flex-col md:flex-row items-center md:items-start justify-center gap-8">
<!-- Game info section -->
<div class="w-full md:w-1/4 bg-gray-800 p-6 rounded-lg shadow-lg">
<div class="mb-6">
<h2 class="text-xl font-semibold mb-2">Game Status</h2>
<div id="gameStatus" class="bg-gray-700 p-3 rounded">White's turn</div>
</div>
<div class="mb-6">
<h2 class="text-xl font-semibold mb-2">Captured Pieces</h2>
<div class="bg-gray-700 p-3 rounded">
<h3 class="font-medium mb-1">White captured:</h3>
<div id="whiteCaptured" class="flex flex-wrap"></div>
<h3 class="font-medium mt-3 mb-1">Black captured:</h3>
<div id="blackCaptured" class="flex flex-wrap"></div>
</div>
</div>
<div>
<h2 class="text-xl font-semibold mb-2">Move History</h2>
<div id="moveHistory" class="bg-gray-700 p-3 rounded max-h-40 overflow-y-auto">
<!-- Move history will be populated here -->
</div>
</div>
</div>
<!-- Chess board -->
<div class="w-full md:w-2/4 max-w-lg mx-auto">
<div class="bg-gray-800 p-4 rounded-lg shadow-lg">
<div id="chessBoard" class="grid grid-cols-8 aspect-square">
<!-- Board will be generated by JavaScript -->
</div>
</div>
</div>
<!-- Controls and info -->
<div class="w-full md:w-1/4 bg-gray-800 p-6 rounded-lg shadow-lg">
<div class="mb-6">
<h2 class="text-xl font-semibold mb-2">Current Player</h2>
<div id="currentPlayer" class="bg-gray-700 p-3 rounded flex items-center">
<div class="w-6 h-6 bg-white rounded-full mr-2"></div> White
</div>
</div>
<div class="mb-6">
<h2 class="text-xl font-semibold mb-2">Game Controls</h2>
<div class="space-y-2">
<button id="flipBoardBtn" class="w-full bg-purple-600 hover:bg-purple-700 py-2 rounded flex items-center justify-center">
<i data-feather="rotate-cw" class="mr-2"></i> Flip Board
</button>
<button id="hintBtn" class="w-full bg-green-600 hover:bg-green-700 py-2 rounded flex items-center justify-center">
<i data-feather="help-circle" class="mr-2"></i> Show Hints
</button>
</div>
</div>
<div>
<h2 class="text-xl font-semibold mb-2">Game Time</h2>
<div class="bg-gray-700 p-3 rounded">
<div class="flex justify-between">
<span>White:</span>
<span id="whiteTime">10:00</span>
</div>
<div class="flex justify-between mt-2">
<span>Black:</span>
<span id="blackTime">10:00</span>
</div>
</div>
</div>
</div>
</main>
<!-- Promotion modal -->
<div id="promotionModal" class="promotion-modal">
<div class="promotion-options">
<div class="promotion-piece" data-piece="q"></div>
<div class="promotion-piece" data-piece="r"></div>
<div class="promotion-piece" data-piece="b"></div>
<div class="promotion-piece" data-piece="n"></div>
</div>
</div>
<footer class="bg-indigo-900 py-4 text-center">
<p>ChessMaster Pro ♟️ - Play like a grandmaster!</p>
</footer>
<script>
document.addEventListener('DOMContentLoaded', function() {
feather.replace();
// Chess game implementation
const chessBoard = document.getElementById('chessBoard');
const gameStatus = document.getElementById('gameStatus');
const currentPlayer = document.getElementById('currentPlayer');
const whiteCaptured = document.getElementById('whiteCaptured');
const blackCaptured = document.getElementById('blackCaptured');
const moveHistory = document.getElementById('moveHistory');
const resetBtn = document.getElementById('resetBtn');
const undoBtn = document.getElementById('undoBtn');
const flipBoardBtn = document.getElementById('flipBoardBtn');
const hintBtn = document.getElementById('hintBtn');
const promotionModal = document.getElementById('promotionModal');
let board = [];
let selectedPiece = null;
let legalMoves = [];
let isWhiteTurn = true;
let boardFlipped = false;
let moveHistoryList = [];
let capturedPieces = { white: [], black: [] };
// Initialize the chess board
function initializeBoard() {
board = [
['br', 'bn', 'bb', 'bq', 'bk', 'bb', 'bn', 'br'],
['bp', 'bp', 'bp', 'bp', 'bp', 'bp', 'bp', 'bp'],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['wp', 'wp', 'wp', 'wp', 'wp', 'wp', 'wp', 'wp'],
['wr', 'wn', 'wb', 'wq', 'wk', 'wb', 'wn', 'wr']
];
renderBoard();
updateGameStatus();
updateCapturedPieces();
moveHistory.innerHTML = '';
moveHistoryList = [];
isWhiteTurn = true;
updateCurrentPlayerDisplay();
}
// Get piece image URL
function getPieceImageUrl(piece) {
const color = piece[0] === 'w' ? 'white' : 'black';
const pieceType = piece[1];
const pieceSymbols = {
'p': '♟', 'r': '♜', 'n': '♞', 'b': '♝', 'q': '♛', 'k': '♚'
};
// Create a canvas to generate the piece image
const canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
const ctx = canvas.getContext('2d');
// Draw background
ctx.fillStyle = 'transparent';
ctx.fillRect(0, 0, 200, 200);
// Draw piece symbol
ctx.font = '120px Arial, sans-serif';
ctx.fillStyle = color === 'white' ? '#ffffff' : '#000000';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(pieceSymbols[pieceType], 100, 100);
return canvas.toDataURL();
}
// Render the chess board
function renderBoard() {
chessBoard.innerHTML = '';
for (let row = 0; row < 8; row++) {
for (let col = 0; col < 8; col++) {
const displayRow = boardFlipped ? 7 - row : row;
const displayCol = boardFlipped ? 7 - col : col;
const square = document.createElement('div');
square.className = `chess-square ${(displayRow + displayCol) % 2 === 0 ? 'bg-amber-100' : 'bg-amber-800'}`;
square.dataset.row = row;
square.dataset.col = col;
const piece = board[row][col];
if (piece) {
const pieceElement = document.createElement('div');
pieceElement.className = `chess-piece ${piece[0] === 'w' ? 'white-piece' : 'black-piece'}`;
pieceElement.style.backgroundImage = `url('${getPieceImageUrl(piece)})`;
pieceElement.dataset.piece = piece;
square.appendChild(pieceElement);
}
square.addEventListener('click', handleSquareClick);
chessBoard.appendChild(square);
}
}
}
// Handle square click
function handleSquareClick(event) {
const square = event.target.closest('.chess-square');
if (!square) return;
const row = parseInt(square.dataset.row);
const col = parseInt(square.dataset.col);
const piece = board[row][col];
// If a piece is already selected
if (selectedPiece) {
// Check if the clicked square is a legal move
const isLegalMove = legalMoves.some(move =>
move.toRow === row && move.toCol === col
);
if (isLegalMove) {
movePiece(selectedPiece.row, selectedPiece.col, row, col);
clearSelection();
} else if (piece && piece[0] === (isWhiteTurn ? 'w' : 'b')) {
// Select a different piece of the same color
selectPiece(row, col);
} else {
// Clicked on an empty square or opponent's piece without a legal move
clearSelection();
}
} else if (piece && piece[0] === (isWhiteTurn ? 'w' : 'b')) {
// Select a piece
selectPiece(row, col);
}
}
// Select a piece
function selectPiece(row, col) {
clearSelection();
selectedPiece = { row, col, piece: board[row][col] };
highlightSquare(row, col, true);
// Calculate legal moves (simplified for this example)
legalMoves = calculateLegalMoves(row, col);
highlightLegalMoves(legalMoves);
}
// Clear selection
function clearSelection() {
if (selectedPiece) {
highlightSquare(selectedPiece.row, selectedPiece.col, false);
}
selectedPiece = null;
legalMoves = [];
// Remove all legal move indicators
document.querySelectorAll('.legal-move').forEach(el => el.remove());
}
// Highlight a square
function highlightSquare(row, col, isSelected) {
const displayRow = boardFlipped ? 7 - row : row;
const displayCol = boardFlipped ? 7 - col : col;
const index = displayRow * 8 + displayCol;
const square = chessBoard.children[index];
if (isSelected) {
square.classList.add('selected');
} else {
square.classList.remove('selected');
}
}
// Highlight legal moves
function highlightLegalMoves(moves) {
moves.forEach(move => {
const displayRow = boardFlipped ? 7 - move.toRow : move.toRow;
const displayCol = boardFlipped ? 7 - move.toCol : move.toCol;
const index = displayRow * 8 + displayCol;
const square = chessBoard.children[index];
const indicator = document.createElement('div');
indicator.className = 'legal-move';
square.appendChild(indicator);
});
}
// Calculate legal moves (simplified version)
function calculateLegalMoves(row, col) {
const piece = board[row][col];
const moves = [];
// This is a simplified version - a real implementation would be more complex
if (piece[1] === 'p') { // Pawn
const direction = piece[0] === 'w' ? -1 : 1;
// Move forward
if (isInBounds(row + direction, col) && !board[row + direction][col]) {
moves.push({ toRow: row + direction, toCol: col });
// Initial double move
if ((piece[0] === 'w' && row === 6) || (piece[0] === 'b' && row === 1)) {
if (!board[row + 2 * direction][col]) {
moves.push({ toRow: row + 2 * direction, toCol: col });
}
}
}
// Capture diagonally
for (let offset of [-1, 1]) {
if (isInBounds(row + direction, col + offset)) {
const target = board[row + direction][col + offset];
if (target && target[0] !== piece[0]) {
moves.push({ toRow: row + direction, toCol: col + offset });
}
}
}
}
// Add more piece movement logic here...
return moves;
}
// Check if coordinates are within bounds
function isInBounds(row, col) {
return row >= 0 && row < 8 && col >= 0 && col < 8;
}
// Move a piece
function movePiece(fromRow, fromCol, toRow, toCol) {
const piece = board[fromRow][fromCol];
const targetPiece = board[toRow][toCol];
// Handle capture
if (targetPiece) {
capturedPieces[piece[0] === 'w' ? 'black' : 'white'].push(targetPiece);
updateCapturedPieces();
}
// Handle pawn promotion (simplified)
if (piece[1] === 'p' && (toRow === 0 || toRow === 7)) {
showPromotionModal(fromRow, fromCol, toRow, toCol);
return;
}
// Execute the move
board[toRow][toCol] = piece;
board[fromRow][fromCol] = '';
// Add to move history
const moveNotation = getMoveNotation(fromRow, fromCol, toRow, toCol, targetPiece);
moveHistoryList.push(moveNotation);
updateMoveHistory();
// Switch turns
isWhiteTurn = !isWhiteTurn;
updateCurrentPlayerDisplay();
renderBoard();
updateGameStatus();
}
// Get algebraic notation for a move
function getMoveNotation(fromRow, fromCol, toRow, toCol, capturedPiece) {
const piece = board[fromRow][fromCol];
const pieceSymbol = piece[1] === 'p' ? '' : piece[1].toUpperCase();
const captureSymbol = capturedPiece ? 'x' : '';
const file = String.fromCharCode(97 + fromCol);
const rank = 8 - fromRow;
const toFile = String.fromCharCode(97 + toCol);
const toRank = 8 - toRow;
return `${isWhiteTurn ? 'White' : 'Black'}: ${pieceSymbol}${file}${rank}${captureSymbol}${toFile}${toRank}`;
}
// Update move history display
function updateMoveHistory() {
moveHistory.innerHTML = '';
moveHistoryList.forEach((move, index) => {
const moveElement = document.createElement('div');
moveElement.textContent = `${index + 1}. ${move}`;
moveHistory.appendChild(moveElement);
});
// Scroll to bottom
moveHistory.scrollTop = moveHistory.scrollHeight;
}
// Update captured pieces display
function updateCapturedPieces() {
whiteCaptured.innerHTML = '';
blackCaptured.innerHTML = '';
capturedPieces.white.forEach(piece => {
const pieceElement = document.createElement('div');
pieceElement.className = 'captured-piece';
pieceElement.style.backgroundImage = `url('${getPieceImageUrl('w' + piece[1])})`;
whiteCaptured.appendChild(pieceElement);
});
capturedPieces.black.forEach(piece => {
const pieceElement = document.createElement('div');
pieceElement.className = 'captured-piece';
pieceElement.style.backgroundImage = `url('${getPieceImageUrl('b' + piece[1])})`;
blackCaptured.appendChild(pieceElement);
});
}
// Update game status display
function updateGameStatus() {
// Simplified status - a real implementation would check for check, checkmate, etc.
gameStatus.textContent = isWhiteTurn ? "White's turn" : "Black's turn";
gameStatus.className = 'bg-gray-700 p-3 rounded';
}
// Update current player display
function updateCurrentPlayerDisplay() {
currentPlayer.innerHTML = isWhiteTurn ?
'<div class="w-6 h-6 bg-white rounded-full mr-2"></div> White' :
'<div class="w-6 h-6 bg-black border border-white rounded-full mr-2"></div> Black';
}
// Show promotion modal
function showPromotionModal(fromRow, fromCol, toRow, toCol) {
promotionModal.style.display = 'flex';
// Set up promotion options
const color = board[fromRow][fromCol][0];
const options = document.querySelectorAll('.promotion-piece');
options.forEach(option => {
const pieceType = option.dataset.piece;
option.style.backgroundImage = `url('${getPieceImageUrl(color + pieceType)})`;
option.onclick = function() {
// Promote the pawn
board[toRow][toCol] = color + pieceType;
board[fromRow][fromCol] = '';
// Add to move history with promotion notation
const moveNotation = getMoveNotation(fromRow, fromCol, toRow, toCol, null) + '=' + pieceType.toUpperCase();
moveHistoryList.push(moveNotation);
updateMoveHistory();
// Switch turns
isWhiteTurn = !isWhiteTurn;
updateCurrentPlayerDisplay();
renderBoard();
updateGameStatus();
// Hide modal
promotionModal.style.display = 'none';
};
});
}
// Event listeners
resetBtn.addEventListener('click', initializeBoard);
undoBtn.addEventListener('click', function() {
if (moveHistoryList.length > 0) {
// Simplified undo - a real implementation would be more complex
alert("Undo functionality would be implemented here!");
}
});
flipBoardBtn.addEventListener('click', function() {
boardFlipped = !boardFlipped;
renderBoard();
});
hintBtn.addEventListener('click', function() {
if (selectedPiece) {
// Already showing hints
return;
}
// Find a piece with legal moves
for (let row = 0; row < 8; row++) {
for (let col = 0; col < 8; col++) {
const piece = board[row][col];
if (piece && piece[0] === (isWhiteTurn ? 'w' : 'b')) {
const moves = calculateLegalMoves(row, col);
if (moves.length > 0) {
selectPiece(row, col);
return;
}
}
}
}
});
// Initialize the game
initializeBoard();
});
</script>
</body>
</html>