@@ -10,9 +10,10 @@ type Cell struct {
1010
1111// Board - 棋盤
1212type Board struct {
13- rows int // 總共格數
14- cols int // 總共列數
15- cells [][]* Cell // 整格棋盤狀態
13+ rows int // 總共格數
14+ cols int // 總共列數
15+ cells [][]* Cell // 整格棋盤狀態
16+ minePositionShuffler positionShuffler // 亂序器用來安排地雷格子
1617}
1718
1819// Game - 遊戲物件
@@ -23,20 +24,35 @@ type Game struct {
2324 remaining int // 剩餘需要翻開的格子數
2425}
2526
26- func NewGame (rows , cols , mineNumbers int ) * Game {
27- board := createBoard (rows , cols )
27+ // coord - 紀錄該格字座標
28+ type coord struct {
29+ Row int
30+ Col int
31+ }
32+
33+ // positionShuffler - 亂序器用來安排地雷格子
34+ type positionShuffler func (coords []coord )
35+
36+ func NewGame (rows , cols , mineCount int ) * Game {
37+ board := NewBoard (rows , cols )
38+ // 設定地雷
39+ board .PlaceMines (mineCount )
40+ // 計算結果
41+ board .CalculateAdjacentMines ()
2842 return & Game {
2943 board : board ,
30- remaining : rows * cols - mineNumbers ,
44+ remaining : rows * cols - mineCount ,
3145 isGameOver : false ,
3246 isPlayerWin : false ,
3347 }
3448}
3549
36- func createBoard (rows , cols int ) * Board {
50+ // NewBoard - 初始化盤面
51+ func NewBoard (rows , cols int ) * Board {
3752 board := & Board {
38- rows : rows ,
39- cols : cols ,
53+ rows : rows ,
54+ cols : cols ,
55+ minePositionShuffler : defaultPositionShuffler ,
4056 }
4157 board .cells = make ([][]* Cell , rows )
4258 for row := range board .cells {
@@ -47,7 +63,11 @@ func createBoard(rows, cols int) *Board {
4763 }
4864 return board
4965}
50- func (g * Game ) Init (board * Board ) {
66+
67+ func (g * Game ) Init (board * Board , minePositionShuffler positionShuffler ) {
68+ if minePositionShuffler != nil {
69+ g .board .minePositionShuffler = minePositionShuffler
70+ }
5171 // 無效的設定
5272 if board == nil || len (board .cells ) != board .rows || len (board .cells [0 ]) != board .cols {
5373 return
@@ -63,3 +83,54 @@ func (g *Game) Init(board *Board) {
6383 }
6484 }
6585}
86+
87+ // PlaceMines - 使用 minePositionShuffler 選出 mineCount 個地雷
88+ func (b * Board ) PlaceMines (mineCount int ) {
89+ // 蒐集所有 coord
90+ coords := make ([]coord , 0 , b .cols * b .rows )
91+ for row := range b .cells {
92+ for col := range b .cells [row ] {
93+ coords = append (coords , coord {Row : row , Col : col })
94+ }
95+ }
96+ // 使用 minePositionShuffler 作洗牌
97+ b .minePositionShuffler (coords )
98+ coordLen := len (coords )
99+ // 避免 mineCount 超過 coords 個數
100+ if mineCount > coordLen {
101+ mineCount = coordLen
102+ }
103+ // 設定前 mineCount 為地雷
104+ for i := 0 ; i < mineCount ; i ++ {
105+ b .cells [coords [i ].Row ][coords [i ].Col ].IsMine = true
106+ }
107+ }
108+
109+ // CalculateAdjacentMines - 計算鄰近地雷個數
110+ func (b * Board ) CalculateAdjacentMines () {
111+ // 鄰近所有方向
112+ neighborDirections := [8 ]coord {
113+ {Row : - 1 , Col : - 1 }, {Row : - 1 , Col : 0 }, {Row : - 1 , Col : 1 },
114+ {Row : 0 , Col : - 1 }, {Row : 0 , Col : 1 },
115+ {Row : 1 , Col : - 1 }, {Row : 1 , Col : 0 }, {Row : 1 , Col : 1 },
116+ }
117+ for row := range b .cells {
118+ for col := range b .cells [row ] {
119+ // 當遇到地雷格時 跳過
120+ if b.cells [row ][col ].IsMine {
121+ continue
122+ }
123+ // 開始累計鄰近的地雷數
124+ accumCount := 0
125+ for _ , direction := range neighborDirections {
126+ neighborRow , neighborCol := row + direction .Row , col + direction .Col
127+ if neighborRow >= 0 && neighborRow < b .rows &&
128+ neighborCol >= 0 && neighborCol < b .cols &&
129+ b.cells [neighborRow ][neighborCol ].IsMine {
130+ accumCount ++
131+ }
132+ }
133+ b.cells [row ][col ].AdjacenetMines = accumCount
134+ }
135+ }
136+ }
0 commit comments