-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain-win.bz
714 lines (546 loc) · 22.7 KB
/
main-win.bz
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
link "raylib"
link "gdi32"
link "winmm"
# I thought I was being clever by making links be in the code, rather than
# in a build script, but it is actually much worse lol
type color {
byte r,
byte g,
byte b,
byte a
}
type texture {
i32 id,
i32 width,
i32 height,
i32 mipmaps,
i32 format
}
type image {
void@ data,
i32 width,
i32 height,
i32 mipmaps,
i32 format
}
type rect {
float x,
float y,
float width,
float height
}
type vec2 {
float x,
float y
}
type cell {
int number,
bool closed,
bool mine,
bool flag,
}
cfn InitWindow(int w, int h, byte[] title)
cfn CloseWindow()
cfn SetWindowSize(int w, int h)
cfn WindowShouldClose() bool
cfn BeginDrawing()
cfn EndDrawing()
cfn ClearBackground(color c)
cfn SetTargetFPS(int fps)
cfn LoadTexture(byte[] path) texture
cfn LoadTextureFromImage(image img) texture
cfn LoadImageFromMemory(byte[] fmt, byte[] data, int size) image
cfn LoadImage(byte[] path) i32
cfn UnloadImage(image img)
cfn DrawTextureRec(texture t, rect r, vec2 pos, color c)
cfn DrawTexturePro(texture t, rect sr, rect dr, vec2 pos, float rot, color c)
cfn GetWorkingDirectory() void@
cfn InitAudioDevice()
cfn GetMouseX() int
cfn GetMouseY() int
cfn GetFrameTime() float
cfn CheckCollisionRecs(rect a, rect b) bool
cfn IsMouseButtonPressed(int button) bool
cfn printf(byte[] fmt, *) i32
cfn time(int) int
cfn srand(int)
cfn rand() int
embed "assets/v2/opened.png" as img_opened
embed "assets/v2/1.png" as img_1
embed "assets/v2/2.png" as img_2
embed "assets/v2/3.png" as img_3
embed "assets/v2/4.png" as img_4
embed "assets/v2/5.png" as img_5
embed "assets/v2/6.png" as img_6
embed "assets/v2/7.png" as img_7
embed "assets/v2/8.png" as img_8
embed "assets/v2/closed.png" as img_closed
embed "assets/v2/mine.png" as img_mine
embed "assets/v2/flag.png" as img_flag
embed "assets/v2/lost.png" as img_lost
embed "assets/v2/correct.png" as img_correct
embed "assets/v2/wrong.png" as img_wrong
embed "assets/v2/d_.png" as img_d_
embed "assets/v2/d0.png" as img_d0
embed "assets/v2/d1.png" as img_d1
embed "assets/v2/d2.png" as img_d2
embed "assets/v2/d3.png" as img_d3
embed "assets/v2/d4.png" as img_d4
embed "assets/v2/d5.png" as img_d5
embed "assets/v2/d6.png" as img_d6
embed "assets/v2/d7.png" as img_d7
embed "assets/v2/d8.png" as img_d8
embed "assets/v2/d9.png" as img_d9
embed "assets/v2/d-.png" as img_dm
embed "assets/v2/dcoff.png" as img_dcoff
embed "assets/v2/dcon.png" as img_dcon
embed "assets/v2/faces/win.png" as img_face_win
embed "assets/v2/faces/loss.png" as img_face_loss
embed "assets/v2/faces/front.png" as img_face_front
embed "assets/v2/faces/blink.png" as img_face_blink
embed "assets/v2/faces/look_m.png" as img_face_look_m
embed "assets/v2/faces/look_l.png" as img_face_look_l
embed "assets/v2/faces/look_ll.png" as img_face_look_ll
embed "assets/v2/faces/look_r.png" as img_face_look_r
embed "assets/v2/faces/look_rr.png" as img_face_look_rr
embed "assets/v2/display1.png" as img_display1
fn loadTexture(byte[] imageData) texture {
let image img = LoadImageFromMemory(".png", imageData, imageData.len)
let texture t = LoadTextureFromImage(img)
UnloadImage(img)
ret t
}
fn expandRect(rect@ r, float factor) {
mut [email protected] = [email protected] - factor
mut [email protected] = [email protected] - factor
mut [email protected] = [email protected] + factor*2
mut [email protected] = [email protected] + factor*2
}
fn restartGame(cell[][]@ grid, int gxOff, int gyOff, int cellSize, int gridWidth, int gridHeight, bool@ init, bool@ end, bool@ won, bool@ lost, float@ gtime) {
for i from 0 until [email protected] {
collect grid@[i]
} collect grid@
mut gtime@ = 0
mut init@ = false
mut end@ = false
mut lost@ = false
mut won@ = false
SetWindowSize(gxOff*2 + cellSize*gridWidth, gyOff+gxOff+cellSize*gridHeight)
mut grid@ = &*gridWidth
for i from 0 until [email protected] {
mut grid@[i] = &*gridHeight
for j from 0 until grid@[i].len {
mut grid@[i][j] = cell!{0,true,false,false}
}
}
}
fn main() {
srand(time(0))
let int gxOff = 30
let int gyOff = 150
let int cellSize = 45
let int gridWidth = 11
let int gridHeight = 11
let int mineCount = 18
let float gameTime = 0
InitWindow(gxOff*2 + cellSize*gridWidth, gyOff+gxOff+cellSize*gridHeight, "Minesweeper FLOAT")
SetTargetFPS(60)
let color bg = color!{ 215, 215, 215, 255 }
# TEXTURES
let texture texClosed = loadTexture(img_closed)
let texture texMine = loadTexture(img_mine)
let texture texFlag = loadTexture(img_flag)
let texture texMineExplode = loadTexture(img_lost)
let texture texFlaggedMine = loadTexture(img_correct)
let texture texIncorrectFlag = loadTexture(img_wrong)
let rect tileSize = rect!{0,0,680,680}
let texture texOpened = loadTexture(img_opened)
let texture _1 = loadTexture(img_1)
let texture _2 = loadTexture(img_2)
let texture _3 = loadTexture(img_3)
let texture _4 = loadTexture(img_4)
let texture _5 = loadTexture(img_5)
let texture _6 = loadTexture(img_6)
let texture _7 = loadTexture(img_7)
let texture _8 = loadTexture(img_8)
let texture[] numbers = [ texOpened, _1, _2, _3, _4, _5, _6, _7, _8 ]
let rect display1rect = rect!{0,0,1200,650}
let texture display1 = loadTexture(img_display1)
let rect digitSize = rect!{0,0,350,520}
let texture d_ = loadTexture(img_d_)
let texture d0 = loadTexture(img_d0)
let texture d1 = loadTexture(img_d1)
let texture d2 = loadTexture(img_d2)
let texture d3 = loadTexture(img_d3)
let texture d4 = loadTexture(img_d4)
let texture d5 = loadTexture(img_d5)
let texture d6 = loadTexture(img_d6)
let texture d7 = loadTexture(img_d7)
let texture d8 = loadTexture(img_d8)
let texture d9 = loadTexture(img_d9)
let texture dm = loadTexture(img_dm)
let texture[] digits = [ d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d_, dm ]
let rect digitColonSize = rect!{0,0,100,520}
let texture dcoff = loadTexture(img_dcoff)
let texture dcon = loadTexture(img_dcon)
let rect faceSize = rect!{0,0,600,550}
let texture texFaceLoss = loadTexture(img_face_loss)
let texture texFaceWin = loadTexture(img_face_win)
let texture texFaceFront = loadTexture(img_face_front)
let texture texFaceBlink = loadTexture(img_face_blink)
let texture texFaceLookM = loadTexture(img_face_look_m)
let texture texFaceLookL = loadTexture(img_face_look_l)
let texture texFaceLookLL = loadTexture(img_face_look_ll)
let texture texFaceLookR = loadTexture(img_face_look_r)
let texture texFaceLookRR = loadTexture(img_face_look_rr)
# TEXTURES
let bool isInitialized = false
let bool acceptInput = true
let bool gameEnded = false
let bool gameLost = false
let bool gameWon = false
let int focus = 2
let color tint = color!{255,255,255,255}
let vec2 origin = vec2!{0,0}
let cell[][] grid = *0
restartGame(@grid, gxOff, gyOff, cellSize, gridWidth, gridHeight, @isInitialized, @gameEnded, @gameWon, @gameLost, @gameTime)
let float animTimerBlink = 0
let bool animTimerBlinkState = false
let int animFaceState = 0
let float animChangeStateTimer = 0
let int BLINK = 0
let int FOLLOW = 1
let bool animBlinkState = false
let float animBlink = 0
while !WindowShouldClose() {
mut acceptInput = !gameEnded
BeginDrawing()
# TODO: GetFrameTime() doesnt work for some reason
let float dt = 1/60
if !gameEnded and isInitialized
mut gameTime = gameTime + dt
ClearBackground(bg)
let rect mouse = rect!{GetMouseX()->float, GetMouseY()->float, 0, 0}
let bool click = IsMouseButtonPressed(0)
let bool rclick = IsMouseButtonPressed(1)
# DRAW INTERFACE
if true && {
let float faceHeight = (gyOff - gxOff)->float
let float faceWidth = faceHeight * 1.1
let float faceX = ((gxOff*2 + cellSize*gridWidth)->float - faceWidth) / 2
let float faceY = (gyOff->float - faceHeight) / 2
let rect r = rect!{faceX,faceY,faceWidth,faceHeight}
let bool hover = CheckCollisionRecs(r, mouse)
if hover
expandRect(@r, focus->float)
if hover and click and isInitialized {
restartGame(@grid, gxOff, gyOff, cellSize, gridWidth, gridHeight, @isInitialized, @gameEnded, @gameLost, @gameWon, @gameTime)
continue
}
let texture faceT = texFaceFront
mut animChangeStateTimer = animChangeStateTimer - dt
if animChangeStateTimer < 0 {
let int newState = rand() %% 2
mut animChangeStateTimer = (rand() %% 6 + 3)->float
mut animFaceState = newState
}
if animFaceState == BLINK {
mut animBlink = animBlink - dt
if animBlink < 0 {
mut animBlinkState = !animBlinkState
if animBlinkState {
mut animBlink = (rand() %% 3 + 1)->float
}
else {
mut animBlink = 0.2
}
}
if animBlinkState
mut faceT = texFaceFront
else
mut faceT = texFaceBlink
}
else if animFaceState == FOLLOW {
let float faceX = faceX + faceWidth/2
let float faceY = faceY + faceHeight/2
let float mouseX = GetMouseX()->float - faceX
let float mouseY = GetMouseY()->float - faceY
let float hypo = sqrt((mouseX*mouseX + mouseY*mouseY)->double)->float
let float ratio = mouseY / hypo
let float middleThreshold = 0.95
let float slightlyThreshold = 0.7
if ratio > middleThreshold or ratio < 0-middleThreshold
mut faceT = texFaceLookM
else if ratio > slightlyThreshold or ratio < 0-slightlyThreshold {
if mouseX < 0
mut faceT = texFaceLookL
else
mut faceT = texFaceLookR
}
else {
if mouseX < 0
mut faceT = texFaceLookLL
else
mut faceT = texFaceLookRR
}
}
if gameWon mut faceT = texFaceWin
if gameLost mut faceT = texFaceLoss
DrawTexturePro(faceT, faceSize, r, origin, 0, tint)
let float maxDisplayHeight = (gyOff - gxOff)->float
let float displayCountWidth = faceX - gxOff->float*1.5
let float displayRatio = 0.4
let float displayCountHeight = displayCountWidth * displayRatio
if displayCountHeight > maxDisplayHeight {
mut displayCountHeight = maxDisplayHeight
mut displayCountWidth = displayCountHeight / displayRatio
}
let float displayCountY = (gyOff->float - displayCountHeight) / 2
let float digitHeight = displayCountHeight * 0.6
let float digitWidth = digitHeight / 520 * 350
let float digitY = displayCountY + ((displayCountHeight - digitHeight)/2)
let float mineCountX = gxOff->float
let rect mineCountRect = rect!{mineCountX,displayCountY,displayCountWidth,displayCountHeight}
DrawTexturePro(display1, display1rect, mineCountRect, origin, 0, tint)
let int remainingMinesTrue = (mineCount - countFlags(grid))
let int remainingMines = mabs(remainingMinesTrue)
let int rmThou = remainingMines / 1000
let int rmHndr = (remainingMines % 1000) / 100
let int rmTens = (remainingMines % 100) / 10
let int rmOnes = (remainingMines % 10)
if remainingMinesTrue < 0 {
if rmTens == 0 and rmHndr == 0 and rmThou == 0 mut rmTens = 10
if rmHndr == 0 and rmThou == 0 mut rmHndr = 10
if rmThou == 0 mut rmThou = 10
if rmTens == 10 mut rmTens = 11
else if rmHndr == 10 mut rmHndr = 11
else mut rmThou = 11
}
let float digitGap = 7
let float mineCountDigitsWidth = digitWidth*4 + digitGap*3
let float mineCountDigitXOffset = mineCountX + (displayCountWidth - mineCountDigitsWidth)/2
DrawTexturePro(digits[rmThou], digitSize, rect!{mineCountDigitXOffset + digitGap*0 + digitWidth*0,digitY,digitWidth,digitHeight},origin,0,tint)
DrawTexturePro(digits[rmHndr], digitSize, rect!{mineCountDigitXOffset + digitGap*1 + digitWidth*1,digitY,digitWidth,digitHeight},origin,0,tint)
DrawTexturePro(digits[rmTens], digitSize, rect!{mineCountDigitXOffset + digitGap*2 + digitWidth*2,digitY,digitWidth,digitHeight},origin,0,tint)
DrawTexturePro(digits[rmOnes], digitSize, rect!{mineCountDigitXOffset + digitGap*3 + digitWidth*3,digitY,digitWidth,digitHeight},origin,0,tint)
let float timeCountX = (gxOff+gridWidth*cellSize)->float - displayCountWidth
let rect timeCountRect = rect!{timeCountX,displayCountY,displayCountWidth,displayCountHeight}
DrawTexturePro(display1, display1rect, timeCountRect, origin, 0, tint)
let int intTime = (gameTime-0.5)->int
let int seconds = intTime %% 60
let int secondsOnes = seconds %% 10
let int secondsTens = seconds / 10
let int minutes = intTime / 60
let int minutesOnes = minutes %% 10
let int minutesTens = minutes / 10
let float timeDigitGap = 3
let float timeColonWidth = digitHeight/520*100
let float timeCountDigitsWidth = digitWidth*4 + timeColonWidth + timeDigitGap*4
let float timeCountDigitXOffset = timeCountX + (displayCountWidth - timeCountDigitsWidth)/2
let texture colonTexture = dcon
if gameWon {
mut animTimerBlink = animTimerBlink - 1.2*dt
if animTimerBlink < 0 {
mut animTimerBlink = 1
mut animTimerBlinkState = !animTimerBlinkState
}
if !animTimerBlinkState {
mut colonTexture = dcoff
mut secondsOnes = 10
mut secondsTens = 10
mut minutesOnes = 10
mut minutesTens = 10
}
}
DrawTexturePro(digits[minutesTens], digitSize, rect!{timeCountDigitXOffset + timeDigitGap*0 + digitWidth*0,digitY,digitWidth,digitHeight},origin,0,tint)
DrawTexturePro(digits[minutesOnes], digitSize, rect!{timeCountDigitXOffset + timeDigitGap*1 + digitWidth*1,digitY,digitWidth,digitHeight},origin,0,tint)
DrawTexturePro(colonTexture, digitColonSize, rect!{timeCountDigitXOffset + timeDigitGap*2 + digitWidth*2,digitY,timeColonWidth,digitHeight},origin,0,tint)
DrawTexturePro(digits[secondsTens], digitSize, rect!{timeCountDigitXOffset + timeDigitGap*3 + timeColonWidth + digitWidth*2,digitY,digitWidth,digitHeight},origin,0,tint)
DrawTexturePro(digits[secondsOnes], digitSize, rect!{timeCountDigitXOffset + timeDigitGap*4 + timeColonWidth + digitWidth*3,digitY,digitWidth,digitHeight},origin,0,tint)
}
for i from 0 until gridWidth {
for j from 0 until gridHeight {
let rect r = rect!{(i*cellSize+gxOff)->float, (j*cellSize+gyOff)->float, cellSize->float, cellSize->float}
let cell@ mutcell = @grid[i][j]
let cell c = mutcell@
let bool hover = CheckCollisionRecs(r, mouse)
if hover
expandRect(@r, focus->float)
if acceptInput {
if hover and click and !isInitialized {
populateGrid(grid, i, j, mineCount)
mut isInitialized = true
}
if hover and click {
let bool result = true
if !c.closed
mut result = tryChord(grid, i, j)
else if !c.flag
mut result = recursivelyOpen(grid, i, j, true)
mut gameLost = !result
mut gameWon = !gameLost and checkWin(grid)
if gameWon flagAllMines(grid)
mut gameEnded = gameLost or gameWon
mut acceptInput = !gameEnded
}
if hover and rclick and c.closed
mut grid[i][j].flag = !c.flag
} #acceptInput
let texture t = texClosed
if !c.closed and c.mine
mut t = texMine
else if !c.closed and !c.flag
mut t = numbers[c.number]
else if c.closed and c.flag
mut t = texFlag
if gameEnded {
if c.mine and !c.closed
mut t = texMineExplode
else if c.mine and !c.flag
mut t = texMine
else if c.mine and c.flag
mut t = texFlaggedMine
else if !c.mine and c.flag
mut t = texIncorrectFlag
}
DrawTexturePro(t, tileSize, r, origin, 0, tint)
}
}
EndDrawing()
}
CloseWindow()
# There is probably some memory leak (not sure), but it takes 2 seconds to close without the exit()
exit(0)
}
# "abs" is taken in clib I suppose, I definitely need to do the module system
fn mabs(int i) int { if i > 0 ret i else ret -i ret 0 }
cfn sqrt(double f) double
cfn exit(int)
fn countFlags(cell[][] grid) int {
let int flagCount = 0
for i from 0 until grid.len {
for j from 0 until grid[i].len {
if grid[i][j].flag
mut flagCount = flagCount + 1
}
}
ret flagCount
}
fn clearGrid(cell[][] grid) {
for i from 0 until grid.len && {
for j from 0 until grid[i].len && {
mut grid[i][j] = cell!{0,true,false,false}
}
}
}
fn checkWin(cell[][] grid) bool {
let int closed = 0
let int mines = 0
for i from 0 until grid.len {
for j from 0 until grid[i].len {
if grid[i][j].closed mut closed = closed + 1
if grid[i][j].mine mut mines = mines + 1
}
}
ret closed == mines
}
fn flagAllMines(cell[][] grid) {
for i from 0 until grid.len
for j from 0 until grid[i].len
if grid[i][j].mine mut grid[i][j].flag = true
}
fn populateGrid(cell[][] grid, int xo, int yo, int targetMineCount) {
for _ from 0 until targetMineCount {
let bool stop = false
while !stop {
let int rx = rand() %% grid.len
let int ry = rand() %% grid[0].len
if grid[rx][ry].mine continue
# More empty spaces near the starting point
let int dx = mabs(xo - rx)
let int dy = mabs(yo - ry)
if dx + dy < 3 continue
mut grid[rx][ry].mine = true
mut stop = true
}
}
for i from 0 until grid.len {
for j from 0 until grid[i].len {
let int around = 0
for in from -1 until 2 {
for jn from -1 until 2 {
if in == 0 and jn == 0 continue
let int id = i + in
let int jd = j + jn
if id < 0 or id >= grid.len continue
if jd < 0 or jd >= grid[i].len continue
if grid[id][jd].mine
mut around = around + 1
}
}
mut grid[i][j].number = around
}
}
}
# returns false if boom boom
fn tryChord(cell[][] grid, int x, int y) bool {
let cell c = grid[x][y]
if c.closed ret true
if c.mine ret true
let int flagged = 0
for i from -1 until 2 {
for j from -1 until 2 {
if i == 0 and j == 0 continue
if x + i < 0 or x + i >= grid.len continue
if y + j < 0 or y + j >= grid[0].len continue
if grid[x+i][y+j].flag
mut flagged = flagged + 1
}
}
if flagged != c.number ret true
let bool safe = true
for i from -1 until 2 {
for j from -1 until 2 {
if i == 0 and j == 0 continue
if x + i < 0 or x + i >= grid.len continue
if y + j < 0 or y + j >= grid[0].len continue
if grid[x+i][y+j].flag continue
if grid[x+i][y+j].mine {
# Opens that single cell with mine
recursivelyOpen(grid, x+i, y+j, true)
mut safe = false
}
}
}
if !safe ret safe
for i from -1 until 2 {
for j from -1 until 2 {
if i == 0 and j == 0 continue
if x + i < 0 or x + i >= grid.len continue
if y + j < 0 or y + j >= grid[0].len continue
if grid[x+i][y+j].flag continue
let bool result = recursivelyOpen(grid, x+i, y+j, true)
# Technically useless, but gonna leave it in
if !result mut safe = false
}
}
ret safe
}
# False if mine
fn recursivelyOpen(cell[][] grid, int x, int y, bool initial) bool {
if x < 0 or x >= grid.len ret true
if y < 0 or y >= grid[0].len ret true
if grid[x][y].flag ret true
# A chain shouldn't open a mine lol
if !initial and grid[x][y].mine ret true
if !grid[x][y].closed ret true
mut grid[x][y].closed = false
if grid[x][y].mine ret false
if grid[x][y].number > 0 ret true
for i from -1 until 2 {
for j from -1 until 2 {
recursivelyOpen(grid, x+i, y+j, false)
}
}
ret true
}