gambas-source-code/app/examples/Games/MineSweeper/.src/MineSweeperGame.class
Benoît Minisini c6a9cd69c2 [EXAMPLES]
* NEW: Add examples again. I hope correctly this time.


git-svn-id: svn://localhost/gambas/trunk@6726 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2014-12-12 19:58:52 +00:00

194 lines
4.8 KiB
Text

' Gambas class file
Property Read Width As Integer
Property Read Height As Integer
Property Read Status As Integer
Property Read FlagCount As Integer
Event OnStart()
Event OnEnd()
Event OnRefresh()
Public Enum BLOCK_COVERED, BLOCK_FLAGGED, BLOCK_REVEALED
Public Enum GAME_READY, GAME_STARTED, GAME_WIN, GAME_LOSE
Public Enum NUM_MINE = 9
Private $width As Integer
Private $height As Integer
Private $blocks As New Integer[]
Private $status As New Integer[]
Private $mine_count As Integer
Private $flag_count As Integer
Private $covered_block_count As Integer
Private $game_state As Integer
Public Sub _new(w As Integer, h As Integer, n As Integer)
$width = w
$height = h
$mine_count = n
$covered_block_count = 0
$blocks = New Integer[w, h]
$status = New Integer[w, h]
Reset()
End
Public Function Reset()
Dim x, y As Integer
For x = 0 To $width - 1
For y = 0 To $height - 1
$status[x, y] = BLOCK_COVERED
$blocks[x, y] = 0
Next
Next
$game_state = GAME_READY
$covered_block_count = $width * $height
$flag_count = $mine_count
Raise OnRefresh()
End
Public Function GetBlockNumber(x As Integer, y As Integer) As Integer
Return $blocks[x, y]
End
Public Function GetBlockStatus(x As Integer, y As Integer) As Integer
Return $status[x, y]
End
Public Sub OpenBlock(x As Integer, y As Integer)
If $game_state = GAME_READY Then
$game_state = GAME_STARTED
GenerateRandomMines($mine_count, x, y)
Raise OnStart()
Endif
If $game_state = GAME_STARTED And $status[x, y] = BLOCK_COVERED
If $blocks[x, y] = NUM_MINE Then ' stepped on a mine
$game_state = GAME_LOSE
Raise OnEnd()
Else
RecursiveOpen(x, y)
If AllMinesFound() Then
FlagAllMines()
$game_state = GAME_WIN
Raise OnEnd()
Endif
Endif
Endif
Raise OnRefresh()
End
Public Sub ToggleFlag(x As Integer, y As Integer)
If $game_state = GAME_STARTED Then
If $status[x, y] = BLOCK_COVERED Then
$status[x, y] = BLOCK_FLAGGED
$flag_count -= 1
Else If $status[x, y] = BLOCK_FLAGGED Then
$status[x, y] = BLOCK_COVERED
$flag_count += 1
Else
Return
Endif
Raise OnRefresh()
Endif
End
Private Function Width_Read() As Integer
Return $width
End
Private Function Height_Read() As Integer
Return $height
End
Private Function Status_Read() As Integer
Return $game_state
End
Private Function FlagCount_Read() As Integer
Return $flag_count
End
' Generate n mines in the field and guarantee that (nx, ny) does not contain a mine.
Private Sub GenerateRandomMines(n As Integer, nx As Integer, ny As Integer)
Dim i As Integer
Dim x, y As Integer
Dim x2, y2 As Integer
Dim count As Integer = $width * $height
Dim index As Integer
' check if the range is correct
' note that the field should contain at most (w*h-1) mines, not w*h
If n >= count Then Error.Raise("Index out of bounds")
' put n mines into the first blocks, and fill in zero in the rest
For i = 0 To count - 1
x = i Mod $width
y = i / $width
$blocks[x, y] = IIf(i < n, NUM_MINE, 0)
Next
' if a mine is located in (nx, ny), then move the mine to the last block
If $blocks[nx, ny] = NUM_MINE Then Swap $blocks[nx, ny], $blocks[$width - 1, $height - 1]
' shuffle
For i = 0 To count - 1
x = i Mod $width
y = i / $width
x2 = Int(Rnd(0, $width))
y2 = Int(Rnd(0, $height))
If (x = nx And y = ny) Or (x2 = nx And y2 = ny) Then Continue ' skip (nx, ny)
Swap $blocks[x, y], $blocks[x2, y2]
Next
' generate the numbers
For x = 0 To $width - 1
For y = 0 To $height - 1
If $blocks[x, y] = NUM_MINE Then
For x2 = x - 1 To x + 1
For y2 = y - 1 To y + 1
Try IncrementBlockMineCount(x2, y2)
Next
Next
Endif
Next
Next
End
Private Sub IncrementBlockMineCount(x As Integer, y As Integer)
If $blocks[x, y] <> NUM_MINE Then $blocks[x, y] += 1
End
Private Sub RecursiveOpen(x As Integer, y As Integer)
Dim x2, y2 As Integer
If $status[x, y] = BLOCK_COVERED Then
$status[x, y] = BLOCK_REVEALED
$covered_block_count -= 1
If $blocks[x, y] = 0 Then
For x2 = x - 1 To x + 1
For y2 = y - 1 To y + 1
RecursiveOpen(x2, y2)
Next
Next
Endif
Endif
Catch
End
Private Function AllMinesFound() As Boolean
Return $covered_block_count = $mine_count
End
' Automatically mark all mines as flag
Private Sub FlagAllMines()
Dim x, y As Integer
For x = 0 To $width - 1
For y = 0 To $height - 1
If $blocks[x, y] = NUM_MINE Then
$status[x, y] = BLOCK_FLAGGED
Endif
Next
Next
End