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);
}
}