五子棋盤面 15×15 或 19×19,每落一子需即時判斷是否形成五連珠。暴力掃描全盤 O(N²) 過慢,**僅掃描最新落子周圍四方向** 可達 O(1) (常數時間,與盤面大小無關)。
(x, y),顏色 color (1=黑, 2=白)。(1,0) 橫、(0,1) 直、(1,1) 右斜、(1,-1) 左斜。宣告 BOARD_SIZE + 8 陣列 (四周各擴 4 格),落子座標偏移 (4,4),掃描時**無需邊界判斷**,超出實際盤面區域預設為 0 (無子),自然終止計數。
#include
#include
#define N 15
#define EXT 4
#define SZ (N + 2*EXT) // 15+8=23
#define EMPTY 0
#define BLACK 1
#define WHITE 2
int board[SZ][SZ] = {0}; // 全域零初始化,擴展區自動為 0
/* 方向向量:右、下、右下、右上 */
const int dx[4] = {1, 0, 1, 1};
const int dy[4] = {0, 1, 1, -1};
bool check_win(int x, int y, int color) {
for (int dir = 0; dir < 4; ++dir) {
int count = 1; // 含新落子自己
/* 正向延伸 */
for (int step = 1; step < 5; ++step) {
int nx = x + dx[dir] * step;
int ny = y + dy[dir] * step;
if (board[nx][ny] == color) ++count;
else break;
}
/* 反向延伸 */
for (int step = 1; step < 5; ++step) {
int nx = x - dx[dir] * step;
int ny = y - dy[dir] * step;
if (board[nx][ny] == color) ++count;
else break;
}
if (count >= 5) return true;
}
return false;
}
int main(void) {
/* 簡易測試:黑棋在 (7,7) 形成橫向五連 */
int moves[][2] = {{7,7},{7,8},{7,9},{7,10},{7,11}};
for (int i = 0; i < 5; ++i) {
int x = moves[i][0] + EXT, y = moves[i][1] + EXT;
board[x][y] = BLACK;
if (check_win(x, y, BLACK)) {
printf("第 %d 手獲勝!\n", i+1);
break;
}
}
return 0;
}
| 技巧 | 作用 |
|---|---|
| 擴展棋盤 + 偏移 | 消除邊界 `if`,簡化邏輯、提升分支預測率 |
| 方向向量表驅動 | 四方向統一迴圈,無重複代碼,易維護 |
| 雙向延伸計數 | 以新子為中心,正負各延伸 4 格,覆蓋所有含新子的五連組合 |
| 提早結束 | 任一方向達 5 即返回,避免多餘計算 |
將每列/行/對角線編碼為 64-bit 整數,落子相當於 `board |= (1ULL << pos)`,判斷五連珠轉為位運算 (board & (board >> 1) & (board >> 2) & (board >> 3) & (board >> 4)) != 0,極致高效,適合 AI 引擎。
| 錯誤 | 修正 |
|---|---|
| 只掃描正向 | 需雙向延伸,否則漏判新子在五連中間的情況 |
| 未處理邊界導致越界 | 用擴展棋盤或加 `if (nx<0||nx>=N||ny<0||ny>=N) break;` |
| 重複掃描已檢查方向 | 四方向向量正交,無重複 |
| 長連珠 (六連、七連) 判定邏輯錯誤 | 規則通常「五子以上即勝」,`count >= 5` 正確涵蓋 |
五子棋勝負判定的核心是**局部增量檢查**。善用擴展棋盤消除邊界、方向向量表驅動、雙向延伸計數,可寫出簡潔、高效、無 Bug 的判定邏輯。此模式廣泛適用於連連看、圍棋氣計算、消消樂匹配等格盤遊戲。