Skip to content

luizferreira7/batalhaNaval

Repository files navigation

batalhaNaval

Link para video no Youtube: https://youtu.be/id08ZJ85yOo

Relatório Trabalho 1 de Intro C/C++ 2020-2

Batalha Naval

Aluno:  Helena Coelho Nicolli  

Aluno:  Luiz Carlos Ferreira Carvalho  

Aluno:  Yuri Ferreira Melo                                            

A. Descrição do Jogo e seu Objetivo

O jogo desenvolvido foi o Batalha Naval, que possui 3 modalidades, a primeira onde o jogador enfrenta o computador, com 3 opções de dificuldade, 
a segunda onde 2 jogadores se enfrentam, e a terceira onde dois computadores se enfrentam. Em todos os modos o objetivo é afundar todos os navios 
do inimigo alcançando a pontuação máxima de 14 pontos (Soma dos tamanhos dos 4 navios, Submarino, Destroyer, Cruzado e Porta-Aviões).
Ele consiste em escolher posições para os navios em um tabuleiro 10x10, sempre marcando a primeira e última posições desejadas para cada navio. 
Os jogadores podem pedir para o computador preencher o tabuleiro automaticamente em vez de eles mesmos o preencherem manualmente.

B. Regras do Jogo

I - Cada jogador deve posicionar os navios em seu tabuleiro.

II - Cada navio tem um tamanho fixo.

III - Os navios não podem se sobrepor.

IV - Os jogadores não podem ver o tabuleiro um do outro.

V - O jogador deve escolher uma posição para atacar.

VI - O jogador alvo deve dizer se o outro acertou alguma parte do navio.

VII - Se o jogador acertar ele joga novamente até errar.

VIII - Se o jogador acertar todas as partes de um navio o outro deve avisar que esse afundou.

IX - Ganha quem afunda todos os navios.

C. Organização do Código

O código implementa 3 estruturas, a primeira definida como “Jogo” que contém as principais informações sobre o jogo, como dificuldade e modalidade 
escolhidas, a segunda estrutura “Jogador” contém as informações sobre cada participante do jogo, se ele é um usuário ou computador, armazena o tabuleiro,
o nome, a pontuação, se acertou a jogada anterior entre outros, a terceira estrutura Navio armazena o nome, a classe, e o tamanho de cada embarcação.
A utilização das estruturas foi extremamente útil ao longo de todo projeto, pois elas permitem que alterações feitas em variáveis dentro de uma função
fiquem salvas de forma global ao longo da execução do código, além de ser fácil de armazenar dados para cada jogador, como por exemplo saber se o usuário 
acertou o disparo anterior ou qual foi a jogada anterior dele, diferenciando a rotina do programa a partir desses dados.
Ele foi construído por partes, sempre pensando em etapa por etapa do jogo, as primeiras parte feitas foram a de criação dos jogadores, do tabuleiro e 
entrada das posições dos navios, que demandou uma função bastante complexa para verificar se a posição escolhida é válida ou não. O código também foi 
pensado para ser reutilizável em outras partes, então funções como imprimeTabuleiro foram criadas para evitar repetições, além de permitir que uma função 
setTabuleiro (fazia parte anteriormente de setNavio antes de ser dividida) fosse usada tanto pelo usuário, tanto pelo computador, com poucas funções 
sendo feitas exclusivamente para uma situação como a realizaDisparoIA que é bastante diferente da realizaDisparo dos jogadores.
O código foi pensado originalmente com o modo Jogador vs CPU como base, os modos de 2 jogadores e CPU x CPU foram adicionados posteriormente, este 
último adicionado pois como a rotina da CPU contra o jogador estava pronta, nada impedia de colocar duas CPU se enfrentando.
A existência de níveis de dificuldade foi planejada desde o início e implementada na função realizaDisparoIA com 3 possibilidades, a primeira fácil 
onde a CPU sempre faz disparos aleatórios, a segunda normal, onde a CPU após um acerto tenta o disparo em uma posição em volta do acerto, e a terceira
difícil, onde a CPU após o primeiro acerto sempre acerta as próximas jogadas até o fim do navio, podendo não afunda-lo caso o primeiro acerto tenha 
sido no meio.
Para a parte do código de sortear as posições tanto para setTabuleiro quanto realizaDisparo foi usada a função rand() que demandou bastante atenção 
para ser usada corretamente e não repetir sequências semelhantes, por exemplo quando usada na função sorteiaTitulo ambos os jogadores acabavam recebendo 
o mesmo título de forma seguida pois o tempo entre a definição do título de um e do outro não era grande o bastante, por isso passou-se a se utilizar 
como semente na srand() além da “hora” da função time() o tamanho de cada nome com a strlen().

Rotina do código:

1 - Função main inicia e cria os 4 tipos de Navios com a função setNavio, passando os atributos de cada um como tamanho, nome e classe.

2 - Inicia a função setJogo que a partir das funções chamadas dentro dela (escolheDificuldade e escolheModoJogo) define como será a partida e 
retorna o jogo para a variável do tipo jogo iniciada na main.

3 - A partir do modo de jogo escolhido entra em um dos ifs definidos para diferenciar o que fazer em cada modo.

4 - Chama a função setJogador que retorna uma variável do tipo Jogador aonde constam os dados de cada jogador como nome, título (definido na função
sorteiaTitulo), se é humano ou não etc. Além de preencher o tabuleiro do jogador com água (‘~’) (função preencheTabuleiro) e a lista de jogadas 
realizadas com n (função preencheJogadas) para eliminar qualquer lixo, e poder fazer comparações mais tarde.

5 - No caso de um usuário inicia uma rotina para saber se ele quer colocar os navios no tabuleiro de forma manual ou automatizada pela CPU. 
Os navios sempre são colocados a partir da função setTabuleiro que determina o que fazer a partir dos atributos de entrada, como modo de jogo 
entre outros, além de receber a variável do tipo navio, que será colocado no tabuleiro.

6 - Dentro da setTabuleiro é chamada a função getPosicao responsável por ler as entradas do usuário no caso de escolha manual das posições dos navios,
ou usar as funções sorteiaI e sorteiaJ para posições automatizadas. São sempre escolhidas ou escolhidas as posições Inicial e Final do navio.

7 - Após isso, ainda dentro da setTabuleiro é chamada a função verificaPosicao, para checar se as posições escolhidas ou sorteadas anteriormente 
são válidas, e então colocar o navio no tabuleiro. também é feita a diferenciação para quando é uma posição inicial e quando é final.

8 - A rotina de ler entrada, verificá-la e colocar no tabuleiro é feita para cada jogador independente do tipo, quando o modo de jogo envolve um 
usuário ele pode escolher se está satisfeito ou se deseja escolher as posições novamente de todos os navios.

9 - Após a preparação para o jogo terminar, ele entra em um while que repete a chamada das funções de disparo para cada jogador.

10 - Se for um jogador usuário ele inicia a função realizaDisparo, que verifica se a jogada já foi realizada antes e se está dentro do tabuleiro, 
após isso verifica se acertou, somando 1 ponto em caso de acerto e alterando o atributo acertou disparo anterior para true.



11 - Se o jogador for computador ele chama a função realizaDisparoIA que se baseia na dificuldade escolhida na setJogo para determinar o comportamento 
do disparo da IA, que no caso fácil, sempre sorteia o disparo, no normal após primeiro acerto tenta acertar em volta do primeiro,  e no difícil 
sempre acerta o segundo tiro seguindo em umas das 4 posições possíveis a partir do primeiro tiro, podendo afundar completamente ou não um navio.

12 - No caso de acertar o disparo a função entra em outro while que se repetirá enquanto o jogador acertar a jogada, pois de acordo com as regras do 
jogo, sempre que acerta um navio o jogador jogo de novo.

13 - Em casos de acertos a função verificaSeAfundou é chamada para verificar se o navio atingido afundou ou não. Além de sempre salvar a posição 
escolhida para disparo na lista de jogadas realizadas do jogador ou computador mesmo em caso de erro.

14 - Caso o jogador erre o tiro ou atinja a pontuação máxima ele sai do while e passa para a verificação que encerra o jogo quando um jogador atinge 
a pontuação máxima. 

15 - Caso o jogador não tenha atingido a pontuação máxima e tenha errado o disparo passa a vez do próximo jogador que repete a rotina de disparo 
descrita acima.15 - Se nenhum dos dois atinge a pontuação máxima e erra os disparos as rotinas são repetidas até que a pontuação máxima seja alcançada 
por alguma dos dois. A pontuação máxima é a quantidade de acertos necessários para afundar todos os navios de um jogador.

D. Dificuldades no desenvolvimento do Trabalho

Uma das maiores dificuldades encontradas foi a conexão de internet dos integrantes do grupo, pois a ideia original era trabalhar usando o LiveShare 
do Visual Studio Code.
Em relação ao código, a maior dificuldade foi a verificação de posição válida, pois existiam muitos casos a serem cobertos, e demandou um dia inteiro 
para ficar pronta. No início o grupo pensou em ler posição por posição para cada parte do Navio, por exemplo se o Cruzador tendo tamanho 4 seriam lidas
4 entradas. Porém optou-se por ler apenas duas entradas, uma representando a posição inicial e a outra a posição final, no caso do Cruzador com 
posição inicial A0 as posições finais possíveis seriam: A3 e D0.
Criar uma função que sorteia números também foi difícil pelas limitações da função rand() que, se usada de forma simplória, sempre sorteia o mesmo número.
Criar a modalidade para 2 jogadores também demandou tempo e paciência pois o grupo nunca chegava a um consenso sobre a exposição dos tabuleiros na tela 
dos jogadores, que, em teoria, estariam utilizando a mesma máquina para jogar.

E. Bibliotecas extras não ensinadas no período e utilizadas no código

Foram utilizadas as bibliotecas: windows.h para colocar cor no terminal do Windows, e time.h para usar de semente da função rand().

F. Aprendizados no desenvolvimento do jogo

Yuri: Aperfeiçoamento do uso e construção de matrizes em C.

Helena: Desenvolvimento de código seguindo uma lógica compartilhada e combinada pelo grupo, não individual. Implementação de modalidades e níveis 
de dificuldade a um jogo; uso de structs, pois exigem uma visão inicial abrangente do que o programa será e precisará posteriormente; implementar 
cor de texto, uso de tempo, função de seleção aleatória, em C.

Luiz: Aprender a sortear números pseudo-aleatórios em C, colocar cor nos terminais Unix e do Windows, melhorar o uso de vetores, strings e passagem 
de parâmetros em funções em C.

G. Códigos que foram utilizados de Inspiração ou Referência

Link e código consultado/usado para colocar cor no terminal do Windows:
https://www.programmersought.com/article/11014261013/

Links e códigos consultados/usados para colocar cor no terminal do Linux/Mac:
https://www.theurbanpenguin.com/4184-2/
https://www.programmersought.com/article/17911867710/

Link e código usado como referência para sorteio de números pseudo-aleatórios.
https://www.geeksforgeeks.org/rand-and-srand-in-ccpp/

H. Sistema Operacional Utilizado

Luiz trabalhou no macOS, enquanto Yuri usou Linux e Helena trabalhou no Windows.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages