How to optimize the game naval battle in JAVA?

12

I do not know if this is allowed here on the site, so if I break some rule let me know!

I recently started learning the JAVA language. I did a naval battle game (human vs. computer) using everything I've learned so far and would like to hear more experienced programmers' opinions about the game in order to improve my knowledge.

Some points like what would you have done differently? How would you optimize existing code? Did I commit some redundancy or write more than I needed?

How did I think about the game's programming?

I created two arrays 5x5. One stores the game board. It starts with the default value 0 for all elements. With one method, I draw 3 of these elements, which will represent the position of the boats to be sunk. To them they assign the value 1. The other array stores the positions where the player fired, 0 symbolizes an area where it has not yet attacked and 1 an area where it has attacked.

To display the tray, I cross the two arrays into a check. Where it has not yet been attacked, it appears as "~", where it was attacked and there is no ship like "*" and where it attacked and sank a ship like "X". I have created a method for each turn to display a tip indicating whether the number of ships in the row and column of the last shot taken.

Code :

BatalhaNaval.java

package batalhanaval;
import java.util.Scanner;

public class BatalhaNaval
{
    public static void main(String[] args)
    {
        Scanner entrada = new Scanner(System.in);
        Tabuleiro tab = new Tabuleiro();
        char option; //Opção do menu principal

        do
        {
            showMenu();
            option = entrada.next().charAt(0);
            System.out.println("\n\n");
            switch(option)
            {
                case '1': //Novo jogo
                {
                    initGame(entrada, tab);
                    break;
                }
                case '2':
                {
                    System.out.println("O seu objetivo no jogo é afundar os 3 navios inimigos que encontram-se no seu litoral.\n"
                            + "Para fazer um disparo, informe a posição(linha e coluna) do seu mapa na qual deseja lançar o míssel.\n"
                            + "O símbolo ~ indica uma área ainda não conhecida.\n"
                            + "O símbolo * indica uma área na qual você disparou e não havia nenhum navio.\n"
                            + "O símbolo X indica uma área onde você afundou um navio inimigo.\n"
                            + "A cada disparo realizado você receberá uma dica informando se há navios na linha e na coluna nas quais você realizou o disparo.");
                    break;
                }
                case '3': //Recorde
                {
                    if(tab.recorde == 1000)
                    {
                       System.out.println("<Recorde atual: nenhum>");
                    }
                    else
                    {
                       System.out.println("<Recorde atual: " + tab.recorde + " turnos>");
                    }
                    break;
                }
                case '4':
                {
                    System.out.println("Finalizando...");
                    break;
                }
                default:
                {
                    System.out.println("Opção inválida!");
                }
            }
            System.out.println("\n");         
        }while(option != '4');

    }
    //Método que retorna true caso a String seja um número inteiro
    public static boolean isInt(String str)
    {
        try 
        {  
            Integer.parseInt(str.trim());
            return true;     
        } 
        catch (NumberFormatException ex) 
        {  
            return false;         
        }  
    }
    //Main menu
    public static void showMenu()
    {
        System.out.println("Bem vindo ao jogo <Batalha Naval>!!! (Criado por Talendar)\nEscolha uma opção:");
        System.out.println("1 - Novo jogo");
        System.out.println("2 - Tutorial");
        System.out.println("3 - Recorde");
        System.out.println("4 - Sair");
    }
    //Jogo
    public static void initGame(Scanner entrada, Tabuleiro tab)
    {
        String linha = ""; //As variáveis linha e coluna foram criadas como String para poderem ser submetidas a checagem do método isInt(str) localizado abaixo.
        String coluna = "";

        tab.initTab();
        tab.initShips();
        do
        {
            System.out.println("\n");
            //Exibe a dica a partir do segundo turno
            if(tab.turno > 1)
            {
                tab.dica(Integer.parseInt(linha), Integer.parseInt(coluna));
            }
            System.out.println();

            //Exibe o tabuleiro em seu estado atual
            tab.printTab();

            //Pede a linha
            System.out.print("Linha:");
            linha = entrada.next();
            while(!isInt(linha))
            {
                System.out.println("Apenas números inteiros de 1 a 5!\nLinha:");
                linha = entrada.next();
            }
            while(Integer.parseInt(linha) < 1 || Integer.parseInt(linha) > 5)
            {
                System.out.println("Apenas números inteiros de 1 a 5!\nLinha:");
                linha = entrada.next();
            }

            //Pede a coluna
            System.out.print("Coluna:");
            coluna = entrada.next();
            while(!isInt(coluna))
            {
                System.out.println("Apenas números inteiros de 1 a 5!\nColuna:");
                coluna = entrada.next();
            }
            while(Integer.parseInt(coluna) < 1 || Integer.parseInt(coluna) > 5)
            {
                System.out.println("Apenas números inteiros de 1 a 5!\nColuna:");
                coluna = entrada.next();
            }
            System.out.println("\n\n");

            //Tiro
            tab.tiro(Integer.parseInt(linha), Integer.parseInt(coluna));
            System.out.println();

        }while(tab.acertos != 3);
        System.out.println("\nVOCÊ DERROTOU O INIMIGO!!!! Turnos: " + tab.turno);
        if(tab.turno < tab.recorde)
        {
            tab.recorde = tab.turno;
            System.out.println("\nNOVO RECORDE (" + tab.recorde + ")!!!!");
        }
    }
}

Tab.java

/* Água não descoberta(~)
   Água vazia(*): 0
   Navio(X): 1
*/
package batalhanaval;
import java.util.Random;

public class Tabuleiro
{
    int turno = 1; //Turno em questão
    int acertos = 0; //Armazena o número de acertos
    int recorde = 1000; //Armazena o recorde
    int[][] tab = new int[5][5]; //Tabuleiro
    int[][] tiros = new int[5][5]; //Armazeana as posições dos tiros dados: 0 para área desconhecida e 1 para área onde se atirou.

    // Inicia o tabuleiro com o valor padrão 0
    public void initTab()
    {
        acertos = 0;
        turno = 1;
        for(int[] i: tab)
        {
            for(int j = 0; j < i.length; j++)
            {
                i[j] = 0;
            }
        }
    }
    //Sorteia os navios
    public void initShips()
    {
        Random rand = new Random();
        int i; //Linha
        int j; //Coluna

        for(int n = 0; n < 3; n++)
        {
            do
            {
                i = rand.nextInt(5);
                j = rand.nextInt(5);  
            }while(tab[i][j] != 0);
            tab[i][j] = 1;
        }
    }
    //Mostra o tabuleiro de inteiros
    public void printTabInt()
    {
        System.out.print("     (1)  (2)  (3)  (4)  (5)\n\n");
        for(int i = 0; i < tab.length; i++)
        {
            System.out.print("("+ (i+1) + ")  ");
            for(int j = 0; j < tab[i].length; j++)
            {
                System.out.print(" "+tab[i][j]+"   ");
            }
            System.out.println("\n");
        }
    }
    //Mostra o tabuleiro de jogo
    public void printTab()
    {
        System.out.print("     (1)  (2)  (3)  (4)  (5)\n\n");
        for(int i = 0; i < tab.length; i++)
        {
            System.out.print("("+ (i+1) + ")  ");
            for(int j = 0; j < tab[i].length; j++)
            {
                if(tiros[i][j] == 1)
                {
                    if(tab[i][j] == 1)
                    {
                        System.out.print(" X   ");
                    }
                    else
                    {
                        System.out.print(" *   ");
                    }
                }
                else
                {
                    System.out.print(" ~   ");
                }
            }
            System.out.println("\n");
        }
    }
    //Tiro
    public void tiro(int linha, int coluna)
    {
        if(tiros[linha-1][coluna-1] == 0) //Checa se já foi dado tiro na posição fornecida
        {
            tiros[linha-1][coluna-1] = 1; //Muda o valor da posição fornecida para que conste como uma área atirada
            if(tab[linha-1][coluna-1] == 1) //Checa se há um navio na posição fornecida
            {
                System.out.println("Você afundou um navio inimigo!!!");
                acertos++; //Aumenta +1 em acertos
            }
            else
            {
                System.out.println("Você atingiu a água...");
            }
            turno++; //Avança o turno
        }
        else
        {
            System.out.println("Você já atirou nessa posição!");
        }
    }
    //Dica: informa o turno e se há alguma navio na linha e na coluna do último tiro disparado
    public void dica(int linha, int coluna)
    {
        System.out.println("Turno: " + turno);

        int countL = 0;
        for(int i: tab[linha-1])
        {
            if(i == 1)
            {
                countL++;
            }
        }
        System.out.println("Dica: há " + countL + " navio(s) na linha " + linha);

        int countC = 0;
        for(int[] i: tab)
        {
            if(i[coluna-1] == 1)
            {
                countC++;
            }
        }
        System.out.println("      há " + countC + " navio(s) na coluna " + coluna);
    }
}
    
asked by anonymous 11.09.2016 / 20:09

1 answer

1

I think you're searching for more knowledge about good code practice, object orientation, automated testing, and so on.

I suggest that you yourself have the critical sense of self-evaluating your code in order to look for flaws. Good programmers learn from their own error.

To try to raise your knowledge, I will suggest some topics with links for you to delve into the subject. Here are some:

Test Driven Design:

Test-based software development. You evolve your code just to pass the test. This makes it easier for you to build a better design of your architecture and objects, ensuring simplicity, low coupling and automatic coverage of your tests.

Object Orientation

Ensures that your system has single-purpose classes that communicate with each other, ensuring their maintainability, usability, and system evolution. If you are interested in the subject, I have created 10 rules to ensure that your code follows good practice in object orientation based on The ThoughtWorks Anthology: Essays on Software.

link

I'll cite some examples of your code that violates some rules:

Rule 4 : Only 1 point per line Improves readability of code.

The code snippet below violates this rule, making it difficult to read.

tab.dica(Integer.parseInt(linha), Integer.parseInt(coluna));

Better practice would be    Integer line = Integer.parseInt (line);    Integer column = Integer.parseInt (column);    (line, column);

Rule 9 : Method must have only 7 lines of code. This ensures that their methods have high cohesion, that is, they do only what they should do, and nothing else. Your printTab method for example violates the rule.

To conclude, I must add that every method must be in the infinitive. This is a good practice adopted in many object-oriented languages. In this case, the tab.dica method should be changed to tab.exhibitDictionary (...)     

26.09.2016 / 22:57