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