Thanks to Julio Marchi for this space in MSX All
 

Games Course


 

MSX Minesweeper
Basic

Portugues


1. Introduction
  On this version we focus on the game main routines. They were written in Basic for an easier understanding.

2. Mines map creation
  The following program creates an 8x8 game map, selects randomly the 10 mines locations and notifies all neighborhood about the mines.

5 ' MarMSX 2018
10 COLOR15,1,1:SCREEN0:WIDTH40:KEYOFF
20 DIM MA$(8,8)
30 GOSUB 500:GOSUB 800
40 END
500 '
501 ' Create mines
502 '
510 GOSUB 600
520 FOR M=1 TO 10
530 X=INT(8*RND(-TIME))+1
540 Y=INT(8*RND(-TIME))+1
550 IF MA$(X,Y)="*" THEN 530 ELSE MA$(X,Y)="*"
560 NEXT M
570 GOSUB 700:RETURN
600 '
601 ' Clear map
602 '
610 FOR X=1 TO 8:FOR Y=1 TO 8
620 MA$(X,Y)="0"
630 NEXT Y,X
640 RETURN
700 '
701 ' Neighborhood mapping
702 '
710 FOR X=1 TO 8:FOR Y=1 TO 8
720 IF MA$(X,Y)="*" THEN GOSUB 750
730 NEXT Y,X
740 RETURN
750 '
751 ' Notify neighbors
752 '
760 FOR VX=X-1 TO X+1:FOR VY=Y-1 TO Y+1
770 IF VX<1 OR VX>8 OR VYX<1 OR VY>8 THEN 780 ELSE IF MA$(VX,VY)="*" THEN 780
775 MA$(VX,VY)=RIGHT$(STR$(VAL(MA$(VX,VY))+1),1)
780 NEXT VY,VX
790 RETURN
800 '
801 ' Print map
802 '
810 FOR X=16 TO 23:FOR Y=2 TO 9
820 LOCATE X,Y:PRINT MA$(X-15,Y-1);
830 NEXT Y,X
840 RETURN

  The chapter 4 from the game development manual explains the game map process.


3. User map creation
  The next step creates an user's map "MU" to control the map coordinates opened by the user.
  The printing rules are the following: places not opened are printed as "."; if a flag is being used, print "+"; at last, print the information according to the game's map "MA$".
  For the first map printing, we may use "." directly. As soon the user opens a place, we print it using the rules above.

5 ' MarMSX 2018
10 COLOR15,1,1:SCREEN0:WIDTH40:KEYOFF
20 DIM MA$(8,8):DIM MU(8,8)
...
600 '
601 ' Clear map
602 '
610 FOR X=1 TO 8:FOR Y=1 TO 8
620 MA$(X,Y)="0":MU(X,Y)=0
630 NEXT Y,X
640 RETURN
...
800 '
801 ' Print map
802 '
810 FOR X=16 TO 23:FOR Y=2 TO 9
820 LOCATE X,Y:PRINT"."
830 NEXT Y,X
840 RETURN

  MU values:
  • 0 - place not opened.
  • 1 - place opened.
  • 2 - place with flag.


4. Game main loop
  This routine controls the player's actions.

40 CX=16:CY=2
50 LOCATE CX,CY:A$=INPUT$(1):A=ASC(A$)
60 IF A=29 THEN CX=CX-1:IF CX<16 THEN CX=16
70 IF A=28 THEN CX=CX+1:IF CX>23 THEN CX=23
80 IF A=30 THEN CY=CY-1:IF CY<2 THEN CY=2
90 IF A=31 THEN CY=CY+1:IF CY>9 THEN CY=9
100 IF A=13 THEN IF MU(CX-15,CY-1)<>1 THEN MU(CX-15,CY-1)=-(MU(CX-15,CY-1)=0)*2:
GOSUB 850
110 IF A=32 THEN IF MU(CX-15,CY-1)=0 THEN MU(CX-15,CY-1)=1:GOSUB 850
120 GOTO 50
...
850 '
851 ' Print current position
852 '
860 LOCATE CX,CY
870 IF MU(CX-15,CY-1)=0 THEN PRINT".":RETURN
875 IF MU(CX-15,CY-1)=2 THEN PRINT"+":RETURN
880 IF MA$(CX-15,CY-1)="0" THEN PRINT" " ELSE PRINT MA$(CX-15,CY-1)
890 RETURN


5. Check for the game ending
  Everytime the user opens a place on the map, if there is a mine, it blows up and the game is over. Thus, if all clean places on the map are opened, the player wins and the game ends.

40 CX=16:CY=2:LA=0
...
110 IF A=32 THEN IF MU(CX-15,CY-1)=0 THEN MU(CX-15,CY-1)=1:GOSUB 850:LA=LA+1:GOSUB900
...
900 '
901 ' Check game ending
902 '
910 IF MA$(CX-15,CY-1)="*" THEN LOCATE 0,12:PRINT"You found a bomb. Gave over."
:END
920 IF LA>53 THEN LOCATE 0,12:PRINT"Congratulations. You cleaned the area.":END
930 RETURN

  A little "trick" is applied to verify if all "clean" places were opend: we just count the number of opened places, and when the number 54 is reached, the player wins and game ends.

  Hint: in order to verify the code, add the following line to print also the game map:
825 LOCATE X-16,Y+10:PRINT MA$(X-15,Y-1)


6. Improving the game: flood-fill
  The flood-fill algorithm may be used to open some clear places automatically.
  Once the Basic has no function call like Pascal and C, let's make use of flood-fill with stack.

  The pseudo-code for a 4-neighbors flood-fill is:
var stack : array [1..M, 1..N] of integer;
    p : integer;

procedure flood_fill(x, y : integer)
begin
  p ← 0;
  push(x,y);

  while (p>0)
    pop();
    if test_condition(X,Y) = true then
      do_something();
      push(x+1,y);
      push(x-1,y);
      push(x,y+1);
      push(x,y-1);
    end_if
  end_while

end_procedure

  Game changes using 8-neighbors flood-fill:
20 DIM MA$(8,8):DIM MU(8,8):DEFINT S:DIM S(64,2)
...
110 IF A=32 THEN IF MU(CX-15,CY-1)=0 THEN GOSUB 1000:GOSUB900
...
1000 '
1001 ' Flood-fill
1002 '
1010 P=0:SX=CX:SY=CY: ' Store CY and CY
1020 P=P+1:S(P,1)=CX:S(P,2)=CY: ' Push
1030 CX=S(P,1):CY=S(P,2):P=P-1: ' Pop 
1040 IF CX<16 OR CX>23 OR CY<2 OR CY>9 THEN 1110
1045 IF MU(CX-15,CY-1)=1 THEN 1110: ' If open place, skip
1050 MU(CX-15,CY-1)=1:GOSUB 850:LA=LA+1: ' Open place
1060 IF MA$(CX-15,CY-1)<>"0" THEN 1110: ' If place not "0", skip
1070 P=P+1:S(P,1)=CX+1:S(P,2)=CY
1075 P=P+1:S(P,1)=CX+1:S(P,2)=CY+1
1080 P=P+1:S(P,1)=CX:S(P,2)=CY+1
1085 P=P+1:S(P,1)=CX-1:S(P,2)=CY+1
1090 P=P+1:S(P,1)=CX-1:S(P,2)=CY
1095 P=P+1:S(P,1)=CX-1:S(P,2)=CY-1
1100 P=P+1:S(P,1)=CX:S(P,2)=CY-1
1105 P=P+1:S(P,1)=CX+1:S(P,2)=CY-1
1110 IF P>0 THEN 1030: ' Do .. while P>0
1120 CX=SX:CY=SY:RETURN

  Note: although we open a place anyway, we spread new coordinates only if the current position is "0".


7. The whole game
  Control:
  • Cursors: navigates the map.
  • Space: open place under cursor.
  • Enter: mark/unmark place with a flag.
5 ' MarMSX 2018
10 COLOR15,1,1:SCREEN0:WIDTH40:KEYOFF
20 DIM MA$(8,8):DIM MU(8,8):DEFINT S:DIM S(64,2)
30 GOSUB 500:GOSUB 800
40 CX=16:CY=2:LA=0
50 LOCATE CX,CY:A$=INPUT$(1):A=ASC(A$)
60 IF A=29 THEN CX=CX-1:IF CX<16 THEN CX=16
70 IF A=28 THEN CX=CX+1:IF CX>23 THEN CX=23
80 IF A=30 THEN CY=CY-1:IF CY<2 THEN CY=2
90 IF A=31 THEN CY=CY+1:IF CY>9 THEN CY=9
100 IF A=13 THEN IF MU(CX-15,CY-1)<>1 THEN MU(CX-15,CY-1)=-(MU(CX-15,CY-1)=0)*2
:GOSUB 850
110 IF A=32 THEN IF MU(CX-15,CY-1)=0 THEN GOSUB 1000:GOSUB900
120 GOTO 50
500 '
501 ' Create mines
502 '
510 GOSUB 600
520 FOR M=1 TO 10
530 X=INT(8*RND(-TIME))+1
540 Y=INT(8*RND(-TIME))+1
550 IF MA$(X,Y)="*" THEN 530 ELSE MA$(X,Y)="*"
560 NEXT M
570 GOSUB 700:RETURN
600 '
601 ' Clear map
602 '
610 FOR X=1 TO 8:FOR Y=1 TO 8
620 MA$(X,Y)="0":MU(X,Y)=0
630 NEXT Y,X
640 RETURN
700 '
701 ' Neighborhood mapping
702 '
710 FOR X=1 TO 8:FOR Y=1 TO 8
720 IF MA$(X,Y)="*" THEN GOSUB 750
730 NEXT Y,X
740 RETURN
750 '
751 ' Notify neighbors
752 '
760 FOR VX=X-1 TO X+1:FOR VY=Y-1 TO Y+1
770 IF VX<1 OR VX>8 OR VY<1 OR VY>8 THEN 780 ELSE IF MA$(VX,VY)="*" THEN 780
775 MA$(VX,VY)=RIGHT$(STR$(VAL(MA$(VX,VY))+1),1)
780 NEXT VY,VX
790 RETURN
800 '
801 ' Print map
802 '
810 FOR X=16 TO 23:FOR Y=2 TO 9
820 LOCATE X,Y:PRINT"."
830 NEXT Y,X
840 RETURN
850 '
851 ' Print current position
852 '
860 LOCATE CX,CY
870 IF MU(CX-15,CY-1)=0 THEN PRINT".":RETURN
875 IF MU(CX-15,CY-1)=2 THEN PRINT"+":RETURN
880 IF MA$(CX-15,CY-1)="0" THEN PRINT" " ELSE PRINT MA$(CX-15,CY-1)
890 RETURN
900 '
901 ' Check game ending
902 '
910 IF MA$(CX-15,CY-1)="*" THEN LOCATE 0,12:PRINT"You found a bomb. Gave over."
:END
920 IF LA>53 THEN LOCATE 0,12:PRINT"Congratulations. You cleaned the area.":END
930 RETURN
1000 '
1001 ' Flood-fill
1002 '
1010 P=0:SX=CX:SY=CY
1020 P=P+1:S(P,1)=CX:S(P,2)=CY
1030 CX=S(P,1):CY=S(P,2):P=P-1
1040 IF CX<16 OR CX>23 OR CY<2 OR CY>9 THEN 1110
1045 IF MU(CX-15,CY-1)=1 THEN 1110
1050 MU(CX-15,CY-1)=1:GOSUB 850:LA=LA+1
1060 IF MA$(CX-15,CY-1)<>"0" THEN 1110
1070 P=P+1:S(P,1)=CX+1:S(P,2)=CY
1075 P=P+1:S(P,1)=CX+1:S(P,2)=CY+1
1080 P=P+1:S(P,1)=CX:S(P,2)=CY+1
1085 P=P+1:S(P,1)=CX-1:S(P,2)=CY+1
1090 P=P+1:S(P,1)=CX-1:S(P,2)=CY
1095 P=P+1:S(P,1)=CX-1:S(P,2)=CY-1
1100 P=P+1:S(P,1)=CX:S(P,2)=CY-1
1105 P=P+1:S(P,1)=CX+1:S(P,2)=CY-1
1110 IF P>0 THEN 1030
1120 CX=SX:CY=SY:RETURN


Marcelo Silveira
Systems and Computing Engineer
Expert in Image Processing and Artificial Intelligence
© MarMSX 1999-2024