<!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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
color: white;
}
.container {
max-width: 800px;
width: 100%;
text-align: center;
}
h1 {
font-size: 2.8rem;
margin: 20px 0;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
background: linear-gradient(to right, #ffd700, #ffffff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.game-info {
background: rgba(0, 0, 0, 0.3);
border-radius: 15px;
padding: 15px;
margin: 20px 0;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.status {
font-size: 1.4rem;
margin: 10px 0;
font-weight: bold;
}
.controls {
display: flex;
justify-content: center;
gap: 15px;
margin: 15px 0;
flex-wrap: wrap;
}
button {
background: linear-gradient(to bottom, #4a9bff, #1a5bbd);
color: white;
border: none;
padding: 12px 25px;
border-radius: 50px;
font-size: 1.1rem;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
button:hover {
transform: translateY(-3px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
background: linear-gradient(to bottom, #5aa7ff, #2a6bd0);
}
button:active {
transform: translateY(1px);
}
.game-board {
background: #d9b38c;
border: 15px solid #8b4513;
border-radius: 10px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
margin: 20px auto;
position: relative;
overflow: hidden;
}
canvas {
display: block;
background: #d9b38c;
margin: 0 auto;
}
.instructions {
background: rgba(0, 0, 0, 0.3);
border-radius: 15px;
padding: 20px;
margin: 20px 0;
text-align: left;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.instructions h2 {
margin-bottom: 15px;
color: #ffd700;
}
.instructions ul {
padding-left: 20px;
}
.instructions li {
margin: 10px 0;
line-height: 1.5;
}
.win-message {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.85);
color: gold;
font-size: 2.5rem;
font-weight: bold;
padding: 20px 40px;
border-radius: 15px;
display: none;
z-index: 10;
box-shadow: 0 0 30px rgba(255, 215, 0, 0.5);
border: 3px solid gold;
}
@media (max-width: 600px) {
h1 {
font-size: 2rem;
}
.game-info {
padding: 10px;
}
.status {
font-size: 1.2rem;
}
button {
padding: 10px 20px;
font-size: 1rem;
}
.instructions {
padding: 15px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>五子棋游戏</h1>
<div class="game-info">
<div class="status" id="status">当前玩家: 黑子</div>
<div class="controls">
<button id="newGame">新游戏</button>
<button id="undo">悔棋</button>
<button id="hint">提示</button>
</div>
</div>
<div class="game-board">
<canvas id="board" width="540" height="540"></canvas>
<div class="win-message" id="winMessage"></div>
</div>
<div class="instructions">
<h2>游戏规则:</h2>
<ul>
<li>黑子先手,双方轮流在棋盘上放置棋子</li>
<li>率先在横、竖或斜方向连成五子的一方获胜</li>
<li>点击棋盘空白位置下棋</li>
<li>可以使用悔棋功能撤销上一步</li>
<li>点击提示按钮可获得下一步建议</li>
</ul>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('board');
const ctx = canvas.getContext('2d');
const statusElement = document.getElementById('status');
const winMessage = document.getElementById('winMessage');
const newGameButton = document.getElementById('newGame');
const undoButton = document.getElementById('undo');
const hintButton = document.getElementById('hint');
// 游戏常量
const BOARD_SIZE = 15;
const CELL_SIZE = canvas.width / BOARD_SIZE;
const RADIUS = CELL_SIZE / 2 - 2;
// 游戏状态
let board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(0));
let currentPlayer = 1; // 1为黑子,2为白子
let gameActive = true;
let moveHistory = [];
// 初始化游戏
function initGame() {
board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(0));
currentPlayer = 1;
gameActive = true;
moveHistory = [];
winMessage.style.display = 'none';
updateStatus();
drawBoard();
}
// 绘制棋盘
function drawBoard() {
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制棋盘背景
ctx.fillStyle = '#d9b38c';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制网格线
ctx.strokeStyle = '#000';
ctx.lineWidth = 1;
for (let i = 0; i < BOARD_SIZE; i++) {
// 垂直线
ctx.beginPath();
ctx.moveTo(CELL_SIZE / 2, CELL_SIZE / 2 + i * CELL_SIZE);
ctx.lineTo(CELL_SIZE / 2 + (BOARD_SIZE - 1) * CELL_SIZE, CELL_SIZE / 2 + i * CELL_SIZE);
ctx.stroke();
// 水平线
ctx.beginPath();
ctx.moveTo(CELL_SIZE / 2 + i * CELL_SIZE, CELL_SIZE / 2);
ctx.lineTo(CELL_SIZE / 2 + i * CELL_SIZE, CELL_SIZE / 2 + (BOARD_SIZE - 1) * CELL_SIZE);
ctx.stroke();
}
// 绘制星位点
const starPoints = [3, 7, 11];
ctx.fillStyle = '#000';
for (let i of starPoints) {
for (let j of starPoints) {
ctx.beginPath();
ctx.arc(
CELL_SIZE / 2 + i * CELL_SIZE,
CELL_SIZE / 2 + j * CELL_SIZE,
4,
0,
Math.PI * 2
);
ctx.fill();
}
}
// 绘制棋子
for (let row = 0; row < BOARD_SIZE; row++) {
for (let col = 0; col < BOARD_SIZE; col++) {
if (board[row][col] !== 0) {
drawPiece(row, col, board[row][col]);
}
}
}
}
// 绘制棋子
function drawPiece(row, col, player) {
const x = CELL_SIZE / 2 + col * CELL_SIZE;
const y = CELL_SIZE / 2 + row * CELL_SIZE;
ctx.beginPath();
ctx.arc(x, y, RADIUS, 0, Math.PI * 2);
if (player === 1) {
// 黑子
ctx.fillStyle = '#000';
ctx.fill();
// 添加高光效果
ctx.beginPath();
ctx.arc(x - RADIUS/3, y - RADIUS/3, RADIUS/3, 0, Math.PI * 2);
ctx.fillStyle = '#333';
ctx.fill();
} else {
// 白子
ctx.fillStyle = '#fff';
ctx.fill();
// 添加边框
ctx.strokeStyle = '#000';
ctx.lineWidth = 1;
ctx.stroke();
// 添加高光效果
ctx.beginPath();
ctx.arc(x - RADIUS/3, y - RADIUS/3, RADIUS/3, 0, Math.PI * 2);
ctx.fillStyle = '#ddd';
ctx.fill();
}
}
// 更新状态显示
function updateStatus() {
statusElement.textContent = `当前玩家: ${currentPlayer === 1 ? '黑子' : '白子'}`;
}
// 检查是否获胜
function checkWin(row, col) {
const player = board[row][col];
// 检查四个方向:水平、垂直、两个对角线
const directions = [
[0, 1], // 水平
[1, 0], // 垂直
[1, 1], // 对角线 \
[1, -1] // 对角线 /
];
for (let [dx, dy] of directions) {
let count = 1; // 包含当前位置
// 正向检查
for (let i = 1; i < 5; i++) {
const newRow = row + dx * i;
const newCol = col + dy * i;
if (newRow >= 0 && newRow < BOARD_SIZE &&
newCol >= 0 && newCol < BOARD_SIZE &&
board[newRow][newCol] === player) {
count++;
} else {
break;
}
}
// 反向检查
for (let i = 1; i < 5; i++) {
const newRow = row - dx * i;
const newCol = col - dy * i;
if (newRow >= 0 && newRow < BOARD_SIZE &&
newCol >= 0 && newCol < BOARD_SIZE &&
board[newRow][newCol] === player) {
count++;
} else {
break;
}
}
if (count >= 5) {
return true;
}
}
return false;
}
// 处理点击事件
canvas.addEventListener('click', (e) => {
if (!gameActive) return;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 计算点击位置对应的棋盘坐标
const col = Math.round((x - CELL_SIZE / 2) / CELL_SIZE);
const row = Math.round((y - CELL_SIZE / 2) / CELL_SIZE);
// 检查坐标是否有效且该位置为空
if (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] === 0) {
// 下棋
board[row][col] = currentPlayer;
moveHistory.push({row, col});
// 检查是否获胜
if (checkWin(row, col)) {
gameActive = false;
winMessage.textContent = `${currentPlayer === 1 ? '黑子' : '白子'} 获胜!`;
winMessage.style.display = 'block';
} else if (moveHistory.length === BOARD_SIZE * BOARD_SIZE) {
// 平局
gameActive = false;
winMessage.textContent = '平局!';
winMessage.style.display = 'block';
} else {
// 切换玩家
currentPlayer = currentPlayer === 1 ? 2 : 1;
updateStatus();
}
drawBoard();
}
});
// 悔棋功能
undoButton.addEventListener('click', () => {
if (moveHistory.length > 0 && gameActive) {
const lastMove = moveHistory.pop();
board[lastMove.row][lastMove.col] = 0;
currentPlayer = currentPlayer === 1 ? 2 : 1;
updateStatus();
drawBoard();
}
});
// 新游戏
newGameButton.addEventListener('click', initGame);
// 提示功能
hintButton.addEventListener('click', () => {
if (gameActive) {
// 简单的提示算法:选择第一个可用位置
for (let row = 0; row < BOARD_SIZE; row++) {
for (let col = 0; col < BOARD_SIZE; col++) {
if (board[row][col] === 0) {
// 高亮提示位置
const x = CELL_SIZE / 2 + col * CELL_SIZE;
const y = CELL_SIZE / 2 + row * CELL_SIZE;
ctx.beginPath();
ctx.arc(x, y, RADIUS, 0, Math.PI * 2);
ctx.strokeStyle = 'rgba(255, 0, 0, 0.7)';
ctx.lineWidth = 3;
ctx.stroke();
setTimeout(() => {
drawBoard();
}, 500);
return;
}
}
}
}
});
// 初始化游戏
initGame();
});
</script>
</body>
</html>
index.html
index.html