for 遍歷 3×3 區域,配合 if (ni>=0 ...) 邊界檢查。原始碼片段:
char round_num_mines(int i, int j) {
if (map[i][j] == '*') return '*';
int k = 0;
if (map[i+1][j] == '*') k++;
if (map[i+1][j-1] == '*') k++;
if (map[i+1][j+1] == '*') k++;
if (map[i][j+1] == '*') k++;
if (map[i-1][j] == '*') k++;
if (map[i-1][j+1] == '*') k++;
if (map[i][j-1] == '*') k++;
if (map[i-1][j-1] == '*') k++;
return k;
}
答案:此段代碼**假設**調用者傳入的 i,j 已經是**物理陣列下標**(即已含哨兵偏移),且物理陣列大小為 [MAX_X+2][MAX_Y+2]。
若邏輯棋盤為 m×n,物理索引範圍為 1..m, 1..n,哨兵佔據 0 與 m+1/n+1。
核心迴圈最大訪問 i±1, j±1 ∈ [0..m+1],**嚴格在分配範圍內**。
// 1. 定義方向向量
static const int dx[8] = {-1,-1,-1, 0,0, 1,1,1};
static const int dy[8] = {-1, 0, 1,-1,1,-1,0,1};
char round_num_mines(int x, int y) { // x,y 為邏輯座標 0-based
if (map[x+1][y+1] == '*') return '*';
int cnt = 0;
for (int d = 0; d < 8; ++d)
if (map[x+1+dx[d]][y+1+dy[d]] == '*') cnt++;
return (char)('0' + cnt);
}
if,便於維護與擴展(如六角棋盤只需改向量表)。| 錯誤現象 | 原因 | 修正 |
|---|---|---|
| 運行時崩潰/異常數值 | 未分配哨兵圈,或邏輯座標未 +1 直接用於物理陣列 | 陣列定義 [MAX+2][MAX+2],初始化哨兵,調用時 +1 |
| 邊緣格子計數錯誤 | 忘記跳過自身 (dx,dy)==(0,0) | 方向向量表只含 8 個鄰居,或迴圈內 continue |
| 地雷顯示為數字 | 未優先判斷 map[x+1][y+1]=='*' | 函式開頭立即返回 '*' |
-O2 下編譯出的機器碼**幾乎相同**(循環展開、邊界檢查消除)。第三篇將進入 **Win32 API 視窗建立、GDI 繪圖、訊息迴圈**,把邏輯層接上圖形介面。