用html5写一个国际象棋

<!DOCTYPE html>

<html lang="zh-CN">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>国际象棋大师 | 在线对弈平台</title>

<style>

* {

margin: 0;

padding: 0;

box-sizing: border-box;

}

:root {

--primary-dark: #0f172a;

--secondary-dark: #1e293b;

--accent-gold: #f59e0b;

--accent-silver: #94a3b8;

--text-light: #f1f5f9;

--text-gray: #cbd5e1;

--board-light: #f0d9b5;

--board-dark: #8b6914;

}

body {

font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

background: linear-gradient(135deg, var(--primary-dark) 0%, #000 100%);

color: var(--text-light);

min-height: 100vh;

overflow-x: hidden;

}

/* 导航栏 */

header {

padding: 1.5rem 5%;

display: flex;

justify-content: space-between;

align-items: center;

background: rgba(15, 23, 42, 0.9);

backdrop-filter: blur(10px);

position: fixed;

width: 100%;

top: 0;

z-index: 1000;

border-bottom: 1px solid rgba(148, 163, 184, 0.1);

}

.logo {

font-size: 1.5rem;

font-weight: bold;

display: flex;

align-items: center;

gap: 0.5rem;

}

.logo::before {

content: '♔';

font-size: 2rem;

color: var(--accent-gold);

}

nav ul {

display: flex;

list-style: none;

gap: 2rem;

}

nav a {

color: var(--text-gray);

text-decoration: none;

transition: color 0.3s;

font-weight: 500;

}

nav a:hover {

color: var(--accent-gold);

}

/* 主游戏区域 */

.game-section {

margin-top: 80px;

padding: 2rem 5%;

max-width: 1400px;

margin-left: auto;

margin-right: auto;

display: grid;

grid-template-columns: 1fr 2fr 1fr;

gap: 2rem;

align-items: start;

}

/* 左侧控制面板 */

.control-panel {

background: rgba(30, 41, 59, 0.6);

border-radius: 12px;

padding: 1.5rem;

border: 1px solid rgba(148, 163, 184, 0.1);

}

.control-panel h3 {

color: var(--accent-gold);

margin-bottom: 1rem;

font-size: 1.2rem;

}

.game-controls {

display: flex;

flex-direction: column;

gap: 0.75rem;

margin-bottom: 2rem;

}

.btn {

padding: 0.75rem 1rem;

border: none;

border-radius: 6px;

font-size: 1rem;

font-weight: 600;

cursor: pointer;

transition: all 0.3s;

text-decoration: none;

display: inline-block;

text-align: center;

}

.btn-primary {

background: linear-gradient(135deg, var(--accent-gold) 0%, #d97706 100%);

color: var(--primary-dark);

}

.btn-primary:hover {

transform: translateY(-2px);

box-shadow: 0 5px 15px rgba(245, 158, 11, 0.3);

}

.btn-secondary {

background: transparent;

color: var(--accent-silver);

border: 2px solid var(--accent-silver);

}

.btn-secondary:hover {

background: var(--accent-silver);

color: var(--primary-dark);

}

.move-history {

max-height: 300px;

overflow-y: auto;

background: rgba(15, 23, 42, 0.4);

border-radius: 6px;

padding: 1rem;

font-family: 'Courier New', monospace;

font-size: 0.9rem;

}

.move-item {

padding: 0.25rem 0;

color: var(--text-gray);

border-bottom: 1px solid rgba(148, 163, 184, 0.1);

}

.move-item:last-child {

border-bottom: none;

}

/* 中央棋盘 */

.chess-board-container {

background: rgba(30, 41, 59, 0.6);

border-radius: 12px;

padding: 2rem;

border: 1px solid rgba(148, 163, 184, 0.1);

display: flex;

flex-direction: column;

align-items: center;

}

.board-status {

margin-bottom: 1rem;

text-align: center;

}

.current-player-display {

font-size: 1.5rem;

font-weight: bold;

padding: 0.5rem 2rem;

border-radius: 8px;

display: inline-block;

}

.current-player-display.white {

background: linear-gradient(135deg, #fff 0%, #f0f0f0 100%);

color: var(--primary-dark);

}

.current-player-display.black {

background: linear-gradient(135deg, #000 0%, #333 100%);

color: #fff;

}

.chess-board {

display: grid;

grid-template-columns: repeat(8, 60px);

grid-template-rows: repeat(8, 60px);

border: 3px solid var(--secondary-dark);

border-radius: 6px;

box-shadow: 0 10px 30px rgba(0,0,0,0.5);

margin: 1rem 0;

}

.board-square {

width: 60px;

height: 60px;

display: flex;

align-items: center;

justify-content: center;

cursor: pointer;

transition: all 0.3s;

position: relative;

}

.board-square.light {

background: var(--board-light);

}

.board-square.dark {

background: var(--board-dark);

}

.board-square.selected {

background: #7fb069 !important;

box-shadow: inset 0 0 10px rgba(0,0,0,0.3);

}

.board-square.valid-move {

background: #4ecdc4 !important;

position: relative;

}

.board-square.valid-move::after {

content: '';

position: absolute;

width: 20px;

height: 20px;

background: rgba(78, 205, 196, 0.7);

border-radius: 50%;

}

.board-square.check {

background: #e74c3c !important;

}

.board-square.king-captured {

background: #9b59b6 !important;

animation: pulse 1s infinite;

}

@keyframes pulse {

0%, 100% { opacity: 1; }

50% { opacity: 0.7; }

}

.chess-piece {

font-size: 2.5rem;

cursor: pointer;

transition: transform 0.3s;

user-select: none;

z-index: 10;

}

.chess-piece:hover {

transform: scale(1.1);

}

.chess-piece.dragging {

opacity: 0.5;

cursor: grabbing;

}

/* 右侧信息面板 */

.info-panel {

background: rgba(30, 41, 59, 0.6);

border-radius: 12px;

padding: 1.5rem;

border: 1px solid rgba(148, 163, 184, 0.1);

}

.info-section {

margin-bottom: 2rem;

}

.info-section h3 {

color: var(--accent-gold);

margin-bottom: 0.75rem;

font-size: 1.1rem;

}

.info-section p {

color: var(--text-gray);

line-height: 1.6;

font-size: 0.9rem;

}

.captured-pieces {

display: flex;

gap: 0.5rem;

flex-wrap: wrap;

margin-top: 0.5rem;

}

.captured-piece {

font-size: 1.5rem;

opacity: 0.7;

}

/* 响应式设计 */

@media (max-width: 1200px) {

.game-section {

grid-template-columns: 1fr;

gap: 1rem;

}

.chess-board-container {

order: -1;

}

.chess-board {

grid-template-columns: repeat(8, 50px);

grid-template-rows: repeat(8, 50px);

}

.board-square {

width: 50px;

height: 50px;

}

.chess-piece {

font-size: 2rem;

}

}

@media (max-width: 600px) {

.chess-board {

grid-template-columns: repeat(8, 40px);

grid-template-rows: repeat(8, 40px);

}

.board-square {

width: 40px;

height: 40px;

}

.chess-piece {

font-size: 1.5rem;

}

}

/* 游戏结束覆盖层 */

.game-over-overlay {

position: fixed;

top: 0;

left: 0;

right: 0;

bottom: 0;

background: rgba(0,0,0,0.8);

display: none;

align-items: center;

justify-content: center;

z-index: 2000;

}

.game-over-modal {

background: var(--secondary-dark);

border-radius: 12px;

padding: 3rem;

text-align: center;

border: 2px solid var(--accent-gold);

max-width: 500px;

width: 90%;

}

.game-over-modal h2 {

color: var(--accent-gold);

font-size: 2.5rem;

margin-bottom: 1rem;

}

.game-over-modal p {

font-size: 1.2rem;

margin-bottom: 2rem;

color: var(--text-gray);

}

.game-over-modal .reason {

font-size: 1.4rem;

font-weight: bold;

color: #e74c3c;

margin-bottom: 1rem;

}

/* 警告提示 */

.warning-message {

position: fixed;

top: 100px;

left: 50%;

transform: translateX(-50%);

background: rgba(231, 76, 60, 0.9);

color: white;

padding: 1rem 2rem;

border-radius: 8px;

font-weight: bold;

display: none;

z-index: 1500;

animation: slideDown 0.3s ease-out;

}

@keyframes slideDown {

from {

transform: translateX(-50%) translateY(-100px);

opacity: 0;

}

to {

transform: translateX(-50%) translateY(0);

opacity: 1;

}

}

</style>

</head>

<body>

<header>

<div class="logo">国际象棋大师</div>

<nav>

<ul>

<li><a href="#play">开始对局</a></li>

<li><a href="#learn">学习规则</a></li>

<li><a href="#puzzles">战术谜题</a></li>

<li><a href="#about">关于我们</a></li>

</ul>

</nav>

</header>

<section class="game-section" id="play">

<!-- 左侧控制面板 -->

<aside class="control-panel">

<h3>游戏控制</h3>

<div class="game-controls">

<button class="btn btn-primary" onclick="resetGame()">🔄 新游戏</button>

<button class="btn btn-secondary" onclick="undoMove()">↩️ 悔棋</button>

<button class="btn btn-secondary" onclick="flipBoard()">🔄 翻转棋盘</button>

<button class="btn btn-secondary" onclick="showHint()">💡 提示</button>

</div>

<h3>对局记录</h3>

<div class="move-history" id="moveHistory">

<div class="move-item">等待开始对局...</div>

</div>

</aside>

<!-- 中央棋盘 -->

<main class="chess-board-container">

<div class="board-status">

<div class="current-player-display white" id="currentPlayerDisplay">

白方回合

</div>

</div>

<div class="chess-board" id="chessBoard"></div>

<div style="margin-top: 1rem; text-align: center;">

<small style="color: var(--text-gray);">点击棋子选择,点击目标位置移动</small>

</div>

</main>

<!-- 右侧信息面板 -->

<aside class="info-panel">

<div class="info-section">

<h3>游戏状态</h3>

<p id="gameStatus">对局进行中</p>

</div>

<div class="info-section">

<h3>被吃掉的棋子</h3>

<div class="captured-pieces" id="capturedPieces">

</div>

</div>

<div class="info-section">

<h3>快速规则</h3>

<p style="font-size: 0.85rem; line-height: 1.4;">

♔ 王:横、直、斜走一格<br>

♕ 后:横、直、斜任意格<br>

♖ 车:横、直任意格<br>

♗ 象:斜线任意格<br>

♞ 马:日字形移动<br>

♟ 兵:前进一格,吃子斜一格

</p>

</div>

<div class="info-section">

<h3>特殊规则</h3>

<p style="font-size: 0.85rem; line-height: 1.4;">

• 王车易位:王和车未移动,王车之间无棋子<br>

• 吃过路兵:对方兵跳两格时可斜吃<br>

• 升变:兵到达底线可变成后、车、象或马

</p>

</div>

</aside>

</section>

<!-- 游戏结束覆盖层 -->

<div class="game-over-overlay" id="gameOverOverlay">

<div class="game-over-modal">

<h2 id="gameOverTitle">游戏结束</h2>

<p class="reason" id="gameOverReason">王被吃掉!</p>

<p id="gameOverMessage">获胜方:白方</p>

<button class="btn btn-primary" onclick="resetGame()">再玩一局</button>

</div>

</div>

<!-- 警告提示 -->

<div class="warning-message" id="warningMessage"></div>

<script>

// 国际象棋游戏逻辑

class ChessGame {

constructor() {

this.board = [];

this.currentPlayer = 'white';

this.selectedSquare = null;

this.moveHistory = [];

this.capturedPieces = { white: [], black: [] };

this.kingPositions = { white: [7, 4], black: [0, 4] };

this.castlingRights = { white: { king: true, queen: true }, black: { king: true, queen: true } };

this.gameOver = false;

this.pieces = {

'K': '♔', 'Q': '♕', 'R': '♖', 'B': '♗', 'N': '♘', 'P': '♙',

'k': '♚', 'q': '♛', 'r': '♜', 'b': '♝', 'n': '♞', 'p': '♟'

};

this.initializeBoard();

this.renderBoard();

}

initializeBoard() {

// 初始化8x8棋盘

for (let row = 0; row < 8; row++) {

this.board[row] = [];

for (let col = 0; col < 8; col++) {

this.board[row][col] = '';

}

}

// 摆放棋子

// 黑方(上方)

this.board[0] = ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'];

this.board[1] = ['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'];

// 白方(下方)

this.board[6] = ['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'];

this.board[7] = ['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R'];

}

renderBoard() {

const boardElement = document.getElementById('chessBoard');

boardElement.innerHTML = '';

for (let row = 0; row < 8; row++) {

for (let col = 0; col < 8; col++) {

const square = document.createElement('div');

square.className = `board-square ${(row + col) % 2 === 0 ? 'light' : 'dark'}`;

square.dataset.row = row;

square.dataset.col = col;

const piece = this.board[row][col];

if (piece) {

const pieceElement = document.createElement('span');

pieceElement.className = 'chess-piece';

pieceElement.textContent = this.pieces[piece];

pieceElement.dataset.piece = piece;

square.appendChild(pieceElement);

}

if (this.kingPositions.white[0] === row && this.kingPositions.white[1] === col && this.isKingInCheck('white')) {

square.classList.add('check');

}

if (this.kingPositions.black[0] === row && this.kingPositions.black[1] === col && this.isKingInCheck('black')) {

square.classList.add('check');

}

square.onclick = () => this.handleSquareClick(row, col);

boardElement.appendChild(square);

}

}

this.updateDisplay();

}

handleSquareClick(row, col) {

if (this.gameOver) return;

if (this.selectedSquare) {

const fromRow = this.selectedSquare[0];

const fromCol = this.selectedSquare[1];

if (fromRow === row && fromCol === col) {

// 取消选择

this.selectedSquare = null;

this.renderBoard();

} else if (this.isValidMove(fromRow, fromCol, row, col)) {

// 执行移动

this.makeMove(fromRow, fromCol, row, col);

} else {

// 重新选择

this.selectedSquare = [row, col];

this.highlightMoves(fromRow, fromCol, row, col);

}

} else {

// 选择棋子

const piece = this.board[row][col];

if (piece && this.getPieceColor(piece) === this.currentPlayer) {

this.selectedSquare = [row, col];

this.highlightMoves(row, col);

}

}

}

highlightMoves(row, col) {

this.renderBoard();

const validMoves = this.getValidMoves(row, col);

validMoves.forEach(([toRow, toCol]) => {

const square = document.querySelector(`[data-row="{toRow}"\]\[data-col="{toCol}"]`);

if (square) {

square.classList.add('valid-move');

}

});

const selectedSquare = document.querySelector(`[data-row="{row}"\]\[data-col="{col}"]`);

if (selectedSquare) {

selectedSquare.classList.add('selected');

}

}

getPieceColor(piece) {

return piece === piece.toUpperCase() ? 'white' : 'black';

}

isValidMove(fromRow, fromCol, toRow, toCol) {

const piece = this.board[fromRow][fromCol];

const targetPiece = this.board[toRow][toCol];

if (!piece || this.getPieceColor(piece) !== this.currentPlayer) return false;

if (targetPiece && this.getPieceColor(targetPiece) === this.currentPlayer) return false;

const moves = this.getValidMoves(fromRow, fromCol);

return moves.some(([r, c]) => r === toRow && c === toCol);

}

getValidMoves(row, col) {

const piece = this.board[row][col];

const color = this.getPieceColor(piece);

const moves = [];

switch (piece.toUpperCase()) {

case 'P':

moves.push(...this.getPawnMoves(row, col, color));

break;

case 'R':

moves.push(...this.getRookMoves(row, col, color));

break;

case 'N':

moves.push(...this.getKnightMoves(row, col, color));

break;

case 'B':

moves.push(...this.getBishopMoves(row, col, color));

break;

case 'Q':

moves.push(...this.getQueenMoves(row, col, color));

break;

case 'K':

moves.push(...this.getKingMoves(row, col, color));

break;

}

// 过滤会导致己方被将军的走法

return moves.filter(([toRow, toCol]) => {

const tempBoard = this.board.map(row => [...row]);

tempBoard[toRow][toCol] = tempBoard[row][col];

tempBoard[row][col] = '';

const tempKingPos = { ...this.kingPositions };

if (piece.toUpperCase() === 'K') {

tempKingPos[color] = [toRow, toCol];

}

return !this.isKingInCheck(color, tempBoard, tempKingPos);

});

}

getPawnMoves(row, col, color) {

const moves = [];

const direction = color === 'white' ? -1 : 1;

const startRow = color === 'white' ? 6 : 1;

// 前进

if (this.board[row + direction] && this.board[row + direction][col] === '') {

moves.push([row + direction, col]);

// 初始位置可以走两格

if (row === startRow && this.board[row + 2 * direction][col] === '') {

moves.push([row + 2 * direction, col]);

}

}

// 吃子

-1, 1\].forEach(offset =\> { if (this.board\[row + direction\] \&\& this.board\[row + direction\]\[col + offset\]) { const target = this.board\[row + direction\]\[col + offset\]; if (target \&\& this.getPieceColor(target) !== color) { moves.push(\[row + direction, col + offset\]); } } }); return moves; } getRookMoves(row, col, color) { return this.getLineMoves(row, col, \[\[0, 1\], \[1, 0\], \[0, -1\], \[-1, 0\]\], color); } getBishopMoves(row, col, color) { return this.getLineMoves(row, col, \[\[1, 1\], \[1, -1\], \[-1, 1\], \[-1, -1\]\], color); } getQueenMoves(row, col, color) { return \[ ...this.getRookMoves(row, col, color), ...this.getBishopMoves(row, col, color) \]; } getKnightMoves(row, col, color) { const moves = \[\]; const knightMoves = \[ \[2, 1\], \[2, -1\], \[-2, 1\], \[-2, -1\], \[1, 2\], \[1, -2\], \[-1, 2\], \[-1, -2

];

knightMoves.forEach(([dr, dc]) => {

const newRow = row + dr;

const newCol = col + dc;

if (newRow >= 0 && newRow < 8 && newCol >= 0 && newCol < 8) {

const target = this.board[newRow][newCol];

if (!target || this.getPieceColor(target) !== color) {

moves.push([newRow, newCol]);

}

}

});

return moves;

}

getKingMoves(row, col, color) {

const moves = [];

for (let dr = -1; dr <= 1; dr++) {

for (let dc = -1; dc <= 1; dc++) {

if (dr === 0 && dc === 0) continue;

const newRow = row + dr;

const newCol = col + dc;

if (newRow >= 0 && newRow < 8 && newCol >= 0 && newCol < 8) {

const target = this.board[newRow][newCol];

if (!target || this.getPieceColor(target) !== color) {

moves.push([newRow, newCol]);

}

}

}

}

return moves;

}

getLineMoves(row, col, directions, color) {

const moves = [];

directions.forEach(([dr, dc]) => {

let newRow = row + dr;

let newCol = col + dc;

while (newRow >= 0 && newRow < 8 && newCol >= 0 && newCol < 8) {

const target = this.board[newRow][newCol];

if (!target) {

moves.push([newRow, newCol]);

} else {

if (this.getPieceColor(target) !== color) {

moves.push([newRow, newCol]);

}

break;

}

newRow += dr;

newCol += dc;

}

});

return moves;

}

isKingInCheck(color, board = this.board, kingPos = this.kingPositions) {

const [kingRow, kingCol] = kingPos[color];

// 检查对方所有棋子是否能吃到王

for (let row = 0; row < 8; row++) {

for (let col = 0; col < 8; col++) {

const piece = board[row][col];

if (piece && this.getPieceColor(piece) !== color) {

const moves = this.getPotentialMoves(row, col, board);

if (moves.some(([r, c]) => r === kingRow && c === kingCol)) {

return true;

}

}

}

}

return false;

}

getPotentialMoves(row, col, board) {

const piece = board[row][col];

const color = this.getPieceColor(piece);

const moves = [];

switch (piece.toUpperCase()) {

case 'P':

const direction = color === 'white' ? -1 : 1;

-1, 1\].forEach(offset =\> { if (board\[row + direction\] \&\& board\[row + direction\]\[col + offset\]) { moves.push(\[row + direction, col + offset\]); } }); break; case 'N': const knightMoves = \[ \[2, 1\], \[2, -1\], \[-2, 1\], \[-2, -1\], \[1, 2\], \[1, -2\], \[-1, 2\], \[-1, -2

];

knightMoves.forEach(([dr, dc]) => {

const newRow = row + dr;

const newCol = col + dc;

if (newRow >= 0 && newRow < 8 && newCol >= 0 && newCol < 8) {

moves.push([newRow, newCol]);

}

});

break;

case 'K':

for (let dr = -1; dr <= 1; dr++) {

for (let dc = -1; dc <= 1; dc++) {

if (dr === 0 && dc === 0) continue;

moves.push([row + dr, col + dc]);

}

}

break;

case 'R':

moves.push(...this.getLineMoves(row, col, [[0, 1], [1, 0], [0, -1], [-1, 0]], color, board));

break;

case 'B':

moves.push(...this.getLineMoves(row, col, [[1, 1], [1, -1], [-1, 1], [-1, -1]], color, board));

break;

case 'Q':

moves.push(...this.getLineMoves(row, col, [[0, 1], [1, 0], [0, -1], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]], color, board));

break;

}

return moves;

}

makeMove(fromRow, fromCol, toRow, toCol) {

const piece = this.board[fromRow][fromCol];

const capturedPiece = this.board[toRow][toCol];

// 记录移动

const moveNotation = this.getMoveNotation(fromRow, fromCol, toRow, toCol, capturedPiece);

this.moveHistory.push(moveNotation);

// 处理被吃掉的棋子

if (capturedPiece) {

this.capturedPieces[this.getPieceColor(capturedPiece)].push(this.pieces[capturedPiece]);

// 检查是否吃掉王

if (capturedPiece.toUpperCase() === 'K') {

this.handleKingCaptured(this.getPieceColor(capturedPiece));

return;

}

}

// 移动棋子

this.board[toRow][toCol] = this.board[fromRow][fromCol];

this.board[fromRow][fromCol] = '';

// 更新王的位置

if (piece.toUpperCase() === 'K') {

this.kingPositions[this.currentPlayer] = [toRow, toCol];

}

// 检查升变

if (piece.toUpperCase() === 'P' && (toRow === 0 || toRow === 7)) {

this.board[toRow][toCol] = piece.toUpperCase() === 'P' ? 'Q' : 'q';

}

// 切换玩家

this.currentPlayer = this.currentPlayer === 'white' ? 'black' : 'white';

this.selectedSquare = null;

this.renderBoard();

this.updateHistory();

// 检查游戏状态

this.checkGameState();

}

handleKingCaptured(loserColor) {

this.gameOver = true;

const winner = loserColor === 'white' ? '黑方' : '白方';

const loser = loserColor === 'white' ? '白方' : '黑方';

// 显示警告动画

this.showWarning(`${loser}的王被吃掉了!`);

// 延迟显示游戏结束弹窗

setTimeout(() => {

this.showGameOver(`{winner}获胜!\`, \`{loser}的王被吃掉`, 'king-captured');

}, 1500);

// 标记被吃掉王的位置

const kingPos = this.kingPositions[loserColor];

const square = document.querySelector(`[data-row="{kingPos\[0\]}"\]\[data-col="{kingPos[1]}"]`);

if (square) {

square.classList.add('king-captured');

}

}

showWarning(message) {

const warningElement = document.getElementById('warningMessage');

warningElement.textContent = message;

warningElement.style.display = 'block';

setTimeout(() => {

warningElement.style.display = 'none';

}, 3000);

}

getMoveNotation(fromRow, fromCol, toRow, toCol, capturedPiece) {

const piece = this.board[fromRow][fromCol];

const files = 'abcdefgh';

const ranks = '87654321';

let notation = '';

// 棋子符号(兵不写)

if (piece.toUpperCase() !== 'P') {

notation += piece.toUpperCase();

}

// 吃子标记

if (capturedPiece) {

if (piece.toUpperCase() === 'P') {

notation += files[fromCol];

}

notation += 'x';

}

// 目标位置

notation += files[toCol] + ranks[toRow];

return notation;

}

updateHistory() {

const historyElement = document.getElementById('moveHistory');

historyElement.innerHTML = this.moveHistory.map((move, i) => {

if (i % 2 === 0) {

return `<div class="move-item">{Math.floor(i / 2) + 1}. {move}</div>`;

} else {

return `<div class="move-item">${move}</div>`;

}

}).join('');

historyElement.scrollTop = historyElement.scrollHeight;

}

updateDisplay() {

const display = document.getElementById('currentPlayerDisplay');

if (this.gameOver) {

display.textContent = '游戏结束';

} else {

display.textContent = `{this.currentPlayer === 'white' ? '⚪' : '⚫'} {this.currentPlayer === 'white' ? '白方' : '黑方'}回合`;

}

display.className = `current-player-display ${this.currentPlayer}`;

}

checkKingExistence() {

let whiteKingExists = false;

let blackKingExists = false;

for (let row = 0; row < 8; row++) {

for (let col = 0; col < 8; col++) {

const piece = this.board[row][col];

if (piece) {

if (piece === 'K') whiteKingExists = true;

if (piece === 'k') blackKingExists = true;

}

}

}

if (!whiteKingExists) {

return { gameOver: true, winner: 'black', loser: 'white', reason: '白方王被吃' };

}

if (!blackKingExists) {

return { gameOver: true, winner: 'white', loser: 'black', reason: '黑方王被吃' };

}

return { gameOver: false };

}

checkGameState() {

// 首先检查王是否存在

const kingCheck = this.checkKingExistence();

if (kingCheck.gameOver) {

this.handleKingCaptured(kingCheck.loser);

return;

}

// 检查是否有合法移动

let hasValidMove = false;

for (let row = 0; row < 8; row++) {

for (let col = 0; col < 8; col++) {

const piece = this.board[row][col];

if (piece && this.getPieceColor(piece) === this.currentPlayer) {

if (this.getValidMoves(row, col).length > 0) {

hasValidMove = true;

break;

}

}

}

if (hasValidMove) break;

}

if (!hasValidMove) {

const isInCheck = this.isKingInCheck(this.currentPlayer);

if (isInCheck) {

const winner = this.currentPlayer === 'white' ? '黑方' : '白方';

const reason = '将死';

this.showGameOver(`${winner}获胜!`, reason);

} else {

this.showGameOver('平局!', '逼和');

}

}

}

showGameOver(result, reason, type = '') {

this.gameOver = true;

document.getElementById('gameOverTitle').textContent = result;

document.getElementById('gameOverReason').textContent = reason;

document.getElementById('gameOverMessage').textContent = `获胜方:${result.includes('白方') ? '白方' : '黑方'}`;

document.getElementById('gameOverOverlay').style.display = 'flex';

// 更新游戏状态显示

this.updateDisplay();

}

reset() {

this.board = [];

this.currentPlayer = 'white';

this.selectedSquare = null;

this.moveHistory = [];

this.capturedPieces = { white: [], black: [] };

this.kingPositions = { white: [7, 4], black: [0, 4] };

this.castlingRights = { white: { king: true, queen: true }, black: { king: true, queen: true } };

this.gameOver = false;

this.initializeBoard();

this.renderBoard();

this.updateHistory();

document.getElementById('gameOverOverlay').style.display = 'none';

document.getElementById('warningMessage').style.display = 'none';

}

undoMove() {

if (this.moveHistory.length > 0) {

this.moveHistory.pop();

// 简化实现:重置棋盘

this.reset();

}

}

}

// 全局实例

let game = null;

// 页面加载完成后初始化

document.addEventListener('DOMContentLoaded', function() {

game = new ChessGame();

});

// 全局函数

function resetGame() {

game.reset();

}

function undoMove() {

game.undoMove();

}

function flipBoard() {

alert('翻转棋盘功能开发中...');

}

function showHint() {

alert('提示功能开发中...');

}

</script>

</body>

</html>

相关推荐
遇见~未来3 小时前
前端原生能力速查笔记(HTML + 浏览器 API 实战篇)
前端
2401_860319523 小时前
在React Native中开发一个轮播组件(Swipe轮播),通过组件react-native-snap-carousel来实现
javascript·react native·react.js
博客zhu虎康3 小时前
Vue全局挂载Element消息组件技巧
前端·javascript·vue.js
2401_860319523 小时前
在React Native中,开发自定义组件(例如一个`Tag`组件)通常涉及到创建React组件,并且实现一个点击事件处理器
javascript·react native·react.js
尼罗河女娲3 小时前
【测试开发】为什么 UI 自动化总是看起来不稳定?为什么需要引入SessionDirty flag?
开发语言·前端·javascript
JQ_Zhang3 小时前
手把手教你封装一个高性能、多功能的 React 锚点导航组件 (Anchor)
前端
soda_yo3 小时前
隐式类型转换:哈基米 == 猫 ? true :false
前端·javascript·面试
Alair‎3 小时前
200React-Query基础
前端·react.js·前端框架
Alair‎3 小时前
201React-Query:useQuery基本使用
前端·react.js