Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Advanced Chess</title> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.3/chess.min.js"></script> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Arial', sans-serif; | |
| background: linear-gradient(45deg, #1a1a2e, #16213e); | |
| min-height: 100vh; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| color: #fff; | |
| } | |
| .container { | |
| padding: 2rem; | |
| background: rgba(255, 255, 255, 0.05); | |
| border-radius: 20px; | |
| backdrop-filter: blur(10px); | |
| box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); | |
| } | |
| .game-header { | |
| text-align: center; | |
| margin-bottom: 1.5rem; | |
| } | |
| .game-title { | |
| font-size: 2.5rem; | |
| background: linear-gradient(45deg, #4CAF50, #45a049); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin-bottom: 1rem; | |
| } | |
| .difficulty-control { | |
| width: 300px; | |
| margin: 0 auto 2rem auto; | |
| } | |
| .slider { | |
| -webkit-appearance: none; | |
| width: 100%; | |
| height: 8px; | |
| border-radius: 4px; | |
| background: #2c394b; | |
| outline: none; | |
| margin: 15px 0; | |
| } | |
| .slider::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| width: 24px; | |
| height: 24px; | |
| border-radius: 50%; | |
| background: #4CAF50; | |
| cursor: pointer; | |
| box-shadow: 0 0 10px rgba(76, 175, 80, 0.5); | |
| transition: all 0.3s ease; | |
| } | |
| .slider::-webkit-slider-thumb:hover { | |
| background: #45a049; | |
| transform: scale(1.1); | |
| } | |
| .difficulty-label { | |
| text-align: center; | |
| font-size: 1.2rem; | |
| color: #4CAF50; | |
| text-shadow: 0 0 10px rgba(76, 175, 80, 0.3); | |
| } | |
| .board { | |
| width: 560px; | |
| height: 560px; | |
| display: grid; | |
| grid-template-columns: repeat(8, 1fr); | |
| border: 3px solid #334756; | |
| border-radius: 4px; | |
| overflow: hidden; | |
| } | |
| .square { | |
| width: 70px; | |
| height: 70px; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| font-size: 3rem; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| } | |
| .white { | |
| background: #f0d9b5; | |
| } | |
| .black { | |
| background: #b58863; | |
| } | |
| .piece { | |
| width: 85%; | |
| height: 85%; | |
| background-size: contain; | |
| background-repeat: no-repeat; | |
| background-position: center; | |
| transition: transform 0.3s ease; | |
| } | |
| .square:hover .piece { | |
| transform: scale(1.1); | |
| } | |
| .selected { | |
| box-shadow: inset 0 0 20px rgba(76, 175, 80, 0.5); | |
| } | |
| .possible-move::after { | |
| content: ''; | |
| position: absolute; | |
| width: 25px; | |
| height: 25px; | |
| background: rgba(76, 175, 80, 0.3); | |
| border-radius: 50%; | |
| } | |
| .game-info { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-top: 1rem; | |
| padding: 1rem; | |
| background: rgba(255, 255, 255, 0.05); | |
| border-radius: 10px; | |
| } | |
| .status { | |
| font-size: 1.2rem; | |
| color: #4CAF50; | |
| } | |
| .captured-pieces { | |
| display: flex; | |
| gap: 10px; | |
| font-size: 1.5rem; | |
| } | |
| .btn { | |
| padding: 0.8rem 1.5rem; | |
| border: none; | |
| border-radius: 5px; | |
| background: #4CAF50; | |
| color: white; | |
| cursor: pointer; | |
| font-size: 1rem; | |
| transition: all 0.3s ease; | |
| } | |
| .btn:hover { | |
| background: #45a049; | |
| transform: translateY(-2px); | |
| } | |
| @keyframes movePiece { | |
| from { | |
| transform: scale(1); | |
| } | |
| 50% { | |
| transform: scale(1.2); | |
| } | |
| to { | |
| transform: scale(1); | |
| } | |
| } | |
| .moving { | |
| animation: movePiece 0.3s ease; | |
| } | |
| @media (max-width: 600px) { | |
| .board { | |
| width: 320px; | |
| height: 320px; | |
| } | |
| .square { | |
| width: 40px; | |
| height: 40px; | |
| font-size: 1.8rem; | |
| } | |
| .container { | |
| padding: 1rem; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="game-header"> | |
| <h1 class="game-title">Advanced Chess</h1> | |
| <div class="difficulty-control"> | |
| <div class="difficulty-label">AI Difficulty: <span id="difficulty-value">Medium</span></div> | |
| <input type="range" min="1" max="5" value="3" class="slider" id="difficulty-slider"> | |
| </div> | |
| </div> | |
| <div class="board" id="board"></div> | |
| <div class="game-info"> | |
| <div class="status" id="status">White to move</div> | |
| <div class="captured-pieces" id="captured"></div> | |
| <button class="btn" onclick="newGame()">New Game</button> | |
| </div> | |
| </div> | |
| <script> | |
| const chess = new Chess(); | |
| let selectedSquare = null; | |
| let userColor = 'w'; | |
| let aiDepth = 3; | |
| const pieceValues = { | |
| 'p': 1, | |
| 'n': 3, | |
| 'b': 3, | |
| 'r': 5, | |
| 'q': 9, | |
| 'k': 0 | |
| }; | |
| const difficultySlider = document.getElementById('difficulty-slider'); | |
| const difficultyValue = document.getElementById('difficulty-value'); | |
| function updateDifficulty() { | |
| const difficulties = ['Beginner', 'Easy', 'Medium', 'Hard', 'Master']; | |
| difficultyValue.textContent = difficulties[difficultySlider.value - 1]; | |
| aiDepth = parseInt(difficultySlider.value) + 1; | |
| } | |
| difficultySlider.addEventListener('input', updateDifficulty); | |
| function createBoard() { | |
| const board = document.getElementById('board'); | |
| board.innerHTML = ''; | |
| for (let row = 0; row < 8; row++) { | |
| for (let col = 0; col < 8; col++) { | |
| const square = document.createElement('div'); | |
| square.className = `square ${(row + col) % 2 === 0 ? 'white' : 'black'}`; | |
| const position = String.fromCharCode(97 + col) + (8 - row); | |
| square.dataset.position = position; | |
| const piece = chess.get(position); | |
| if (piece) { | |
| const pieceDiv = document.createElement('div'); | |
| pieceDiv.className = 'piece'; | |
| pieceDiv.style.backgroundImage = `url('https://lichess1.org/assets/piece/cburnett/${piece.color}${piece.type.toUpperCase()}.svg')`; | |
| square.appendChild(pieceDiv); | |
| } | |
| square.addEventListener('click', handleSquareClick); | |
| board.appendChild(square); | |
| } | |
| } | |
| updateStatus(); | |
| } | |
| function handleSquareClick(e) { | |
| const square = e.target.closest('.square'); | |
| const position = square.dataset.position; | |
| if (selectedSquare === null) { | |
| const piece = chess.get(position); | |
| if (piece && piece.color === userColor) { | |
| selectedSquare = position; | |
| highlightSquare(square); | |
| highlightMoves(position); | |
| } | |
| } else { | |
| const moves = chess.moves({ square: selectedSquare, verbose: true }); | |
| const move = moves.find(m => m.to === position); | |
| if (move) { | |
| makeMove(selectedSquare, position); | |
| } | |
| clearHighlights(); | |
| selectedSquare = null; | |
| } | |
| } | |
| function highlightSquare(square) { | |
| clearHighlights(); | |
| square.classList.add('selected'); | |
| } | |
| function highlightMoves(position) { | |
| const moves = chess.moves({ square: position, verbose: true }); | |
| moves.forEach(move => { | |
| const square = document.querySelector(`[data-position="${move.to}"]`); | |
| square.classList.add('possible-move'); | |
| }); | |
| } | |
| function clearHighlights() { | |
| document.querySelectorAll('.square').forEach(square => { | |
| square.classList.remove('selected', 'possible-move'); | |
| }); | |
| } | |
| function makeMove(from, to) { | |
| const move = chess.move({ | |
| from: from, | |
| to: to, | |
| promotion: 'q' | |
| }); | |
| if (move) { | |
| animateMove(from, to); | |
| setTimeout(() => { | |
| createBoard(); | |
| if (!chess.game_over()) { | |
| setTimeout(makeAiMove, 500); | |
| } | |
| }, 300); | |
| } | |
| } | |
| function animateMove(from, to) { | |
| const fromSquare = document.querySelector(`[data-position="${from}"]`); | |
| const pieceDiv = fromSquare.querySelector('.piece'); | |
| if (pieceDiv) { | |
| pieceDiv.classList.add('moving'); | |
| } | |
| } | |
| function makeAiMove() { | |
| const move = getBestMove(chess, aiDepth); | |
| if (move) { | |
| chess.move(move); | |
| createBoard(); | |
| } | |
| } | |
| function getBestMove(game, depth) { | |
| if (depth === 0) return null; | |
| const moves = game.moves(); | |
| let bestMove = null; | |
| let bestValue = -9999; | |
| for (let i = 0; i < moves.length; i++) { | |
| game.move(moves[i]); | |
| const value = -minimax(game, depth - 1, -10000, 10000, false); | |
| game.undo(); | |
| if (value >= bestValue) { | |
| bestValue = value; | |
| bestMove = moves[i]; | |
| } | |
| } | |
| return bestMove; | |
| } | |
| function minimax(game, depth, alpha, beta, isMaximizing) { | |
| if (depth === 0) return evaluateBoard(game.board()); | |
| const moves = game.moves(); | |
| if (isMaximizing) { | |
| let maxEval = -9999; | |
| for (let i = 0; i < moves.length; i++) { | |
| game.move(moves[i]); | |
| const eval = minimax(game, depth - 1, alpha, beta, false); | |
| game.undo(); | |
| maxEval = Math.max(maxEval, eval); | |
| alpha = Math.max(alpha, eval); | |
| if (beta <= alpha) break; | |
| } | |
| return maxEval; | |
| } else { | |
| let minEval = 9999; | |
| for (let i = 0; i < moves.length; i++) { | |
| game.move(moves[i]); | |
| const eval = minimax(game, depth - 1, alpha, beta, true); | |
| game.undo(); | |
| minEval = Math.min(minEval, eval); | |
| beta = Math.min(beta, eval); | |
| if (beta <= alpha) break; | |
| } | |
| return minEval; | |
| } | |
| } | |
| function evaluateBoard(board) { | |
| let totalEvaluation = 0; | |
| for (let i = 0; i < 8; i++) { | |
| for (let j = 0; j < 8; j++) { | |
| totalEvaluation += getPieceValue(board[i][j], i, j); | |
| } | |
| } | |
| return totalEvaluation; | |
| } | |
| function getPieceValue(piece, x, y) { | |
| if (piece === null) return 0; | |
| const absoluteValue = pieceValues[piece.type]; | |
| return piece.color === 'w' ? absoluteValue : -absoluteValue; | |
| } | |
| function updateStatus() { | |
| const status = document.getElementById('status'); | |
| if (chess.in_checkmate()) { | |
| status.textContent = 'Checkmate!'; | |
| } else if (chess.in_draw()) { | |
| status.textContent = 'Draw!'; | |
| } else if (chess.in_check()) { | |
| status.textContent = `${chess.turn() === 'w' ? 'White' : 'Black'} is in check`; | |
| } else { | |
| status.textContent = `${chess.turn() === 'w' ? 'White' : 'Black'} to move`; | |
| } | |
| } | |
| function newGame() { | |
| chess.reset(); | |
| selectedSquare = null; | |
| createBoard(); | |
| } | |
| // Initialize the game | |
| createBoard(); | |
| updateDifficulty(); | |
| </script> | |
| </body> | |
| </html> |