簡介
本程序有人人對戰和人機對戰,歡迎挑戰
源碼
'''
<!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>
body { font-family: Arial, sans-serif; text-align: center; }
.board { display: inline-block; border: 2px solid #000; }
.row { display: flex; }
.cell { width: 40px; height: 40px; border: 1px solid #ccc; position: relative; cursor: pointer; }
.cell.black { background-color: #f0f0f0; }
.piece { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; font-weight: bold; user-select: none; }
.piece.red { color: #f00; }
.piece.black { color: #000; }
.selected { background-color: #ff9 !important; }
.valid-move { background-color: #9f9; }
#info { margin-top: 10px; font-size: 16px; }
.menu { margin-bottom: 20px; padding: 10px; background-color: #f9f9f9; border-radius: 5px; display: inline-block; }
button, select { margin: 5px; padding: 5px 10px; }
#difficulty-selector { display: none; }
</style>
</head>
<body>
<h1>迷你象棋</h1>
<div class="menu">
<div>
<label>遊戲模式:</label>
<select id="game-mode">
<option value="human">人人對戰</option>
<option value="ai">人機對戰</option>
</select>
</div>
<div id="difficulty-selector">
<label>難度:</label>
<select id="difficulty">
<option value="easy">簡單</option>
<option value="medium">困難</option>
<option value="hard">地獄</option>
</select>
</div>
<button id="start-game">開始遊戲</button>
</div>
<div id="board" class="board"></div>
<div id="info"></div>
<script>
const BOARD_SIZE = 10;
const INITIAL_POSITIONS = [
{x:0,y:9,type:'R',color:'red'},{x:1,y:9,type:'N',color:'red'},{x:2,y:9,type:'E',color:'red'},{x:3,y:9,type:'A',color:'red'},{x:4,y:9,type:'K',color:'red'},{x:5,y:9,type:'A',color:'red'},{x:6,y:9,type:'E',color:'red'},{x:7,y:9,type:'N',color:'red'},{x:8,y:9,type:'R',color:'red'},
{x:1,y:7,type:'C',color:'red'},{x:7,y:7,type:'C',color:'red'},
{x:0,y:6,type:'P',color:'red'},{x:2,y:6,type:'P',color:'red'},{x:4,y:6,type:'P',color:'red'},{x:6,y:6,type:'P',color:'red'},{x:8,y:6,type:'P',color:'red'},
{x:0,y:0,type:'R',color:'black'},{x:1,y:0,type:'N',color:'black'},{x:2,y:0,type:'E',color:'black'},{x:3,y:0,type:'A',color:'black'},{x:4,y:0,type:'K',color:'black'},{x:5,y:0,type:'A',color:'black'},{x:6,y:0,type:'E',color:'black'},{x:7,y:0,type:'N',color:'black'},{x:8,y:0,type:'R',color:'black'},
{x:1,y:2,type:'C',color:'black'},{x:7,y:2,type:'C',color:'black'},
{x:0,y:3,type:'P',color:'black'},{x:2,y:3,type:'P',color:'black'},{x:4,y:3,type:'P',color:'black'},{x:6,y:3,type:'P',color:'black'},{x:8,y:3,type:'P',color:'black'}
];
const PIECE_NAMES = {R:'車',N:'馬',E:'相',A:'士',K:'將',C:'炮',P:'兵'};
const PIECE_VALUES = {K: 1000, A: 20, E: 20, N: 40, C: 45, R: 90, P: 10};
// 位置權重表 - 基於中國象棋開局理論優化的位置價值評估
const POSITION_WEIGHTS = {
'red': {
'R': [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[2, 2, 2, 2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4, 4, 4, 4],
[5, 5, 5, 5, 5, 5, 5, 5, 5],
[10, 0, 0, 0, 0, 0, 0, 0, 10]
],
'N': [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 10, 0, 10, 0, 10, 0, 0],
[0, 10, 0, 0, 0, 0, 0, 10, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 10, 0, 0, 0, 0, 0, 10, 0],
[0, 0, 15, 0, 15, 0, 15, 0, 0],
[0, 0, 0, 20, 0, 20, 0, 0, 0],
[0, 5, 0, 0, 0, 0, 0, 5, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]
],
'C': [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[5, 5, 5, 10, 10, 10, 5, 5, 5],
[5, 5, 5, 10, 10, 10, 5, 5, 5],
[5, 5, 5, 10, 10, 10, 5, 5, 5],
[5, 5, 5, 10, 10, 10, 5, 5, 5],
[10, 0, 0, 15, 15, 15, 0, 0, 10],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]
],
'P': [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[10, 10, 10, 10, 10, 10, 10, 10, 10],
[15, 15, 15, 15, 15, 15, 15, 15, 15],
[20, 20, 20, 20, 20, 20, 20, 20, 20],
[30, 30, 30, 30, 30, 30, 30, 30, 30],
[0, 0, 0, 0, 0, 0, 0, 0, 0]
]
},
'black': {
'R': [
[10, 0, 0, 0, 0, 0, 0, 0, 10],
[5, 5, 5, 5, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 4, 4, 4, 4, 4],
[3, 3, 3, 3, 3, 3, 3, 3, 3],
[2, 2, 2, 2, 2, 2, 2, 2, 2],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]
],
'N': [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 5, 0, 0, 0, 0, 0, 5, 0],
[0, 0, 0, 20, 0, 20, 0, 0, 0],
[0, 0, 15, 0, 15, 0, 15, 0, 0],
[0, 10, 0, 0, 0, 0, 0, 10, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 10, 0, 0, 0, 0, 0, 10, 0],
[0, 0, 10, 0, 10, 0, 10, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]
],
'C': [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[10, 0, 0, 15, 15, 15, 0, 0, 10],
[5, 5, 5, 10, 10, 10, 5, 5, 5],
[5, 5, 5, 10, 10, 10, 5, 5, 5],
[5, 5, 5, 10, 10, 10, 5, 5, 5],
[5, 5, 5, 10, 10, 10, 5, 5, 5],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]
],
'P': [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[30, 30, 30, 30, 30, 30, 30, 30, 30],
[20, 20, 20, 20, 20, 20, 20, 20, 20],
[15, 15, 15, 15, 15, 15, 15, 15, 15],
[10, 10, 10, 10, 10, 10, 10, 10, 10],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]
]
}
};
let board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(null));
let currentPlayer = 'red';
let selectedPiece = null;
let gameOver = false;
let gameMode = 'human'; // 'human' or 'ai'
let difficulty = 'easy'; // 'easy', 'medium', 'hard'
let aiColor = 'black';
// DOM元素
const gameModeSelect = document.getElementById('game-mode');
const difficultySelector = document.getElementById('difficulty-selector');
const difficultySelect = document.getElementById('difficulty');
const startGameButton = document.getElementById('start-game');
// 事件監聽器
gameModeSelect.addEventListener('change', () => {
if (gameModeSelect.value === 'ai') {
difficultySelector.style.display = 'block';
} else {
difficultySelector.style.display = 'none';
}
});
startGameButton.addEventListener('click', () => {
gameMode = gameModeSelect.value;
difficulty = difficultySelect.value;
initBoard();
});
// 初始化棋盤
function initBoard() {
const boardElement = document.getElementById('board');
boardElement.innerHTML = '';
// 初始化棋盤數據
board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(null));
currentPlayer = 'red';
selectedPiece = null;
gameOver = false;
for (let y = 0; y < BOARD_SIZE; y++) {
const row = document.createElement('div');
row.className = 'row';
for (let x = 0; x < BOARD_SIZE; x++) {
const cell = document.createElement('div');
cell.className = `cell ${(x + y) % 2 === 1 ? 'black' : ''}`;
cell.dataset.x = x;
cell.dataset.y = y;
cell.addEventListener('click', () => handleCellClick(x, y));
row.appendChild(cell);
}
boardElement.appendChild(row);
}
// 放置初始棋子
INITIAL_POSITIONS.forEach(pos => {
board[pos.y][pos.x] = {type: pos.type, color: pos.color};
renderPiece(pos.x, pos.y, pos.type, pos.color);
});
updateInfo();
}
// 渲染棋子
function renderPiece(x, y, type, color) {
const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
if (!cell) return;
while (cell.firstChild) cell.removeChild(cell.firstChild);
if (type && color) {
const piece = document.createElement('div');
piece.className = `piece ${color}`;
piece.textContent = PIECE_NAMES[type];
cell.appendChild(piece);
}
}
// 處理單元格點擊
function handleCellClick(x, y) {
if (gameOver || (gameMode === 'ai' && currentPlayer === aiColor)) return;
if (board[y][x] && board[y][x].color === currentPlayer) {
selectPiece(x, y);
return;
}
if (selectedPiece) {
const fromX = selectedPiece.x;
const fromY = selectedPiece.y;
if (isValidMove(fromX, fromY, x, y)) {
movePiece(fromX, fromY, x, y);
checkGameOver();
currentPlayer = currentPlayer === 'red' ? 'black' : 'red';
// 如果是人機對戰且輪到AI回合,執行AI移動
if (gameMode === 'ai' && currentPlayer === aiColor && !gameOver) {
setTimeout(aiMakeMove, 500); // 延遲執行,讓玩家能看到
}
}
deselectAll();
updateInfo();
}
}
// 選中棋子
function selectPiece(x, y) {
deselectAll();
selectedPiece = {x, y};
const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
cell.classList.add('selected');
showValidMoves(x, y);
}
// 取消所有選中
function deselectAll() {
selectedPiece = null;
document.querySelectorAll('.cell').forEach(cell => {
cell.classList.remove('selected', 'valid-move');
});
}
// 顯示有效移動
function showValidMoves(fromX, fromY) {
for (let y = 0; y < BOARD_SIZE; y++) {
for (let x = 0; x < BOARD_SIZE; x++) {
if (isValidMove(fromX, fromY, x, y)) {
const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
cell.classList.add('valid-move');
}
}
}
}
// 檢查移動是否有效
function isValidMove(fromX, fromY, toX, toY) {
const piece = board[fromY][fromX];
if (board[toY][toX] && board[toY][toX].color === piece.color) return false;
switch (piece.type) {
case 'R': return isValidRookMove(fromX, fromY, toX, toY);
case 'N': return isValidKnightMove(fromX, fromY, toX, toY);
case 'E': return isValidElephantMove(fromX, fromY, toX, toY);
case 'A': return isValidAdvisorMove(fromX, fromY, toX, toY);
case 'K': return isValidKingMove(fromX, fromY, toX, toY);
case 'C': return isValidCannonMove(fromX, fromY, toX, toY);
case 'P': return isValidPawnMove(fromX, fromY, toX, toY);
default: return false;
}
}
// 車的移動規則
function isValidRookMove(fromX, fromY, toX, toY) {
if (fromX !== toX && fromY !== toY) return false;
if (fromX === toX) {
const minY = Math.min(fromY, toY) + 1;
const maxY = Math.max(fromY, toY);
for (let y = minY; y < maxY; y++) {
if (board[y][fromX]) return false;
}
} else {
const minX = Math.min(fromX, toX) + 1;
const maxX = Math.max(fromX, toX);
for (let x = minX; x < maxX; x++) {
if (board[fromY][x]) return false;
}
}
return true;
}
// 馬的移動規則
function isValidKnightMove(fromX, fromY, toX, toY) {
const dx = Math.abs(toX - fromX);
const dy = Math.abs(toY - fromY);
if (!((dx === 1 && dy === 2) || (dx === 2 && dy === 1))) return false;
if (dx === 2) {
const midX = fromX + (toX > fromX ? 1 : -1);
if (board[fromY][midX]) return false;
} else {
const midY = fromY + (toY > fromY ? 1 : -1);
if (board[midY][fromX]) return false;
}
return true;
}
// 相/象的移動規則
function isValidElephantMove(fromX, fromY, toX, toY) {
const dx = Math.abs(toX - fromX);
const dy = Math.abs(toY - fromY);
if (dx !== 2 || dy !== 2) return false;
const midX = (fromX + toX) / 2;
const midY = (fromY + toY) / 2;
if (board[midY][midX]) return false;
const riverY = 5;
if ((board[fromY][fromX].color === 'red' && toY < riverY) ||
(board[fromY][fromX].color === 'black' && toY > riverY)) {
return false;
}
return true;
}
// 士的移動規則
function isValidAdvisorMove(fromX, fromY, toX, toY) {
const dx = Math.abs(toX - fromX);
const dy = Math.abs(toY - fromY);
if (dx !== 1 || dy !== 1) return false;
if (board[fromY][fromX].color === 'red') {
return toX >= 3 && toX <= 5 && toY >= 7 && toY <= 9;
} else {
return toX >= 3 && toX <= 5 && toY >= 0 && toY <= 2;
}
}
// 將/帥的移動規則
function isValidKingMove(fromX, fromY, toX, toY) {
const dx = Math.abs(toX - fromX);
const dy = Math.abs(toY - fromY);
if (!((dx === 0 && dy === 1) || (dx === 1 && dy === 0))) return false;
if (board[fromY][fromX].color === 'red') {
return toX >= 3 && toX <= 5 && toY >= 7 && toY <= 9;
} else {
return toX >= 3 && toX <= 5 && toY >= 0 && toY <= 2;
}
}
// 炮的移動規則
function isValidCannonMove(fromX, fromY, toX, toY) {
const hasTarget = board[toY][toX] !== null;
let obstacleCount = 0;
if (fromX !== toX && fromY !== toY) return false;
if (fromX === toX) {
const minY = Math.min(fromY, toY) + 1;
const maxY = Math.max(fromY, toY);
for (let y = minY; y < maxY; y++) {
if (board[y][fromX]) obstacleCount++;
}
} else {
const minX = Math.min(fromX, toX) + 1;
const maxX = Math.max(fromX, toX);
for (let x = minX; x < maxX; x++) {
if (board[fromY][x]) obstacleCount++;
}
}
return (hasTarget && obstacleCount === 1) || (!hasTarget && obstacleCount === 0);
}
// 兵/卒的移動規則
function isValidPawnMove(fromX, fromY, toX, toY) {
const piece = board[fromY][fromX];
const direction = piece.color === 'red' ? -1 : 1;
const dx = toX - fromX;
const dy = toY - fromY;
const riverY = piece.color === 'red' ? 5 : 4;
const hasCrossedRiver = (piece.color === 'red' && fromY <= riverY) ||
(piece.color === 'black' && fromY >= riverY);
if (dx === 0 && dy === direction) return true;
if (hasCrossedRiver && Math.abs(dx) === 1 && dy === 0) return true;
return false;
}
// 移動棋子
function movePiece(fromX, fromY, toX, toY) {
const piece = board[fromY][fromX];
board[toY][toX] = piece;
board[fromY][fromX] = null;
renderPiece(fromX, fromY, null, null);
renderPiece(toX, toY, piece.type, piece.color);
}
// 檢查遊戲是否結束
function checkGameOver() {
let redKingExists = false;
let blackKingExists = false;
for (let y = 0; y < BOARD_SIZE; y++) {
for (let x = 0; x < BOARD_SIZE; x++) {
if (board[y][x] && board[y][x].type === 'K') {
if (board[y][x].color === 'red') redKingExists = true;
else blackKingExists = true;
}
}
}
if (!redKingExists) {
gameOver = true;
document.getElementById('info').textContent = '黑方勝利!';
} else if (!blackKingExists) {
gameOver = true;
document.getElementById('info').textContent = '紅方勝利!';
}
}
// 更新遊戲信息
function updateInfo() {
if (!gameOver) {
document.getElementById('info').textContent = `${currentPlayer === 'red' ? '紅' : '黑'}方回合`;
}
}
// AI移動
function aiMakeMove() {
if (gameOver) return;
let bestMove = null;
switch (difficulty) {
case 'easy':
bestMove = getEasyAIMove();
break;
case 'medium':
bestMove = getMediumAIMove();
break;
case 'hard':
bestMove = getHardAIMove();
break;
}
if (bestMove) {
movePiece(bestMove.fromX, bestMove.fromY, bestMove.toX, bestMove.toY);
checkGameOver();
currentPlayer = currentPlayer === 'red' ? 'black' : 'red';
updateInfo();
}
}
// 獲取所有可能的移動
function getAllPossibleMoves(color) {
const moves = [];
for (let y = 0; y < BOARD_SIZE; y++) {
for (let x = 0; x < BOARD_SIZE; x++) {
if (board[y][x] && board[y][x].color === color) {
for (let toY = 0; toY < BOARD_SIZE; toY++) {
for (let toX = 0; toX < BOARD_SIZE; toX++) {
if (isValidMove(x, y, toX, toY)) {
moves.push({
fromX: x,
fromY: y,
toX: toX,
toY: toY
});
}
}
}
}
}
}
return moves;
}
// 簡單難度AI:隨機選擇一個可行的移動
function getEasyAIMove() {
const moves = getAllPossibleMoves(aiColor);
if (moves.length === 0) return null;
// 簡單難度:90%概率隨機移動,10%概率選擇喫子移動
if (Math.random() < 0.9) {
return moves[Math.floor(Math.random() * moves.length)];
} else {
const capturingMoves = moves.filter(move => board[move.toY][move.toX] !== null);
return capturingMoves.length > 0 ? capturingMoves[Math.floor(Math.random() * capturingMoves.length)] : moves[Math.floor(Math.random() * moves.length)];
}
}
// 中等難度AI:考慮基本策略
function getMediumAIMove() {
const moves = getAllPossibleMoves(aiColor);
if (moves.length === 0) return null;
// 評估每個移動的分數
let bestScore = -Infinity;
let bestMoves = [];
for (const move of moves) {
const score = evaluateMove(move);
if (score > bestScore) {
bestScore = score;
bestMoves = [move];
} else if (score === bestScore) {
bestMoves.push(move);
}
}
return bestMoves[Math.floor(Math.random() * bestMoves.length)];
}
// 地獄難度AI:使用優化版極小極大算法
function getHardAIMove() {
let bestScore = -Infinity;
let bestMove = null;
const moves = getAllPossibleMoves(aiColor);
if (moves.length === 0) return null;
// 對移動進行排序,優先評估可能更好的移動(喫子、中心位置等)
moves.sort((a, b) => {
const valueA = board[a.toY][a.toX] ? (PIECE_VALUES[board[a.toY][a.toX].type] || 0) : 0;
const valueB = board[b.toY][b.toX] ? (PIECE_VALUES[board[b.toY][b.toX].type] || 0) : 0;
return valueB - valueA;
});
// 限制最大移動評估數量
const maxMovesToEvaluate = Math.min(10, moves.length);
for (let i = 0; i < maxMovesToEvaluate; i++) {
const move = moves[i];
// 檢查計算時間是否過長(限制為300毫秒)
if (Date.now() - startTime > 300) {
console.log('AI計算超時,提前返回當前最優解');
break;
}
// 模擬移動
const capturedPiece = board[move.toY][move.toX];
board[move.toY][move.toX] = board[move.fromY][move.fromX];
board[move.fromY][move.fromX] = null;
// 降低搜索深度到3層
const score = -minimax(2, -Infinity, Infinity, aiColor === 'red' ? 'black' : 'red', startTime);
// 撤銷移動
board[move.fromY][move.fromX] = board[move.toY][move.toX];
board[move.toY][move.toX] = capturedPiece;
if (score > bestScore) {
bestScore = score;
bestMove = move;
}
}
// 如果沒有找到最優解,返回第一個可行移動
return bestMove || moves[0];
}
// 優化版極小極大算法帶Alpha-Beta剪枝
function minimax(depth, alpha, beta, color, startTime) {
// 檢查計算時間是否過長(限制為250毫秒)
if (Date.now() - startTime > 250) {
// 超時情況下返回一個快速評估的分數
return evaluateBoardFast();
}
if (depth === 0) {
return evaluateBoardFast();
}
const moves = getAllPossibleMoves(color);
if (moves.length === 0) {
// 如果沒有合法移動,檢查是否被將死
return -10000; // 被將死,分數極低
}
// 簡化版移動排序,只基於喫子價值
moves.sort((a, b) => {
const valA = board[a.toY][a.toX] ? (PIECE_VALUES[board[a.toY][a.toX].type] || 0) : 0;
const valB = board[b.toY][b.toX] ? (PIECE_VALUES[board[b.toY][b.toX].type] || 0) : 0;
return color === aiColor ? valB - valA : valA - valB;
});
// 限制每層的搜索分支數量
const maxBranches = Math.min(15, moves.length);
if (color === aiColor) {
let maxScore = -Infinity;
for (let i = 0; i < maxBranches; i++) {
const move = moves[i];
// 模擬移動
const capturedPiece = board[move.toY][move.toX];
board[move.toY][move.toX] = board[move.fromY][move.fromX];
board[move.fromY][move.fromX] = null;
const score = minimax(depth - 1, alpha, beta, aiColor === 'red' ? 'black' : 'red', startTime);
// 撤銷移動
board[move.fromY][move.fromX] = board[move.toY][move.toX];
board[move.toY][move.toX] = capturedPiece;
maxScore = Math.max(maxScore, score);
alpha = Math.max(alpha, score);
if (beta <= alpha) {
break; // Beta剪枝
}
}
return maxScore;
} else {
let minScore = Infinity;
for (let i = 0; i < maxBranches; i++) {
const move = moves[i];
// 模擬移動
const capturedPiece = board[move.toY][move.toX];
board[move.toY][move.toX] = board[move.fromY][move.fromX];
board[move.fromY][move.fromX] = null;
const score = minimax(depth - 1, alpha, beta, aiColor, startTime);
// 撤銷移動
board[move.fromY][move.fromX] = board[move.toY][move.toX];
board[move.toY][move.toX] = capturedPiece;
minScore = Math.min(minScore, score);
beta = Math.min(beta, score);
if (beta <= alpha) {
break; // Alpha剪枝
}
}
return minScore;
}
}
// 簡化版移動評估函數(中等難度)
function evaluateMove(move) {
let score = 0;
// 喫子加分
const capturedPiece = board[move.toY][move.toX];
if (capturedPiece) {
score += PIECE_VALUES[capturedPiece.type] * 1.5;
}
// 保護自己的將/帥
const movingPiece = board[move.fromY][move.fromX];
if (movingPiece.type === 'K') {
score += 10;
}
// 簡化版位置價值評估
if (POSITION_WEIGHTS[aiColor] && POSITION_WEIGHTS[aiColor][movingPiece.type]) {
const fromWeight = POSITION_WEIGHTS[aiColor][movingPiece.type][move.fromY][move.fromX];
const toWeight = POSITION_WEIGHTS[aiColor][movingPiece.type][move.toY][move.toX];
score += (toWeight - fromWeight) * 0.5;
}
// 棋子價值
score += PIECE_VALUES[movingPiece.type];
return score;
}
// 快速版棋盤評估函數(用於地獄難度)
function evaluateBoardFast() {
let score = 0;
// 1. 簡化版棋子價值評估
for (let y = 0; y < BOARD_SIZE; y++) {
for (let x = 0; x < BOARD_SIZE; x++) {
const piece = board[y][x];
if (piece) {
let pieceScore = PIECE_VALUES[piece.type];
// 2. 簡化版位置價值評估
if (POSITION_WEIGHTS[piece.color] && POSITION_WEIGHTS[piece.color][piece.type]) {
pieceScore += POSITION_WEIGHTS[piece.color][piece.type][y][x] * 0.8;
}
// 3. 過河兵加成
if (piece.type === 'P') {
if ((piece.color === 'red' && y <= 4) || (piece.color === 'black' && y >= 5)) {
pieceScore *= 1.8;
}
}
// 4. 根據顏色調整分數
if (piece.color === aiColor) {
score += pieceScore;
} else {
score -= pieceScore;
}
}
}
}
// 5. 簡化版將的安全性評估
const aiKingPos = findKingPosition(aiColor);
const playerKingPos = findKingPosition(aiColor === 'red' ? 'black' : 'red');
if (aiKingPos && playerKingPos && aiKingPos.x === playerKingPos.x) {
let hasObstacle = false;
const minY = Math.min(aiKingPos.y, playerKingPos.y) + 1;
const maxY = Math.max(aiKingPos.y, playerKingPos.y);
for (let y = minY; y < maxY; y++) {
if (board[y][aiKingPos.x]) {
hasObstacle = true;
break;
}
}
if (!hasObstacle) {
// 如果AI是黑方,紅方老將對面是優勢
if (aiColor === 'black') {
score += 100;
} else {
score -= 100;
}
}
}
return score;
}
// 找到將/帥的位置
function findKingPosition(color) {
for (let y = 0; y < BOARD_SIZE; y++) {
for (let x = 0; x < BOARD_SIZE; x++) {
if (board[y][x] && board[y][x].type === 'K' && board[y][x].color === color) {
return {x, y};
}
}
}
return null;
}
// 初始化遊戲
window.onload = function() {
// 顯示菜單,等待用户開始遊戲
document.getElementById('info').textContent = '請選擇遊戲模式並點擊開始遊戲';
};
</script>
</body>
</html>
'''