Jogo: Batalha Naval em C

Curso Java Progressivo - Como fazer o jogo Batalha Naval em Java
Agora que aprendemos como passar vetores/arrays (de qualquer dimensão) para funções, 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 C: if else, laço do while, laço for, funções  números aleatórios, arrays, arrays multidimensionais e muita criatividade.






Regras: 

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 C:

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

Funções:


  • void inicializaTabuleiro() - inicialmente coloca o valor -1 em todas as partes do tabuleiro
  • void mostraTabuleiro() - recebe o tabuleiro de inteiros e os exibe
  • void iniciaNavios() - esse função sorteia 3 pares de inteiros, que são a localização dos 3 navios
  • void darTiro() - recebe um tiro (linha e coluna) do usuário, e armazena na variável tiro[]
  • boolean acertou() - checa se o tiro dado acertou um navio
  • void dica() - dá a dica de quantos navios existem naquela linha e naquela coluna onde o tiro foi dado
  • void alteraTabuleiro() - 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.

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

Depois é a função 'iniciaNavios()', que vai sortear a posição de 3 navios (linha e coluna).
Essa função 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()'.
Essa função 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 da função '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 C é 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 C 5x5 isso representa a posição (0,0).

Após o tiro ser dado, nosso jogo em C vai checar se esse tiro acertou algum navio. Isso é feito com a função 'acertou()', que retorna 'true' caso acerte e 'false' caso erre.
Na função, 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 da função '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 da função 'alteraTabuleiro()'.
Aqui, usamos uma função dentro do outro. Coisa que já explicamos em nosso curso de C.
Checamos se o tiro dado 'tiro[2]' acertou através da função, 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 '~'.


#include <stdio.h>
#include <stdlib.h>

void inicializaTabuleiro(int tabuleiro[][5])
{
    int linha, coluna;
        for(linha=0 ; linha < 5 ; linha++ )
            for(coluna=0 ; coluna < 5 ; coluna++ )
                tabuleiro[linha][coluna]=-1;
}

void mostraTabuleiro(int tabuleiro[][5])
{

    int linha, coluna;

        printf("\t1 \t2 \t3 \t4 \t5");
        printf("\n");

        for(linha=0 ; linha < 5 ; linha++ ){
            printf("%d",linha+1);
            for(coluna=0 ; coluna < 5 ; coluna++ ){
                if(tabuleiro[linha][coluna]==-1){
                    printf("\t~");
                }else if(tabuleiro[linha][coluna]==0){
                    printf("\t*");
                }else if(tabuleiro[linha][coluna]==1){
                    printf("\tX");
                }

            }
            printf("\n");
        }

    }

void iniciaNavios(int navios[][2]){
        srand(time(NULL));
        int navio, anterior;

        for(navio=0 ; navio < 3 ; navio++){
            navios[navio][0]= rand()%5;
            navios[navio][1]= rand()%5;

            //agora vamos checar se esse par não foi sorteado
            //se foi, so sai do do...while enquanto sortear um diferente
            for(anterior=0 ; anterior < navio ; anterior++){
                if( (navios[navio][0] == navios[anterior][0])&&(navios[navio][1] == navios[anterior][1]) )
                    do{
                        navios[navio][0]= rand()%5;
                        navios[navio][1]= rand()%5;
                    }while( (navios[navio][0] == navios[anterior][0])&&(navios[navio][1] == navios[anterior][1]) );
            }

        }
    }

void darTiro(int tiro[2])
{

        printf("Linha: ");
        scanf("%d",&tiro[0]);
        tiro[0]--;

        printf("Coluna: ");
        scanf("%d",&tiro[1]);
        tiro[1]--;

}

int acertou(int tiro[2], int navios[][2])
{
    int navio;

        for(navio=0 ; navio < 3 ; navio++){
            if( tiro[0]==navios[navio][0] && tiro[1]==navios[navio][1]){
                printf("Você acertou o tiro (%d,%d)\n",tiro[0]+1,tiro[1]+1);
                return 1;
            }
        }
        return 0;
    }

void dica(int tiro[2], int navios[][2], int tentativa)
{
        int linha=0,
            coluna=0,
            fila;

        //conta quantos navios há na linha tiro[0]
        for(fila=0 ; fila < 3 ; fila++){
            if(navios[fila][0]==tiro[0])
                linha++;
            if(navios[fila][1]==tiro[1])
                coluna++;
        }

        printf("\nDica %d: \nlinha %d -> %d navios\ncoluna %d -> %d navios\n",tentativa,tiro[0]+1,linha,tiro[1]+1,coluna);
}

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

int main() {
        int tabuleiro[5][5];
        int navios[3][2];
        int tiro[2];
        int tentativas=0,
            acertos=0;

        inicializaTabuleiro(tabuleiro);
        iniciaNavios(navios);

        printf("\n");

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

        printf("\n\n\nJogo terminado. Você acertou os 3 navios em %d tentativas", tentativas);
        mostraTabuleiro(tabuleiro);
    }



4 comentários:

Protasio Junior disse...

Gostei!
Na linha 28, ao invés do printf("\tX");
eu mudei para
printf("\t\2");
Achei que fica mais divertido.
Parabéns pelo curso...
Eu estou gostando muito!

Mowload disse...

E no caso se fossem 2 tabuleiros...tipo usuário vs computador?...estou tendo um pouco de dificuldade para desenvolver o algoritmo para esta maneira...tem alguma dica?...vlw..
E parabéns pelo site...está me ajudando mesmo.

Anônimo disse...

esta dando um erro da hora de compilar
38 24 C:\Users\user\Documents\Projetos C\batalhanaval\main.cpp [Error] 'time' was not declared in this scope

estou tentando compilar com dev-c++

Mateus Souza disse...

Eu estou fazendo ainda melhor. Agora o computador também sorteia números e tenta acertar os navios do usuário, além de permitir o usuário de escolher os próprios navios. Depois que conseguir, eu comento aqui, junto com o código C.

Gostou desse tutorial de C?
Sabia que o acervo do portal C Progressivo é o mesmo, ou maior que, de um livro ou curso presencial?
E o melhor: totalmente gratuito.

Mas para nosso projeto se manter é preciso divulgação.
Para isso, basta curtir nossa página no Facebook e/ou clicar no botão +1 do Google.
Contamos e precisamos de seu apoio.