📄 minesweeper.mpsrc
字号:
program Minesweeper;
const maxWidth = 30;
maxHeight = 30;
minesDensity = 10; { 10 percent of the fields contain mines }
var xPos, yPos : integer;
fieldWidth, fieldHeight : integer;
numOfMines : integer;
cellSize : integer;
xDelta, yDelta : integer;
quit, play, clicked : command;
{
values at the mineField element are two digit numbers where:
the first digit is 0-8, the number of the mines around
the second digit is:
0 - does not contain a mine/1-contains a mine
0 - is not opened/2 - is opened
0 - is not marked/4 - is marked as a mine
}
mineField: array[1..maxWidth, 1..maxHeight] of integer;
{
the imageArray contains the block images:
1-8: images with numbers 1-8
9 - element not yet open
10 - empty element that is open
11 - mine element
12 - element marked as a mine
}
imageArray: array[1..12] of image;
gameStatus : integer; { 0 - playing, 1 - lost, 2 - won }
{ initialize - initializes the global variables and the mine field }
procedure initialize;
var i, j: integer;
width, height: integer;
begin
{ initialize the cursor position }
xPos := 1;
yPos := 1;
{ load the images }
for i:=1 to 12 do
begin
imageArray[i] := loadImage('/' + i + '.png');
end;
{ calculate the width and height of the field }
cellSize := getImageWidth(imageArray[1]);
fieldWidth := getWidth / cellSize;
fieldHeight := getHeight / cellSize;
if fieldWidth > maxWidth then fieldWidth := maxWidth;
if fieldHeight > maxHeight then fieldHeight := maxHeight;
xDelta := (getWidth - fieldWidth*cellSize) / 2;
yDelta := (getHeight - fieldHeight*cellSize) / 2;
numOfMines := fieldWidth * fieldHeight * minesDensity / 100;
gameStatus := 0;
{ initialize the game field }
for i:=1 to fieldWidth do
for j:=1 to fieldHeight do
mineField[i,j] := 0;
{ place the mines }
for i:=1 to numOfMines do
begin
width := random(fieldWidth) + 1;
height := random(fieldHeight) + 1;
if (mineField[width,height] <> 0)
or ((width = 1) and (height = 1)) then
i := i - 1;
else
mineField[width,height] := 1;
end;
{ calculate the number of surronding mines for each cell }
for i:=1 to fieldWidth do
for j:=1 to fieldHeight do
begin
if ((mineField[i,j] mod 10) mod 2) = 1 then
begin
if i>1 then
mineField[i-1,j] := mineField[i-1,j] + 10;
if i<fieldWidth then
mineField[i+1,j] := mineField[i+1,j] + 10;
if j>1 then
mineField[i,j-1] := mineField[i,j-1] + 10;
if j<fieldHeight then
mineField[i,j+1] := mineField[i,j+1] + 10;
if (i>1) and (j>1) then
mineField[i-1,j-1] := mineField[i-1,j-1] + 10;
if (i<fieldWidth) and (j>1) then
mineField[i+1,j-1] := mineField[i+1,j-1] + 10;
if (i<fieldWidth) and (j<fieldHeight) then
mineField[i+1,j+1] := mineField[i+1,j+1] + 10;
if (i>1) and (j<fieldHeight) then
mineField[i-1,j+1] := mineField[i-1,j+1] + 10;
end;
end;
end;
{ game over - returns true if the game is over and sets the
global game success code }
function gameOver: boolean;
var i,j:integer;
begin
gameStatus := 2;
for i:=1 to fieldWidth do
for j:=1 to fieldHeight do
begin
{ if a cell is open and it contains a mine, the player lost }
if ((((mineField[i,j] mod 10) mod 4)div 2) = 1)
and (((mineField[i,j] mod 10) mod 2) = 1) then
begin
gameStatus := 1;
{ these two commands act as break }
i := fieldWidth - 1;
j := fieldHeight - 1;
end;
{ if a cell is not open, but it does not contain a mine, the game is still on }
if (not (((mineField[i,j] mod 10) mod 2) = 1))
and not((((mineField[i,j] mod 10) mod 4)div 2) = 1)
and (gameStatus <> 1)
then
gameStatus := 0;
end;
if gameStatus = 0 then
gameOver := false;
else
gameOver := true;
end;
{ drawField - draws the current state of the field on the screen }
procedure drawField;
var i, j : integer;
imageIndex : integer;
text : string;
x, y, width, height : integer;
begin
{ clear the screen }
setColor(0, 0, 0);
fillRect(0, 0, getWidth, getHeight);
{ draw all the elements }
for i:=1 to fieldWidth do
for j:=1 to fieldHeight do
begin
{ if the element is open }
if (((mineField[i,j] mod 10) mod 4)div 2) = 1 then
begin
{ if it contains the mine }
if ((mineField[i,j] mod 10) mod 2) = 1 then
imageIndex := 11;
else
imageIndex := mineField[i,j] div 10;
if imageIndex = 0 then imageIndex := 10;
end;
else { the element is not open }
begin
{ if the non opened elemet is marked as a mine }
if ((mineField[i,j] mod 10) div 4) = 1 then
imageIndex := 12;
else
imageIndex := 9;
end;
drawImage(imageArray[imageIndex], (i-1)*cellSize + xDelta, (j-1)*cellSize + yDelta);
end;
{ draw the rectangle around the selected cell }
setColor(0, 0, 255);
drawRect((xPos-1)*cellSize + xDelta, (yPos-1)*cellSize + yDelta, cellSize, cellSize);
drawRect((xPos-1)*cellSize + xDelta + 1, (yPos-1)*cellSize + yDelta + 1, cellSize-2, cellSize-2);
if gameStatus = 1 then
begin
setColor(63, 0, 0);
text := 'You lost the game';
end;
if gameStatus = 2 then
begin
setColor(0, 63, 0);
text := 'You won!';
end;
{ print the game status inside a rectangle }
if gameStatus <> 0 then
begin
setFont(FONT_FACE_SYSTEM, FONT_STYLE_BOLD, FONT_SIZE_MEDIUM);
width := getStringWidth(text) + 6;
height := getStringHeight(text) + 6;
x := (getWidth - width)/2;
y := (getHeight - height)/2;
drawRect(x, y, width, height);
drawRect(x+1, y+1, width-2, height-2);
setColor(getColorRed*2, getColorGreen*2, 0);
fillRect(x+2, y+2, width-3, height-3);
setColor(255, 255, 255);
drawText(text, x+3, y+3);
end;
repaint;
end;
{ openEmptyMine - recursively opens all surrounding empty mines }
procedure openEmptyMine(x,y: integer);
begin
if ((mineField[x, y] mod 10) mod 4) div 2 = 0 then
begin
mineField[x, y] := mineField[x, y] + 2;
{ if the current mine field is labeled 0, open it }
if mineField[x,y] < 10 then
begin
{ open all surrounding fields }
if x>1 then
openEmptyMine(x-1, y);
if x<fieldWidth then
openEmptyMine(x+1, y);
if y>1 then
openEmptyMine(x, y-1);
if y<fieldHeight then
openEmptyMine(x, y+1);
if (x>1) and (y>1) then
openEmptyMine(x-1, y-1);
if (x<fieldWidth) and (y>1) then
openEmptyMine(x+1, y-1);
if (x<fieldWidth) and (y<fieldHeight) then
openEmptyMine(x+1, y+1);
if (x>1) and (y<fieldHeight) then
openEmptyMine(x-1, y+1);
end;
end;
end;
{ openMine - opens the mine that contains the cursor and opens all
surrounding empty cells }
procedure openMine(x, y: integer);
begin
if ((mineField[x, y] mod 10) mod 4) div 2 = 0 then
begin
if mineField[x,y] < 10 then
openEmptyMine(x,y);
else
mineField[x, y] := mineField[x, y] + 2;
end;
end;
{ playGame - the main game loop }
procedure playGame;
var mineCommand, quitCommand, clickedCommand : command;
keyAction : integer;
begin
mineCommand := createCommand('*', CM_SCREEN, 1);
quitCommand := createCommand('Exit', CM_EXIT, 1);
addCommand(mineCommand);
addCommand(quitCommand);
repaint;
repeat
{ read the key from the keypad }
keyAction := keyToAction(getKeyClicked);
if keyAction <> GA_NONE then
begin
if keyAction = GA_UP then
yPos := yPos - 1;
if keyAction = GA_DOWN then
yPos := yPos + 1;
if keyAction = GA_LEFT then
xPos := xPos - 1;
if keyAction = GA_RIGHT then
xPos := xPos + 1;
if xPos < 1 then xPos := 1;
if yPos < 1 then yPos := 1;
if xPos > fieldWidth then xPos := fieldWidth;
if yPos > fieldWidth then yPos := fieldWidth;
if keyAction = GA_FIRE then
openMine(xPos, yPos);
drawField;
end;
{ read the pressed command }
clickedCommand := getClickedCommand;
if clickedCommand = mineCommand then
begin
if ((mineField[xPos, yPos] mod 10) div 4) = 1 then
mineField[xPos, yPos] := mineField[xPos, yPos] - 4;
else
mineField[xPos, yPos] := mineField[xPos, yPos] + 4;
drawField;
end;
until gameOver or (clickedCommand = quitCommand);
drawField;
removeCommand(mineCommand);
removeCommand(quitCommand);
end;
{ showWelcomeScreen - displays the game info screen }
procedure showWelcomeScreen;
var
textToDisplay : string;
textXPos : integer;
textYPos : integer;
begin
setColor(255, 255, 255);
fillRect(0, 0, getWidth, getHeight);
setColor(0, 0, 255);
setFont(FONT_FACE_PROPORTIONAL, FONT_STYLE_BOLD, FONT_SIZE_LARGE);
textToDisplay := 'Minesweeper';
textXPos := (getWidth - getStringWidth(textToDisplay)) div 2;
textYPos := (getHeight - getStringHeight(textToDisplay)) / 2;
drawText(textToDisplay, textXPos, textYPos);
textYPos := textYPos + getStringHeight(textToDisplay);
setColor(0, 0, 0);
setFont(FONT_FACE_PROPORTIONAL, FONT_STYLE_PLAIN, FONT_SIZE_SMALL);
textToDisplay := 'Created with MIDletPascal';
textXPos := (getWidth - getStringWidth(textToDisplay)) div 2;
drawText(textToDisplay, textXPos, textYPos);
textYPos := textYPos + getStringHeight(textToDisplay);
repaint;
end;
begin
showWelcomeScreen;
repeat
until getKeyClicked <> KE_NONE;
repeat
initialize;
drawField;
playGame;
if gameStatus <> 0 then
begin
quit := createCommand('OK', CM_OK, 1);
addCommand(quit);
repaint;
repeat
clicked := getClickedCommand;
until clicked <> emptyCommand;
removeCommand(quit);
end;
showWelcomeScreen;
quit := createCommand('Exit', CM_EXIT, 1);
play := createCommand('Play', CM_OK, 1);
addCommand(quit);
addCommand(play);
repaint;
repeat
clicked := getClickedCommand;
until clicked <> emptyCommand;
removeCommand(quit);
removeCommand(play);
until clicked = quit;
end.