-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmineSweeper.tcl
More file actions
285 lines (219 loc) · 8.25 KB
/
mineSweeper.tcl
File metadata and controls
285 lines (219 loc) · 8.25 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
#! /bin/env wish
package require Tk
set GRID_SIZE 25
set BUTTON_SIZE 18
# Number of bombs is 20% of the number of tiles
#set NUM_BOMBS [expr {int( [expr $GRID_SIZE * $GRID_SIZE] * 0.2)}]
set NUM_BOMBS [expr {int( [expr $GRID_SIZE * $GRID_SIZE] * 0.1)}]
set NUM_LENGTH [string length $GRID_SIZE]
puts "NUM LENGTH"
puts $NUM_LENGTH
set uniqueID 0
set bombsPlaced 0
set bombsLeft $NUM_BOMBS
# 1 = Game Over, 0 = Game not over
set gameOver 0
# Import the various image files -------------------------
set bomb [image create photo -file images/minesweeperBomb.png]
set flag [image create photo -file images/minesweeperFlag.png]
set empty [image create photo -file images/minesweeperEmpty.png]
set redBomb [image create photo -file images/minesweeperBombRedX.png]
set zero [image create photo -file images/grey.png]
set one [image create photo -file images/one.png]
set two [image create photo -file images/two.png]
set three [image create photo -file images/three.png]
set four [image create photo -file images/four.png]
set five [image create photo -file images/five.png]
set six [image create photo -file images/six.png]
set seven [image create photo -file images/seven.png]
set eight [image create photo -file images/eight.png]
# --------------------------------------------------------
set firstClick true
set board() []
set flagBoard() []
proc updateButton {x y newImage} {
global BUTTON_SIZE uniqueID
set xy $x,$y
grid [button .myButtonUnique$uniqueID$xy -image $newImage -height $BUTTON_SIZE -width $BUTTON_SIZE]
grid .myButtonUnique$uniqueID$xy -row $y -column $x
incr uniqueID
}
proc bombPopulate {x y} {
global board bombsPlaced NUM_BOMBS GRID_SIZE NUM_LENGTH
while {$NUM_BOMBS > $bombsPlaced} {
set xPosition [expr {int(rand() * $GRID_SIZE)}]
set yPosition [expr {int(rand() * $GRID_SIZE)}]
set xyPosition ${xPosition},${yPosition}
set xy ${x},${y}
# If position randomly selected is the bomb position, reselect position or if position already has a bomb
if {$xyPosition == $xy || $board($xyPosition) == 1} {
continue
}
# Sets position to be a bomb position
set board($xyPosition) 1
incr bombsPlaced
}
}
# Generates a minesweeper board without a bomb at x y
proc generateBoard {x y} {
global GRID_SIZE board NUM_LENGTH
# Sets entire grid to initalize with no bomb status
for {set xCurrent 0} {$xCurrent < $GRID_SIZE} {incr xCurrent} {
for {set yCurrent 0} {$yCurrent < $GRID_SIZE} {incr yCurrent} {
set xy ${xCurrent},${yCurrent}
# 0 == no bomb
# 1 == bomb
set board($xy) 0
}
}
bombPopulate $x $y
}
proc checkBombNeighbours {x y} {
global board zero GRID_SIZE NUM_LENGTH
set bombCount 0
set xPO [expr [expr [scan $x %d]] + 1]
set xNO [expr [expr [scan $x %d]] - 1]
set yPO [expr [expr [scan $y %d]] + 1]
set yNO [expr [expr [scan $y %d]] - 1]
if {$xPO < $GRID_SIZE && $board($xPO,$y) == 1} {incr bombCount}
if {$yPO < $GRID_SIZE && $board($x,$yPO) == 1} {incr bombCount}
if {$yNO >= 0 && $board($x,$yNO) == 1} {incr bombCount}
if {$xNO >= 0 && $board($xNO,$y) == 1} {incr bombCount}
if {$yNO >= 0 && $xPO < $GRID_SIZE && $board($xPO,$yNO) == 1} {incr bombCount}
if {$xNO >= 0 && $yPO < $GRID_SIZE && $board($xNO,$yPO) == 1} {incr bombCount}
if {$xNO >= 0 && $yNO >= 0 && $board($xNO,$yNO) == 1} {incr bombCount}
if {$xPO < $GRID_SIZE && $yPO < $GRID_SIZE && $board($xPO,$yPO) == 1} {incr bombCount}
set board(${x},${y}) 2
return $bombCount
}
# Recursively go through board and display adjact bomb values
proc uncoverState {x y} {
global one two three four five six seven eight zero
global board GRID_SIZE NUM_LENGTH gameOver
if {$x >= $GRID_SIZE} {set x [expr $GRID_SIZE - 1]}
if {$y >= $GRID_SIZE} {set y [expr $GRID_SIZE - 1]}
if {$x < 0} {set $x 0}
if {$y < 0} {set $y 0}
set value [checkBombNeighbours $x $y]
if {$value == 0} {
set xPO [expr [expr [scan $x %d]] + 1]
set xNO [expr [expr [scan $x %d]] - 1]
set yPO [expr [expr [scan $y %d]] + 1]
set yNO [expr [expr [scan $y %d]] - 1]
if {$xPO >= $GRID_SIZE} {set $xPO [expr $GRID_SIZE - 1]}
if {$yPO >= $GRID_SIZE} {set $yPO [expr $GRID_SIZE - 1]}
if {$xNO < 0} {set $xNO 0}
if {$yNO < 0} {set $yNO 0}
set xP [format {%0*s} $NUM_LENGTH $xPO]
set xN [format {%0*s} $NUM_LENGTH $xNO]
set yP [format {%0*s} $NUM_LENGTH $yPO]
set yN [format {%0*s} $NUM_LENGTH $yNO]
# To stop infinite recursion, sets current board position to 3
set $board(${x},${y}) 3
if {$xPO < $GRID_SIZE && $board(${xPO},${y}) < 2 } {uncoverState $xPO $y}
if {$yNO >= 0 && $xPO < $GRID_SIZE && $board(${xPO},${yNO}) < 2} {uncoverState $xPO $yPO}
if {$yNO >= 0 && $board(${x},${yNO}) < 2} {uncoverState $x $yNO}
if {$xNO >= 0 && $yNO >= 0 && $board(${xNO},${yNO}) < 2} {uncoverState $xNO $yNO}
if {$xNO >= 0 && $board(${xNO},${y}) < 2} {uncoverState $xNO $y}
if {$xNO >= 0 && $yPO < $GRID_SIZE && $board(${xNO},${yPO}) < 2} {uncoverState $xNO $yPO}
if {$yPO < $GRID_SIZE && $board(${x},${yPO}) < 2} {uncoverState $x $yPO}
if {$xPO < $GRID_SIZE && $yPO < $GRID_SIZE && ($board(${xPO},${yPO}) < 2)} {uncoverState $xPO $yPO}
}
if {$value == 0 && $gameOver == 0} {updateButton $x $y $zero}
if {$value == 1 && $gameOver == 0} {updateButton $x $y $one}
if {$value == 2 && $gameOver == 0} {updateButton $x $y $two}
if {$value == 3 && $gameOver == 0} {updateButton $x $y $three}
if {$value == 4 && $gameOver == 0} {updateButton $x $y $four}
if {$value == 5 && $gameOver == 0} {updateButton $x $y $five}
if {$value == 6 && $gameOver == 0} {updateButton $x $y $six}
if {$value == 7 && $gameOver == 0} {updateButton $x $y $seven}
if {$value == 8 && $gameOver == 0} {updateButton $x $y $eight}
}
# If bomb was clicked, shows all bombs on screen
proc lostState {xPressed yPressed} {
global board GRID_SIZE NUM_LENGTH
global bomb redBomb gameOver
set gameOver 1
for {set x 0} {$x < $GRID_SIZE} {incr x} {
for {set y 0} {$y < $GRID_SIZE} {incr y} {
set xPadded [format {%0*s} $NUM_LENGTH $x]
set yPadded [format {%0*s} $NUM_LENGTH $y]
#set xy $xPadded$yPadded
set xy ${x},${y}
if {$board($xy) == 1} {
updateButton $x $y $bomb
}
}
}
updateButton $xPressed $yPressed $redBomb
}
proc buttonClicked {x y} {
global firstClick board
global flag bomb empty
global one two three four five six seven eight
set xy ${x},${y}
puts $xy
#Check if location is a bomb or not...
if {$firstClick == true} {
set firstClick false
# generate board where their click is not a bomb
generateBoard $x $y
}
# Position clicked is bomb...
if {$board($xy) == 1} {
# Uncover all bombs
lostState $x $y
}
# Position clicked is not a bomb
if {$board($xy) == 0} {
uncoverState $x $y
}
}
menu .menu -tearoff 0
.menu add command -label "Option 1"
.menu add command -label "Option 2"
proc rightClick {xPass yPass} {
global flag BUTTON_SIZE bombsLeft flagBoard empty gameOver
puts "Right click"
puts $flagBoard($xPass,$yPass)
if {$gameOver != 1} {
if {$flagBoard($xPass,$yPass) == 1} {
set flagBoard($xPass,$yPass) 0
set bombsLeft [incr $bombsLeft]
puts $bombsLeft
updateButton $xPass $yPass $empty
} else {
set flagBoard($xPass,$yPass) 1
set bombsLeft [expr $bombsLeft -1]
puts $bombsLeft
updateButton $xPass $yPass $flag
}
}
}
proc initGrid {} {
global GRID_SIZE BUTTON_SIZE NUM_LENGTH
global flag bomb empty
global one two three four five six seven eight
global bombsLeft
global flagBoard
grid [label .locationLable -text "" -textvar locationText]
for {set yy 0} {$yy < $GRID_SIZE} {incr yy} {
for {set xx 0} {$xx < $GRID_SIZE} {incr xx} {
#set xPadded [format {%0*s} $NUM_LENGTH $x]
#set yPadded [format {%0*s} $NUM_LENGTH $y]
#set xy $xPadded$yPadded
set xy ${xx},${yy}
set flagBoard($xx,$yy) 0
set b .myButton${xx},${yy}
grid [button $b -image $empty -height $BUTTON_SIZE -width $BUTTON_SIZE -command "buttonClicked $xx $yy"]
bind $b <Button-3> "rightClick $xx $yy"
grid $b -row $yy -column $xx
}
}
label .lt -text "Bombs Left: "
label .l -textvariable bombsLeft
#label .l -textvariable "Bombs Left: $bombsLeft"
grid .lt -row $GRID_SIZE -column 0 -columnspan $GRID_SIZE
grid .l -row $GRID_SIZE -column 4 -columnspan $GRID_SIZE
}
initGrid