console
<!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>
:root {
--bg-color: #2c3e50;
--board-light: #f0d9b5;
--board-dark: #b58863;
--highlight: rgba(255, 255, 0, 0.5);
--valid-move: rgba(0, 255, 0, 0.4);
}
body {
background-color: var(--bg-color);
color: white;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
margin: 0;
padding: 20px;
}
h1 { margin-bottom: 10px; }
.controls {
margin-bottom: 20px;
display: flex;
gap: 15px;
align-items: center;
}
select, button {
padding: 8px 12px;
font-size: 16px;
border-radius: 5px;
border: none;
cursor: pointer;
}
button {
background-color: #e74c3c;
color: white;
font-weight: bold;
transition: 0.2s;
}
button:hover { background-color: #c0392b; }
.status {
margin-bottom: 15px;
font-size: 1.2rem;
font-weight: bold;
height: 24px;
}
/* 棋盘样式 */
#board {
display: grid;
grid-template-columns: repeat(8, 60px);
grid-template-rows: repeat(8, 60px);
border: 4px solid #1a252f;
box-shadow: 0 10px 20px rgba(0,0,0,0.5);
}
.square {
width: 60px;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
font-size: 45px;
cursor: pointer;
user-select: none;
position: relative;
}
.square.light { background-color: var(--board-light); }
.square.dark { background-color: var(--board-dark); }
.square.selected { background-color: var(--highlight) !important; }
.square.valid-move::after {
content: '';
width: 15px;
height: 15px;
background-color: var(--valid-move);
border-radius: 50%;
position: absolute;
}
.square.capture-move::after {
width: 100%;
height: 100%;
border-radius: 0;
background-color: transparent;
border: 4px solid var(--valid-move);
box-sizing: border-box;
}
/* 统一使用 Unicode 字符展示棋子,更美观 */
.piece-white { color: #ffffff; text-shadow: 1px 1px 2px #000, -1px -1px 2px #000, 1px -1px 2px #000, -1px 1px 2px #000; }
.piece-black { color: #000000; text-shadow: 1px 1px 2px #fff, -1px -1px 2px #fff, 1px -1px 2px #fff, -1px 1px 2px #fff; }
</style>
</head>
<body>
<h1>国际象棋</h1>
<div class="controls">
<select id="gameMode">
<option value="pvp">双人对战</option>
<option value="pve">人机对战 (你执白)</option>
</select>
<button onclick="resetGame()">重新开始</button>
</div>
<div class="status" id="status">白方走棋</div>
<div id="board"></div>
<script>
// 棋盘初始状态 (大写为白方,小写为黑方,. 为空格)
const initialBoard = [
['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'],
['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
['.', '.', '.', '.', '.', '.', '.', '.'],
['.', '.', '.', '.', '.', '.', '.', '.'],
['.', '.', '.', '.', '.', '.', '.', '.'],
['.', '.', '.', '.', '.', '.', '.', '.'],
['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
];
// 棋子对应的 Unicode 字符
const pieces = {
'K': '♔', 'Q': '♕', 'R': '♖', 'B': '♗', 'N': '♘', 'P': '♙',
'k': '♚', 'q': '♛', 'r': '♜', 'b': '♝', 'n': '♞', 'p': '♟'
};
let board = [];
let turn = 'w'; // 'w' 白方, 'b' 黑方
let selectedSquare = null;
let isGameOver = false;
const boardElement = document.getElementById('board');
const statusElement = document.getElementById('status');
const modeSelect = document.getElementById('gameMode');
// 初始化棋盘
function init() {
board = JSON.parse(JSON.stringify(initialBoard));
turn = 'w';
selectedSquare = null;
isGameOver = false;
updateStatus();
renderBoard();
}
// 渲染棋盘
function renderBoard() {
boardElement.innerHTML = '';
for (let r = 0; r < 8; r++) {
for (let c = 0; c < 8; c++) {
const square = document.createElement('div');
square.className = `square ${(r + c) % 2 === 0 ? 'light' : 'dark'}`;
square.dataset.row = r;
square.dataset.col = c;
const piece = board[r][c];
if (piece !== '.') {
const span = document.createElement('span');
span.textContent = pieces[piece];
span.className = piece === piece.toUpperCase() ? 'piece-white' : 'piece-black';
square.appendChild(span);
}
if (selectedSquare && selectedSquare.row === r && selectedSquare.col === c) {
square.classList.add('selected');
}
square.addEventListener('click', () => handleSquareClick(r, c));
boardElement.appendChild(square);
}
}
}
// 处理点击事件
function handleSquareClick(r, c) {
if (isGameOver || (modeSelect.value === 'pve' && turn === 'b')) return;
const piece = board[r][c];
// 如果已经选中了棋子,尝试移动
if (selectedSquare) {
const validMoves = getValidMoves(selectedSquare.row, selectedSquare.col);
const isMoveValid = validMoves.some(m => m.row === r && m.col === c);
if (isMoveValid) {
makeMove(selectedSquare.row, selectedSquare.col, r, c);
return;
}
}
// 选中/取消选中己方棋子
if (piece !== '.') {
const isWhitePiece = piece === piece.toUpperCase();
if ((turn === 'w' && isWhitePiece) || (turn === 'b' && !isWhitePiece)) {
selectedSquare = { row: r, col: c };
renderBoard();
showValidMoves(r, c);
return;
}
}
// 点击空白处取消选择
selectedSquare = null;
renderBoard();
}
// 显示合法移动位置
function showValidMoves(r, c) {
const moves = getValidMoves(r, c);
moves.forEach(move => {
const index = move.row * 8 + move.col;
const square = boardElement.children[index];
if (board[move.row][move.col] !== '.') {
square.classList.add('capture-move');
} else {
square.classList.add('valid-move');
}
});
}
// 执行移动
function makeMove(fromR, fromC, toR, toC) {
board[toR][toC] = board[fromR][fromC];
board[fromR][fromC] = '.';
selectedSquare = null;
turn = turn === 'w' ? 'b' : 'w';
updateStatus();
renderBoard();
// 人机对战逻辑
if (modeSelect.value === 'pve' && turn === 'b') {
setTimeout(makeAIMove, 300); // 延迟一下让玩家看清自己的走子
}
}
// 更新状态提示
function updateStatus() {
if (isGameOver) return;
statusElement.textContent = turn === 'w' ? '白方走棋' : '黑方走棋 (思考中...)';
if (modeSelect.value === 'pvp') {
statusElement.textContent = turn === 'w' ? '白方走棋' : '黑方走棋';
}
}
// 核心规则:获取合法移动 (简化版,未包含王车易位、吃过路兵、逼王等)
function getValidMoves(r, c) {
const piece = board[r][c];
if (piece === '.') return [];
const isWhite = piece === piece.toUpperCase();
const type = piece.toLowerCase();
const moves = [];
const addMove = (row, col) => {
if (row < 0 || row > 7 || col < 0 || col > 7) return false;
const target = board[row][col];
if (target === '.') {
moves.push({ row, col });
return true;
} else {
const isTargetWhite = target === target.toUpperCase();
if (isWhite !== isTargetWhite) {
moves.push({ row, col }); // 可以吃子
}
return false; // 遇到棋子阻挡
}
};
if (type === 'p') { // 兵
const dir = isWhite ? -1 : 1;
const startRow = isWhite ? 6 : 1;
// 前进
if (r + dir >= 0 && r + dir <= 7 && board[r + dir][c] === '.') {
moves.push({ row: r + dir, col: c });
// 开局走两格
if (r === startRow && board[r + dir * 2][c] === '.') {
moves.push({ row: r + dir * 2, col: c });
}
}
// 吃子
[-1, 1].forEach(offset => {
const nc = c + offset;
const nr = r + dir;
if (nr >= 0 && nr <= 7 && nc >= 0 && nc <= 7) {
const target = board[nr][nc];
if (target !== '.' && (target === target.toUpperCase()) !== isWhite) {
moves.push({ row: nr, col: nc });
}
}
});
}
else if (type === 'n') { // 马
const offsets = [[-2,-1],[-2,1],[-1,-2],[-1,2],[1,-2],[1,2],[2,-1],[2,1]];
offsets.forEach(([dr, dc]) => addMove(r + dr, c + dc));
}
else if (type === 'r') { // 车
const dirs = [[0,1],[0,-1],[1,0],[-1,0]];
dirs.forEach(([dr, dc]) => {
let nr = r + dr, nc = c + dc;
while (addMove(nr, nc)) { nr += dr; nc += dc; }
});
}
else if (type === 'b') { // 象
const dirs = [[1,1],[1,-1],[-1,1],[-1,-1]];
dirs.forEach(([dr, dc]) => {
let nr = r + dr, nc = c + dc;
while (addMove(nr, nc)) { nr += dr; nc += dc; }
});
}
else if (type === 'q') { // 后
const dirs = [[0,1],[0,-1],[1,0],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]];
dirs.forEach(([dr, dc]) => {
let nr = r + dr, nc = c + dc;
while (addMove(nr, nc)) { nr += dr; nc += dc; }
});
}
else if (type === 'k') { // 王
const dirs = [[0,1],[0,-1],[1,0],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]];
dirs.forEach(([dr, dc]) => addMove(r + dr, c + dc));
}
return moves;
}
// 简易 AI (贪心算法:评估所有走法,选择能吃掉最高价值棋子的走法,否则随机)
function makeAIMove() {
if (isGameOver) return;
let bestMove = null;
let maxScore = -Infinity;
// 棋子价值评估
const values = { 'p': 10, 'n': 30, 'b': 30, 'r': 50, 'q': 90, 'k': 1000 };
// 遍历所有黑方棋子
for (let r = 0; r < 8; r++) {
for (let c = 0; c < 8; c++) {
const piece = board[r][c];
if (piece !== '.' && piece === piece.toLowerCase()) {
const moves = getValidMoves(r, c);
moves.forEach(move => {
// 计算这步棋的分数(吃子价值)
let score = 0;
const targetPiece = board[move.row][move.col];
if (targetPiece !== '.') {
score = values[targetPiece.toLowerCase()];
}
// 加入一点随机性,防止 AI 每次走法完全一样
score += Math.random();
if (score > maxScore) {
maxScore = score;
bestMove = { fromR: r, fromC: c, toR: move.row, toC: move.col };
}
});
}
}
}
if (bestMove) {
// 检查是否吃掉王(极简版胜负判定)
if (board[bestMove.toR][bestMove.toC].toLowerCase() === 'k') {
board[bestMove.toR][bestMove.toC] = board[bestMove.fromR][bestMove.fromC];
board[bestMove.fromR][bestMove.fromC] = '.';
renderBoard();
statusElement.textContent = "黑方胜利!游戏结束。";
isGameOver = true;
return;
}
makeMove(bestMove.fromR, bestMove.fromC, bestMove.toR, bestMove.toC);
}
}
// 重新开始
function resetGame() {
init();
}
// 监听模式切换
modeSelect.addEventListener('change', resetGame);
// 启动游戏
init();
</script>
</body>
</html>