edutecnica

Esercizio 10       

Scrivi un programma di battaglia navale che si svolga fra un giocatore e il PC che si svolga su una matrice di 10x10 celle e che preveda per ciascuna parte l'utilizzo della seguente flotta:
1 nave da 4 celle
2 navi da 3 celle
2 navi da 2 celle
1 nave da 1 cella.


Il programma simula lo svogimento di una battaglia navale fra un giocatore e il computer, la battaglia si svolge su una matrice di 10x10 celle.
La numerazione delle coordinate delle celle è coerente con il sistema di indicizzazione della matrice stessa; per cui la cella in alto a sinistra sarà indicata con coordinate 0,0 quella in basso a destra con coordinate 9,9.
L'inserimento di coordinate maggiori di 9 o minori di 0 causa istantanemanete l'interruzione della partita..

Il gioco si svolge (per ciascun giocatore) con

1 nave da 4 celle
2 navi da 3 celle
2 navi da 2 celle
1 nave da 1 cella

Il principale problema che si pone, riguarda la collocazione delle navi entro i limiti della matrice 10x10, seguito dalla necessità di non far intersecare fra di loro le navi collocate sulla scacchiera 10x10.

La collocazione delle navi avviene in due modi: in modo random sul lato del PC e tramite il caricamento da tastiera sul lato dell'utente.
Il PC usa una matrice M[int][int]  per disporre le sue navi
Questa matrice di interi viene prima di tutto inizializzata con tutte le celle a 0 dalla funzione
iniz(char T[n][n],int M[n][n],int H[n][n],int HPC[n][n])
che si occupa di resettare anche tutte le altre matrici di interi presenti.
In questa struttura sarà indicata col valore 1, la cella occupata da una nave; con il valore 0 una cella libera.. 
Il caricamento della matrice M del PC viene eseguito dalla funzione
set(int M[n][n])
che si occupa di collocare in modo random tutte le 6 navi. Ovviamente, si fa ampio uso dei generatori di numeri casuali
srand(); rand(); con particolare attenzione a rispettare i limiti dell'array e a non collocare navi su celle già occupate; la prima nave, quella da 4 celle, è l'unica a non avere questo problema.
Si usano dei cicli do-while per ritentare la disposizione di una nave qualora essa risulti in collisione con un'altra nave già disposta. La matrice
T[char][char]
è solo rappresentativa dei tiri del giocatore, viene inizializzata riempiendo le celle col carattere '=' questo carattere commuta nel simbolo 'X' quando l'utente colpisce la nave del PC.  Questa gestione avviene nel ciclo do-while principale all'interno del main() dove appaiono le istruzioni:
if(M[i][j]==1){T[i][j]='X';M[i][j]=0;conta++;}
    else T[i][j]='0';

è evidente che la matrice T è in relazione con la matrice M; quando una nave del PC viene colpita la corrispondente cella in M viene azzerata e la stessa cella viene indicata con la lettera X sulla struttura T.
In fase di avvio si nota l'istruzione carica(H); che è una vera e propria procedura per collocare le navi sulla scacchiera del giocatore in modo manuale.
Il giocatore deve indicare la cella iniziale dove disporre la nave e l'orientamento della stessa; usando convenzionalmente lo 0 per il senso orizzontale e l'1 per il senso verticale. In ogni caso la cella iniziale rappresenta la cella più a sinistra nel caso orizzontale, mentre viene intesa come la cella più in alto nel caso del senso verticale..
In questa procedura si notano dei cicli do-while in abbinamento con la variabile booleana 'valido' che ha il compito di verificare che la nave sia nei limiti della scacchiera e che non ci siano intersezioni con le altre navi.
La matrice H dell'utente viene utilizzata (inevitabilmente) durante l'esecuzione del tiro del PC
bool lancioPC(int H[n][n],int HPC[n][n]);
All'interno di questa funzione, H viene confrontata con una sua omologa HPC che il PC usa per capire se il suo tiro è andato a segno oppure no.
La funzione lancioPC restituisce un valore booleano true se il PC ha colpito una nave del giocatore o false in caso contrario. Il programma è impostato in modo tale da eseguire un beep del suo speaker nel caso sia stata colpita una nave del giocatore. Simultaneamente sulla matrice H, dove il giocatore ha messo le sue navi e che viene stampata a video scomparirà il simbolo '1' corrispondente alla cella colpita dal PC col suo tiro.

Si può notare che il PC, nell'esecuzioni dei suoi tiri, non segue una particolare politica; esso si limita a tirare in modo casuale nell'insieme di celle non non ha ancora tirato. Viene lasciato come sviluppo futuro l'implementazione di una strategia di combattimento più efficace da parte del PC.
Nel main() si nota la presenza di due variabili intere:
conta e contaPC ovviamente inizializzate a 0, che valutano la vittoria del giocatore o del PC al raggiungimento dela 15sima cella colpita; infatti la somma delle celle per le suddette navi disposte sulla singola scacchiera del giocatore o del PC è appunto 15.
Si fa notare che il codice commentato nella funzione print() :
/* for(i=0;i < n;i++){//stampa M
              for(j=0;j < n;j++) cout << M[i][j];
               cout << endl;
}*/

permette di visualizzare oltre alla struttura H e T anche la matrice M della disposizione delle navi 'pensata' dal PC. Invece la funzione
void p(int H[n][n])
è una procedura di stampa di servizio usata soltanto durante l'esecuzione della funzione carica(int H[n][n]) che in via preliminare permette all'utente di collocare le sue navi sulla sua scacchiera.


#include<iostream>
#include<time.h>
#include<stdlib.h>
const int n=10;
using namespace std;
bool lancioPC(int H[n][n],int HPC[n][n]);//tira il PC
void p(int H[n][n]);//funzione di stampa ausiliaria
void print(char T[n][n],int M[n][n],int H[n][n]);//stampa
//reset di T ed M H ed HPC
void iniz(char T[n][n],int M[n][n],int H[n][n],int HPC[n][n]);
void set(int M[n][n]);//matrice del computer
void carica(int H[n][n]);//matrice del giocatore

main(){
bool exit=false, colpito=false;
int i,j;
char T[n][n],ch;
int M[n][n],H[n][n],HPC[n][n],conta=0,contaPC=0;
//inizializz. e caricamento navi lato giocatore
iniz(T,M,H,HPC);
set(M);
carica(H);
//inizio gioco
do{
system("CLS");
print(T,M,H);
cout << "riga:";cin >> i;
cout << "colonna:";cin >> j;
if(i >= 0 && j >= 0 && i < n && j < n)
   if(M[i][j]==1){T[i][j]='X';M[i][j]=0;conta++;}
   else T[i][j]='0';
else exit=true;
colpito=lancioPC(H,HPC);
if(colpito){contaPC++; cout << "\a" << flush;}
if(conta==15){cout << "HAI VINTO!!!";print(T,M,H);break;}
if(contaPC==15){cout << "ha vinto il PC";print(T,M,H);break;}
}while(exit!=true);
} //fine main
void p(int H[n][n]){
int i,j;
for(i=0;i < n;i++){//stampa T
for(j=0;j < n;j++)cout << H[i][j];
cout << endl;
}
}//fine p

void print(char T[n][n],int M[n][n],int H[n][n]){
int i,j;
for(i=0;i < n;i++){//stampa T
for(j=0;j < n;j++) cout << T[i][j];
cout << endl;
}
cout << "----------" << endl;
for(i=0;i < n;i++){//stampa H
for(j=0;j < n;j++) cout << H[i][j];
cout << endl; }
}//fine print


void iniz(
char T[n][n],int M[n][n],int H[n][n],int HPC[n][n]){
int i,j;
for(i=0;i < n;i++)//iniz.T
   for(j=0;j < n;j++) T[i][j]='=';

for(i=0;i < n;i++)//iniz.M
   for(j=0;j < n;j++) M[i][j]=0;

for(i=0;i < n;i++)//iniz.H
   for(j=0;j < n;j++) H[i][j]=0;

for(i=0;i < n;i++)//iniz.HPC
   for(j=0;j < n;j++) HPC[i][j]=0;
}//fine iniz

void set(int M[n][n]){
bool occupato=false;
int row,col,i,j,s;
srand(time(0));
//caricamento nave da 4
s=rand()%2;
row=rand()%7;
col=rand()%7;
if(s==0)for(j=col;j < col+4;j++)M[row][j]=1;
else for(i=row; i < row+4;i++)M[i][col]=1;
//caricamento 2 navi da 3
for(i=0;i < 2;i++){
do{
occupato =false;
s=rand()%2;
row=rand()%8;
col=rand()%8;
if(M[row][col]!=0)occupato=true;
else{
   if(s==0){ if(M[row][col+1]!=0 || M[row][col+2]!=0)occupato=true;
   else { M[row][col]=1;M[row][col+1]=1;M[row][col+2]=1;}
}else{
if(M[row+1][col]!=0 || M[row+2][col]!=0)occupato=true;
else { M[row][col]=1;M[row+1][col]=1;M[row+2][col]=1;}
}
}
}while(occupato==true); }//fine for
//caricamento 2 navi da 2
for(i=0;i < 2;i++){
do{
occupato =false;
s=rand()%2;
row=rand()%8;
col=rand()%8;
if(M[row][col]!=0)occupato=true;
else{
if(s==0){
   if(M[row][col+1]!=0)occupato=true; else {    M[row][col]=1;M[row][col+1]=1;}
}else{
   if(M[row+1][col]!=0)occupato=true;
else { M[row][col]=1;M[row+1][col]=1;}
}
}
}while(occupato==true); }//fine for

//caricamento una nave da 1
do{
occupato =false;
row=rand()%10;
col=rand()%10;
if(M[row][col]!=0)occupato=true;
else M[row][col]=1;
}while(occupato==true); //fine caricamento una nave da 1
}//fine set(M)

void carica(int H[n][n]){
//'valido' controlla che la nave sia nei limiti della matrice
//e che non vada a collidere con altre navi

bool occupato=false,
valido=false;
int row,col,i,j,s;
do{//caricamento nave da 4
valido=false;
cout<<"riga iniz.nave da 4:";cin>>row;
cout<<"colonna iniz.nave da 4:";cin>>col;
cout<<"orientamento (0/1):";cin>>s;
if(row >= 0 && col >= 0 && row < n && col < n){
if(s==0 && col+4 < n){
   for(j=col;j < col+4;j++)H[row][j]=1;
   valido=true;system("CLS");p(H);
}
if(s==1 && row+4 < n){
for(i=row;i < row+4;i++)H[i][col]=1;
system("CLS");
valido=true;p(H);
}
}else valido=false;
}while(valido!=true);
//fine caricamento nave da 4
for(i=0;i < 2;i++){//caricamento 2 navi da 3
do{
valido=false;
cout<<"riga iniz.nave da 3:";cin>>row;
cout<<"colonna iniz.nave da 3:";cin>>col;
cout<<"orientamento (0/1):";cin>>s;
if(row >= 0 && col >= 0 && row < n && col < n){
   if(H[row][col]==0){
   if(s==0 && col+2 < n && H[row][col+1]==0 && H[row][col+2]==0){
      for(j=col;j < col+3;j++)H[row][j]=1;
      system("CLS");
      valido=true;p(H);
   }
   if(s==1 && row+2 < n && H[row+1][col]==0 && H[row+2][col]==0){
   for(j=row;j < row+3;j++)H[j][col]=1;
   system("CLS");
   valido=true;p(H);
   }
}else valido=false;
}else valido=false;
}while(valido==false);
}//fine caricamento 2 navi da 3

for(i=0;i<2;i++){//caricamento 2 navi da 2
do{
valido=false;
cout<<"riga iniz.nave da 2:";cin>>row;
cout<<"colonna iniz.nave da 2:";cin>>col;
cout<<"orientamento (0/1):";cin>>s;
if(row >= 0 && col >= 0 && row < n && col < n){
if(H[row][col]==0){
if(s==0 && col+1 < n && H[row][col+1]==0){
   for(j=col;j < col+2;j++)H[row][j]=1;
   system("CLS");
   valido=true;p(H);
   }
if(s==1 && row+1 < n && H[row+1][col]==0){
   for(j=row;j < row+2;j++)H[j][col]=1;
   system("CLS");
valido=true;p(H);
   }
}else valido=false;
}else valido=false;
}while(valido==false);
}//fine caricamento 2 navi da 2

do{//caricamento una nave da 1
valido=false;
cout<<"riga nave da 1:"; cin>>row;
cout<<"colonna nave da 1:";cin>>col;
if(H[row][col]!=0)valido=false;
else {H[row][col]=1;valido=true;}
}while(valido==false); //fine caricamento una nave da 1
}//fine carica(H)

bool lancioPC(int H[n][n],int HPC[n][n]){
bool valido=false;
int row,col;
bool trovato=false;
srand(time(0));
do{
   valido=false;
   row=rand()%10;
   col=rand()%10;
   if(HPC[row][col]==1)valido=false;
   else {valido=true;HPC[row][col]=1;}
   if(valido)
      if(H[row][col]==1){ H[row][col]=0;trovato=true;} }while(valido==false);
return trovato;
}//fine lancioPC