Jogo: Batalha Naval em Java

Curso Java Progressivo - Como fazer o jogo Batalha Naval em Java
Agora que aprendemos como passar arrays (de qualquer dimensão) para métodos, já podemos fazer algo mais útil. Vamos fazer o famoso batalha naval, no modo texto.

Usaremos tudo que aprendemos até o momento em nosso curso de Java: if else, laço do while, laço for, métodos, números aleatórios, arrays, arrays multidimensionais e muita criatividade.

Regras do Jogo Batalha Naval em Java 

Há um tabuleiro de 5x5, ou seja, 25 blocos. Há 3 navios escondidos (um em cada bloco).
O objetivo do jogar é descobrir onde estão estes navios e acertá-los.
A cada tiro dado é dito se você acertou algum navio. Caso tenha errado, é dito quantos navios existem naquela linha e naquela coluna.
O jogo só acaba quando você descobrir e afundar os 3 navios.

Legenda pro usuário:
~ : água no bloco. Ainda não foi dado tiro.
* : tiro dado, não há nada ali.
X : tiro dado, havia um navio ali.

Como jogar:

A cada rodada, entre com dois números: o número da linha e o número da coluna onde quer dar o tiro.
Depois é só esperar pra ver se acertou, ou a dica.


Para os programadores Java:

O tabuleiro 5x5 é de inteiros. Ele é inicializado com valores '-1'.
A cada tiro ele é atualizado, dependendo se o usuário acertou ou errou. Esses números servirão para exibir '~', '*' ou 'X' para o usuário.
Também servirão para exibir as dicas.

Legenda do tabuleiro:

-1 : nenhum tiro foi dado naquele bloco (~)
 0 : o tiro foi dado e não havia nada (*)
 1 : o usuário atirou e tinha um navio lá (X)

Curso Java Progressivo - Como fazer o jogo Batalha Naval em Java

Métodos:

  • void inicializaTabuleiro(int[][] tabuleiro) - inicialmente coloca o valor -1 em todas as partes do tabuleiro
  • void mostraTabuleiro(int[][] tabuleiro) - recebe o tabuleiro de inteiros e os exibe
  • void iniciaNavios(int[][] navios) - esse método sorteia 3 pares de inteiros, que são a localização dos 3 navios
  • void darTiro(int[] tiro) - recebe um tiro (linha e coluna) do usuário, e armazena na variável tiro[]
  • boolean acertou(int[] tiro, int[][] navios) - checa se o tiro dado acertou um navio
  • void dica(int[] tiro, int[][] navios, int tentativa) - dá a dica de quantos navios existem naquela linha e naquela coluna onde o tiro foi dado
  • void alteraTabuleiro(int[] tiro, int[][] navios, int[][] tabuleiro) - após o tiro ser dado, o tabuleiro é alterado, mostrando o tiro que foi dado(se acertou ou errou)

Lógica do problema

Inicialmente, são criadas as variáveis 'tabuleiro[5][5]', que vai armazenar o tabuleiro do jogo, a variável 'navios[3][2]', que vai armazenar a posição (linha e coluna) dos 3 navios que estão escondidos no tabuleiro, a variável 'tiro[2]' que vai armazenar a posição (linha e coluna) do tiro que o jogador vai dar a cada rodada, além da variável 'tentativa', que vai armazenar o número de tentativas que o jogador fez até acertar os 3 navios e, por fim, a variável 'acertos' que contabiliza o número de navios que você acertou.

O método 'inicializaTabuleiro()' é acionado, pra criar o tabuleiro com o número '-1' em todas as posições.

Depois é o método 'iniciaNavios()', que vai sortear a posição de 3 navios (linha e coluna).
Esse método sorteia dois números, entre 0 e 4. Depois ele checa se esse número já saiu, pois não podem existir dois barcos na mesma posição.
Caso já tenha saído, entra num laço do...while que fica sorteando números, e só sai quando sorteia outro par de números que ainda não é a localização de um navio.


Após isso, na main(), vamos iniciar o jogo.
Os jogos geralmente se iniciam através de um laço do...while. No caso, a condição do while é 'acertos!=3'. Ou seja, enquanto você não acertar os 3 navios, o jogo não para.

A primeira coisa que ocorre no laço é mostrar o tabuleiro, através do laço 'mostraTabuleiro()'.
Esse método checa cada posição o 'tabuleiro'. Se for -1 ele exibe água, '~'. Se for 0, ele exibe o tiro que foi dado e errou '*', e se for 1, ele exibe 'X' que indica que você acertou um navio naquela posição.

Após mostrar o tabuleiro, você vai dar seu tiro, através do método 'darTiro()', que recebe dois inteiros.
Note que, o usuário vai digitar números de 1 até 5, pois ele conta de 1 até 5.
Você, como programador Java é que conta de 0 até 4.
Portanto, quando o usuário entrar com a linha e com a coluna, SUBTRAIA 1 de cada valor desses.
Ou seja, se  usuário entrou com (1,1), no seu tabuleiro Java 5x5 isso representa a posição (0,0).

Após o tiro ser dado, nosso jogo em Java vai checar se esse tiro acertou algum navio. Isso é feito com o método 'acertou()', que retorna 'true' caso acerte e 'false' caso erre.
No método, ele simplesmente checa se esse par de valores - 'tiro[2]' - que definem seu tiro, batem com algum dos valores que definem a posição dos navios - navios[3][2].
Caso acerte, o valor de 'acertos' aumenta.
Acertando ou errando, 'tentativas' aumenta, pois uma tentativa foi feita.

Acertando ou errando, uma dica também é exibida. Essa dica é exibida através do método 'dica()', que vai olhar o seu 'tiro[2]', e olha se na linha e na coluna que você tentou existe mais algum navio, catando na 'navios[3][2]'.
Note que, a linha do seu tiro é 'tiro[0]' e a coluna é 'tiro[1]'.
A linha de cada navio é 'navios[x][0]' e a coluna de cada navio é 'navios[x][1]', onde 'x' é o número dos navios. No nosso caso, são 3 navios, ou seja, vai de 0 até 2.

Acertando ou errando, o tabuleiro vai ser alterado. O tiro que você deu vai alterar aquele local do tabuleiro, vai aparecer tiro dado '*' ou tiro que acertou 'X'.
Vamos fazer isso através do método 'alteraTabuleiro()'.
Aqui, usamos um método dentro do outro. Coisa que já explicamos em nosso curso de Java.
Checamos se o tiro dado 'tiro[2]' acertou através do método, que já usamos e explicamos, 'acertou'.
Caso acerte, a posição do tabuleiro referente ao tiro que você deu vai mudar de '-1' para '1'.
Caso erre, a posição do tabuleiro referente ao tiro que você deu vai mudar de '-1' para '0'.
Assim, quando o tabuleiro for exibido, já vai exibir com '*' ou 'X' no lugar desse antigo '~'.

import java.util.Random;
import java.util.Scanner;

public class batalhaNaval {

    public static void main(String[] args) {
        int[][] tabuleiro = new int[5][5];
        int[][] navios = new int[3][2];
        int[] tiro = new int[2];
        int tentativas=0,
            acertos=0;
        
        inicializaTabuleiro(tabuleiro);
        iniciaNavios(navios);
        
        System.out.println();
        
        do{
            mostraTabuleiro(tabuleiro);
            darTiro(tiro);
            tentativas++;
            
            if(acertou(tiro,navios)){
                dica(tiro,navios,tentativas);
                acertos++;
            }                
            else
                dica(tiro,navios,tentativas);
            
            alteraTabuleiro(tiro,navios,tabuleiro);
            

        }while(acertos!=3);
        
        System.out.println("\n\n\nJogo terminado. Você acertou os 3 navios em "+tentativas+" tentativas");
        mostraTabuleiro(tabuleiro);
    }
    
    public static void inicializaTabuleiro(int[][] tabuleiro){
        for(int linha=0 ; linha < 5 ; linha++ )
            for(int coluna=0 ; coluna < 5 ; coluna++ )
                tabuleiro[linha][coluna]=-1;
    }
    
    public static void mostraTabuleiro(int[][] tabuleiro){
        System.out.println("\t1 \t2 \t3 \t4 \t5");
        System.out.println();
        
        for(int linha=0 ; linha < 5 ; linha++ ){
            System.out.print((linha+1)+"");
            for(int coluna=0 ; coluna < 5 ; coluna++ ){
                if(tabuleiro[linha][coluna]==-1){
                    System.out.print("\t"+"~");
                }else if(tabuleiro[linha][coluna]==0){
                    System.out.print("\t"+"*");
                }else if(tabuleiro[linha][coluna]==1){
                    System.out.print("\t"+"X");
                }
                
            }
            System.out.println();
        }

    }

    public static void iniciaNavios(int[][] navios){
        Random sorteio = new Random();
        
        for(int navio=0 ; navio < 3 ; navio++){
            navios[navio][0]=sorteio.nextInt(5);
            navios[navio][1]=sorteio.nextInt(5);
            
            //agora vamos checar se esse par não foi sorteado
            //se foi, so sai do do...while enquanto sortear um diferente
            for(int anterior=0 ; anterior < navio ; anterior++){
                if( (navios[navio][0] == navios[anterior][0])&&(navios[navio][1] == navios[anterior][1]) )
                    do{
                        navios[navio][0]=sorteio.nextInt(5);
                        navios[navio][1]=sorteio.nextInt(5);
                    }while( (navios[navio][0] == navios[anterior][0])&&(navios[navio][1] == navios[anterior][1]) );
            }
            
        }
    }

    public static void darTiro(int[] tiro){
        Scanner entrada = new Scanner(System.in);
        
        System.out.print("Linha: ");
        tiro[0] = entrada.nextInt();
        tiro[0]--;
        
        System.out.print("Coluna: ");
        tiro[1] = entrada.nextInt();
        tiro[1]--;
        
    }
    
    public static boolean acertou(int[] tiro, int[][] navios){
        
        for(int navio=0 ; navio<navios.length ; navio++){
            if( tiro[0]==navios[navio][0] && tiro[1]==navios[navio][1]){
                System.out.printf("Você acertou o tiro (%d,%d)\n",tiro[0]+1,tiro[1]+1);
                return true;
            }
        }
        return false;
    }

    public static void dica(int[] tiro, int[][] navios, int tentativa){
        int linha=0,
            coluna=0;
        
        for(int fila=0 ; fila < navios.length ; fila++){
            if(navios[fila][0]==tiro[0])
                linha++;
            if(navios[fila][1]==tiro[1])
                coluna++;
        }
        
        System.out.printf("\nDica %d: \nlinha %d -> %d navios\n" +
                                 "coluna %d -> %d navios\n",tentativa,tiro[0]+1,linha,tiro[1]+1,coluna);
    }

    public static void alteraTabuleiro(int[] tiro, int[][] navios, int[][] tabuleiro){
        if(acertou(tiro,navios))
            tabuleiro[tiro[0]][tiro[1]]=1;
        else
            tabuleiro[tiro[0]][tiro[1]]=0;
    }
}


Fica como desafio você fazer um jogo Batalha Naval, mas humano x humano. Faça assim, primeiro um  dos jogadores preenche onde quer colocar seus navios.
Depois o outro.

O jogo será por turnos. Crie uma variável chamada 'turno' que é incrementada a cada rodada, e use o resto da divisão por 2 pra saber de quem é a vez.
Por exemplo, se
turno=1 -> turno%2 = 1 -> vez do jogador 1
turno=2 -> turno%2 = 0 -> vez do jogador 2
turno=3 -> turno%2 = 1 -> vez do jogador 1
turno=4 -> turno%2 = 0 -> vez do jogador 2
...
Crie duas variáveis 'tabuleiro', duas 'tentativas', duas 'navios' e duas 'acertos', para armazenar em variáveis diferentes os dados de cada usuário.
O jogo termina quando uma das variáveis 'acertos' é 3.
Ou você pode alterar o tamanho do tabuleiro, o número de navios, a dica etc...sua criatividade é que conta.

Jogos com programação gráfica em Java

Já fizemos um exemplo de jogo em Java usando caixas de diálogo, assim como fizemos o mesmo em modo texto.
Você viu que, a lógica é a mesma, e é, de longe, a parte mais importante.

Entendendo e fazendo o jogo Batalha Naval em Java em modo texto, você saberá como funciona a lógica do game. A parte gráfica usará a mesma lógica. Você irá, simplesmente, colocar alguns recursos visuais/gráficos (GUI - Graphic User Interface) nessa sua aplicação Java.

Muitas pessoas pensam que programar jogos é apenas a parte visual.
Porém, essa é apenas uma parte. Geralmente não é difícil, não é a mais importante nem a que dá mais trabalho.
Programar Jogos é, primeiro, programar. Aprenda antes a linguagem, a lógica, a sintaxe.
Depois, ao longo do curso, você aprenderá a usar os recursos gráficos do Java, como menus, janelas e botões, e iremos ensinar como usar para fazer esse mesmo jogo em uma maneira gráfica, para você enviar para seus amigos :)

Por hora, estude a lógica e tenha calma.
Programar é uma profissão. Não se cria um game ou se aprende a programar em Java em poucas semanas ou meses. Continue estudando...

8 comentários:

FLABIANA disse...

Adorei,entendi bem a lógica do jogo,mas já tentei colocar o visual e não consegui,vi que vc disse que iria postar o visual do jogo,aonde se encontra?
Obrigada.

FLABIANA disse...

Adorei o jogo,tentei colocar no modo gráfico mas não consegui,vi que vc escreveu que ira disponibilizar,aonde se encontra?
Obrigada

Java Progressivo disse...

Olá Flabiana,

A programação do jogo com elementos gráficos ainda não foi feita.

Já demos início aos artigos, falando sobre JPanel, JFrame, desenhos geométricos...em breve estará tudo aí.

Walter Calombe disse...

Valeu Cara....vou tomar proveiro dessas dicas....voltou em breve

Adriano Marques disse...

Primeiramente, parabéns pelo trabalho de vocês no site! Eu venho acompanhando algumas aulas e tenho gostado bastante.

Enfim, eu queria informar algo que eu percebi no código desse jogo. No método iniciaNavios, existe a possibilidade do navio[0] ter as mesmas coordenadas do navio[2], o que impede o jogador de conseguir 3 acertos e, portanto, de terminar a partida.

Isso acontece caso o navio[2], em um primeiro sorteio, seja igual ao navio[1]. Nesse caso, é realizado um novo sorteio para o navio[2]. Porém, as novas coordenadas do navio[2] não são novamente comparadas com a do navio[0], o que possibilita que elas sejam iguais.

Obrigado.

Rafael Mello disse...

Desculpe mas não consegui entender a logica do iniciar navios, somente a parte do random

for(int navio=0 ; navio < 3 ; navio++){
navios[navio][0]=sorteio.nextInt(5);
navios[navio][1]=sorteio.nextInt(5);

Apostila Java Progressivo disse...

Rafael, são 3 navios: o 0, o 1 e o 2.

Para inicializar cada um desses navios precisamos fornecer duas coisas: a linha e a coluna.

A linha fica na posição [0] e a coluna na posição [1] de cada navio (cada navio é um vetor de dois inteiros).

Por isso usamos o random duas vezes, pra gerar uma linha e uma coluna aleatoria.

Anônimo disse...

Muito bom.
Estou tentando criar uma Batalha Naval tbm, no entanto, na linha de cima das coordenadas preciso colocar letras, não sei como comparar a coordenada passada pelo jogador com aonde está os navios.
Preciso criar uma matriz de String e inicializar com letras?

Dicas e Novidades de Java por e-mail

Sabe quanto custa um bom livro de java?
Entre R$ 100,00 e R$300,00

Sabe quanto custa um bom curso presencial de Java?
Entre R$ 1.500,00 até R$ 4.000,00

Sabe quanto custa estudar pelo Java Progressivo?
Absolutamente nada.

Porém, também precisamos de sua ajuda e apoio.
Para isso, basta curtir nossa Fan Page e clicar no botão G+ do Google.