五子棋,一键生成

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>五子棋游戏</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#8B5A2B',
secondary: '#D2B48C',
board: '#DEB887',
black: '#000000',
white: '#FFFFFF',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.board-shadow {
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15);
}
.piece-transition {
transition: all 0.2s ease-out;
}
.hover-cell:hover::before {
content: '';
position: absolute;
width: 80%;
height: 80%;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.1);
}
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex flex-col items-center justify-center p-4">
<div class="max-w-4xl w-full bg-white rounded-xl shadow-lg overflow-hidden">
<!-- 游戏标题 -->
<div class="bg-primary text-white text-center py-4 px-6">
<h1 class="text-2xl md:text-3xl font-bold flex items-center justify-center">
<i class="fa fa-gamepad mr-3"></i>五子棋
</h1>
</div>
<!-- 游戏区域 -->
<div class="flex flex-col md:flex-row p-4 md:p-6">
<!-- 左侧游戏信息 -->
<div class="w-full md:w-1/4 mb-6 md:mb-0 md:pr-6">
<div class="bg-gray-50 rounded-lg p-4 h-full flex flex-col">
<div class="mb-4">
<h2 class="text-lg font-semibold mb-2 text-gray-800 flex items-center">
<i class="fa fa-info-circle mr-2"></i>游戏信息
</h2>
<div class="space-y-3">
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-black mr-3"></div>
<span>黑方先行</span>
</div>
<div class="flex items-center">
<div class="w-6 h-6 rounded-full bg-white border border-gray-300 mr-3"></div>
<span>白方后行</span>
</div>
</div>
</div>
<div class="mb-4">
<h2 class="text-lg font-semibold mb-2 text-gray-800 flex items-center">
<i class="fa fa-trophy mr-2"></i>游戏状态
</h2>
<div id="status" class="py-2 px-3 bg-secondary/30 rounded-md text-center font-medium">
黑方回合
</div>
</div>
<div class="mt-auto">
<button id="restartBtn" class="w-full py-3 px-4 bg-primary hover:bg-primary/90 text-white rounded-lg transition-all duration-300 flex items-center justify-center">
<i class="fa fa-refresh mr-2"></i>重新开始
</button>
</div>
</div>
</div>
<!-- 右侧棋盘 -->
<div class="w-full md:w-3/4 flex justify-center">
<div class="relative">
<div id="board" class="bg-board rounded-lg board-shadow relative">
<!-- 棋盘将通过JavaScript动态生成 -->
</div>
<!-- 胜利提示 -->
<div id="winMessage" class="hidden absolute inset-0 bg-black/50 flex items-center justify-center rounded-lg">
<div class="bg-white p-6 rounded-xl text-center shadow-xl">
<h2 class="text-2xl font-bold mb-4" id="winnerText"></h2>
<button id="newGameBtn" class="py-2 px-6 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors">
开始新游戏
</button>
</div>
</div>
</div>
</div>
</div>
<!-- 游戏控制 -->
<div class="bg-gray-50 p-4 border-t border-gray-200">
<div class="flex flex-wrap justify-center gap-4">
<button id="undoBtn" class="py-2 px-4 bg-gray-200 hover:bg-gray-300 text-gray-800 rounded-lg transition-colors flex items-center">
<i class="fa fa-undo mr-2"></i>悔棋
</button>
<button id="hintBtn" class="py-2 px-4 bg-blue-100 hover:bg-blue-200 text-blue-800 rounded-lg transition-colors flex items-center">
<i class="fa fa-lightbulb-o mr-2"></i>提示
</button>
<button id="settingsBtn" class="py-2 px-4 bg-gray-200 hover:bg-gray-300 text-gray-800 rounded-lg transition-colors flex items-center">
<i class="fa fa-cog mr-2"></i>设置
</button>
</div>
</div>
</div>
<!-- 设置模态框 -->
<div id="settingsModal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div class="bg-white rounded-xl p-6 max-w-md w-full shadow-2xl">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold">游戏设置</h2>
<button id="closeSettingsBtn" class="text-gray-500 hover:text-gray-700">
<i class="fa fa-times"></i>
</button>
</div>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">棋盘大小</label>
<select id="boardSize" class="w-full p-2 border border-gray-300 rounded-md">
<option value="11">11 x 11</option>
<option value="15" selected>15 x 15</option>
<option value="19">19 x 19</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">难度级别</label>
<select id="difficulty" class="w-full p-2 border border-gray-300 rounded-md">
<option value="easy">简单</option>
<option value="medium" selected>中等</option>
<option value="hard">困难</option>
</select>
</div>
<div class="pt-4">
<button id="saveSettingsBtn" class="w-full py-2 px-4 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors">
保存设置
</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// 游戏常量
const BOARD_SIZE = 15; // 默认棋盘大小
const CELL_SIZE = 40; // 单元格大小(像素)
const PIECE_SIZE = CELL_SIZE * 0.8; // 棋子大小
// 游戏状态
let currentPlayer = 'black'; // 'black' 或 'white'
let gameBoard = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(null));
let gameOver = false;
let moveHistory = []; // 记录下棋历史
let hintPosition = null; // 提示位置
// DOM 元素
const boardElement = document.getElementById('board');
const statusElement = document.getElementById('status');
const winMessageElement = document.getElementById('winMessage');
const winnerTextElement = document.getElementById('winnerText');
const restartBtn = document.getElementById('restartBtn');
const undoBtn = document.getElementById('undoBtn');
const hintBtn = document.getElementById('hintBtn');
const settingsBtn = document.getElementById('settingsBtn');
const settingsModal = document.getElementById('settingsModal');
const closeSettingsBtn = document.getElementById('closeSettingsBtn');
const saveSettingsBtn = document.getElementById('saveSettingsBtn');
const boardSizeSelect = document.getElementById('boardSize');
const difficultySelect = document.getElementById('difficulty');
const newGameBtn = document.getElementById('newGameBtn');
// 初始化棋盘
function initializeBoard() {
// 设置棋盘尺寸
const boardDimension = CELL_SIZE * (BOARD_SIZE - 1);
boardElement.style.width = `${boardDimension}px`;
boardElement.style.height = `${boardDimension}px`;
// 清空棋盘
boardElement.innerHTML = '';
// 创建棋盘单元格
for (let row = 0; row < BOARD_SIZE; row++) {
for (let col = 0; col < BOARD_SIZE; col++) {
const cell = document.createElement('div');
cell.classList.add('absolute', 'hover-cell');
cell.style.width = `${CELL_SIZE}px`;
cell.style.height = `${CELL_SIZE}px`;
cell.style.left = `${col * CELL_SIZE}px`;
cell.style.top = `${row * CELL_SIZE}px`;
cell.dataset.row = row;
cell.dataset.col = col;
// 添加棋盘线
const line = document.createElement('div');
line.classList.add('absolute', 'bg-gray-700');
// 水平线
if (row === 0) {
line.style.width = '100%';
line.style.height = '1px';
line.style.top = '50%';
} else if (row === BOARD_SIZE - 1) {
line.style.width = '100%';
line.style.height = '1px';
line.style.bottom = '50%';
} else {
line.style.width = '100%';
line.style.height = '2px';
line.style.top = '50%';
line.style.transform = 'translateY(-50%)';
}
cell.appendChild(line.cloneNode(true));
// 垂直线
if (col === 0) {
line.style.width = '1px';
line.style.height = '100%';
line.style.left = '50%';
line.style.top = '0';
} else if (col === BOARD_SIZE - 1) {
line.style.width = '1px';
line.style.height = '100%';
line.style.right = '50%';
line.style.top = '0';
} else {
line.style.width = '2px';
line.style.height = '100%';
line.style.left = '50%';
line.style.transform = 'translateX(-50%)';
}
cell.appendChild(line);
// 添加天元和星位(仅15x15棋盘)
if (BOARD_SIZE === 15 &&
((row === 3 || row === 7 || row === 11) && (col === 3 || col === 7 || col === 11))) {
const dot = document.createElement('div');
dot.classList.add('absolute', 'bg-gray-800', 'rounded-full');
dot.style.width = '6px';
dot.style.height = '6px';
dot.style.left = '50%';
dot.style.top = '50%';
dot.style.transform = 'translate(-50%, -50%)';
cell.appendChild(dot);
}
// 点击落子
cell.addEventListener('click', () => {
if (!gameOver && !gameBoard[row][col]) {
placePiece(row, col);
}
});
boardElement.appendChild(cell);
}
}
// 重置游戏状态
gameBoard = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(null));
currentPlayer = 'black';
gameOver = false;
moveHistory = [];
updateStatus();
clearHints();
}
// 放置棋子
function placePiece(row, col) {
// 记录历史
moveHistory.push({row, col, player: currentPlayer});
// 更新游戏板
gameBoard[row][col] = currentPlayer;
// 渲染棋子
renderPiece(row, col, currentPlayer);
// 检查胜利条件
if (checkWin(row, col, currentPlayer)) {
gameOver = true;
const winner = currentPlayer === 'black' ? '黑方' : '白方';
winnerTextElement.textContent = `${winner}获胜!`;
winMessageElement.classList.remove('hidden');
return;
}
// 切换玩家
currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
updateStatus();
// 简单AI自动落子(如果是电脑玩家)
if (gameOver === false && currentPlayer === 'white') {
setTimeout(() => {
const aiMove = getAIMove();
placePiece(aiMove.row, aiMove.col);
}, 500);
}
}
// 渲染棋子
function renderPiece(row, col, player) {
const piece = document.createElement('div');
piece.classList.add('absolute', 'rounded-full', 'piece-transition');
piece.style.width = `${PIECE_SIZE}px`;
piece.style.height = `${PIECE_SIZE}px`;
piece.style.left = `${col * CELL_SIZE + (CELL_SIZE - PIECE_SIZE) / 2}px`;
piece.style.top = `${row * CELL_SIZE + (CELL_SIZE - PIECE_SIZE) / 2}px`;
piece.style.zIndex = '10';
if (player === 'black') {
piece.classList.add('bg-black');
piece.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1)';
} else {
piece.classList.add('bg-white', 'border', 'border-gray-300');
piece.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1)';
}
// 添加动画效果
piece.style.transform = 'scale(0)';
piece.style.opacity = '0';
boardElement.appendChild(piece);
// 触发重排,然后应用动画
setTimeout(() => {
piece.style.transform = 'scale(1)';
piece.style.opacity = '1';
}, 10);
// 如果是历史步骤的一部分,添加标记
if (hintPosition && hintPosition.row === row && hintPosition.col === col) {
clearHints();
}
}
// 清除提示标记
function clearHints() {
const hintElements = document.querySelectorAll('.hint-marker');
hintElements.forEach(el => el.remove());
hintPosition = null;
}
// 显示提示
function showHint() {
clearHints();
// 简单AI计算最佳位置
const hintMove = getAIMove();
hintPosition = hintMove;
// 创建提示标记
const hintMarker = document.createElement('div');
hintMarker.classList.add('absolute', 'hint-marker', 'rounded-full', 'bg-yellow-300', 'opacity-50');
hintMarker.style.width = `${PIECE_SIZE * 1.2}px`;
hintMarker.style.height = `${PIECE_SIZE * 1.2}px`;
hintMarker.style.left = `${hintMove.col * CELL_SIZE + (CELL_SIZE - PIECE_SIZE * 1.2) / 2}px`;
hintMarker.style.top = `${hintMove.row * CELL_SIZE + (CELL_SIZE - PIECE_SIZE * 1.2) / 2}px`;
hintMarker.style.zIndex = '5';
boardElement.appendChild(hintMarker);
}
// 简单AI计算最佳落子位置
function getAIMove() {
const difficulty = difficultySelect.value;
let bestScore = -Infinity;
let bestMove = {row: 0, col: 0};
// 简单的评分系统:检查每个空位,找到能形成最长连续棋子的位置
for (let row = 0; row < BOARD_SIZE; row++) {
for (let col = 0; col < BOARD_SIZE; col++) {
if (!gameBoard[row][col]) {
// 计算AI在此位置落子的分数
const aiScore = evaluateMove(row, col, 'white');
// 计算玩家在此位置落子的分数(防守)
const playerScore = evaluateMove(row, col, 'black');
// 综合得分 = 进攻得分 + 防守得分 * 权重
const score = aiScore + playerScore * 0.8;
// 根据难度添加随机性
let randomFactor = 1;
if (difficulty === 'easy') {
randomFactor = 0.7 + Math.random() * 0.3; // 70%-100% 的准确度
} else if (difficulty === 'medium') {
randomFactor = 0.85 + Math.random() * 0.15; // 85%-100% 的准确度
} else {
randomFactor = 0.95 + Math.random() * 0.05; // 95%-100% 的准确度
}
const weightedScore = score * randomFactor;
if (weightedScore > bestScore) {
bestScore = weightedScore;
bestMove = {row, col};
}
}
}
}
return bestMove;
}
// 评估落子位置的分数
function evaluateMove(row, col, player) {
const directions = [
[0, 1], // 水平
[1, 0], // 垂直
[1, 1], // 对角线
[1, -1] // 反对角线
];
let maxScore = 0;
// 检查四个方向
for (const [dx, dy] of directions) {
let score = 0;
let count = 1; // 当前位置算一个
let blockedEnds = 0;
// 正向检查
for (let i = 1; i < 5; i++) {
const r = row + i * dx;
const c = col + i * dy;
if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE) {
blockedEnds++;
break;
}
if (gameBoard[r][c] === player) {
count++;
} else if (gameBoard[r][c] !== null) {
blockedEnds++;
break;
} else {
break;
}
}
// 反向检查
for (let i = 1; i < 5; i++) {
const r = row - i * dx;
const c = col - i * dy;
if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE) {
blockedEnds++;
break;
}
if (gameBoard[r][c] === player) {
count++;
} else if (gameBoard[r][c] !== null) {
blockedEnds++;
break;
} else {
break;
}
}
// 评分规则
if (count >= 5) {
return 10000; // 五连,必胜
} else if (count === 4 && blockedEnds === 0) {
score = 1000; // 活四
} else if (count === 4 && blockedEnds === 1) {
score = 100; // 冲四
} else if (count === 3 && blockedEnds === 0) {
score = 50; // 活三
} else if (count === 3 && blockedEnds === 1) {
score = 10; // 冲三
} else if (count === 2 && blockedEnds === 0) {
score = 5; // 活二
}
if (score > maxScore) {
maxScore = score;
}
}
return maxScore;
}
// 检查胜利条件
function checkWin(row, col, player) {
const directions = [
[0, 1], // 水平
[1, 0], // 垂直
[1, 1], // 对角线
[1, -1] // 反对角线
];
// 检查四个方向
for (const [dx, dy] of directions) {
let count = 1; // 当前位置算一个
// 正向检查
for (let i = 1; i < 5; i++) {
const r = row + i * dx;
const c = col + i * dy;
if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE || gameBoard[r][c] !== player) {
break;
}
count++;
}
// 反向检查
for (let i = 1; i < 5; i++) {
const r = row - i * dx;
const c = col - i * dy;
if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE || gameBoard[r][c] !== player) {
break;
}
count++;
}
// 五连子获胜
if (count >= 5) {
// 高亮显示获胜的棋子
highlightWinningPieces(row, col, dx, dy, player);
return true;
}
}
return false;
}
// 高亮显示获胜的棋子
function highlightWinningPieces(row, col, dx, dy, player) {
// 存储所有获胜的棋子位置
let winningPositions = [{row, col}];
// 正向检查
for (let i = 1; i < 5; i++) {
const r = row + i * dx;
const c = col + i * dy;
if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE || gameBoard[r][c] !== player) {
break;
}
winningPositions.push({row: r, col: c});
}
// 反向检查
for (let i = 1; i < 5; i++) {
const r = row - i * dx;
const c = col - i * dy;
if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE || gameBoard[r][c] !== player) {
break;
}
winningPositions.push({row: r, col: c});
}
// 高亮显示
setTimeout(() => {
for (const pos of winningPositions) {
const x = pos.col * CELL_SIZE + (CELL_SIZE - PIECE_SIZE) / 2;
const y = pos.row * CELL_SIZE + (CELL_SIZE - PIECE_SIZE) / 2;
const highlight = document.createElement('div');
highlight.classList.add('absolute', 'rounded-full', 'z-20');
highlight.style.width = `${PIECE_SIZE * 1.1}px`;
highlight.style.height = `${PIECE_SIZE * 1.1}px`;
highlight.style.left = `${x - (PIECE_SIZE * 0.1) / 2}px`;
highlight.style.top = `${y - (PIECE_SIZE * 0.1) / 2}px`;
if (player === 'black') {
highlight.classList.add('border-2', 'border-yellow-400');
} else {
highlight.classList.add('border-2', 'border-red-400');
}
boardElement.appendChild(highlight);
// 添加闪烁动画
highlight.animate([
{ opacity: 0.7 },
{ opacity: 1 },
{ opacity: 0.7 }
], {
duration: 1500,
iterations: Infinity
});
}
}, 100);
}
// 更新游戏状态显示
function updateStatus() {
if (gameOver) {
statusElement.textContent = '游戏结束';
} else {
const playerText = currentPlayer === 'black' ? '黑方' : '白方';
statusElement.textContent = `${playerText}回合`;
// 更新状态背景色
if (currentPlayer === 'black') {
statusElement.classList.remove('bg-white', 'border-gray-300');
statusElement.classList.add('bg-black', 'text-white');
} else {
statusElement.classList.remove('bg-black', 'text-white');
statusElement.classList.add('bg-white', 'border', 'border-gray-300');
}
}
}
// 悔棋
function undoMove() {
if (moveHistory.length > 0 && !gameOver) {
const lastMove = moveHistory.pop();
gameBoard[lastMove.row][lastMove.col] = null;
// 移除最后一个棋子
const pieces = boardElement.querySelectorAll('.piece-transition');
if (pieces.length > 0) {
const lastPiece = pieces[pieces.length - 1];
lastPiece.style.transform = 'scale(0)';
lastPiece.style.opacity = '0';
setTimeout(() => {
lastPiece.remove();
}, 200);
}
// 切换回上一个玩家
currentPlayer = lastMove.player;
updateStatus();
}
}
// 事件监听器
restartBtn.addEventListener('click', initializeBoard);
undoBtn.addEventListener('click', undoMove);
hintBtn.addEventListener('click', showHint);
// 设置相关
settingsBtn.addEventListener('click', () => {
settingsModal.classList.remove('hidden');
});
closeSettingsBtn.addEventListener('click', () => {
settingsModal.classList.add('hidden');
});
saveSettingsBtn.addEventListener('click', () => {
const newBoardSize = parseInt(boardSizeSelect.value);
if (newBoardSize !== BOARD_SIZE) {
// 重新初始化棋盘
initializeBoard();
}
settingsModal.classList.add('hidden');
});
newGameBtn.addEventListener('click', () => {
winMessageElement.classList.add('hidden');
initializeBoard();
});
// 点击模态框外部关闭
settingsModal.addEventListener('click', (e) => {
if (e.target === settingsModal) {
settingsModal.classList.add('hidden');
}
});
// 初始化棋盘
initializeBoard();
});
</script>
</body>
</html>
五子棋
游戏信息
游戏状态
黑方回合

浙公网安备 33010602011771号