html
复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>五子棋 - deveco</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f5f5f5;
}
h1 {
color: #333;
}
#board {
display: flex;
flex-direction: column;
background-color: #dcb35c;
padding: 10px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
margin: 20px 0;
}
.row {
display: flex;
}
.cell {
width: 30px;
height: 30px;
border: 1px solid #000;
display: flex;
justify-content: center;
align-items: center;
position: relative;
cursor: pointer;
}
.piece {
width: 24px;
height: 24px;
border-radius: 50%;
}
.black {
background-color: #000;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
}
.white {
background-color: #fff;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
}
#status {
font-size: 18px;
font-weight: bold;
margin: 10px 0;
}
button {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin: 0 5px;
}
#controls {
display: flex;
margin-bottom: 15px;
}
.difficulty {
margin-top: 15px;
}
select {
padding: 5px;
margin-left: 10px;
}
</style>
</head>
<body>
<h1>五子棋</h1>
<div id="status">当前玩家:黑棋</div>
<div id="controls">
<button id="restart">重新开始</button>
<button id="toggle-ai">切换AI模式</button>
</div>
<div class="difficulty">
难度:
<select id="ai-level">
<option value="easy">简单</option>
<option value="medium" selected>中等</option>
<option value="hard">困难</option>
</select>
</div>
<div id="board"></div>
<script>
// 游戏状态
const gameState = {
board: [],
currentPlayer: 1, // 1=黑棋, 2=白棋
gameOver: false,
size: 15,
aiEnabled: true,
aiPlayer: 2, // AI默认使用白棋
aiLevel: 'medium'
};
// 初始化棋盘
function initGame() {
gameState.board = Array(gameState.size).fill().map(() => Array(gameState.size).fill(0));
gameState.currentPlayer = 1;
gameState.gameOver = false;
renderBoard();
// 更新AI状态按钮
document.getElementById('toggle-ai').textContent =
gameState.aiEnabled ? "关闭AI模式" : "开启AI模式";
}
// 渲染棋盘
function renderBoard() {
const board = document.getElementById('board');
board.innerHTML = '';
for (let i = 0; i < gameState.size; i++) {
const row = document.createElement('div');
row.className = 'row';
for (let j = 0; j < gameState.size; j++) {
const cell = document.createElement('div');
cell.className = 'cell';
if (gameState.board[i][j] === 1) {
const piece = document.createElement('div');
piece.className = 'piece black';
cell.appendChild(piece);
} else if (gameState.board[i][j] === 2) {
const piece = document.createElement('div');
piece.className = 'piece white';
cell.appendChild(piece);
}
cell.addEventListener('click', () => makeMove(i, j));
row.appendChild(cell);
}
board.appendChild(row);
}
// 更新状态
const status = document.getElementById('status');
if (gameState.gameOver) {
const winner = gameState.currentPlayer === 1 ? '黑棋' : '白棋';
const isAI = gameState.aiEnabled && gameState.currentPlayer === gameState.aiPlayer;
status.textContent = `游戏结束,${winner}${isAI ? '(AI)' : ''}胜利!`;
} else {
const currentPlayerText = gameState.currentPlayer === 1 ? '黑棋' : '白棋';
const isAI = gameState.aiEnabled && gameState.currentPlayer === gameState.aiPlayer;
status.textContent = `当前玩家:${currentPlayerText}${isAI ? '(AI思考中...)' : ''}`;
}
}
// 落子
function makeMove(row, col) {
// 如果游戏结束或该位置已有棋子,则不允许落子
if (gameState.gameOver || gameState.board[row][col] !== 0) {
return;
}
// 如果当前是AI回合且AI启用,则忽略玩家点击
if (gameState.aiEnabled && gameState.currentPlayer === gameState.aiPlayer) {
return;
}
// 玩家落子
gameState.board[row][col] = gameState.currentPlayer;
// 检查是否获胜
if (checkWin(row, col)) {
gameState.gameOver = true;
renderBoard();
return;
}
// 切换玩家
gameState.currentPlayer = gameState.currentPlayer === 1 ? 2 : 1;
renderBoard();
// 如果AI启用且现在是AI回合,则AI落子
if (gameState.aiEnabled && gameState.currentPlayer === gameState.aiPlayer && !gameState.gameOver) {
setTimeout(makeAIMove, 500); // 延迟500ms,让玩家能看到自己的落子
}
}
// AI落子
function makeAIMove() {
if (gameState.gameOver) return;
const move = findBestMove();
if (move) {
gameState.board[move.row][move.col] = gameState.aiPlayer;
if (checkWin(move.row, move.col)) {
gameState.gameOver = true;
renderBoard();
return;
}
gameState.currentPlayer = gameState.currentPlayer === 1 ? 2 : 1;
renderBoard();
}
}
// AI寻找最佳落子位置
function findBestMove() {
const aiLevel = gameState.aiLevel;
const emptyPositions = [];
// 找出所有空位置
for (let i = 0; i < gameState.size; i++) {
for (let j = 0; j < gameState.size; j++) {
if (gameState.board[i][j] === 0) {
emptyPositions.push({row: i, col: j});
}
}
}
// 如果是第一步,随机选择靠近中心的位置
if (emptyPositions.length === gameState.size * gameState.size) {
const center = Math.floor(gameState.size / 2);
const offset = Math.floor(Math.random() * 3) - 1; // -1, 0, 或 1
return {
row: center + offset,
col: center + Math.floor(Math.random() * 3) - 1
};
}
// 评估每个位置的分数
const movesWithScores = emptyPositions.map(pos => {
return {
...pos,
score: evaluatePosition(pos.row, pos.col, aiLevel)
};
});
// 根据难度增加随机性
if (aiLevel === 'easy') {
// 简单模式有50%概率随机落子
if (Math.random() < 0.5) {
return emptyPositions[Math.floor(Math.random() * emptyPositions.length)];
}
} else if (aiLevel === 'medium') {
// 中等模式有20%概率不选最佳位置
if (Math.random() < 0.2) {
movesWithScores.sort((a, b) => b.score - a.score);
const topMoves = movesWithScores.slice(0, Math.min(5, movesWithScores.length));
return topMoves[Math.floor(Math.random() * topMoves.length)];
}
}
// 选择分数最高的位置
movesWithScores.sort((a, b) => b.score - a.score);
return movesWithScores[0];
}
// 评估位置分数
function evaluatePosition(row, col, aiLevel) {
const humanPlayer = gameState.aiPlayer === 1 ? 2 : 1;
let score = 0;
// 优先考虑靠近中心的位置
const center = Math.floor(gameState.size / 2);
const distanceFromCenter = Math.abs(row - center) + Math.abs(col - center);
score -= distanceFromCenter;
// 检查周围是否有棋子
let hasNeighbor = false;
for (let i = Math.max(0, row - 2); i <= Math.min(gameState.size - 1, row + 2); i++) {
for (let j = Math.max(0, col - 2); j <= Math.min(gameState.size - 1, col + 2); j++) {
if (gameState.board[i][j] !== 0) {
hasNeighbor = true;
break;
}
}
if (hasNeighbor) break;
}
if (!hasNeighbor) {
return score - 50; // 远离所有棋子的位置不太好
}
// 检查各个方向的得分
const directions = [
[0, 1], // 水平
[1, 0], // 垂直
[1, 1], // 右下对角线
[1, -1] // 右上对角线
];
for (const [dr, dc] of directions) {
// 检查AI自己的得分
score += evaluateDirection(row, col, dr, dc, gameState.aiPlayer) * 2;
// 检查阻止对手的得分
const humanScore = evaluateDirection(row, col, dr, dc, humanPlayer);
// 如果对手即将获胜,优先阻止
if (humanScore >= 100) {
score += humanScore * 1.5;
} else {
score += humanScore;
}
}
// 根据难度调整
if (aiLevel === 'hard') {
// 困难模式增加攻击性,更注重自己的连子
score *= 1.2;
} else if (aiLevel === 'easy') {
// 简单模式减弱AI能力
score *= 0.7;
}
return score;
}
// 评估某个方向上的得分
function evaluateDirection(row, col, dr, dc, player) {
const opponent = player === 1 ? 2 : 1;
let score = 0;
// 模拟在该位置放置棋子
const tempBoard = JSON.parse(JSON.stringify(gameState.board));
tempBoard[row][col] = player;
// 检查连续棋子
let count = 1; // 包括当前位置
let open = [true, true]; // 两端是否开放
// 正向检查
for (let i = 1; i < 5; i++) {
const r = row + i * dr;
const c = col + i * dc;
if (r >= 0 && r < gameState.size && c >= 0 && c < gameState.size) {
if (tempBoard[r][c] === player) {
count++;
} else if (tempBoard[r][c] === opponent) {
open[0] = false;
break;
} else {
break;
}
} else {
open[0] = false;
break;
}
}
// 反向检查
for (let i = 1; i < 5; i++) {
const r = row - i * dr;
const c = col - i * dc;
if (r >= 0 && r < gameState.size && c >= 0 && c < gameState.size) {
if (tempBoard[r][c] === player) {
count++;
} else if (tempBoard[r][c] === opponent) {
open[1] = false;
break;
} else {
break;
}
} else {
open[1] = false;
break;
}
}
// 根据连续棋子数和开放端计算得分
const openEnds = (open[0] ? 1 : 0) + (open[1] ? 1 : 0);
if (count >= 5) return 10000; // 五连珠,必胜
if (count === 4) {
if (openEnds === 2) return 5000; // 活四
if (openEnds === 1) return 1000; // 冲四
}
if (count === 3) {
if (openEnds === 2) return 500; // 活三
if (openEnds === 1) return 100; // 冲三
}
if (count === 2) {
if (openEnds === 2) return 50; // 活二
if (openEnds === 1) return 10; // 冲二
}
if (count === 1) {
if (openEnds === 2) return 5; // 活一
if (openEnds === 1) return 1; // 冲一
}
return 0;
}
// 检查是否获胜
function checkWin(row, col) {
const directions = [
[0, 1], // 水平
[1, 0], // 垂直
[1, 1], // 右下对角线
[1, -1] // 右上对角线
];
const player = gameState.board[row][col];
for (const [dr, dc] of directions) {
let count = 1;
// 正向检查
for (let i = 1; i < 5; i++) {
const r = row + i * dr;
const c = col + i * dc;
if (r >= 0 && r < gameState.size && c >= 0 && c < gameState.size &&
gameState.board[r][c] === player) {
count++;
} else {
break;
}
}
// 反向检查
for (let i = 1; i < 5; i++) {
const r = row - i * dr;
const c = col - i * dc;
if (r >= 0 && r < gameState.size && c >= 0 && c < gameState.size &&
gameState.board[r][c] === player) {
count++;
} else {
break;
}
}
if (count >= 5) {
return true;
}
}
return false;
}
// 启动游戏
document.addEventListener('DOMContentLoaded', () => {
initGame();
// 重新开始按钮
document.getElementById('restart').addEventListener('click', initGame);
// 切换AI模式按钮
document.getElementById('toggle-ai').addEventListener('click', () => {
gameState.aiEnabled = !gameState.aiEnabled;
document.getElementById('toggle-ai').textContent =
gameState.aiEnabled ? "关闭AI模式" : "开启AI模式";
// 如果切换到AI模式且当前是AI回合,则AI立即落子
if (gameState.aiEnabled && gameState.currentPlayer === gameState.aiPlayer && !gameState.gameOver) {
setTimeout(makeAIMove, 500);
}
});
// 难度选择
document.getElementById('ai-level').addEventListener('change', (e) => {
gameState.aiLevel = e.target.value;
});
});
</script>
</body>
</html>