001: #include<stdio.h>
002: #include<stdlib.h>
003: #include<time.h>
004: 
005: // un po' di costanti che usero' per memorizzare la situazione griglia
006: #define VUOTO        0
007: #define NAVE         1
008: #define COLPITO     -1
009: #define COLPOAVUOTO  3
010: 
011: void place_ship(int n, int grid[n][n], int l);
012: void print_grid(int n, int grid[n][n]);
013: int  shoot(int n, int grid[n][n], int c, int r);
014: 
015: int main(int argc, char **argv){
016: 
017:   // genero casualmente la dimensione della griglia nell'intervallo [9,13]
018:   srand(time(0));
019:   const int n = rand()%5 + 9;
020: 
021:   // definiamo la griglia allocando dinamicamente un array bidimensionale n x n in cui, inizialmente, pongo tutte le celle a 0 (vuoto)
022:   int grid[n][n];
023:   for(int c = 0; c < n; ++c)
024:     for(int r = 0; r < n; ++r)
025:       grid[r][c] = VUOTO;
026: 
027:   // invoco la funzione place_ship() per inserire le navi come da testo
028:   place_ship(n, grid, 4);
029:   place_ship(n, grid, 3);
030:   place_ship(n, grid, 3);
031:   place_ship(n, grid, 2);
032:   place_ship(n, grid, 2);
033:   place_ship(n, grid, 2);
034:   place_ship(n, grid, 1);
035:   place_ship(n, grid, 1);
036:   place_ship(n, grid, 1);
037:   place_ship(n, grid, 1);
038:   int n_ship_cells = 4 + 3 + 3 + 2 + 2 + 2 + 1 + 1 + 1 + 1; // tengo traccia di quante celle sono occupate da navi
039:   
040:   // stampa di debug
041:   print_grid(n, grid);
042: 
043:   // entro in ciclo che terminero' solo quanto avro' colpito tutte le navi in tutte le celle
044:   while(n_ship_cells)
045:   {
046:     printf("Inserire le coordinate per il tentativo (griglia %dx%d): ", n, n);
047:     int r, c;
048:     scanf("%d%d", &r, &c); // per semplicita' uso coordinate solo numeriche
049:     int colpito = shoot(n, grid, c - 1, r - 1); // tradizionalmente le coordinate partono da 1, correggo nel caso degli array
050:     if(colpito)
051:     {
052:       printf("Colpito!\n");
053:       --n_ship_cells;
054:     }
055:     else
056:     {
057:       printf("Niente...\n");
058:     }
059:     print_grid(n, grid);
060:   }
061: 
062:   return 0;
063: }
064: 
065: void place_ship(int n, int grid[n][n], int l)
066: {
067:   // in questa funzione devo piazzare una nava di lunghezza l in una posizione casuale
068:   // anche il fatto che sia in orizzontale e verticale va deciso casualmente
069:   // pero' devo anche considerare che ci stia e non si sovrapponga ad altre navi gia' precedentemente inserite
070:   // quindi genero casualmente coordinate e direzione e ripeto fino a che le condizioni non sono soddisfatte
071:   // una volta stabilito che ci sta imposto ad '1' tutte le celle della griglia che la contengono
072: 
073:   // entro in un ciclo da cui esco se e solo se le coordinate generate e la direzione generata sono tali da poter piazzare
074:   // la nave senza che esca dai bordi o si sovrapponga ad altre navi
075:   int c, r, dir; // variabili che uso per memorizzare coordinate e direzione scelte casualmente
076:   while(1)
077:   {
078:     // genero coordinate e direzioni casuali per piazzare nave
079:     c   = rand()%n; // colonna
080:     r   = rand()%n; // riga
081:     dir = rand()%2; // 0 -> orizzontale, 1 -> verticale
082: 
083:     // controllo che non esca
084:     if(!dir & c+l >= n) // controllo che non esca in orizzontale
085:       continue; // ripeto
086:     
087:     if(dir & r+l >= n) // controllo che non esca in verticale
088:       continue; // ripeto
089:     
090:     // guardo tutte le celle dove dovrei piazzarla se per caso sono gia' occupate
091:     int conflitto = 0; // variabile che uso per capire se "incontro" altre navi
092: 
093:     if(!dir)
094:     {
095:       for(int i = c; i < (c + l); ++i)
096:   if(grid[r][i] == NAVE)
097:     conflitto = 1;
098:     }
099:     else
100:     {
101:       for(int i = r; i < (r + l); ++i)
102:   if(grid[i][c] == NAVE)
103:     conflitto = 1;
104:     }
105: 
106:     if(conflitto) // diventa 1 se e solo se nella posizione generata casualmente si sovrapporrebbe ad altre navi
107:       continue; // ripeto
108: 
109:     // se arrivo qui la nave ci starebbe e di conseguenza esco dal ciclo
110:     break;
111:   }
112: 
113:   // piazzo la nave
114: 
115:   if(!dir)
116:     for(int i = c; i < (c + l); ++i)
117:       grid[r][i] = NAVE;
118:   else
119:     for(int i = r; i < (r + l); ++i)
120:       grid[i][c] = NAVE;
121: }
122: 
123: 
124: // funzione di stampa (molto minimale)
125: void print_grid(int n, int grid[n][n])
126: {
127:   printf("%dx%d grid:\n", n, n);
128: 
129:   // stampo coordinate colonne
130:   printf("   ");
131:   for(int r = 0; r < n; ++r)
132:   {
133:     printf("%c", 'A' + r);
134:   }
135:   printf("\n");
136: 
137:   for(int r = 0; r < n; ++r)
138:   {
139:     printf(" %2d", r+1); // coordinate righe
140:     for(int c = 0; c < n; ++c)
141:     {
142:       switch(grid[r][c])
143:       {
144:   case NAVE: // nave
145:     printf("#");
146:     break;
147:   case COLPITO: // nave colpita
148:     printf("*");
149:     break;
150:   case VUOTO: // cella vuota
151:     printf(" ");
152:     break;
153:   case COLPOAVUOTO: // colpo a vuoto
154:     printf(".");
155:     break;
156:       }
157:     }
158:     printf("\n");
159:   }
160: }
161: 
162: int shoot(int n, int grid[n][n], int c, int r)
163: {
164:   if(grid[r][c] == NAVE) // c'e' una nave in quelle coordinate?
165:   {
166:     grid[r][c] = COLPITO; // segno il colpo e restituisco 1
167:     return 1;
168:   }
169: 
170:   // altrimenti era una cella vuota (o comunque dove avevo gia' sparato)
171:   grid[r][c] = COLPOAVUOTO;
172:   return 0;
173: }
174: