提示词:使用js完成中国象棋游戏,非AI方可以和AI自动对弈,要求非Ai方选择棋子时,自动给出可能走到的位置,用圈虚线框表示,当点击虚线框时完成落子,落子后需要棋子闪动2秒。
输出结果:
创建一个完整的中国象棋游戏涉及多个复杂的部分,包括棋盘绘制、棋子移动逻辑、规则验证、AI对弈等。以下是一个基础的实现示例,涵盖了您提到的主要功能:
1. **棋盘和棋子绘制**:使用HTML5 Canvas绘制棋盘和棋子。
2. **用户交互**:允许用户选择棋子,并显示可移动的位置(用虚线圆圈表示)。
3. **落子动画**:实现棋子闪动效果。
4. **AI对弈**:简单的随机走子AI。
### 项目结构
```
chinese-chess/
├── index.html
├── style.css
└── script.js
```
### 1. `index.html`
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>中国象棋游戏</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="chessboard" width="800" height="900"></canvas>
<script src="script.js"></script>
</body>
</html>
```
### 2. `style.css`
```css
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0d9b5;
}
canvas {
border: 2px solid #333;
background-color: #f0d9b5;
}
```
### 3. `script.js`
```javascript
const canvas = document.getElementById('chessboard');
const ctx = canvas.getContext('2d');
const CELL_SIZE = 80;
const FLASH_DURATION = 2000; // 2秒
// 定义棋子类型和初始位置(简化版本,仅红方和黑方部分棋子)
const initialBoard = [
// 黑方
[{ type: '車', side: 'black', x: 0, y: 0 }, { type: '馬', side: 'black', x: 1, y: 0 }, /* ... */],
// 红方
[{ type: '車', side: 'red', x: 0, y: 9 }, { type: '馬', side: 'red', x: 1, y: 9 }, /* ... */]
];
let board = []; // 存储棋子
let selectedPiece = null;
let possibleMoves = [];
let flashingPieces = [];
// 初始化棋盘
function initBoard() {
// 这里需要根据中国象棋的具体规则初始化棋子位置
// 为简化起见,这里只放置几个棋子
board = [
{ type: '車', side: 'black', x: 0, y: 0 },
{ type: '馬', side: 'black', x: 1, y: 0 },
{ type: '車', side: 'red', x: 0, y: 9 },
{ type: '馬', side: 'red', x: 1, y: 9 }
// 添加更多棋子...
];
}
// 绘制棋盘
function drawBoard() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = '#000';
// 绘制横线
for (let i = 0; i < 10; i++) {
ctx.beginPath();
ctx.moveTo(CELL_SIZE, CELL_SIZE + i * CELL_SIZE);
ctx.lineTo(9 * CELL_SIZE, CELL_SIZE + i * CELL_SIZE);
ctx.stroke();
}
// 绘制竖线
for (let i = 0; i < 9; i++) {
ctx.beginPath();
if (i === 0 || i === 8) {
ctx.moveTo(CELL_SIZE + i * CELL_SIZE, CELL_SIZE);
ctx.lineTo(CELL_SIZE + i * CELL_SIZE, 10 * CELL_SIZE);
} else {
ctx.moveTo(CELL_SIZE + i * CELL_SIZE, CELL_SIZE);
ctx.lineTo(CELL_SIZE + i * CELL_SIZE, 5 * CELL_SIZE);
ctx.moveTo(CELL_SIZE + i * CELL_SIZE, 6 * CELL_SIZE);
ctx.lineTo(CELL_SIZE + i * CELL_SIZE, 10 * CELL_SIZE);
}
ctx.stroke();
}
// 绘制棋子
board.forEach(piece => drawPiece(piece));
// 绘制可能的移动位置
if (possibleMoves.length > 0) {
possibleMoves.forEach(move => {
ctx.beginPath();
ctx.arc(move.x * CELL_SIZE + CELL_SIZE / 2, move.y * CELL_SIZE + CELL_SIZE / 2, 20, 0, 2 * Math.PI);
ctx.setLineDash([5, 5]);
ctx.strokeStyle = 'blue';
ctx.stroke();
ctx.setLineDash([]);
});
}
// 绘制闪动效果
flashingPieces.forEach(piece => {
ctx.beginPath();
ctx.arc(piece.x * CELL_SIZE + CELL_SIZE / 2, piece.y * CELL_SIZE + CELL_SIZE / 2, CELL_SIZE / 2 - 5, 0, 2 * Math.PI);
ctx.fillStyle = 'yellow';
ctx.globalAlpha = 0.5;
ctx.fill();
ctx.globalAlpha = 1.0;
});
}
// 绘制单个棋子
function drawPiece(piece) {
const img = new Image();
img.src = getPieceImage(piece);
img.onload = () => {
ctx.drawImage(img, piece.x * CELL_SIZE + 5, piece.y * CELL_SIZE + 5, CELL_SIZE - 10, CELL_SIZE - 10);
};
}
// 获取棋子图片路径(需要准备对应的图片)
function getPieceImage(piece) {
return `images/${piece.side}_${piece.type}.png`;
}
// 处理点击事件
canvas.addEventListener('click', (e) => {
const rect = canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
const x = Math.floor(mouseX / CELL_SIZE);
const y = Math.floor(mouseY / CELL_SIZE);
if (selectedPiece) {
// 检查是否点击在可能的移动位置
const move = possibleMoves.find(m => m.x === x && m.y === y);
if (move) {
movePiece(selectedPiece, { x, y });
selectedPiece = null;
possibleMoves = [];
drawBoard();
setTimeout(aiMove, 500); // AI 延迟移动
return;
}
}
// 选择棋子
const piece = board.find(p => p.x === x && p.y === y);
if (piece && piece.side === 'red') { // 假设红方是非AI方
selectedPiece = piece;
possibleMoves = getPossibleMoves(piece);
drawBoard();
}
});
// 获取棋子的可能移动位置(简化版,需根据中国象棋规则完善)
function getPossibleMoves(piece) {
let moves = [];
// 示例:车可以水平和垂直移动
if (piece.type === '車') {
// 向上
for (let i = piece.y - 1; i >= 0; i--) {
if (isBlocked(piece.x, i)) break;
moves.push({ x: piece.x, y: i });
}
// 向下
for (let i = piece.y + 1; i <= 9; i++) {
if (isBlocked(piece.x, i)) break;
moves.push({ x: piece.x, y: i });
}
// 向左
for (let i = piece.x - 1; i >= 0; i--) {
if (isBlocked(i, piece.y)) break;
moves.push({ x: i, y: piece.y });
}
// 向右
for (let i = piece.x + 1; i <= 8; i++) {
if (isBlocked(i, piece.y)) break;
moves.push({ x: i, y: piece.y });
}
}
// 添加其他棋子的移动逻辑...
return moves;
}
// 检查目标位置是否被阻挡
function isBlocked(x, y) {
return board.some(p => p.x === x && p.y === y);
}
// 移动棋子
function movePiece(piece, to) {
// 捕获棋子
const target = board.find(p => p.x === to.x && p.y === to.y);
if (target) {
board = board.filter(p => p !== target);
}
// 更新位置
piece.x = to.x;
piece.y = to.y;
// 添加闪动效果
flashingPieces.push(piece);
setTimeout(() => {
flashingPieces = flashingPieces.filter(p => p !== piece);
drawBoard();
}, FLASH_DURATION);
drawBoard();
}
// 简单的AI移动(随机选择棋子和移动)
function aiMove() {
const aiPieces = board.filter(p => p.side === 'black');
if (aiPieces.length === 0) return;
const piece = aiPieces[Math.floor(Math.random() * aiPieces.length)];
const moves = getPossibleMoves(piece);
if (moves.length === 0) return;
const move = moves[Math.floor(Math.random() * moves.length)];
movePiece(piece, move);
}
// 初始化
initBoard();
drawBoard();
```
### 4. 准备棋子图片
为了让棋子显示正确,您需要准备对应的棋子图片,并按照以下命名