Skip to content

Commit 94c2217

Browse files
committed
✨ (mine-sweeper): add draw basic layout with state un reveal
1 parent 09eb51b commit 94c2217

File tree

6 files changed

+126
-11
lines changed

6 files changed

+126
-11
lines changed

cmd/main.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
import (
4+
"log"
5+
6+
"github.com/hajimehoshi/ebiten/v2"
7+
"github.com/leetcode-golang-classroom/mine-sweeper/internal/game"
8+
"github.com/leetcode-golang-classroom/mine-sweeper/internal/layout"
9+
)
10+
11+
func main() {
12+
ebiten.SetWindowSize(layout.ScreenWidth, layout.ScreenHeight)
13+
ebiten.SetWindowTitle("Mine Sweeper Grid")
14+
gameInstance := game.NewGame(layout.Rows, layout.Cols, layout.MineCounts)
15+
gameLayout := layout.NewGameLayout(gameInstance)
16+
if err := ebiten.RunGame(gameLayout); err != nil {
17+
log.Fatal(err)
18+
}
19+
}

go.mod

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,20 @@ go 1.24.0
44

55
require github.com/stretchr/testify v1.11.1
66

7+
require (
8+
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 // indirect
9+
github.com/ebitengine/hideconsole v1.0.0 // indirect
10+
github.com/ebitengine/purego v0.8.0 // indirect
11+
github.com/jezek/xgb v1.1.1 // indirect
12+
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
13+
golang.org/x/sync v0.8.0 // indirect
14+
golang.org/x/sys v0.25.0 // indirect
15+
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
16+
)
17+
718
require (
819
github.com/davecgh/go-spew v1.1.1 // indirect
20+
github.com/hajimehoshi/ebiten/v2 v2.8.8
921
github.com/pmezard/go-difflib v1.0.0 // indirect
1022
gopkg.in/yaml.v3 v3.0.1 // indirect
1123
)

go.sum

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,32 @@
11
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
22
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 h1:Gk1XUEttOk0/hb6Tq3WkmutWa0ZLhNn/6fc6XZpM7tM=
4+
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325/go.mod h1:ulhSQcbPioQrallSuIzF8l1NKQoD7xmMZc5NxzibUMY=
5+
github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE=
6+
github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A=
7+
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
8+
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
9+
github.com/hajimehoshi/ebiten/v2 v2.8.8 h1:xyMxOAn52T1tQ+j3vdieZ7auDBOXmvjUprSrxaIbsi8=
10+
github.com/hajimehoshi/ebiten/v2 v2.8.8/go.mod h1:durJ05+OYnio9b8q0sEtOgaNeBEQG7Yr7lRviAciYbs=
11+
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
12+
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
13+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
14+
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
15+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
16+
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
17+
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
318
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
419
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
520
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
621
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=
22+
golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
23+
golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
24+
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
25+
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
26+
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
27+
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
828
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
29+
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
30+
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
931
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
1032
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/game/game.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type Board struct {
1818

1919
// Game - 遊戲物件
2020
type Game struct {
21-
board *Board // 棋盤物件
21+
Board *Board // 棋盤物件
2222
isGameOver bool // 是否遊戲結束
2323
isPlayerWin bool // 玩家是否獲勝
2424
remaining int // 剩餘需要翻開的格子數
@@ -40,7 +40,7 @@ func NewGame(rows, cols, mineCount int) *Game {
4040
// 計算結果
4141
board.CalculateAdjacentMines()
4242
return &Game{
43-
board: board,
43+
Board: board,
4444
remaining: rows*cols - mineCount,
4545
isGameOver: false,
4646
isPlayerWin: false,
@@ -66,7 +66,7 @@ func NewBoard(rows, cols int) *Board {
6666

6767
func (g *Game) Init(board *Board, minePositionShuffler positionShuffler) {
6868
if minePositionShuffler != nil {
69-
g.board.minePositionShuffler = minePositionShuffler
69+
g.Board.minePositionShuffler = minePositionShuffler
7070
}
7171
// 無效的設定
7272
if board == nil || len(board.cells) != board.rows || len(board.cells[0]) != board.cols {
@@ -76,16 +76,19 @@ func (g *Game) Init(board *Board, minePositionShuffler positionShuffler) {
7676
for row := range board.cells {
7777
for col := range board.cells[row] {
7878
sourceCell := board.cells[row][col]
79-
g.board.cells[row][col].AdjacenetMines = sourceCell.AdjacenetMines
80-
g.board.cells[row][col].IsMine = sourceCell.IsMine
81-
g.board.cells[row][col].Revealed = sourceCell.Revealed
82-
g.board.cells[row][col].Flagged = sourceCell.Flagged
79+
g.Board.cells[row][col].AdjacenetMines = sourceCell.AdjacenetMines
80+
g.Board.cells[row][col].IsMine = sourceCell.IsMine
81+
g.Board.cells[row][col].Revealed = sourceCell.Revealed
82+
g.Board.cells[row][col].Flagged = sourceCell.Flagged
8383
}
8484
}
8585
}
8686

8787
// PlaceMines - 使用 minePositionShuffler 選出 mineCount 個地雷
8888
func (b *Board) PlaceMines(mineCount int) {
89+
if mineCount < 0 {
90+
return
91+
}
8992
// 蒐集所有 coord
9093
coords := make([]coord, 0, b.cols*b.rows)
9194
for row := range b.cells {
@@ -134,3 +137,7 @@ func (b *Board) CalculateAdjacentMines() {
134137
}
135138
}
136139
}
140+
141+
func (board *Board) GetCell(row, col int) *Cell {
142+
return board.cells[row][col]
143+
}

internal/game/game_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ func TestGameInit(t *testing.T) {
363363
t.Run(tt.name, func(t *testing.T) {
364364
game := NewGame(tt.input.rows, tt.input.cols, tt.input.minesNumber)
365365
game.Init(tt.input.board, func(coords []coord) {})
366-
assert.Equal(t, tt.want.cells, game.board.cells)
366+
assert.Equal(t, tt.want.cells, game.Board.cells)
367367
})
368368
}
369369
}
@@ -602,8 +602,8 @@ func TestCalculateAdjacentMines(t *testing.T) {
602602
t.Run(tt.name, func(t *testing.T) {
603603
game := NewGame(tt.input.rows, tt.input.cols, tt.input.minesNumber)
604604
game.Init(tt.input.board, func(coords []coord) {})
605-
game.board.CalculateAdjacentMines()
606-
assert.Equal(t, tt.want.cells, game.board.cells)
605+
game.Board.CalculateAdjacentMines()
606+
assert.Equal(t, tt.want.cells, game.Board.cells)
607607
})
608608
}
609609
}

internal/layout/layout.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package layout
2+
3+
import (
4+
"image/color"
5+
6+
"github.com/hajimehoshi/ebiten/v2"
7+
"github.com/hajimehoshi/ebiten/v2/vector"
8+
"github.com/leetcode-golang-classroom/mine-sweeper/internal/game"
9+
)
10+
11+
const (
12+
gridSize = 32
13+
Rows = 10
14+
Cols = 10
15+
ScreenWidth = gridSize * Rows
16+
ScreenHeight = gridSize * Cols
17+
MineCounts = 9
18+
)
19+
20+
type GameLayout struct {
21+
gameInstance *game.Game
22+
}
23+
24+
func NewGameLayout(gameInstance *game.Game) *GameLayout {
25+
return &GameLayout{gameInstance: gameInstance}
26+
}
27+
func (g *GameLayout) Update() error {
28+
return nil
29+
}
30+
31+
func (g *GameLayout) drawUnTouchCell(screen *ebiten.Image, row, col int) {
32+
vector.DrawFilledRect(
33+
screen,
34+
float32(row*gridSize),
35+
float32(col*gridSize),
36+
gridSize-1,
37+
gridSize-1,
38+
color.RGBA{0xcc, 0xcc, 0xcc, 0xff},
39+
false,
40+
)
41+
}
42+
func (g *GameLayout) Draw(screen *ebiten.Image) {
43+
for row := 0; row < Rows; row++ {
44+
for col := 0; col < Cols; col++ {
45+
cell := g.gameInstance.Board.GetCell(row, col)
46+
if !cell.Revealed {
47+
g.drawUnTouchCell(screen, row, col)
48+
}
49+
}
50+
}
51+
}
52+
53+
func (g *GameLayout) Layout(outsideWidth, outsideHeight int) (int, int) {
54+
return ScreenWidth, ScreenHeight
55+
}

0 commit comments

Comments
 (0)