Campo Minado em Pascal

Iniciado por black0ut, 18 de Julho , 2008, 07:53:25 PM

tópico anterior - próximo tópico

0 Membros e 1 Visitante estão vendo este tópico.

black0ut

Falaí povo. Me registrei faz um tempinho mas nunca postei. Resolvi então compartilhar o source de um trabalho meu pra facul. Tou no primeiro ano de Ciências da Computação e esse aqui foi um trabalho que eu tive que fazer. Foi feito em Pascal (diagmos que é a versão não gráfica de Delphi), e justamente por nao ter GUI, foi foda de fazer. O programa deveria dar a opção de salvar e abrir um novo jogo, mas ele não abre com sucesso (tá dando erro quando vai gerar a matriz a partir dos dados armazenados no arquivo de salvamento). Quem quiser fuçar, fica à vontade.

 Pra compilar, eu recomendo o Dev Pascal. O Turbo ou mesmo o Free Pascal também compilam, mas precisa fazer algumas modificações no source porque eles não aceitam procedures sem declaração de parâmetros. Fora que são feios aiwuewaiueh

 Tá aí o source:


{

            Campo Minado (Tr.2)


}





program campominado;

uses crt;





type matriz = array[1..100,1..100] of char;   {servira para guardar os chars do campo grafico}
     reg = record
         stat:boolean;              {verdadeiro se a casa ja tiver sido visitada}
         tembomba:boolean;          {verdadeiro se a casa contiver uma bomba}
         tembandeira:boolean;       {verdadeiro se a casa contiver uma bandeira}
         lin,col:integer;           {contem o numero de linhas e colunas do campo (especificado pelo usuario, facilita salvamento e recuperacao)}
         numero:integer;            {se uma casa for selecionada e um numero for escrito, este numero e guardado aqui}
         difi:integer               {guarda a dificuldade escolhida pelo usuario}
         end;
     matrizc = array[1..100,1..100] of reg;     {matriz que formara a base de dados do campo}
     arq = file of matrizc;                      {arquivo para manipulacao de jogos salvos}


var cmd: char;
    camp: matrizc;








procedure perdeu();
begin
     Textbackground(black);
     clrscr;
     gotoxy(18,8);
     TextColor(white);
     writeln('Voce Perdeu x(');
     Textbackground(White);
     Textbackground(black);
     delay(2000);
     halt;
     gotoxy(1,1);

end;


procedure venceu();
begin
     clrscr;
     gotoxy(18,8);
     TextColor(green);
     writeln('Voce Venceu x)');
     TextColor(black);
     delay(2000);
     halt;
     gotoxy(1,1);
end;



{Procedimento da tecla X}

procedure bandeira(Xa,Ya,totalminas:integer;var campo:matrizc;var contaband:integer);
begin
     if (campo[Xa,Ya].stat=false) then          {verifica se a casa nao foi visitada antes}
        begin
             if (campo[Xa,Ya].tembandeira=false) then     {verifica se ja nao ha uma bandeira aqui}
             begin
                  campo[Xa,Ya].tembandeira:=true;
                  TextColor(green);
                  write('X');
                  TextColor(black);
                  gotoxy(Xa,Ya);
                  if (campo[Xa,Ya].tembomba=true) then contaband:=contaband+1;   {incrementa o contador de bandeiras CERTAS (se chegar no total (=total de casas - total de minas), o usuario ganha}
                  if (contaband=totalminas) then venceu();
             end
        else
        begin
             campo[Xa,Ya].tembandeira:=false;
             TextColor(black);
             write('0');                    {se a casa ja tiver bandeira, entao o programa a retira}
             contaband:=contaband-1;
             gotoxy(Xa,Ya);
        end;
     end;
end;


{Fim do Procedimento de bandeiras}




{Início dos procedimentos de movimento pelas teclas W, S, A, D}

{ Em cada movimento, o procedimento respectivo verifica se o cursor nao esta no limite do campo atraves das variaveis Xma, Xmi, Yma e Ymi}


procedure movecima(Xa,Ya,Ymi,Yma:integer);
begin
     Ya:=Ya-1;
     if (Ymi < Ya) and (Ya < Yma) then gotoxy(Xa,Ya);
end;



procedure movebaixo(Xa,Ya,Ymi,Yma:integer);
begin
     Ya:=Ya+1;
     if (Ymi < Ya) and (Ya <= Yma) then gotoxy(Xa,Ya);
end;


procedure movedireita(Xa,Ya,Xmi,Xma:integer);
begin
     Xa:=Xa-1;
     if (Xmi < Xa) and (Xa <= Xma) then gotoxy(Xa,Ya);
end;


procedure moveesquerda(Xa,Ya,Xmi,Xma:integer);
begin
     Xa:=Xa+1;
     if (Xmi < Xa) and (Xa <= Xma) then gotoxy(Xa,Ya);
end;

{Fim dos procedimentos de movimento}





{ Início do procedimento que cuida das detonações (tecla Z) }

procedure detonar(X,Y,Xmi,Xma,Ymi,Yma,li,co:integer;var contalivre:integer;totalminas:integer;var mapa:matrizc;nrecur:integer);
var numero,c1,c2,ponttotal:integer;

begin

     if(nrecur < 4) then                      {checa o fator de recursao do campo minado (quantas expansoes serao feitas a partir da casa atual)}
     begin
          nrecur:=nrecur+1;                  {incrementa o fator a cada vez que e executado}
          ponttotal:=(li*co)-totalminas;
          numero:=0;
          if (mapa[X,Y].stat=false) then             {verifica se a casa selecionada ja nao foi visitada antes}
          begin
               if (mapa[X,Y].tembandeira=false) then       {verifica se a casa nao tem bandeira}
               begin
                    if (mapa[X,Y].tembomba=true) then        {se tiver bomba, o jogador perde}
                    begin
                         gotoxy(X,Y);
                         TextColor(Red);
                         write('@');
                         TextColor(black);
                         gotoxy(X,Y);
                         perdeu();
                    end
               else
               begin
                    if (mapa[Y,X].stat=false) then
                    begin
                         for c1:=-1 to 1 do         {o programa roda em torno da casa selecionada para verificar se ha bombas. Se nao houver, abre
                                                      as casas. Se houver, nao as abre e incrementa o contador que determinara o numero que sera escrito
                                                      na casa selecionada}
                         begin
                              for c2:=-1 to 1 do
                              begin
                                   if (c1<>0) or (c2<>0) and (X+c1 < Xma) or (X+c1 > Xmi) and (Y+c2 > Ymi) or (Y+c2 < Yma) then
                                   begin
                                        if (mapa[X+c1,Y+c2].tembandeira=false) then
                                        begin
                                             if (mapa[X+c1,Y+c2].tembomba=true) then   {se tiver bomba, incrementar o contador}
                                             begin
                                                  numero:=numero+1;
                                                  gotoxy(X,Y);
                                                  end
                                                  else
                                                  begin
                                                  if (mapa[X+c1,Y+c2].stat=false) then     {se a casa perimetral nao tiver sido visitada, mexer com ela}
                                                  begin
                                                       gotoxy(X+c1,Y+c2);
                                                       write(' ');
                                                       contalivre:=contalivre+1;
                                                       detonar(X+c1,Y+c2,Xmi,Xma,Ymi,Yma,li,co,contalivre,totalminas,mapa,nrecur);  {ativar a recursividade para expansao}
                                                       mapa[X+c1,Y+c2].stat:=true;
                                                       gotoxy(X,Y);
                                                  end;
                                             end;
                                        end;
                                   end;
                              end;
                         end;
                         if numero<>0 then      {se houver bombas ao redor da casa, o contador sera positivo. Neste caso, escrever o numero.}
                         begin
                              gotoxy(X,Y);
                              TextColor(Red);
                              write(numero);
                              TextColor(Black);
                              contalivre:=contalivre+1;    {incrementar o contador de acertos}
                              mapa[X,Y].stat:=true;
                              mapa[X,Y].numero:=numero;      {gravar o numero escrito nesta casa, para o salvamento do jogo}
                              gotoxy(X,Y);
                         end
                         else
                         begin
                              gotoxy(X,Y);
                              write(' ');
                              contalivre:=contalivre+1;        {se o contador = 0, nao escrever nada na casa}
                              gotoxy(X,Y);
                              mapa[X,Y].stat:=true;
                         end;
                    end;
               end;
          end;
     end;
     ponttotal:=(li*co)-totalminas;      {verifica se o usuario ja ganhou o jogo neste lance}
     if (contalivre=ponttotal) then
     clrscr
     ;
    end
    else
    gotoxy(X,Y);
    ;

end;



{Fim do procedimento das detonações}






{Inicio do procedimento da tecla K}

procedure sair(campo:matrizc);
var resposta,extensao,nomearq,inicio:string;
    arquivo:arq;
    c1,c2:integer;
begin
     clrscr;
     readln(c1);readln(c2);
     writeln(campo[c1,c2].stat);
     inicio:='C:\';
     extensao:='.cm';
     write('Deseja salvar o jogo? (sim/nao) '); readln(resposta);
     if (upcase(resposta)='SIM') or (upcase(resposta)='S') then
     begin
          writeln;
          writeln;
          write('Digite o nome do jogo a ser salvo: '); readln(resposta);   {sera o nome do arquivo}
          nomearq:=concat({inicio,}resposta,extensao);                      {junta o nome do arquivo a extensao do jogo. Aqui, eu comentei o nome do drive para que os arquivos sejam criados no mesmo diretorio.}
          assign(arquivo,nomearq);                                        {cria o handle}
          rewrite(arquivo);                                               {apaga quaisquer jogos com o mesmo nome e cria um nobo arquivo}
          write(arquivo,campo);                                           {armazena os dados do campo no arquivo}
          writeln;
          writeln;
          close(arquivo);                                                 {fecha o arquivo}
          writeln;
          writeln;
          writeln('Jogo salvo com sucesso. Pressione qualquer tecla para sair');
          readkey;
          halt;                                                         {sai do programa}
     end
     else
     halt
     ;


end;









{Procedimento de coordenação do andamento do jogo pela captura das teclas.}

procedure jogar(li,co,totalminas,diff:integer;mapa:matrizc); {co e li são usadas para determinar o valor máximo das posições X e Y para os quais
                                   o usuário pode mover-se. O valor é passado do procedimento que gera o campo minado
                                   para que possa ser enviado para os procedimentos de movimento, e lá ser usado por ele
                                   para limitar o movimento dentro do campo. }

var tecla: char;
    xmi,xma,ymi,yma,contaband,contalivre,nini:integer; {variáveis de x e y máximo e mínimos. Serão usadas para passar informações aos procedimentos de movimento.
                                        contaband e a variavel que cuida do controle de bandeiras certas, para garantir vitoria caso todas as minas
                                        sejam cobertas. Contalivre faz o mesmo com as casas livres.}
    sempre:boolean;  {garante que as teclas sempre serão detectadas}

begin
     nini:=1;
     contaband:=0;
     contalivre:=0;
     sempre:=true;

     xma:=WhereX;  {detecta a posição máxima do eixo X, pois neste momento o campo acabou de ser gerado e escrito}
     xmi:=xma-li;  {calcula a posição mínima do mesmo eixo}
     yma:=WhereY;  {detecta a posição máxima do eixo Y, pois neste momento o campo acabou de ser gerado e escrito}
     ymi:=yma-co;  {calcula a posição mínima do mesmo eixo}

     gotoxy(xmi-18,yma+5);
     writeln('Z: testar posicao  |  X: colocar bandeira  |  K: sair e salvar');
     gotoxy(xmi-9,ymi+5);
     write('W');
     gotoxy(xmi-9,ymi+6);
     write('S');
     gotoxy(xmi-7,ymi+6);
     write('A');
     gotoxy(9,ymi+6);
     write('D');

     gotoxy(xma,yma);

     while(sempre) do
     begin
          tecla:=readkey;
          case upcase(tecla) of
          'W'  : movecima(WhereX,WhereY,ymi,yma);
          'S'  : movebaixo(WhereX,WhereY,ymi,yma);                         {Chama os procedimentos referentes a cada tecla}
          'A'  : movedireita(WhereX,WhereY,xmi,xma);
          'D'  : moveesquerda(WhereX,WhereY,xmi,xma);

          'Z'  : detonar(WhereX,WhereY,xmi,xma,ymi,yma,li,co,contalivre,totalminas,mapa,nini);
          'K'  : sair(mapa);
          'X'  : bandeira(WhereX,WhereY,totalminas,mapa,contaband);
          end;
  end;
end;






{Início do procedimento que gera o campo minado.}

procedure geramina(mapa:matrizc;linhas,colunas,diff:integer);
var c1,c2,cont1,cont2,li,co,total,minas: integer;
    campopro: matriz;
begin
     randomize;
     clrscr;
     writeln('Gerando campo minado...');
     total:=linhas*colunas*diff div 10;                      {total de minas a ser geradas, determinado pela dificuldade escolhida}
     writeln('Total de Casas: ',linhas*colunas);
     writeln('Minas a serem geradas: ',total);
     writeln('Linhas: ',linhas);
     writeln('Colunas: ',colunas);
     minas:=0;
     writeln;
     writeln('Pressione qualquer tecla para jogar.');
     for c1:=1 to 100 do
     begin
          for c2:=1 to 100 do
          begin
               mapa[c2,c1].stat:=false;                   { Esta parte reseta os dados da matriz, e ja armazena alguns dados novos (linhas, colunas, dificuldade)}
               mapa[c2,c1].tembomba:=false;
               mapa[c2,c1].tembandeira:=false;
               mapa[c2,c1].lin:=linhas;
               mapa[c2,c1].col:=colunas;
               mapa[c2,c1].difi:=diff;
          end;
     end;
     while (minas < total) do    {enquanto o número de minas não for alcançado, continuar gerando}
     begin
          li:=random(linhas)+6;                       {calcular uma coordenada para a mina, usando o fator de correcao 6, por causa da funcao gotoxy(20,5)}
          co:=random(colunas)+21;                     {o mesmo}
          if (mapa[co,li].tembomba=false) then        {checa se a posicao encontrada ja nao contem uma mina}
          begin
               mapa[co,li].tembomba:=true;
               minas:=minas+1;
          end
     end;
     readln;
     clrscr;
     TextColor(black);
     gotoxy(20,5);     { <---------------------------------- }
     for cont1:=1 to linhas do                        {gera e desenha o campo na tela}
     begin
          for cont2:=1 to colunas do
          begin
               campopro[cont2,cont1]:='0';            {a matriz grafica recebe os 0s que formam o campo grafico inicial}
          end;
     end;
     for cont1:=1 to linhas do
     begin
          for cont2:=1 to colunas do
          begin
               if (cont2 = colunas) then
               begin
                    gotoxy(20+cont2,5+cont1);
                    write(campopro[cont2,cont1]);
               end
               else
               begin
                    gotoxy(20+cont2,5+cont1);
                    write(campopro[cont2,cont1]);
               end;
          end;
     end;
     TextColor(black);
     gotoxy(20+cont2,5+cont1);

     jogar(colunas,linhas,total,diff,mapa);     {Comeca o jogo}


end;







 {Início do procedimento de novo jogo.}

procedure novojogo(var mapa:matrizc);
var diff, linhas, colunas: integer;
begin                                                        { A parte a seguir e referente a coleta de dados (opcoes do usuario)}
     clrscr;
     writeln;
     gotoxy(10,10);
     write('Determine a dificuldade desejada (1 a 8, ou 0 para default): '); readln(diff);
     if (diff < 1) or (diff > 8) then            {checa os limites}
     begin
          if (diff <> 0) then
          begin
               writeln('Dificuldade invalida!');
               readln;
               novojogo(mapa);
          end
          else
          begin
              writeln;
              diff:=2;       {se o valor for 0, foi escolhido default}
          end;
     end;
     clrscr;
     gotoxy(5,10);
     write('Determine o numero de linhas do campo (de 8 a 20, ou 0 para default): '); readln(linhas);
     if (linhas < 8) or (linhas > 20) then            {checa os limites}
     begin
          if (linhas <> 0) then
          begin
               writeln('O numero de linhas fornecido e invalido.');
               readln;
               novojogo(mapa);
          end
          else                                {se o valor for 0, foi escolhido default}
          begin
              writeln;
              linhas:=10;
          end;
     end;
     clrscr;
     gotoxy(5,10);
     write('Determine o numero de colunas do campo: (de 8 a 50, ou 0 para default): '); readln(colunas);
     if (colunas < 8) or (colunas > 50) then         {checa os limites}
     begin
          if (colunas <> 0) then
          begin
               writeln('O numero de colunas fornecido e invalido.');
               readln;
               novojogo(mapa);
          end
          else
          begin
              writeln;
              colunas:=10;                          {se o valor for 0, foi escolhido default}
          end;
     end;
     clrscr;
     geramina(mapa,linhas,colunas,diff);

end;

 {Fim do procedimento de novo jogo.}




 {Procedimento usado para abrir um jogo existente de um arquivo.}

procedure abrir();
var nome,extensao,nomefinal,inicio:string;
    arquivo:arq;
    armazena:matrizc;
    graf:matriz;
    c1,c2,linhas,colunas,minas,diff:integer;

begin
     clrscr;
     write('Escolheu abrir jogo salvo');
     readln;
     clrscr;
     extensao:='.cm';
     inicio:='C:\';
     write('Digite o nome do seu jogo: '); readln(nome);     {nome do jogo, que coincide com o nome do arquivo}
     nomefinal:=concat({inicio,}nome,extensao);
     writeln('Caminho do arquivo criado');
     assign(arquivo,nomefinal);
     writeln;
     writeln('Arquivo associado ao handle');
     reset(arquivo);
     writeln('Arquivo aberto com sucesso... carregando.');
     while not eof(arquivo) do
     begin
          read(arquivo,armazena);                        {armazena o conteudo do arquivo em uma nova matriz de registros}
          writeln;
          writeln('Leu o arquivo');
                                                        {pega o numero de linhas e colunas do campo salvo. Este dado esta presente em
                                                          todos os elementos da matriz de registros}
          linhas:=armazena[21,6].lin;
          colunas:=armazena[21,6].col;

          writeln('iniciando criacao grafica');
          writeln('linhas: ',linhas);
          writeln('colunas: ',colunas); readln;
          clrscr;
          TextColor(black);
          for c1:=1 to linhas do
          begin
               for c2:=1 to colunas do
               begin                                                     {Aqui, uma nova matriz grafica e preenchida de acordo com os dados do arquivo}
                    if (armazena[c1,c2].stat=false) then
                    graf[c1,c2]:='0'
                    ;
                    if (armazena[c1,c2].numero<>0) then
                    graf[c1,c2]:=chr(armazena[c1,c2].numero)
                    ;
                    if (armazena[c1,c2].tembandeira=true) then
                    graf[c1,c2]:='X';
                    ;
                    if (armazena[c1,c2].stat=true) then
                    graf[c1,c2]:=' ';
                    ;
                    if (armazena[c1,c2].tembomba=true) then
                    minas:=minas+1
                    ;
               end;
          end;
          for c1:=1 to linhas do
          begin
               for c2:=1 to colunas do
               begin
                    gotoxy(20+c2,5+c1);
                    write(graf[c2,c1]);
               end;
          end;
          TextColor(black);
          gotoxy(20+c1,5+c2);
          close(arquivo);
          jogar(colunas,linhas,minas,diff,armazena);               {chama o jogo}
     end;
end;

  {Fim do procedimento de arquivo.}







      {PROGRAMA PRINCIPAL}

begin
     randomize;
     Textbackground(white);
     Textcolor(black);
     clrscr;
     gotoxy(5,5);
     writeln('Pressione a tecla da funcao desejada: ');
     writeln;
     gotoxy(5,7);
     writeln('N - Novo Jogo');
     gotoxy(5,8);
     writeln('A - Abrir jogo salvo');
     cmd:=readkey;
     case upcase(cmd) of
     'N'  :   novojogo(camp);
     'A'  :   abrir();

     end;
end.
Regere Sanguine, Regere in Veritatem Est.