RosettaCodeData/Task/Minesweeper-game/Liberty-BASIC/minesweeper-game.basic
2025-08-11 18:05:26 -07:00

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