Skip to content

Commit a1f6b5d

Browse files
committed
♻️ (mine-sweepr): refactor with logic
1 parent 71a10f3 commit a1f6b5d

File tree

3 files changed

+99
-12
lines changed

3 files changed

+99
-12
lines changed

internal/game/game.go

Lines changed: 81 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ type Cell struct {
1010

1111
// Board - 棋盤
1212
type 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+
}

internal/game/game_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,8 @@ func TestGameInit(t *testing.T) {
362362
for _, tt := range tests {
363363
t.Run(tt.name, func(t *testing.T) {
364364
game := NewGame(tt.input.rows, tt.input.cols, tt.input.minesNumber)
365-
game.Init(tt.input.board)
366-
assert.Equal(t, tt.want, game.board)
365+
game.Init(tt.input.board, func(coords []coord) {})
366+
assert.Equal(t, tt.want.cells, game.board.cells)
367367
})
368368
}
369369
}

internal/game/random.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package game
2+
3+
import (
4+
"math/rand"
5+
"time"
6+
)
7+
8+
var defaultPositionShuffler positionShuffler = func(coords []coord) {
9+
if len(coords) <= 1 {
10+
return
11+
}
12+
rand.New(rand.NewSource(time.Now().UnixNano()))
13+
rand.Shuffle(len(coords), func(i, j int) {
14+
coords[i], coords[j] = coords[j], coords[i]
15+
})
16+
}

0 commit comments

Comments
 (0)