iT邦幫忙

2025 iThome 鐵人賽

DAY 14
2

🎯 主題

  • 隨機布雷與周圍雷數計算

目標

  • 實作在 Board 上隨機放置 mineCount 顆地雷。
  • 完成每格 AdjacentMines 的計算。
  • 產出可重複呼叫的初始化流程(NewGame)。

前置:資料結構(延用 Day 2)

// 單一格子 (Cell)
type Cell struct {
	IsMine        bool
	Revealed      bool
	Flagged       bool
	AdjacentMines int
}

// 棋盤 (Board)
type Board struct {
	rows  int
	cols  int
	cells [][]Cell
}

// 遊戲狀態 (Game)
type Game struct {
	board     *Board
	isGameOver  bool
	isPlayerWin   bool
	remaining int // 剩餘需要翻開的安全格子數
}

一、隨機布雷(PlaceMines)

設計重點

  • 將所有座標展平成 slice,洗牌後取前 mineCount 個 → 放雷。
  • 好處:避免 while 隨機碰撞、確保不重複。
// PlaceMines - 使用 minePositionShuffler 選出 mineCount 個地雷
func (b *Board) PlaceMines(mineCount int) {
	// 蒐集所有 coord
	coords := make([]coord, 0, b.cols*b.rows)
	for row := range b.cells {
		for col := range b.cells[row] {
			coords = append(coords, coord{Row: row, Col: col})
		}
	}
	// 使用 minePositionShuffler 作洗牌
	b.minePositionShuffler(coords)
	coordLen := len(coords)
	// 避免 mineCount 超過 coords 個數
	if mineCount > coordLen {
		mineCount = coordLen
	}
	// 設定前 mineCount 為地雷
	for i := 0; i < mineCount; i++ {
		b.cells[coords[i].Row][coords[i].Col].IsMine = true
	}
}

二、周圍雷數計算(CalculateAdjacentMines)

定義

  • 對於每一格 (r, c)(非地雷),計算其 8 方向內的地雷數,寫入 AdjacentMines。
// CalculateAdjacentMines - 計算鄰近地雷個數
func (b *Board) CalculateAdjacentMines() {
	// 鄰近所有方向
	neighborDirections := [8]coord{
		{Row: -1, Col: -1}, {Row: -1, Col: 0}, {Row: -1, Col: 1},
		{Row: 0, Col: -1}, {Row: 0, Col: 1},
		{Row: 1, Col: -1}, {Row: 1, Col: 0}, {Row: 1, Col: 1},
	}
	for row := range b.cells {
		for col := range b.cells[row] {
			// 當遇到地雷格時 跳過
			if b.cells[row][col].IsMine {
				continue
			}
			// 開始累計鄰近的地雷數
			accumCount := 0
			for _, direction := range neighborDirections {
				neighborRow, neighborCol := row+direction.Row, col+direction.Col
				if neighborRow >= 0 && neighborRow < b.rows &&
					neighborCol >= 0 && neighborCol < b.cols &&
					b.cells[neighborRow][neighborCol].IsMine {
					accumCount++
				}
			}
			b.cells[row][col].AdjacenetMines = accumCount
		}
	}
}

三、初始化整合(NewGame)

func NewGame(rows, cols, mineCount int) *Game {
	board := NewBoard(rows, cols)
	// 設定地雷
	board.PlaceMines(mineCount)
	// 計算結果
	board.CalculateAdjacentMines()
	return &Game{
		board:       board,
		remaining:   rows*cols - mineCount,
		isGameOver:  false,
		isPlayerWin: false,
	}
}

// NewBoard - 初始化盤面
func NewBoard(rows, cols int) *Board {
	board := &Board{
		rows:                 rows,
		cols:                 cols,
		minePositionShuffler: defaultPositionShuffler,
	}
	board.cells = make([][]*Cell, rows)
	for row := range board.cells {
		board.cells[row] = make([]*Cell, cols)
		for col := range board.cells[row] {
			board.cells[row][col] = &Cell{}
		}
	}
	return board
}

四、具體範例(5×5、4 顆地雷)

  • 以下是一組可能的隨機結果(* 為地雷);實際執行會隨機變化。

布雷結果(示意)

[ ][*][ ][ ][ ]
[ ][ ][ ][*][ ]
[ ][ ][*][ ][ ]
[ ][ ][ ][ ][ ]
[*][ ][ ][ ][ ]

計算後(* 保留地雷,其他為 AdjacentMines)

[1][*][2][1][1]
[1][2][3][*][1]
[0][1][*][2][1]
[1][2][1][1][0]
[*][1][0][0][0]

驗證點

  • 地雷格:IsMine=true;數字不顯示(UI 層不畫)。
  • 非雷格:AdjacentMines 等於周圍 8 格內地雷數。
  • Remaining = 25 - 4 = 21。

驗收清單

  • PlaceMines:隨機、無重複、數量正確
  • CalculateAdjacentMines:所有非雷格數字正確
  • NewGame:能一次建立好可用的遊戲狀態

Gemini CLI 測試案例 Prompt

gemnini -p "你是一位 Go 程式碼與資料驗證顧問。請根據以下規格驗證使用者的踩地雷初始化結果是否正確。

### 規格
- 棋盤:Rows×Cols
- 地雷數量:mineCount
- 結構:
  - Cell{ IsMine bool, Revealed bool, Flagged bool, AdjacentMines int }
  - Board{ rows int, cols int, cells [][]*Cell }
  - Game{ board *Board, isGameOver bool, isPlayerWin bool, remaining int }

### 驗證任務
1) 確認「地雷數量 == mineCount」
2) 對每個非雷格 `(r,c)` 驗證 Adjacents:
   Adj(r,c) = 周圍 8 方向中的地雷數量
3) 驗證 `Remaining == Rows*Cols - mineCount`

### 輸出格式(務必遵守)
- 驗證總結表(Markdown):項目 | 期望 | 實際 | 結果(PASS/FAIL) | 備註
- 失敗明細:逐格列出錯誤原因(若有)
- 修正建議:給出可能的程式碼方向

### 使用者輸入(以下貼 CLI 或 JSON)"

github action 測試結果

https://github.com/leetcode-golang-classroom/mine-sweeper-game/actions/runs/17276363400

本日收穫

  • 完成「隨機布雷」與「周圍雷數計算」兩大核心邏輯。
  • 建立 NewGame 讓初始化一行到位。

明日預告

  • 確保邊界條件:四角與邊緣格的鄰居計數。
  • 為 Ebiten 作準備:繪圖前的資料/狀態切片整理。

上一篇
踩地雷遊戲: 遊戲資料結構設計
下一篇
踩地雷遊戲: 使用 Ebiten 繪製踩地雷的基本格子
系列文
在 ai 時代 gopher 遊戲開發者的 30 天自我養成20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言