Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
322 changes: 322 additions & 0 deletions gomoku.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,322 @@
<!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: 'Arial', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.container {
text-align: center;
background: white;
padding: 30px;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}

h1 {
color: #333;
margin-bottom: 20px;
font-size: 2.5em;
}

.game-info {
margin-bottom: 20px;
font-size: 1.2em;
color: #555;
}

.current-player {
font-weight: bold;
color: #667eea;
}

#gameBoard {
display: inline-block;
background: #daa520;
padding: 20px;
border-radius: 10px;
box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.2);
}

.board {
display: grid;
grid-template-columns: repeat(15, 30px);
grid-template-rows: repeat(15, 30px);
gap: 0;
background: #daa520;
}

.cell {
width: 30px;
height: 30px;
border: 1px solid #8b6914;
cursor: pointer;
position: relative;
background: #daa520;
transition: background-color 0.2s;
}

.cell:hover:not(.occupied) {
background-color: #c9a030;
}

.cell.occupied {
cursor: not-allowed;
}

.piece {
width: 24px;
height: 24px;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
animation: placepiece 0.3s ease-out;
}

@keyframes placepiece {
0% {
transform: translate(-50%, -50%) scale(0);
}
50% {
transform: translate(-50%, -50%) scale(1.2);
}
100% {
transform: translate(-50%, -50%) scale(1);
}
}

.piece.black {
background: radial-gradient(circle at 30% 30%, #4a4a4a, #000);
}

.piece.white {
background: radial-gradient(circle at 30% 30%, #fff, #ddd);
}

.controls {
margin-top: 20px;
}

button {
padding: 12px 30px;
font-size: 1.1em;
background: #667eea;
color: white;
border: none;
border-radius: 25px;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}

button:hover {
background: #764ba2;
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(118, 75, 162, 0.4);
}

button:active {
transform: translateY(0);
}

.winner-message {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 40px 60px;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
font-size: 2em;
font-weight: bold;
color: #667eea;
display: none;
z-index: 1000;
animation: popup 0.5s ease-out;
}

@keyframes popup {
0% {
transform: translate(-50%, -50%) scale(0);
}
50% {
transform: translate(-50%, -50%) scale(1.1);
}
100% {
transform: translate(-50%, -50%) scale(1);
}
}

.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: none;
z-index: 999;
}
</style>
</head>
<body>
<div class="overlay" id="overlay"></div>
<div class="winner-message" id="winnerMessage"></div>

<div class="container">
<h1>五子棋游戏</h1>
<div class="game-info">
当前玩家: <span class="current-player" id="currentPlayer">黑棋</span>
</div>
<div id="gameBoard"></div>
<div class="controls">
<button onclick="resetGame()">重新开始</button>
</div>
</div>

<script>
const BOARD_SIZE = 15;
let board = [];
let currentPlayer = 'black'; // 'black' or 'white'
let gameOver = false;

// 初始化游戏
function initGame() {
board = Array(BOARD_SIZE).fill(null).map(() => Array(BOARD_SIZE).fill(null));
currentPlayer = 'black';
gameOver = false;

const gameBoard = document.getElementById('gameBoard');
gameBoard.innerHTML = '<div class="board"></div>';
const boardElement = gameBoard.querySelector('.board');

for (let row = 0; row < BOARD_SIZE; row++) {
for (let col = 0; col < BOARD_SIZE; col++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.dataset.row = row;
cell.dataset.col = col;
cell.addEventListener('click', () => handleCellClick(row, col));
boardElement.appendChild(cell);
}
}

updatePlayerDisplay();
}

// 处理点击棋盘
function handleCellClick(row, col) {
if (gameOver || board[row][col] !== null) {
return;
}

// 放置棋子
board[row][col] = currentPlayer;

// 更新UI
const cell = document.querySelector(`[data-row="${row}"][data-col="${col}"]`);
cell.classList.add('occupied');
const piece = document.createElement('div');
piece.className = `piece ${currentPlayer}`;
cell.appendChild(piece);

// 检查是否获胜
if (checkWin(row, col)) {
gameOver = true;
showWinner(currentPlayer);
return;
}

// 切换玩家
currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
updatePlayerDisplay();
}

// 检查是否获胜
function checkWin(row, col) {
const directions = [
[[0, 1], [0, -1]], // 水平
[[1, 0], [-1, 0]], // 垂直
[[1, 1], [-1, -1]], // 对角线 \
[[1, -1], [-1, 1]] // 对角线 /
];

for (let [dir1, dir2] of directions) {
let count = 1;
count += countDirection(row, col, dir1[0], dir1[1]);
count += countDirection(row, col, dir2[0], dir2[1]);

if (count >= 5) {
return true;
}
}

return false;
}

// 计算某个方向的连续棋子数
function countDirection(row, col, rowDir, colDir) {
let count = 0;
let r = row + rowDir;
let c = col + colDir;

while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE &&
board[r][c] === currentPlayer) {
count++;
r += rowDir;
c += colDir;
}

return count;
}

// 更新当前玩家显示
function updatePlayerDisplay() {
const playerDisplay = document.getElementById('currentPlayer');
playerDisplay.textContent = currentPlayer === 'black' ? '黑棋' : '白棋';
playerDisplay.style.color = currentPlayer === 'black' ? '#333' : '#666';
}

// 显示获胜者
function showWinner(winner) {
const winnerMessage = document.getElementById('winnerMessage');
const overlay = document.getElementById('overlay');
winnerMessage.textContent = `${winner === 'black' ? '黑棋' : '白棋'}获胜!`;
winnerMessage.style.display = 'block';
overlay.style.display = 'block';

setTimeout(() => {
winnerMessage.style.display = 'none';
overlay.style.display = 'none';
}, 3000);
}

// 重置游戏
function resetGame() {
initGame();
}

// 页面加载时初始化游戏
initGame();
</script>
</body>
</html>