-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgame.go
123 lines (110 loc) · 1.99 KB
/
game.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package minesweeper
// Game implements game play.
type Game struct {
m Grid
cellsStat CellsStat
xwalk xset
xbuf []xcell
pressed int
}
// New creates a new Game.
func New(m Grid) *Game {
return &Game{
m: m,
cellsStat: m.Stat(),
xwalk: make(xset),
xbuf: make([]xcell, 0, 8),
}
}
func (g *Game) cellsLeft() int {
return g.cellsStat.Free - g.pressed
}
// Unfold touches a cell. It fails if a bomb pressed.
// Returns amount of remained cells.
// The game passed if no cells left.
func (g *Game) Unfold(i, j int) (int, bool) {
if g.m[i][j].IsBomb() {
g.m[i][j].unfold()
return 0, false
}
g.unfold(i, j)
return g.cellsLeft(), true
}
type xcell struct {
i, j int
}
var xnil = xcell{-1, -1}
type xset map[xcell]struct{}
func (h xset) add(x xcell) {
h[x] = struct{}{}
}
func (h xset) drop() xcell {
for x := range h {
delete(h, x)
return x
}
return xnil
}
func (g *Game) unfold(i, j int) {
x := xcell{i, j}
for ; x != xnil; x = g.xwalk.drop() {
c := &g.m[x.i][x.j]
if c.any(Unfolded | Flagged) {
continue
}
c.unfold()
g.pressed++
bombs := g.suggestBombs(x.i, x.j)
if bombs == 0 {
// need to unfold cells around
for _, x := range g.xbuf {
g.xwalk.add(x)
}
} else {
c.suggest(bombs)
}
g.xbuf = g.xbuf[:0]
}
}
func (g *Game) hasBomb(i, j int) byte {
if g.m[i][j].IsBomb() {
return 1
}
g.xbuf = append(g.xbuf, xcell{i, j})
return 0
}
func (g *Game) suggestBombs(i, j int) (bombs byte) {
if i-1 >= 0 {
// up-left
if j-1 >= 0 {
bombs += g.hasBomb(i-1, j-1)
}
// up
bombs += g.hasBomb(i-1, j)
// up-right
if j+1 < len(g.m[i-1]) {
bombs += g.hasBomb(i-1, j+1)
}
}
// left
if j-1 >= 0 {
bombs += g.hasBomb(i, j-1)
}
// right
if j+1 < len(g.m[i]) {
bombs += g.hasBomb(i, j+1)
}
if i+1 < len(g.m) {
// down-left
if j-1 >= 0 {
bombs += g.hasBomb(i+1, j-1)
}
// down
bombs += g.hasBomb(i+1, j)
// down-right
if j+1 < len(g.m[i+1]) {
bombs += g.hasBomb(i+1, j+1)
}
}
return bombs
}