JS實現(xiàn)五子棋完整步驟及功能擴(kuò)展
五子棋規(guī)則詳解
1. 棋盤與棋子
- 棋盤規(guī)格:標(biāo)準(zhǔn)五子棋使用15×15的方格棋盤,共225個交叉點(日文稱"目")。棋盤通常為木質(zhì)或塑料材質(zhì),橫向標(biāo)記A-O(或1-15),縱向標(biāo)記1-15便于定位
- 棋子:雙方分別使用黑色(先手)和白色(后手)的圓形扁片棋子,直徑約1cm。日本規(guī)則中常用雙凸面的玻璃棋子,落子時會發(fā)出清脆聲響
2. 基本規(guī)則
開局:
- 黑棋先行(現(xiàn)代競技規(guī)則中通常采用"指定開局"制,即黑方必須在棋盤中心區(qū)域完成前三手)
- 傳統(tǒng)民間玩法可采用"自由開局",即黑棋第一手可下在任意位置
落子規(guī)則:
- 棋子必須放在交叉點上,不得放在方格內(nèi)
- 落子后不允許移動或取回(除非采用"禁手"規(guī)則下的提子)
- 雙方交替落子,每次只能下一顆棋子
勝負(fù)判定:
- 先形成"五連"(橫、豎、斜任意方向的連續(xù)五顆同色棋子)者勝
- 若棋盤填滿仍未分勝負(fù)(極罕見),則判為和棋
- 正式比賽通常采用計時制,超時判負(fù)
3. 競技規(guī)則變體
禁手規(guī)則(職業(yè)比賽采用):
- 三三禁手:黑棋禁止同時形成兩個活三
- 四四禁手:黑棋禁止同時形成兩個活四
- 長連禁手:黑棋禁止形成六子或以上的連線
- 出現(xiàn)禁手時白方必須立即指出,經(jīng)裁判確認(rèn)后白方獲勝
交換規(guī)則:
- 國際連珠聯(lián)盟(RIF)標(biāo)準(zhǔn)規(guī)則包含"三手交換":
- 黑方下開局前三手(必須包含對稱布局)
- 白方有權(quán)選擇交換顏色或保持原色
- 之后由白方下第四手,黑方提供第五手的多個打點供白方選擇
- 國際連珠聯(lián)盟(RIF)標(biāo)準(zhǔn)規(guī)則包含"三手交換":
五手兩打:
- 黑方第五手必須提供兩個對稱的打點
- 白方有權(quán)選擇保留其中一個,另一個由黑方收回
4. 特殊術(shù)語
- 活四:兩端無阻擋的四連子,下一步必勝
- 沖四:一端被阻擋的四連子
- 活三:能發(fā)展成活四的三連子
- 眠三:一端被阻擋的三連子
- VCF(Victory by Continuous Four):通過連續(xù)沖四取勝的戰(zhàn)術(shù)
5. 應(yīng)用場景
- 休閑玩法:公園、家庭等場合多采用簡單規(guī)則,不設(shè)禁手
- 網(wǎng)絡(luò)對戰(zhàn):騰訊、野狐等平臺通常提供多種規(guī)則選項
- 職業(yè)比賽:世界連珠錦標(biāo)賽、中國全國智力運動會等采用RIF標(biāo)準(zhǔn)規(guī)則
- AI研究:作為離散數(shù)學(xué)和人工智能的研究對象,2016年AlphaGo團(tuán)隊開發(fā)的AlphaZero已能完勝人類頂尖選手
6. 注意事項
- 正式比賽禁止使用"影子戰(zhàn)術(shù)"(模仿棋)
- 黑棋因先手優(yōu)勢,在現(xiàn)代規(guī)則中受到多重限制
- 日本"連珠"與歐美"Gomoku"規(guī)則存在細(xì)微差異,網(wǎng)絡(luò)對戰(zhàn)需提前確認(rèn)規(guī)則版本
游戲概述
五子棋是一種傳統(tǒng)的策略型棋類游戲,黑白雙方輪流在棋盤上落子,先形成五子連線的一方獲勝。下面介紹如何使用JavaScript實現(xiàn)一個簡單的五子棋游戲。
實現(xiàn)步驟
1. 創(chuàng)建HTML結(jié)構(gòu)
<!DOCTYPE html>
<html>
<head>
<title>JS五子棋</title>
<style>
#board {
display: grid;
grid-template-columns: repeat(15, 30px);
grid-template-rows: repeat(15, 30px);
gap: 1px;
background-color: #DCB35C;
padding: 10px;
}
.cell {
width: 30px;
height: 30px;
background-color: #DCB35C;
border: 1px solid #000;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.black {
background-color: black;
border-radius: 50%;
}
.white {
background-color: white;
border-radius: 50%;
}
</style>
</head>
<body>
<h1>五子棋游戲</h1>
<div id="board"></div>
<div id="status">當(dāng)前玩家: 黑棋</div>
</body>
</html>
2. JavaScript核心邏輯
document.addEventListener('DOMContentLoaded', function() {
const boardSize = 15;
const board = document.getElementById('board');
const statusDiv = document.getElementById('status');
let currentPlayer = 'black';
let gameBoard = Array(boardSize).fill().map(() => Array(boardSize).fill(null));
// 初始化棋盤
function initializeBoard() {
for (let i = 0; i < boardSize; i++) {
for (let j = 0; j < boardSize; j++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.dataset.row = i;
cell.dataset.col = j;
cell.addEventListener('click', handleCellClick);
board.appendChild(cell);
}
}
}
// 處理點擊事件
function handleCellClick(event) {
const row = parseInt(event.target.dataset.row);
const col = parseInt(event.target.dataset.col);
// 如果該位置已有棋子,則返回
if (gameBoard[row][col]) return;
// 更新游戲狀態(tài)
gameBoard[row][col] = currentPlayer;
event.target.classList.add(currentPlayer);
// 檢查是否獲勝
if (checkWin(row, col)) {
setTimeout(() => {
alert(`${currentPlayer === 'black' ? '黑棋' : '白棋'}獲勝!`);
resetGame();
}, 100);
return;
}
// 切換玩家
currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
statusDiv.textContent = `當(dāng)前玩家: ${currentPlayer === 'black' ? '黑棋' : '白棋'}`;
}
// 檢查勝利條件
function checkWin(row, col) {
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 newRow = row + i * dx;
const newCol = col + i * dy;
if (
newRow >= 0 && newRow < boardSize &&
newCol >= 0 && newCol < boardSize &&
gameBoard[newRow][newCol] === currentPlayer
) {
count++;
} else {
break;
}
}
// 反向檢查
for (let i = 1; i < 5; i++) {
const newRow = row - i * dx;
const newCol = col - i * dy;
if (
newRow >= 0 && newRow < boardSize &&
newCol >= 0 && newCol < boardSize &&
gameBoard[newRow][newCol] === currentPlayer
) {
count++;
} else {
break;
}
}
if (count >= 5) return true;
}
return false;
}
// 重置游戲
function resetGame() {
gameBoard = Array(boardSize).fill().map(() => Array(boardSize).fill(null));
currentPlayer = 'black';
statusDiv.textContent = '當(dāng)前玩家: 黑棋';
const cells = document.querySelectorAll('.cell');
cells.forEach(cell => {
cell.classList.remove('black', 'white');
});
}
initializeBoard();
});
功能擴(kuò)展與實現(xiàn)原理詳解
功能擴(kuò)展
悔棋功能
- 實現(xiàn)一個"悔棋"按鈕,點擊后可以撤銷上一步的落子操作
- 需要維護(hù)一個落子歷史棧,存儲每一步的落子位置和玩家信息
- 撤銷時從棧中彈出最近一步,恢復(fù)棋盤對應(yīng)位置為空
- 示例代碼邏輯:
function undoMove() { if (moveHistory.length > 0) { const lastMove = moveHistory.pop(); board[lastMove.row][lastMove.col] = EMPTY; currentPlayer = lastMove.player; updateBoardUI(); } }
游戲計時
- 為黑白雙方分別添加倒計時計時器(如每人15分鐘)
- 使用
setInterval每秒更新計時器顯示 - 當(dāng)某方時間耗盡時自動判負(fù)
- 計時器暫停/恢復(fù)邏輯:
- 開始對方回合時暫停本方計時器
- 對方落子后啟動本方計時器
AI對戰(zhàn)
- 實現(xiàn)簡單AI算法:
- 優(yōu)先在己方四連兩端落子形成五連
- 其次阻擋對方四連
- 然后尋找己方可形成活三的位置
- 隨機(jī)選擇空位作為最后策略
- 使用評估函數(shù)給每個空位打分,選擇最高分位置落子
保存游戲
- 使用
localStorage保存游戲狀態(tài):function saveGame() { const gameState = { board: board, currentPlayer: currentPlayer, moveHistory: moveHistory }; localStorage.setItem('gomokuGame', JSON.stringify(gameState)); } - 加載時解析存儲的JSON數(shù)據(jù)恢復(fù)游戲
音效增強(qiáng)
- 預(yù)加載落子音效和勝利音效文件
- 落子時播放"click"音效
- 勝利時播放"victory"音效
- 示例:
function playSound(type) { const audio = new Audio(`sounds/${type}.mp3`); audio.play(); }
實現(xiàn)原理說明
棋盤表示
- 使用15×15二維數(shù)組表示棋盤:
const board = Array(15).fill().map(() => Array(15).fill(0)); // 0表示空位,1表示黑子,2表示白子
- 每個數(shù)組元素對應(yīng)棋盤交叉點狀態(tài)
勝利檢測
- 從當(dāng)前落子點向四個方向檢查:
- 水平方向(左右)
- 垂直方向(上下)
- 主對角線(左上到右下)
- 副對角線(右上到左下)
- 檢查算法示例:
function checkWin(row, col) { 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 newRow = row + dx * i; const newCol = col + dy * i; if (!isValidPosition(newRow, newCol) || board[newRow][newCol] !== board[row][col]) { break; } count++; } // 反向檢查 for (let i = 1; i < 5; i++) { const newRow = row - dx * i; const newCol = col - dy * i; if (!isValidPosition(newRow, newCol) || board[newRow][newCol] !== board[row][col]) { break; } count++; } if (count >= 5) return true; } return false; }
玩家切換
- 使用變量記錄當(dāng)前玩家:
let currentPlayer = BLACK; // 1表示黑方,2表示白方
- 每次落子后切換玩家:
function switchPlayer() { currentPlayer = currentPlayer === BLACK ? WHITE : BLACK; updatePlayerIndicator(); }
UI更新
- 通過CSS類顯示棋子:
.cell.black { background: black; } .cell.white { background: white; border: 1px solid #333; } - JavaScript動態(tài)添加類:
function updateBoardUI() { for (let row = 0; row < 15; row++) { for (let col = 0; col < 15; col++) { const cell = document.getElementById(`cell-${row}-${col}`); cell.className = 'cell'; if (board[row][col] === BLACK) { cell.classList.add('black'); } else if (board[row][col] === WHITE) { cell.classList.add('white'); } } } }

總結(jié)
到此這篇關(guān)于JS實現(xiàn)五子棋完整步驟及功能擴(kuò)展的文章就介紹到這了,更多相關(guān)JS實現(xiàn)五子棋內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
微信小程序開發(fā)中Promise的使用(aysnc,await)及場景分析
在微信小程序開發(fā)中,錯誤使用Promise可能導(dǎo)致無法正確獲取數(shù)據(jù),本文分析了一個常見錯誤場景,即在異步函數(shù)中未使用await或.then()處理Promise,導(dǎo)致無法獲取異步操作的返回結(jié)果,文章提供了使用await和鏈?zhǔn)秸{(diào)用.then()的解決方法,幫助開發(fā)者避免類似錯誤,確保數(shù)據(jù)正確返回2024-10-10
ts依賴引入報錯:無法找到模塊“xxxxxx”的聲明文件問題解決
這篇文章主要給大家介紹了關(guān)于ts依賴引入報錯:無法找到模塊“xxxxxx”的聲明文件問題的解決辦法,文中通過示例帶將解決辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07
用js查找法實現(xiàn)當(dāng)前欄目的高亮顯示的代碼
本文給大家介紹了使用js查找法實現(xiàn)當(dāng)前欄目的高亮顯示的代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧2007-11-11
JS中call(),apply(),bind()函數(shù)的區(qū)別與用法詳解
這篇文章主要介紹了JS中call(),apply(),bind()函數(shù)的高級用法詳解,需要的朋友可以參考下2022-12-12

