c6a9cd69c2
* NEW: Add examples again. I hope correctly this time. git-svn-id: svn://localhost/gambas/trunk@6726 867c0c6c-44f3-4631-809d-bfa615b0a4ec
194 lines
4.8 KiB
Text
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
|