422 lines
10 KiB
Text
422 lines
10 KiB
Text
' ===============================
|
|
' MINESWEEPER - Liberty BASIC
|
|
' ===============================
|
|
|
|
' --- Constants ---
|
|
global cellSize, gridWidth, gridHeight, infoBarHeight
|
|
global totalMines, WindowWidth, WindowHeight, gameStatus$, minesLeft
|
|
|
|
cellSize = 20
|
|
gridWidth = 18
|
|
gridHeight = 12
|
|
infoBarHeight = 40
|
|
totalMines = 16 + int(rnd(0)*4)
|
|
|
|
WindowWidth = gridWidth * cellSize + 20
|
|
WindowHeight = gridHeight * cellSize + infoBarHeight + 38
|
|
|
|
' --- Game State ---
|
|
dim mineGrid(gridWidth, gridHeight)
|
|
dim adjacentCount(gridWidth, gridHeight)
|
|
dim revealed(gridWidth, gridHeight)
|
|
dim marked(gridWidth, gridHeight)
|
|
|
|
minesLeft = totalMines
|
|
gameStatus$ = "Playing..."
|
|
|
|
' --- Start Program ---
|
|
call setupGame
|
|
call drawGameWindow
|
|
|
|
wait
|
|
|
|
' -------------------------------
|
|
' SUB: Setup the Game
|
|
' -------------------------------
|
|
sub setupGame
|
|
for x = 1 to gridWidth
|
|
for y = 1 to gridHeight
|
|
mineGrid(x, y) = 0
|
|
adjacentCount(x, y) = 0
|
|
revealed(x, y) = 0
|
|
marked(x, y) = 0
|
|
next
|
|
next
|
|
|
|
minesPlaced = 0
|
|
while minesPlaced < totalMines
|
|
rx = int(rnd(0) * gridWidth) + 1
|
|
ry = int(rnd(0) * gridHeight) + 1
|
|
|
|
if mineGrid(rx, ry) = 0 then
|
|
mineGrid(rx, ry) = 1
|
|
minesPlaced = minesPlaced + 1
|
|
end if
|
|
wend
|
|
|
|
for x = 1 to gridWidth
|
|
for y = 1 to gridHeight
|
|
if mineGrid(x, y) = 0 then
|
|
count = 0
|
|
for dx = -1 to 1
|
|
for dy = -1 to 1
|
|
nx = x + dx
|
|
ny = y + dy
|
|
if nx >= 1 and nx <= gridWidth and ny >= 1 and ny <= gridHeight then
|
|
if mineGrid(nx, ny) = 1 then
|
|
count = count + 1
|
|
end if
|
|
end if
|
|
next
|
|
next
|
|
adjacentCount(x, y) = count
|
|
end if
|
|
next
|
|
next
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Draw Game Window
|
|
' -------------------------------
|
|
sub drawGameWindow
|
|
open "Minesweeper" for graphics_nf_nsb as #game
|
|
#game "down; fill white"
|
|
#game "trapclose [quit]"
|
|
#game "when leftButtonDown [leftClick]"
|
|
#game "when rightButtonDown [rightClick]"
|
|
|
|
call drawInfoBar
|
|
call drawGrid
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Draw Info Bar
|
|
' -------------------------------
|
|
sub drawInfoBar
|
|
#game "color black; backcolor white"
|
|
info$ = "Mines Left: "; minesLeft; " Status: "; gameStatus$
|
|
#game "place 10 20"
|
|
#game "\"; info$
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Draw Grid
|
|
' -------------------------------
|
|
sub drawGrid
|
|
for x = 1 to gridWidth
|
|
for y = 1 to gridHeight
|
|
px = 6 + (x - 1) * cellSize
|
|
py = infoBarHeight + (y - 1) * cellSize
|
|
|
|
#game "color black; backcolor lightgray"
|
|
#game "place "; px; " "; py
|
|
#game "boxfilled "; px + cellSize; " "; py + cellSize
|
|
next
|
|
next
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' HANDLER: Left Mouse Click
|
|
' -------------------------------
|
|
[leftClick]
|
|
if gameStatus$ <> "Playing..." then
|
|
call askPlayAgain
|
|
wait
|
|
end if
|
|
|
|
mouseX = MouseX
|
|
mouseY = MouseY
|
|
|
|
gridLeft = 6
|
|
gridTop = infoBarHeight
|
|
gridRight = gridLeft + gridWidth * cellSize
|
|
gridBottom = gridTop + gridHeight * cellSize
|
|
|
|
if mouseX >= gridLeft and mouseX < gridRight and _
|
|
mouseY >= gridTop and mouseY < gridBottom then
|
|
|
|
cellX = int((mouseX - gridLeft) / cellSize) + 1
|
|
cellY = int((mouseY - gridTop) / cellSize) + 1
|
|
|
|
call revealCell cellX, cellY
|
|
call checkWin
|
|
end if
|
|
|
|
wait
|
|
|
|
' -------------------------------
|
|
' HANDLER: Right Mouse Click
|
|
' -------------------------------
|
|
[rightClick]
|
|
if gameStatus$ <> "Playing..." then
|
|
call askPlayAgain
|
|
wait
|
|
end if
|
|
|
|
mouseX = MouseX
|
|
mouseY = MouseY
|
|
|
|
gridLeft = 6
|
|
gridTop = infoBarHeight
|
|
gridRight = gridLeft + gridWidth * cellSize
|
|
gridBottom = gridTop + gridHeight * cellSize
|
|
|
|
if mouseX >= gridLeft and mouseX < gridRight and _
|
|
mouseY >= gridTop and mouseY < gridBottom then
|
|
|
|
cellX = int((mouseX - gridLeft) / cellSize) + 1
|
|
cellY = int((mouseY - gridTop) / cellSize) + 1
|
|
|
|
call toggleMark cellX, cellY
|
|
call checkWin
|
|
end if
|
|
|
|
wait
|
|
|
|
' -------------------------------
|
|
' HANDLER: Close Window
|
|
' -------------------------------
|
|
[quit]
|
|
close #game
|
|
end
|
|
|
|
' -------------------------------
|
|
' SUB: Reveal All Mines
|
|
' -------------------------------
|
|
sub revealAllMines
|
|
for x = 1 to gridWidth
|
|
for y = 1 to gridHeight
|
|
if mineGrid(x, y) = 1 then
|
|
call drawMine x, y
|
|
end if
|
|
next
|
|
next
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Draw Mine Symbol
|
|
' -------------------------------
|
|
sub drawMine x, y
|
|
px = 6 + (x - 1) * cellSize
|
|
py = infoBarHeight + (y - 1) * cellSize
|
|
|
|
#game "color black; backcolor lightgray"
|
|
#game "place "; px; " "; py
|
|
#game "boxfilled "; px + cellSize; " "; py + cellSize
|
|
|
|
#game "color red"
|
|
tx = px + 5
|
|
ty = py + 15
|
|
#game "place "; tx; " "; ty
|
|
#game "\"; "M"
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Reveal All Numbers
|
|
' -------------------------------
|
|
sub revealAllNumbers
|
|
for x = 1 to gridWidth
|
|
for y = 1 to gridHeight
|
|
if mineGrid(x, y) = 1 then
|
|
call drawMine x, y
|
|
else
|
|
call drawNumber x, y, adjacentCount(x, y)
|
|
end if
|
|
next
|
|
next
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Draw Cell Number
|
|
' -------------------------------
|
|
sub drawNumber x, y, n
|
|
px = 6 + (x - 1) * cellSize
|
|
py = infoBarHeight + (y - 1) * cellSize
|
|
|
|
#game "color black; backcolor white"
|
|
#game "place "; px; " "; py
|
|
#game "boxfilled "; px + cellSize; " "; py + cellSize
|
|
|
|
if n > 0 then
|
|
#game "color blue"
|
|
tx = px + 6
|
|
ty = py + 15
|
|
#game "place "; tx; " "; ty
|
|
#game "\"; str$(n)
|
|
end if
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Reveal a Single Cell
|
|
' -------------------------------
|
|
sub revealCell x, y
|
|
if gameStatus$ <> "Playing..." then exit sub
|
|
if revealed(x, y) = 1 then exit sub
|
|
if marked(x, y) = 1 then exit sub
|
|
|
|
revealed(x, y) = 1
|
|
|
|
if mineGrid(x, y) = 1 then
|
|
call animateBoom x, y
|
|
gameStatus$ = "BOOM!!! Game Over!"
|
|
call revealAllMines
|
|
call drawInfoBar
|
|
exit sub
|
|
end if
|
|
|
|
call drawNumber x, y, adjacentCount(x, y)
|
|
|
|
if adjacentCount(x, y) = 0 then
|
|
for dx = -1 to 1
|
|
for dy = -1 to 1
|
|
nx = x + dx
|
|
ny = y + dy
|
|
if nx >= 1 and nx <= gridWidth and ny >= 1 and ny <= gridHeight then
|
|
if revealed(nx, ny) = 0 then
|
|
call revealCell nx, ny
|
|
end if
|
|
end if
|
|
next
|
|
next
|
|
end if
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Check for Win Condition
|
|
' -------------------------------
|
|
sub checkWin
|
|
safeCells = 0
|
|
revealedSafeCells = 0
|
|
|
|
for x = 1 to gridWidth
|
|
for y = 1 to gridHeight
|
|
if mineGrid(x, y) = 0 then
|
|
safeCells = safeCells + 1
|
|
if revealed(x, y) = 1 then
|
|
revealedSafeCells = revealedSafeCells + 1
|
|
end if
|
|
end if
|
|
next
|
|
next
|
|
|
|
if revealedSafeCells = safeCells then
|
|
gameStatus$ = "You Win!"
|
|
call drawInfoBar
|
|
call revealAllMines
|
|
end if
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Mark or unmark a cell
|
|
' -------------------------------
|
|
sub toggleMark x, y
|
|
if gameStatus$ <> "Playing..." then exit sub
|
|
if revealed(x, y) = 1 then exit sub
|
|
|
|
if marked(x, y) = 0 then
|
|
marked(x, y) = 1
|
|
minesLeft = minesLeft - 1
|
|
call drawMark x, y
|
|
else
|
|
marked(x, y) = 0
|
|
minesLeft = minesLeft + 1
|
|
call drawHidden x, y
|
|
end if
|
|
|
|
call drawInfoBar
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Draw a Mark ("?")
|
|
' -------------------------------
|
|
sub drawMark x, y
|
|
px = 6 + (x - 1) * cellSize
|
|
py = infoBarHeight + (y - 1) * cellSize
|
|
|
|
#game "color black; backcolor yellow"
|
|
#game "place "; px; " "; py
|
|
#game "boxfilled "; px + cellSize; " "; py + cellSize
|
|
|
|
#game "color red"
|
|
tx = px + 6
|
|
ty = py + 15
|
|
#game "place "; tx; " "; ty
|
|
#game "\"; "?"
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Draw Hidden Cell
|
|
' -------------------------------
|
|
sub drawHidden x, y
|
|
px = 6 + (x - 1) * cellSize
|
|
py = infoBarHeight + (y - 1) * cellSize
|
|
|
|
#game "color black; backcolor lightgray"
|
|
#game "place "; px; " "; py
|
|
#game "boxfilled "; px + cellSize; " "; py + cellSize
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Animate a Boom
|
|
' -------------------------------
|
|
sub animateBoom x, y
|
|
#game "flush"
|
|
|
|
px = 6 + (x - 1) * cellSize
|
|
py = infoBarHeight + (y - 1) * cellSize
|
|
|
|
centerX = px + cellSize/2
|
|
centerY = py + cellSize/2
|
|
|
|
#game "color red"
|
|
steps = 12
|
|
|
|
#game "backcolor red"
|
|
for i = 1 to steps
|
|
radius = i * 2
|
|
#game "place "; centerX; " "; centerY
|
|
#game "circlefilled "; radius
|
|
timer 5, [continueBoom1]
|
|
wait
|
|
[continueBoom1]
|
|
timer 0
|
|
next
|
|
|
|
#game "backcolor white"
|
|
for i = 1 to steps
|
|
radius = i * 2
|
|
#game "place "; centerX; " "; centerY
|
|
#game "circlefilled "; radius
|
|
timer 5, [continueBoom2]
|
|
wait
|
|
[continueBoom2]
|
|
timer 0
|
|
next
|
|
|
|
#game "redraw"
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Ask to Play Again
|
|
' -------------------------------
|
|
sub askPlayAgain
|
|
confirm "Play again?"; answer
|
|
if answer = 1 then
|
|
call restartGame
|
|
else
|
|
close #game
|
|
end
|
|
end if
|
|
end sub
|
|
|
|
' -------------------------------
|
|
' SUB: Restart the Game
|
|
' -------------------------------
|
|
sub restartGame
|
|
minesLeft = totalMines
|
|
gameStatus$ = "Playing..."
|
|
|
|
call setupGame
|
|
call drawGrid
|
|
call drawInfoBar
|
|
end sub
|