Obrigado a Julio Marchi pelo espaço cedido na MSX All
 

Curso de Jogos


 

Minesweeper
Basic

English


1. Introdução
  Essa versão tem como objetivo apresentar uma versão mais simples do jogo feita em Basic, com as rotinas principais do jogo.


2. A criação do mapa da mina
  O programa a seguir cria um mapa de 8x8 das minas, sorteia a posição das 10 minas e por fim notifica os vizinhos da presenças das bombas.

5 ' MarMSX 2018
10 COLOR15,1,1:SCREEN0:WIDTH40:KEYOFF
20 DIM MA$(8,8)
30 GOSUB 500:GOSUB 800
40 END
500 '
501 ' Cria minas
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 ' Limpa minas 
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 ' Mapa da vizinhanca
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 ' Notifica vizinhos
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 ' Imprime mapa
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

  O capítulo 4 do manual de desenvolvimento do jogo explica como esse mapa é criado.


3. A criação do mapa do usuário
  Nessa nova etapa, o mapa do usuário "MU" é criado para indicar quais as coordenadas do mapa o usuário já abriu.
  A regra de impressão é a seguinte: caso não tenha aberto uma determinada coordenada do mapa, imprime o caractere "."; caso haja uma bandeira, imprime o caractere "+"; por fim, imprime a informação de acordo com o mapa do jogo "MA$".
  Para imprimir o mapa inicial do jogo, podemos inserir direto o caractere ".". Conforme o usuário vai abrindo o mapa, seguiremos a regra acima.

5 ' MarMSX 2018
10 COLOR15,1,1:SCREEN0:WIDTH40:KEYOFF
20 DIM MA$(8,8):DIM MU(8,8)
...
600 '
601 ' Limpa minas 
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 ' Imprime mapa
802 '
810 FOR X=16 TO 23:FOR Y=2 TO 9
820 LOCATE X,Y:PRINT"."
830 NEXT Y,X
840 RETURN

  Valores de MU:
  • 0 - local ainda não aberto.
  • 1 - local aberto.
  • 2 - local sinalizado com bandeira.


4. O controle principal do jogo
  Essa rotina irá controlar as ações do jogador.

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 ' Imprime posicao
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. Verificação de fim de jogo
  Quando o usuário abre um local do mapa, se nesse local há uma mina, ela estoura e o jogo termina. Entretanto, se todos os espaços que não são minas são abertos, o jogo termina com a vitória do jogador.

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 ' Verifica o fim do jogo
902 '
910 IF MA$(CX-15,CY-1)="*" THEN LOCATE 0,12:PRINT"Voce estourou uma bomba. Fim de 
jogo.":END
920 IF LA>53 THEN LOCATE 0,12:PRINT"Parabens. Voce limpou as minas.":END
930 RETURN

  Um pequeno truque permite verificar se todas os locais "limpos" do jogo foram abertos: basta contar as casas limpas abertas e quando atingir o valor de 54, o jogo termina com vitória para o jogador.

  Dica: para verificar o funcionamento do código, adicione a seguinte linha e veja o mapa do jogo:
825 LOCATE X-16,Y+10:PRINT MA$(X-15,Y-1)


6. Incrementando o jogo: flood-fill
  O algoritmo de flood-fill pode ser utilizado para abrir as casas vazias automaticamente.
  Uma vez que o Basic não possui chamadas à funções como no Pascal e C, vamos utilizar o flood-fill com pilha.

  Pseudo-código para vizinhança de 4:
var pilha : vetor [1..M, 1..N] de inteiro;
    p : inteiro;

procedimento flood_fill(x, y : inteiro)
inicio
  p ← 0;
  empilha(x,y);

  enquanto (p>0)
    desempilha();
    se teste_condicao(X,Y) = verdadeiro então
      faz_algo();
      empilha(x+1,y);
      empilha(x-1,y);
      empilha(x,y+1);
      empilha(x,y-1);
    fim_se
  fim_enquanto

fim_procedimento

  Mudanças no jogo com flood-fill de 8 vizinhos:
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: ' Salva CY e CY
1020 P=P+1:S(P,1)=CX:S(P,2)=CY: ' Empilha
1030 CX=S(P,1):CY=S(P,2):P=P-1: ' Desempilha 
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: ' Se local abbreto, salta
1050 MU(CX-15,CY-1)=1:GOSUB 850:LA=LA+1: ' Abre local
1060 IF MA$(CX-15,CY-1)<>"0" THEN 1110: ' Se local não for "0", salta
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

  Nota: embora estejamos abrindo o local corrente incondicionalmente, somente espalhamos novas coordenadas se o local atual for "0".


7. O jogo completo
  Controle:
  • Cursores: navegam pelo mapa.
  • Espaço: abre local sob o cursor.
  • Enter: marca/desmarca local com bandeira.
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 ' Cria minas
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 ' Limpa minas 
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 ' Mapa da vizinhanca
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 ' Notifica vizinhos
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 ' Imprime mapa
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 ' Imprime posicao
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 ' Verifica o fim do jogo
902 '
910 IF MA$(CX-15,CY-1)="*" THEN LOCATE 0,12:PRINT"Voce estourou uma bomba. Fim 
de jogo.":END
920 IF LA>53 THEN LOCATE 0,12:PRINT"Parabens. Voce limpou as minas.":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
Engenheiro de Sistemas e Computação
Especialista em Processamento de Imagens e Inteligência Artificial
© MarMSX 1999-2024