Skip to content

Commit 71a10f3

Browse files
committed
✨ (mine-sweeper): add data structure for mine-sweeper
0 parents  commit 71a10f3

File tree

9 files changed

+581
-0
lines changed

9 files changed

+581
-0
lines changed

.github/workflows/go.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Go
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
10+
jobs:
11+
build_and_test:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
- name: Setup Go
17+
uses: actions/setup-go@v5
18+
with:
19+
go-version: 'stable'
20+
check-latest: true
21+
- name: Setup dependency
22+
run: go mod tidy
23+
# - name: Install Ebitengine dependencies (optional, depending on your project)
24+
# run: |
25+
# sudo apt-get update
26+
# sudo apt-get install -y libgl1-mesa-dev xorg-dev # For Linux builds
27+
# - name: Test Build
28+
# run: make build-game
29+
- name: Test
30+
run: go test -v ./internal/game/...

.gitignore

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Code coverage profiles and other test artifacts
15+
*.out
16+
coverage.*
17+
*.coverprofile
18+
profile.cov
19+
20+
# Dependency directories (remove the comment below to include it)
21+
# vendor/
22+
23+
# Go workspace file
24+
go.work
25+
go.work.sum
26+
27+
# env file
28+
.env
29+
30+
# Editor/IDE
31+
# .idea/
32+
# .vscode/
33+
bin

Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.PHONY=build
2+
3+
build-game:
4+
@CGO_ENABLED=1 GOOS=linux go build -o bin/mine-sweeper-game cmd/main.go
5+
6+
run-game: build-game
7+
@./bin/mine-sweeper-game
8+
9+
10+
coverage:
11+
@go test -v -cover ./internal/game/...
12+
13+
test:
14+
@go test -v ./internal/game/...

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# mine-sweeper
2+
3+
這個 repository 主要用來 demo 使用 golang 來實做踩地雷遊戲的功能
4+
5+
目標會採用 ebiten 來作畫面展現的遊戲引擎
6+
7+
預期會先從核心功能開始寫,最後再加上 ebiten 來作畫面渲染
8+
9+
## 踩地雷遊戲介紹
10+
11+
踩地雷是一款經典益智遊戲,玩家在方格棋盤上翻開格子。部分格子下隱藏著地雷,若踩到地雷則遊戲失敗。安全格子會顯示一個數字,代表「周圍八個格子中有幾顆雷」。玩家需要根據數字推理出地雷位置,並標記旗子避免誤踩。遊戲目標是「找出所有安全格子,並正確標記所有地雷」。
12+
13+
## 🕹️ 遊戲規則(數值化說明)
14+
15+
### 1.盤面大小
16+
17+
* 常見為 9x9、16x16、30x16 三種經典尺寸。
18+
* 每個格子可以是 地雷 或 安全格。
19+
* 📊 例:
20+
* 初級:9x9 = 81 格,含 10 顆雷
21+
* 中級:16x16 = 256 格,含 40 顆雷
22+
* 高級:30x16 = 480 格,含 99 顆雷
23+
24+
### 2. 格子狀態
25+
26+
* 每個格子有三種基本狀態:
27+
* 未揭開:起始狀態,玩家看不到內部內容。
28+
* 已揭開:顯示數字(0~8)或地雷(爆炸)。
29+
* 已標記:玩家插旗,代表懷疑此格有地雷。
30+
31+
### 3. 數字提示
32+
33+
* 當一格被揭開且不是地雷時,會顯示一個數字 N,代表 該格子周圍 8 個格子中有 N 顆地雷。
34+
* N 的範圍是 0 ~ 8。
35+
* 如果 N=0,則會觸發 自動展開,將周圍連鎖的安全格子一起揭開。
36+
* 📊 例:
37+
* 揭開某格顯示 3 → 表示這格的上下左右斜對角八格中總共有 3 顆雷。
38+
39+
### 4. 遊戲勝負條件
40+
41+
* 失敗條件:揭開的格子是地雷。
42+
* 勝利條件:所有 非地雷的格子 都被揭開。
43+
* 判斷方式:
44+
* 假設總格子數為 T,地雷數為 M,安全格數為 S = T - M。
45+
* 當玩家揭開的安全格數量 = S,即可勝利。
46+
47+
48+
## 示意圖
49+
![mine-sweeper display](mine-sweeper.png)

go.mod

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module github.com/leetcode-golang-classroom/mine-sweeper
2+
3+
go 1.24.0
4+
5+
require github.com/stretchr/testify v1.11.1
6+
7+
require (
8+
github.com/davecgh/go-spew v1.1.1 // indirect
9+
github.com/pmezard/go-difflib v1.0.0 // indirect
10+
gopkg.in/yaml.v3 v3.0.1 // indirect
11+
)

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
6+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
7+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
8+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
9+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
10+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/game/game.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package game
2+
3+
// Cell - 單一格子
4+
type Cell struct {
5+
IsMine bool // 是否為地雷
6+
Revealed bool // 是否被翻開
7+
Flagged bool // 是否被插旗
8+
AdjacenetMines int // 周圍地雷數
9+
}
10+
11+
// Board - 棋盤
12+
type Board struct {
13+
rows int // 總共格數
14+
cols int // 總共列數
15+
cells [][]*Cell // 整格棋盤狀態
16+
}
17+
18+
// Game - 遊戲物件
19+
type Game struct {
20+
board *Board // 棋盤物件
21+
isGameOver bool // 是否遊戲結束
22+
isPlayerWin bool // 玩家是否獲勝
23+
remaining int // 剩餘需要翻開的格子數
24+
}
25+
26+
func NewGame(rows, cols, mineNumbers int) *Game {
27+
board := createBoard(rows, cols)
28+
return &Game{
29+
board: board,
30+
remaining: rows*cols - mineNumbers,
31+
isGameOver: false,
32+
isPlayerWin: false,
33+
}
34+
}
35+
36+
func createBoard(rows, cols int) *Board {
37+
board := &Board{
38+
rows: rows,
39+
cols: cols,
40+
}
41+
board.cells = make([][]*Cell, rows)
42+
for row := range board.cells {
43+
board.cells[row] = make([]*Cell, cols)
44+
for col := range board.cells[row] {
45+
board.cells[row][col] = &Cell{}
46+
}
47+
}
48+
return board
49+
}
50+
func (g *Game) Init(board *Board) {
51+
// 無效的設定
52+
if board == nil || len(board.cells) != board.rows || len(board.cells[0]) != board.cols {
53+
return
54+
}
55+
// 設定資料
56+
for row := range board.cells {
57+
for col := range board.cells[row] {
58+
sourceCell := board.cells[row][col]
59+
g.board.cells[row][col].AdjacenetMines = sourceCell.AdjacenetMines
60+
g.board.cells[row][col].IsMine = sourceCell.IsMine
61+
g.board.cells[row][col].Revealed = sourceCell.Revealed
62+
g.board.cells[row][col].Flagged = sourceCell.Flagged
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)