RosettaCodeData/Task/Minesweeper-game/PureBasic/minesweeper-game.basic

179 lines
4.4 KiB
Plaintext

Structure cell
isMine.i
display.c ;character to displays for cell, one of these {'.', '?', ' ', #)
EndStructure
Global Dim grid.cell(0,0)
Global mineCount, minesMarked, isGameOver
Procedure makeGrid(n, m)
Protected rm, x, y
Dim grid.cell(n - 1, m - 1)
mineCount = n * m * (Random(4) + 2) / 10
If mineCount < 0: mineCount = 1: EndIf
For x = 0 To n - 1
For y = 0 To m - 1
grid(x, y)\display = '.'
Next
Next
rm = mineCount
While rm
x = Random(n - 1)
y = Random(m - 1)
If Not grid(x, y)\isMine
rm - 1: grid(x, y)\isMine = #True
EndIf
Wend
minesMarked = 0
isGameOver = #False
EndProcedure
Procedure displayGrid(isEndOfGame = #False)
#lMargin = 4
Protected x, y, display.s
If Not isEndOfGame
PrintN("Grid has " + Str(mineCount) + " mines, " + Str(minesMarked) + " mines marked.")
EndIf
PrintN(Space(#lMargin + 1) + ReplaceString(Space(ArraySize(grid(), 1) + 1), " ", "-"))
For y = 0 To ArraySize(grid(), 2)
Print(RSet(Str(y + 1), #lMargin, " ") + ":")
For x = 0 To ArraySize(grid(), 1)
Print(Chr(grid(x,y)\display))
Next
PrintN("")
Next
EndProcedure
Procedure endGame(msg.s)
Protected ans.s
isGameOver = #True
PrintN(msg): Print("Another game (y/n)?"): ans = Input()
If LCase(Left(Trim(ans),1)) = "y"
makeGrid(6, 4)
EndIf
EndProcedure
Procedure resign()
Protected x, y, found
For y = 0 To ArraySize(grid(), 2)
For x = 0 To ArraySize(grid(), 1)
With grid(x,y)
If \isMine
If \display = '?'
\display = 'Y'
found + 1
ElseIf \display <> 'x'
\display = 'N'
EndIf
EndIf
EndWith
Next
Next
displayGrid(#True)
endGame("You found " + Str(found) + " out of " + Str(mineCount) + " mines.")
EndProcedure
Procedure usage()
PrintN("h or ? - this help,")
PrintN("c x y - clear cell (x,y),")
PrintN("m x y - marks (toggles) cell (x,y),")
PrintN("n - start a new game,")
PrintN("q - quit/resign the game,")
PrintN("where x is the (horizontal) column number and y is the (vertical) row number." + #CRLF$)
EndProcedure
Procedure markCell(x, y)
If grid(x, y)\display = '?'
minesMarked - 1: grid(x, y)\display = '.'
ElseIf grid(x, y)\display = '.'
minesMarked + 1: grid(x, y)\display = '?'
EndIf
EndProcedure
Procedure countAdjMines(x, y)
Protected count, i, j
For j = y - 1 To y + 1
If j >= 0 And j <= ArraySize(grid(), 2)
For i = x - 1 To x + 1
If i >= 0 And i <= ArraySize(grid(), 1)
If grid(i, j)\isMine
count + 1
EndIf
EndIf
Next
EndIf
Next
ProcedureReturn count
EndProcedure
Procedure clearCell(x, y)
Protected count
If x >= 0 And x <= ArraySize(grid(), 1) And y >= 0 And y <= ArraySize(grid(), 2)
If grid(x, y)\display = '.'
If Not grid(x,y)\isMine
count = countAdjMines(x, y)
If count
grid(x, y)\display = Asc(Str(count))
Else
grid(x, y)\display = ' '
clearCell(x + 1, y)
clearCell(x + 1, y + 1)
clearCell(x , y + 1)
clearCell(x - 1, y + 1)
clearCell(x - 1, y)
clearCell(x - 1, y - 1)
clearCell(x , y - 1)
clearCell(x + 1, y - 1)
EndIf
Else
grid(x, y)\display = 'x'
PrintN("Kaboom! You lost!")
resign()
EndIf
EndIf
EndIf
EndProcedure
Procedure testforwin()
Protected x, y, isCleared
If minesMarked = mineCount
isCleared = #True
For x = 0 To ArraySize(grid(), 1)
For y = 0 To ArraySize(grid(), 2)
If grid(x, y)\display = '.': isCleared = #False: EndIf
Next
Next
EndIf
If isCleared: endGame("You won!"): EndIf
EndProcedure
If OpenConsole()
Define action.s
usage()
makeGrid(6, 4): displayGrid()
Repeat
PrintN(""): Print(">"): action = Input()
Select Asc(LCase(Left(action, 1)))
Case 'h', '?'
usage()
Case 'n'
makeGrid(6, 4): displayGrid()
Case 'c'
clearCell(Val(StringField(action, 2, " ")) - 1, Val(StringField(action, 3, " ")) - 1)
If Not isGameOver: displayGrid(): Else: testforwin(): EndIf
Case 'm'
markCell(Val(StringField(action, 2, " ")) - 1, Val(StringField(action, 3, " ")) - 1)
displayGrid()
testforwin()
Case 'q'
resign()
EndSelect
Until isGameOver
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
CloseConsole()
EndIf