chees / index.html
Naikjit's picture
Add 3 files
eeb6e1c verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chess Multiplayer</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.chess-board {
width: min(90vw, 90vh);
height: min(90vw, 90vh);
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-template-rows: repeat(8, 1fr);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
border-radius: 8px;
overflow: hidden;
}
.square {
position: relative;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 0.2s ease;
}
.square:hover {
filter: brightness(1.1);
}
.light {
background-color: #f0d9b5;
}
.dark {
background-color: #b58863;
}
.highlight {
box-shadow: inset 0 0 20px 5px rgba(255, 255, 0, 0.5);
}
.possible-move {
position: absolute;
width: 30%;
height: 30%;
background-color: rgba(0, 0, 0, 0.3);
border-radius: 50%;
}
.capture-move {
position: absolute;
width: 80%;
height: 80%;
border: 5px solid rgba(0, 0, 0, 0.3);
border-radius: 50%;
box-sizing: border-box;
}
.piece {
width: 80%;
height: 80%;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
z-index: 10;
transition: all 0.2s ease;
}
.piece.dragging {
transform: scale(1.2);
z-index: 20;
}
.player-info {
transition: all 0.3s ease;
}
.player-info.active {
transform: scale(1.05);
box-shadow: 0 0 15px rgba(255, 215, 0, 0.5);
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.waiting-animation {
animation: pulse 1.5s infinite;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex flex-col items-center justify-center p-4">
<div class="w-full max-w-6xl">
<header class="text-center mb-6">
<h1 class="text-4xl font-bold text-gray-800 mb-2">Chess Multiplayer</h1>
<p class="text-gray-600">Play chess in real-time with friends</p>
</header>
<div class="flex flex-col lg:flex-row gap-6 items-center lg:items-start justify-center">
<!-- Player 1 Info -->
<div id="player1" class="player-info bg-white rounded-lg shadow-md p-4 w-full lg:w-64 order-1 lg:order-1">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold mr-3">P1</div>
<div>
<h3 class="font-semibold text-gray-800">Player 1</h3>
<p class="text-sm text-gray-500">White Pieces</p>
</div>
</div>
<div class="flex justify-between items-center">
<span class="text-gray-700">Rating: 1200</span>
<div class="relative">
<div class="w-3 h-3 rounded-full bg-green-500 animate-pulse"></div>
<span class="text-xs text-gray-500 ml-1">Online</span>
</div>
</div>
<div class="mt-3 pt-3 border-t border-gray-200">
<div class="flex justify-between">
<span class="text-gray-600">Time:</span>
<span class="font-mono text-gray-800">15:00</span>
</div>
</div>
</div>
<!-- Chess Board -->
<div class="order-3 lg:order-2">
<div class="chess-board" id="board"></div>
<div class="mt-4 flex justify-center gap-4">
<button id="newGameBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition">
<i class="fas fa-plus mr-2"></i>New Game
</button>
<button id="offerDrawBtn" class="bg-yellow-500 hover:bg-yellow-600 text-white px-4 py-2 rounded-lg transition">
<i class="fas fa-handshake mr-2"></i>Offer Draw
</button>
<button id="resignBtn" class="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-lg transition">
<i class="fas fa-flag mr-2"></i>Resign
</button>
</div>
</div>
<!-- Player 2 Info -->
<div id="player2" class="player-info bg-white rounded-lg shadow-md p-4 w-full lg:w-64 order-2 lg:order-3">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-red-500 flex items-center justify-center text-white font-bold mr-3">P2</div>
<div>
<h3 class="font-semibold text-gray-800">Player 2</h3>
<p class="text-sm text-gray-500">Black Pieces</p>
</div>
</div>
<div class="flex justify-between items-center">
<span class="text-gray-700">Rating: 1250</span>
<div class="relative">
<div class="w-3 h-3 rounded-full bg-green-500 animate-pulse"></div>
<span class="text-xs text-gray-500 ml-1">Online</span>
</div>
</div>
<div class="mt-3 pt-3 border-t border-gray-200">
<div class="flex justify-between">
<span class="text-gray-600">Time:</span>
<span class="font-mono text-gray-800">15:00</span>
</div>
</div>
</div>
</div>
<!-- Game Controls -->
<div class="mt-8 bg-white rounded-lg shadow-md p-4">
<h3 class="font-semibold text-lg text-gray-800 mb-3">Game Controls</h3>
<div class="flex flex-wrap gap-3">
<button class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-3 py-1 rounded-lg transition flex items-center">
<i class="fas fa-undo-alt mr-2"></i> Undo
</button>
<button class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-3 py-1 rounded-lg transition flex items-center">
<i class="fas fa-redo-alt mr-2"></i> Redo
</button>
<button class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-3 py-1 rounded-lg transition flex items-center">
<i class="fas fa-volume-up mr-2"></i> Sound
</button>
<button class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-3 py-1 rounded-lg transition flex items-center">
<i class="fas fa-cog mr-2"></i> Settings
</button>
</div>
</div>
<!-- Chat Section -->
<div class="mt-6 bg-white rounded-lg shadow-md p-4">
<h3 class="font-semibold text-lg text-gray-800 mb-3">Game Chat</h3>
<div class="h-40 overflow-y-auto mb-3 border border-gray-200 rounded-lg p-2" id="chatMessages">
<div class="text-sm text-gray-500 italic">No messages yet. Start chatting!</div>
</div>
<div class="flex gap-2">
<input type="text" placeholder="Type your message..." class="flex-1 border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
<button class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition">
<i class="fas fa-paper-plane"></i>
</button>
</div>
</div>
</div>
<!-- Game Over Modal -->
<div id="gameOverModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white rounded-lg p-6 max-w-md w-full mx-4">
<h2 class="text-2xl font-bold text-center mb-4">Game Over</h2>
<p id="gameResult" class="text-center text-lg mb-6">White wins by checkmate!</p>
<div class="flex justify-center gap-4">
<button id="rematchBtn" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg transition">
<i class="fas fa-redo mr-2"></i> Rematch
</button>
<button id="closeModalBtn" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg transition">
Close
</button>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize the chess board
const board = document.getElementById('board');
const squares = [];
let selectedSquare = null;
let currentPlayer = 'white';
let gameActive = true;
// Initialize the board squares
for (let i = 0; i < 8; i++) {
for (let j = 0; j < 8; j++) {
const square = document.createElement('div');
const isLight = (i + j) % 2 === 0;
square.className = `square ${isLight ? 'light' : 'dark'}`;
square.dataset.row = i;
square.dataset.col = j;
// Add coordinates for the first and last ranks
if (i === 0 || i === 7) {
const coord = document.createElement('div');
coord.className = `absolute ${i === 0 ? 'top-1 left-1' : 'bottom-1 right-1'} text-xs font-mono ${isLight ? 'text-gray-800' : 'text-gray-100'}`;
coord.textContent = String.fromCharCode(97 + j);
square.appendChild(coord);
}
// Add coordinates for the a and h files
if (j === 0 || j === 7) {
const coord = document.createElement('div');
coord.className = `absolute ${j === 0 ? 'top-1 left-1' : 'bottom-1 right-1'} text-xs font-mono ${isLight ? 'text-gray-800' : 'text-gray-100'}`;
coord.textContent = 8 - i;
square.appendChild(coord);
}
square.addEventListener('click', () => handleSquareClick(square));
// Drag and drop functionality
square.addEventListener('dragstart', handleDragStart);
square.addEventListener('dragover', handleDragOver);
square.addEventListener('drop', handleDrop);
square.addEventListener('dragend', handleDragEnd);
board.appendChild(square);
squares.push(square);
}
}
// Set up initial pieces
setupInitialPieces();
// Highlight active player
updateActivePlayer();
// Modal controls
document.getElementById('closeModalBtn').addEventListener('click', () => {
document.getElementById('gameOverModal').classList.add('hidden');
});
document.getElementById('rematchBtn').addEventListener('click', () => {
document.getElementById('gameOverModal').classList.add('hidden');
resetGame();
});
document.getElementById('newGameBtn').addEventListener('click', resetGame);
// Simulate a game over after 5 seconds for demo purposes
// setTimeout(() => {
// showGameOver("White wins by checkmate!");
// }, 5000);
function setupInitialPieces() {
// Helper function to create a piece
const createPiece = (type, color) => {
const piece = document.createElement('div');
piece.className = `piece ${color}`;
piece.draggable = true;
piece.dataset.type = type;
piece.dataset.color = color;
// Use Unicode chess characters for pieces
const symbols = {
king: '♔',
queen: '♕',
rook: '♖',
bishop: '♗',
knight: '♘',
pawn: '♙'
};
piece.textContent = color === 'white' ? symbols[type] : symbols[type].toLowerCase();
piece.style.fontSize = '2.5rem';
piece.style.lineHeight = '1';
piece.style.textShadow = '1px 1px 2px rgba(0,0,0,0.3)';
piece.style.color = color === 'white' ? '#fff' : '#000';
return piece;
};
// Set up pawns
for (let i = 0; i < 8; i++) {
squares[8 + i].appendChild(createPiece('pawn', 'white'));
squares[48 + i].appendChild(createPiece('pawn', 'black'));
}
// Set up back row pieces
const backRow = ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook'];
for (let i = 0; i < 8; i++) {
squares[i].appendChild(createPiece(backRow[i], 'white'));
squares[56 + i].appendChild(createPiece(backRow[i], 'black'));
}
}
function handleSquareClick(square) {
if (!gameActive) return;
const piece = square.firstChild;
// If no piece is selected and the clicked square has a piece of the current player's color
if (!selectedSquare && piece && piece.dataset.color === currentPlayer) {
selectedSquare = square;
square.classList.add('highlight');
showPossibleMoves(square);
return;
}
// If a piece is already selected
if (selectedSquare) {
// If clicking on the same piece, deselect it
if (square === selectedSquare) {
clearSelection();
return;
}
// If clicking on another piece of the same color, select that piece instead
if (piece && piece.dataset.color === currentPlayer) {
clearSelection();
selectedSquare = square;
square.classList.add('highlight');
showPossibleMoves(square);
return;
}
// Check if the move is valid (simplified for demo)
const fromRow = parseInt(selectedSquare.dataset.row);
const fromCol = parseInt(selectedSquare.dataset.col);
const toRow = parseInt(square.dataset.row);
const toCol = parseInt(square.dataset.col);
if (isValidMove(fromRow, fromCol, toRow, toCol, selectedSquare.firstChild)) {
// Move the piece
const pieceToMove = selectedSquare.firstChild;
square.innerHTML = '';
square.appendChild(pieceToMove);
// Switch player
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
updateActivePlayer();
}
clearSelection();
}
}
function showPossibleMoves(square) {
const piece = square.firstChild;
if (!piece) return;
const row = parseInt(square.dataset.row);
const col = parseInt(square.dataset.col);
const type = piece.dataset.type;
const color = piece.dataset.color;
// Simplified possible moves for demo
if (type === 'pawn') {
const direction = color === 'white' ? 1 : -1;
// Forward move
const forwardRow = row + direction;
if (forwardRow >= 0 && forwardRow < 8) {
const forwardSquare = squares[forwardRow * 8 + col];
if (!forwardSquare.firstChild) {
addPossibleMoveIndicator(forwardSquare);
}
// Initial double move
if ((color === 'white' && row === 1) || (color === 'black' && row === 6)) {
const doubleRow = row + 2 * direction;
const doubleSquare = squares[doubleRow * 8 + col];
if (!doubleSquare.firstChild && !forwardSquare.firstChild) {
addPossibleMoveIndicator(doubleSquare);
}
}
}
// Capture moves
const captureCols = [col - 1, col + 1];
for (const capCol of captureCols) {
if (capCol >= 0 && capCol < 8) {
const capRow = row + direction;
if (capRow >= 0 && capRow < 8) {
const capSquare = squares[capRow * 8 + capCol];
if (capSquare.firstChild && capSquare.firstChild.dataset.color !== color) {
addCaptureMoveIndicator(capSquare);
}
}
}
}
} else if (type === 'knight') {
const moves = [
[row + 2, col + 1], [row + 2, col - 1],
[row - 2, col + 1], [row - 2, col - 1],
[row + 1, col + 2], [row + 1, col - 2],
[row - 1, col + 2], [row - 1, col - 2]
];
for (const [r, c] of moves) {
if (r >= 0 && r < 8 && c >= 0 && c < 8) {
const moveSquare = squares[r * 8 + c];
if (!moveSquare.firstChild || moveSquare.firstChild.dataset.color !== color) {
if (moveSquare.firstChild) {
addCaptureMoveIndicator(moveSquare);
} else {
addPossibleMoveIndicator(moveSquare);
}
}
}
}
}
}
function addPossibleMoveIndicator(square) {
const indicator = document.createElement('div');
indicator.className = 'possible-move';
square.appendChild(indicator);
}
function addCaptureMoveIndicator(square) {
const indicator = document.createElement('div');
indicator.className = 'capture-move';
square.appendChild(indicator);
}
function clearSelection() {
if (selectedSquare) {
selectedSquare.classList.remove('highlight');
// Remove all possible move indicators
document.querySelectorAll('.possible-move, .capture-move').forEach(ind => ind.remove());
selectedSquare = null;
}
}
function isValidMove(fromRow, fromCol, toRow, toCol, piece) {
// Very simplified move validation for demo
const type = piece.dataset.type;
const color = piece.dataset.color;
if (type === 'pawn') {
const direction = color === 'white' ? 1 : -1;
// Forward move
if (fromCol === toCol) {
// Single move forward
if (toRow === fromRow + direction) {
return !squares[toRow * 8 + toCol].firstChild;
}
// Double move from starting position
if ((color === 'white' && fromRow === 1 && toRow === 3) ||
(color === 'black' && fromRow === 6 && toRow === 4)) {
return !squares[toRow * 8 + toCol].firstChild &&
!squares[(fromRow + direction) * 8 + toCol].firstChild;
}
}
// Capture move
if (Math.abs(toCol - fromCol) === 1 && toRow === fromRow + direction) {
const targetSquare = squares[toRow * 8 + toCol];
return targetSquare.firstChild && targetSquare.firstChild.dataset.color !== color;
}
return false;
} else if (type === 'knight') {
const rowDiff = Math.abs(toRow - fromRow);
const colDiff = Math.abs(toCol - fromCol);
return (rowDiff === 2 && colDiff === 1) || (rowDiff === 1 && colDiff === 2);
}
// For demo, allow any move for other pieces
return true;
}
function updateActivePlayer() {
const player1 = document.getElementById('player1');
const player2 = document.getElementById('player2');
if (currentPlayer === 'white') {
player1.classList.add('active');
player2.classList.remove('active');
} else {
player1.classList.remove('active');
player2.classList.add('active');
}
}
function showGameOver(message) {
gameActive = false;
document.getElementById('gameResult').textContent = message;
document.getElementById('gameOverModal').classList.remove('hidden');
}
function resetGame() {
// Clear the board
squares.forEach(square => {
square.innerHTML = '';
const isLight = (parseInt(square.dataset.row) + parseInt(square.dataset.col)) % 2 === 0;
square.className = `square ${isLight ? 'light' : 'dark'}`;
// Re-add coordinates if needed
const i = parseInt(square.dataset.row);
const j = parseInt(square.dataset.col);
if (i === 0 || i === 7) {
const coord = document.createElement('div');
coord.className = `absolute ${i === 0 ? 'top-1 left-1' : 'bottom-1 right-1'} text-xs font-mono ${isLight ? 'text-gray-800' : 'text-gray-100'}`;
coord.textContent = String.fromCharCode(97 + j);
square.appendChild(coord);
}
if (j === 0 || j === 7) {
const coord = document.createElement('div');
coord.className = `absolute ${j === 0 ? 'top-1 left-1' : 'bottom-1 right-1'} text-xs font-mono ${isLight ? 'text-gray-800' : 'text-gray-100'}`;
coord.textContent = 8 - i;
square.appendChild(coord);
}
});
// Reset game state
currentPlayer = 'white';
gameActive = true;
selectedSquare = null;
// Set up pieces again
setupInitialPieces();
updateActivePlayer();
}
// Drag and drop functions
function handleDragStart(e) {
if (!gameActive) {
e.preventDefault();
return;
}
const piece = e.target;
if (piece.classList.contains('piece') && piece.dataset.color === currentPlayer) {
e.dataTransfer.setData('text/plain', piece.dataset.type);
piece.classList.add('dragging');
// Set the drag image to be transparent
const dragImage = document.createElement('div');
dragImage.style.opacity = '0';
document.body.appendChild(dragImage);
e.dataTransfer.setDragImage(dragImage, 0, 0);
setTimeout(() => document.body.removeChild(dragImage), 0);
} else {
e.preventDefault();
}
}
function handleDragOver(e) {
e.preventDefault();
}
function handleDrop(e) {
e.preventDefault();
if (!gameActive) return;
const fromSquare = document.querySelector('.piece.dragging').parentElement;
const toSquare = e.currentTarget;
if (fromSquare === toSquare) {
document.querySelector('.piece.dragging').classList.remove('dragging');
return;
}
const piece = fromSquare.firstChild;
const fromRow = parseInt(fromSquare.dataset.row);
const fromCol = parseInt(fromSquare.dataset.col);
const toRow = parseInt(toSquare.dataset.row);
const toCol = parseInt(toSquare.dataset.col);
if (isValidMove(fromRow, fromCol, toRow, toCol, piece)) {
// Move the piece
toSquare.innerHTML = '';
toSquare.appendChild(piece);
// Switch player
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
updateActivePlayer();
}
piece.classList.remove('dragging');
}
function handleDragEnd(e) {
document.querySelectorAll('.piece.dragging').forEach(p => p.classList.remove('dragging'));
}
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Naikjit/chees" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>