Enviar um café pro programador

Pode me ajudar a transformar cafeína em código?

Campo Minado em Java: código comentado

Vamos agora explicar, em detalhes, como fazer, entender e programar toda a lógica de um campo minado na linguagem de programação Java.

O código do jogo se encontra em nosso artigo passado de nosso curso online de Java:
Jogo: Campo Minado em Java


Dividimos o jogo em 3 classes, a 'campoMinado' que simplesmente contém a main e cria um objeto do tipo 'Jogo', temos a classe 'Jogo' que irá ministrar toda a lógica e fluxo do jogo e finalmente a classe 'Tabuleiro', que irá gerar os tabuleiros (de minas e visualização) bem como os métodos que lidam com os tabuleiros.

Campo Minado em Java: A classe Tabuleiro.java

Essa classe é a responsável pelo tabuleiro e os métodos que o envolvem.
Na verdade, vamos lidar com dois tabuleiros:

- int[][] minas
Esse tabuleiro é inicialmente preenchido com números '0', através do método 'iniciaMinas()'.

Após isso, vamos sortear 10 locais para colocar as minas, através do método 'sorteiaMinas()'. Nos locais onde existirem minas, vamos colocar o inteiro '-1'.
Esse método sorteia dois números inteiros, entre 1 e 8, através do uso da classe Random. Vamos fazer isso com um looping do while, que a cada iteração vai checar se naquela posição sorteada já existe o número '-1'. Se aquele local já tiver sido sorteado, o booleano 'sorteado' ficará como true e o looping irá se repetir, até que tenhamos 10 locais diferentes com o número '-1'.

Depois disso, vamos preencher as dicas, ou seja, vamos colocar em cada bloco desse tabuleiro o número de minas que existem ao redor.
Assim, se uma posição do tabuleiro tiver o número '2', é porque existem duas minas ao redor daquele bloco.
Fazemos isso apenas contando quantas bombas existem ao redor de cada bloco.
Criamos, na verdade, uma matriz 10x10, onde não usaremos a linha 0 nem a linha 9, bem como a coluna 0 e a coluna 9. Por que isso?
Para que, ao calcular quantas bombas existem na vizinhança, apenas contemos quantas bombas existem nos 8 locais ao redor. Isso é necessário pois se usássemos um tabuleiro 8x8, as casas da borda não teriam 8 vizinhos.

Para checar as bombas ao redor, usamos dois laços for:
for(int i=-1 ; i<=1 ; i++)
    for(int j=-1 ; j<=1 ; j++)

Se queremos checar quantas bombas há ao redor do bloco: mines[linha][coluna], colocamos dentro desses laços:
mines[linha+i][coluna+j]
Esses dois laços irão percorrer os 8 locais ao redor do bloco mines[linha][coluna].
Porém, só vamos checar os arredores se o local em questão não tiver uma mina:
if(minas[line][column] != -1)

Após checado isso, checamos se existe mina na posição ao redor, e se tiver, incrementamos o local do tabuleiro 'minas', pois ele também recebe o número de minas ao redor:
if(minas[line+i][column+j] == -1)
    minas[line][column]++;

Pronto. Agora temos um tabuleiro 10x10, mas usaremos só o 8x8, e nesse tabuleiro 'interno' temos 10 minas e todos os blocos que não são minas armazenarão quantas minas existem ao seu redor.


- char[][] tabuleiro
É um tabuleiro de caracteres, inicialmente carregado com underline '_' através do método 'iniciaTabuleiro()', isso quer dizer que esse campo ainda não foi escolhido.
Temos ainda o método 'exibe()', que simplesmente exibe todo esse tabuleiro de caracteres de maneira formatada.

O método 'exibeMinas()' coloca um asterisco, '*', em todos os locais onde existem minas. Este método serve para mostrar onde existia minas e será acionado quando o jogador perder a partida.


Fazendo uma jogada:
A jogada é feita através do método 'setPosicao()', que retorna 'true' caso você perca (ou seja, caso exista uma mina onde você jogou) e 'false', caso não exista uma mina no local que você escolheu.
Devemos deixar esse método bem robusto, nos certificando que o jogador não entre com números fora do espero (ou seja, maior que 8 ou menor que 1):
(linha < 1 || linha > 8 || coluna < 1 || coluna > 8)

Bem como checar se já o local ele jogou já tenha sido escolhido antes.
(tabuleiro[linha][coluna] != '_') 

Ainda no método 'setPosicao()', usamos o método 'getPosicao()', que retorna o que existe no bloco quando passamos a linha e a coluna. Caso existe '-1' é porque existe mina, retorna 'true' e o jogo acaba. Caso exista qualquer outro número, o método retorna 'false' e o jogo não acaba.

Após jogar, vamos checar se o jogador ganhou através do método 'ganhou()', que simplesmente conta quantos blocos ainda não foram exibidos, ou seja, quantos underlines existem. Caso existam somente 10, é porque os blocos que sobraram foram justamente os que continham minas, o método retorna 'true' e o jogador ganha. Caso tenha mais de 10, é porque ainda não terminou e retorna 'false'.

Outro método importante, e talvez o mais complicado, é o 'exibirVizinhas()', que vai checar todas as casas vizinhas, no tabuleiro de minas, exceto se essas vizinhas estejam localizadas nas linhas 0 ou 9, ou nas colunas 0 ou 9. Durante a checagem, vamos checar se a vizinha possui uma mina, e caso não possua vamos exibir essa casa no tabuleiro de caracteres:
for(int i=-1 ; i<2 ; i++)
    for(int j=-1 ; j<2 ; j++)
if( (minas[linha+i][coluna+j] != -1) && (linha != 0 && linha != 9 && coluna != 0 && coluna != 9) )
tabuleiro[linha+i][coluna+j]=Character.forDigit(minas[linha+i][coluna+j], 10);

Note que usamos o método 'Character.forDigit(int num,int base)', que recebe um inteiro que representa um número e sua base.
O que esse método faz é pegar um número e transformar em caractere. No nosso caso, os número estão na base decimal (por isso o 10) e esses números nada mais são que os inteiros do tabuleiros de minas. Ou seja, estamos colocando números no tabuleiro de caracteres.


Campo Minado em Java: A classe Jogo.java

Essa classe começa com o construtor padrão criando um tabuleiro, o 'board' e chama o método que irá controlar o jogo, o 'Jogar', que recebe o objeto 'board', do tipo Tabuleiro.

O jogo, como de praxe, é controlado por um laço do while, que só termina quando o booleano 'terminar' for verdadeiro.
Esse booleano só se torna 'true' se o método 'setPosicao()' retornar true, dizendo que encontramos uma mina, ou quando o método 'ganhou()' retornar true, dizendo que o jogador ganhou, pois só restavam 10 blocos no jogo.

Usamos o inteiro 'rodada', que irá contar quantas rodadas o jogo teve.
A jogada é feita em:
terminar = board.setPosicao();

Caso não tenhamos atingido uma mina:
if(!terminar)

Vamos abrir os blocos vizinhos desse bloco que escolhemos na 'setPosicao()' para ver as dicas, isso ocorre em:
board.abrirVizinhas();

Após aberto as casas vizinhas, pode ser que o jogador tenha ganhado, fazemos isso checando:
terminar = board.ganhou();

Quanto o jogo terminar, ou seja, quando o aplicativo sair do laço do while, vamos mostrar a mensagem de parabéns ou de perda.

Quando o método 'ganhou()' retorna true é porque o jogador ganhou, então exibimos uma mensagem de parabéns bem como em quantas rodadas ele venceu:
if(board.ganhou()){
System.out.println("Parabéns, você deixou os 8 campos de minas livres em "+rodada+" rodadas");
board.exibeMinas();
}

Ora, se não retorna true no condicional if, o else vai ser o caso em que ele tenha perdido. Então dizemos que ele perdeu e mostramos onde havia minas através do método 'exibeMinas()'.

3 comentários:

Anônimo disse...

Mt massa!

Anônimo disse...

Muito bom , parabéns!

Unknown disse...

Excelente o programa, estava criando um e me deparei com esse tutorial que salvou minha pele! estou tentando criar ele em cima usando o swing do java (Jpanel), vocês tem alguma dica para me ajudar?

Contribuir com o Java Progressivo

Que tal apoiar e fazer crescer o ensino da programação no Brasil ?

Ajudar nosso país a crescer e se desenvolver cada vez mais, tecnologicamente?

Clica abaixo pra saber mais!

Apoiar o Projeto Progressivo


Tutoriais de Java