|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Chess Game</title> |
|
<style> |
|
:root { |
|
--light-square: #f0d9b5; |
|
--dark-square: #b58863; |
|
--highlight: rgba(255, 255, 0, 0.4); |
|
--possible-move: rgba(0, 255, 0, 0.3); |
|
} |
|
|
|
* { |
|
margin: 0; |
|
padding: 0; |
|
box-sizing: border-box; |
|
} |
|
|
|
body { |
|
display: flex; |
|
justify-content: center; |
|
align-items: center; |
|
min-height: 100vh; |
|
background: #2c3e50; |
|
font-family: Arial, sans-serif; |
|
} |
|
|
|
.game-container { |
|
display: flex; |
|
gap: 2rem; |
|
padding: 1rem; |
|
background: #34495e; |
|
border-radius: 10px; |
|
box-shadow: 0 0 20px rgba(0,0,0,0.5); |
|
} |
|
|
|
.board { |
|
width: 560px; |
|
height: 560px; |
|
display: grid; |
|
grid-template-columns: repeat(8, 1fr); |
|
border: 3px solid #111; |
|
} |
|
|
|
.square { |
|
width: 70px; |
|
height: 70px; |
|
display: flex; |
|
justify-content: center; |
|
align-items: center; |
|
font-size: 45px; |
|
cursor: pointer; |
|
position: relative; |
|
} |
|
|
|
.light { |
|
background-color: var(--light-square); |
|
} |
|
|
|
.dark { |
|
background-color: var(--dark-square); |
|
} |
|
|
|
.highlight { |
|
background-color: var(--highlight); |
|
} |
|
|
|
.possible-move::after { |
|
content: ''; |
|
position: absolute; |
|
width: 25px; |
|
height: 25px; |
|
background: var(--possible-move); |
|
border-radius: 50%; |
|
} |
|
|
|
.game-info { |
|
color: white; |
|
padding: 1rem; |
|
width: 200px; |
|
} |
|
|
|
.status { |
|
margin-bottom: 1rem; |
|
padding: 1rem; |
|
background: #2c3e50; |
|
border-radius: 5px; |
|
} |
|
|
|
.captured { |
|
margin-top: 1rem; |
|
display: flex; |
|
flex-wrap: wrap; |
|
gap: 0.5rem; |
|
} |
|
|
|
.piece { |
|
user-select: none; |
|
} |
|
|
|
@media (max-width: 800px) { |
|
.game-container { |
|
flex-direction: column; |
|
} |
|
|
|
.board { |
|
width: 400px; |
|
height: 400px; |
|
} |
|
|
|
.square { |
|
width: 50px; |
|
height: 50px; |
|
font-size: 35px; |
|
} |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="game-container"> |
|
<div class="board" id="board"></div> |
|
<div class="game-info"> |
|
<div class="status" id="status">White's turn</div> |
|
<div>Captured pieces:</div> |
|
<div class="captured" id="captured"></div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
class ChessGame { |
|
constructor() { |
|
this.board = document.getElementById('board'); |
|
this.status = document.getElementById('status'); |
|
this.captured = document.getElementById('captured'); |
|
this.selectedPiece = null; |
|
this.currentPlayer = 'white'; |
|
this.possibleMoves = []; |
|
this.gameBoard = this.initializeBoard(); |
|
this.createBoard(); |
|
this.capturedPieces = []; |
|
} |
|
|
|
initializeBoard() { |
|
return [ |
|
['♜', '♞', '♝', '♛', '♚', '♝', '♞', '♜'], |
|
['♟', '♟', '♟', '♟', '♟', '♟', '♟', '♟'], |
|
['', '', '', '', '', '', '', ''], |
|
['', '', '', '', '', '', '', ''], |
|
['', '', '', '', '', '', '', ''], |
|
['', '', '', '', '', '', '', ''], |
|
['♙', '♙', '♙', '♙', '♙', '♙', '♙', '♙'], |
|
['♖', '♘', '♗', '♕', '♔', '♗', '♘', '♖'] |
|
]; |
|
} |
|
|
|
createBoard() { |
|
this.board.innerHTML = ''; |
|
for (let row = 0; row < 8; row++) { |
|
for (let col = 0; col < 8; col++) { |
|
const square = document.createElement('div'); |
|
square.classList.add('square'); |
|
square.classList.add((row + col) % 2 === 0 ? 'light' : 'dark'); |
|
|
|
const piece = this.gameBoard[row][col]; |
|
if (piece) { |
|
square.innerHTML = `<span class="piece">${piece}</span>`; |
|
} |
|
|
|
square.dataset.row = row; |
|
square.dataset.col = col; |
|
|
|
square.addEventListener('click', (e) => this.handleSquareClick(e)); |
|
this.board.appendChild(square); |
|
} |
|
} |
|
} |
|
|
|
isPieceWhite(piece) { |
|
return '♔♕♖♗♘♙'.includes(piece); |
|
} |
|
|
|
handleSquareClick(e) { |
|
const square = e.target.closest('.square'); |
|
const row = parseInt(square.dataset.row); |
|
const col = parseInt(square.dataset.col); |
|
const piece = this.gameBoard[row][col]; |
|
|
|
if (this.currentPlayer === 'black') return; |
|
|
|
if (this.selectedPiece) { |
|
if (this.possibleMoves.some(move => move.row === row && move.col === col)) { |
|
this.movePiece(row, col); |
|
this.clearHighlights(); |
|
this.selectedPiece = null; |
|
this.possibleMoves = []; |
|
|
|
|
|
setTimeout(() => this.makeAIMove(), 500); |
|
} else { |
|
this.clearHighlights(); |
|
this.selectedPiece = null; |
|
this.possibleMoves = []; |
|
} |
|
} else if (piece && this.isPieceWhite(piece) === (this.currentPlayer === 'white')) { |
|
this.selectedPiece = { row, col, piece }; |
|
this.highlightSquare(row, col); |
|
this.possibleMoves = this.calculatePossibleMoves(row, col, piece); |
|
this.showPossibleMoves(); |
|
} |
|
} |
|
|
|
clearHighlights() { |
|
document.querySelectorAll('.square').forEach(square => { |
|
square.classList.remove('highlight', 'possible-move'); |
|
}); |
|
} |
|
|
|
highlightSquare(row, col) { |
|
const square = this.getSquare(row, col); |
|
square.classList.add('highlight'); |
|
} |
|
|
|
showPossibleMoves() { |
|
this.possibleMoves.forEach(move => { |
|
const square = this.getSquare(move.row, move.col); |
|
square.classList.add('possible-move'); |
|
}); |
|
} |
|
|
|
getSquare(row, col) { |
|
return this.board.children[row * 8 + col]; |
|
} |
|
|
|
calculatePossibleMoves(row, col, piece) { |
|
const moves = []; |
|
|
|
|
|
if (piece === '♙') { |
|
|
|
if (row > 0 && !this.gameBoard[row-1][col]) { |
|
moves.push({row: row-1, col: col}); |
|
|
|
if (row === 6 && !this.gameBoard[row-2][col]) { |
|
moves.push({row: row-2, col: col}); |
|
} |
|
} |
|
|
|
if (row > 0 && col > 0 && this.gameBoard[row-1][col-1] && !this.isPieceWhite(this.gameBoard[row-1][col-1])) { |
|
moves.push({row: row-1, col: col-1}); |
|
} |
|
if (row > 0 && col < 7 && this.gameBoard[row-1][col+1] && !this.isPieceWhite(this.gameBoard[row-1][col+1])) { |
|
moves.push({row: row-1, col: col+1}); |
|
} |
|
} |
|
|
|
|
|
if ('♖♜'.includes(piece)) { |
|
moves.push(...this.getRookMoves(row, col)); |
|
} |
|
if ('♗♝'.includes(piece)) { |
|
moves.push(...this.getBishopMoves(row, col)); |
|
} |
|
if ('♕♛'.includes(piece)) { |
|
moves.push(...this.getRookMoves(row, col)); |
|
moves.push(...this.getBishopMoves(row, col)); |
|
} |
|
if ('♘♞'.includes(piece)) { |
|
const knightMoves = [ |
|
{row: row-2, col: col-1}, {row: row-2, col: col+1}, |
|
{row: row-1, col: col-2}, {row: row-1, col: col+2}, |
|
{row: row+1, col: col-2}, {row: row+1, col: col+2}, |
|
{row: row+2, col: col-1}, {row: row+2, col: col+1} |
|
]; |
|
moves.push(...knightMoves.filter(move => |
|
move.row >= 0 && move.row < 8 && move.col >= 0 && move.col < 8 && |
|
(!this.gameBoard[move.row][move.col] || |
|
this.isPieceWhite(this.gameBoard[move.row][move.col]) !== this.isPieceWhite(piece)) |
|
)); |
|
} |
|
if ('♔♚'.includes(piece)) { |
|
for (let i = -1; i <= 1; i++) { |
|
for (let j = -1; j <= 1; j++) { |
|
if (i === 0 && j === 0) continue; |
|
const newRow = row + i; |
|
const newCol = col + j; |
|
if (newRow >= 0 && newRow < 8 && newCol >= 0 && newCol < 8 && |
|
(!this.gameBoard[newRow][newCol] || |
|
this.isPieceWhite(this.gameBoard[newRow][newCol]) !== this.isPieceWhite(piece))) { |
|
moves.push({row: newRow, col: newCol}); |
|
} |
|
} |
|
} |
|
} |
|
|
|
return moves; |
|
} |
|
|
|
getRookMoves(row, col) { |
|
const moves = []; |
|
const directions = [[0,1], [0,-1], [1,0], [-1,0]]; |
|
for (let [dx, dy] of directions) { |
|
let x = row + dx; |
|
let y = col + dy; |
|
while (x >= 0 && x < 8 && y >= 0 && y < 8) { |
|
if (!this.gameBoard[x][y]) { |
|
moves.push({row: x, col: y}); |
|
} else { |
|
if (this.isPieceWhite(this.gameBoard[x][y]) !== this.isPieceWhite(this.gameBoard[row][col])) { |
|
moves.push({row: x, col: y}); |
|
} |
|
break; |
|
} |
|
x += dx; |
|
y += dy; |
|
} |
|
} |
|
return moves; |
|
} |
|
|
|
getBishopMoves(row, col) { |
|
const moves = []; |
|
const directions = [[1,1], [1,-1], [-1,1], [-1,-1]]; |
|
for (let [dx, dy] of directions) { |
|
let x = row + dx; |
|
let y = col + dy; |
|
while (x >= 0 && x < 8 && y >= 0 && y < 8) { |
|
if (!this.gameBoard[x][y]) { |
|
moves.push({row: x, col: y}); |
|
} else { |
|
if (this.isPieceWhite(this.gameBoard[x][y]) !== this.isPieceWhite(this.gameBoard[row][col])) { |
|
moves.push({row: x, col: y}); |
|
} |
|
break; |
|
} |
|
x += dx; |
|
y += dy; |
|
} |
|
} |
|
return moves; |
|
} |
|
|
|
movePiece(toRow, toCol) { |
|
const fromRow = this.selectedPiece.row; |
|
const fromCol = this.selectedPiece.col; |
|
|
|
|
|
if (this.gameBoard[toRow][toCol]) { |
|
this.capturedPieces.push(this.gameBoard[toRow][toCol]); |
|
this.updateCapturedPieces(); |
|
} |
|
|
|
this.gameBoard[toRow][toCol] = this.gameBoard[fromRow][fromCol]; |
|
this.gameBoard[fromRow][fromCol] = ''; |
|
this.currentPlayer = this.currentPlayer === 'white' ? 'black' : 'white'; |
|
this.status.textContent = `${this.currentPlayer.charAt(0).toUpperCase() + this.currentPlayer.slice(1)}'s turn`; |
|
this.createBoard(); |
|
} |
|
|
|
updateCapturedPieces() { |
|
this.captured.innerHTML = this.capturedPieces.map(piece => |
|
`<span class="piece">${piece}</span>` |
|
).join(''); |
|
} |
|
|
|
makeAIMove() { |
|
|
|
let possibleAIMoves = []; |
|
for (let row = 0; row < 8; row++) { |
|
for (let col = 0; col < 8; col++) { |
|
const piece = this.gameBoard[row][col]; |
|
if (piece && !this.isPieceWhite(piece)) { |
|
const moves = this.calculatePossibleMoves(row, col, piece); |
|
moves.forEach(move => { |
|
possibleAIMoves.push({ |
|
from: {row, col}, |
|
to: move |
|
}); |
|
}); |
|
} |
|
} |
|
} |
|
|
|
if (possibleAIMoves.length > 0) { |
|
const move = possibleAIMoves[Math.floor(Math.random() * possibleAIMoves.length)]; |
|
this.selectedPiece = { |
|
row: move.from.row, |
|
col: move.from.col, |
|
piece: this.gameBoard[move.from.row][move.from.col] |
|
}; |
|
this.movePiece(move.to.row, move.to.col); |
|
} |
|
} |
|
} |
|
|
|
|
|
const game = new ChessGame(); |
|
</script> |
|
</body> |
|
</html> |