001: #include<stdio.h>
002: #include<stdlib.h>
003:
004: // definisco due costanti con le dimensioni della scacchiera
005: #define NCOLS (7)
006: #define NROWS (6)
007:
008: // non era richiesto dal testo ma tengo traccia anche di come si e' vinto
009: #define VINTO_NO (0)
010: #define VINTO_RIGA (1)
011: #define VINTO_COL (2)
012: #define VINTO_DIAG (3)
013:
014:
015: // funzione richiesta dal codice
016: void simula4(char *filename);
017:
018: // funzioni che definisco io e rendono il codice piu' modulare e leggibile
019:
020: // funzione che stampa lo stato della scacchiera
021: void stampa_scacchiera(char s[NROWS][NCOLS]);
022: // funzione che inserisce la pedina di uno dei due giocatori in una specifica colonna
023: int inserisci_pedina(char s[NROWS][NCOLS], int colonna, char simbolo_giocatore);
024: // controlla se uno dei due giocatori ha vinto, internamente poi usa funzioni specifiche per le colonne, righe e diagonali
025: int vinto(char s[NROWS][NCOLS], char simbolo_giocatore, int riga, int colonna);
026:
027: int main(int argc, char **argv){
028:
029: char nome[1000];
030: printf("Inserisci il file che vuoi aprire: ");
031: scanf("%s", nome);
032:
033: simula4(nome);
034:
035: return 0;
036: }
037:
038: void simula4(char *filename)
039: {
040: // definisco la scacchiera e la inizializzo come vuota
041: char scacchiera[NROWS][NCOLS]; // uso un array di char, spazio=casella vuota altrimenti simboli dei giocatori (X e O)
042: for(int r = 0; r < NROWS; ++r)
043: for(int c = 0; c < NCOLS; ++c)
044: scacchiera[r][c] = ' '; // inizialmente vuota
045:
046: FILE *fp = fopen(filename, "r");
047: if(!fp)
048: {
049: perror("");
050: exit(EXIT_FAILURE);
051: }
052:
053: // indico i giocatori con X e O. X gioca per primo. Uso la seguente variabile per tener traccia di chi sta giocando
054: char simbolo_giocatore = 'X';
055:
056: int colonna;
057:
058: // leggo il file mossa per mossa fino al termine del file o fino alla vittoria di qualcuno
059: while(fscanf(fp, "%d", &colonna) == 1)
060: {
061: // inserisco la pedina:
062: int riga = inserisci_pedina(scacchiera, colonna, simbolo_giocatore); // la funzione restituisce anche la riga in cui si e' "fermata " la pedina
063:
064: // stampo la scacchiera aggiornata:
065: stampa_scacchiera(scacchiera);
066:
067: // controllo vittoria e nel caso termino:
068: // passo anche indicazione del giocatore che ha messo la pedina perche', nel caso, solo lui puo' aver vinto, le coordinate
069: // dell'ultima pedina semplificano il controllo
070: int come;
071: if((come = vinto(scacchiera, simbolo_giocatore, riga, colonna)) != VINTO_NO)
072: {
073: printf("Il giocatore [%c] ha vinto la partita allineando le pedine ", simbolo_giocatore);
074: switch(come) // non richiesto dal testo, stampo anche come si e' vinto oltre a chi
075: {
076: case VINTO_RIGA:
077: printf("nella riga %d\n", riga);
078: break;
079: case VINTO_COL:
080: printf("nella colonna %d\n", colonna);
081: break;
082: case VINTO_DIAG:
083: printf("diagonale\n");
084: break;
085: }
086: return; // esco
087: }
088:
089: // commuto il giocatore per il turno successivo
090: if(simbolo_giocatore == 'X')
091: simbolo_giocatore = 'O';
092: else
093: simbolo_giocatore = 'X';
094: // un programmatore un po' piu' scantato avrebbe usato: simbolo_giocatore = (simbolo_giocatore == 'X'?'O':'X');
095: }
096:
097: // se arrivo qui, il file e' finito ma nessuno ha vinto
098: printf("Incredibile, partita patta!\n");
099:
100: }
101:
102: // inserisce la pedina nella colonna di indice colonna. giocatore contiene il simbolo della pedina
103: // ovvero 'X' o 'O'
104: int inserisci_pedina(char s[NROWS][NCOLS], int colonna, char simbolo_giocatore)
105: {
106: // a partire dall'alto cerco la prima posizione libera in quella colonna e vi scrivo il simbolo
107: // personalmente considero le righe numerate dal basso quindi la riga di indice 0 e' la prima in basso
108: // quella di indice 1 la seconda a partire dal basso ecc.
109: // era del tutto possibile la convenzione opposta. Basta che inserimento e stampa siano coerenti
110:
111: for(int r = 0; r < NROWS; ++r)
112: if(s[r][colonna] == ' ')
113: {
114: printf("\nInserisco pedina [%c] nella colonna %d, questa finisce alla riga %d\n", simbolo_giocatore, colonna, r);
115: s[r][colonna] = simbolo_giocatore;
116: return r;
117: }
118:
119: // i file sono stati generati casualmente, questo non era richiesto ma lo aggiungo per sicurezza
120: printf("Errore nel file, ho tentato di inserire la pedina nella colonna %d ma era gia' piena\n", colonna);
121: exit(1);
122: }
123:
124: void stampa_scacchiera(char s[NROWS][NCOLS])
125: {
126: // stampo riga per riga tenendo conto pero' che ho scelto come convenzione che la riga 0 sia
127: // quella in basso ecc.
128: printf(" 0 1 2 3 4 5 6 \n");
129: printf(" +-+-+-+-+-+-+-+\n");
130: for(int r = NROWS - 1; r >= 0; --r)
131: {
132: printf("%d ", r);
133: for(int c = 0; c < NCOLS; ++c)
134: {
135: printf("|%c", s[r][c]);
136: }
137: printf("|\n +-+-+-+-+-+-+-+\n");
138: }
139: printf("\n");
140: }
141:
142: // funzione che controlla se nella riga passata ci sono 4 simboli consecutivi
143: // le controllo tutte sebbene si potesse ottimizzare e limitarsi all'ultima riga
144: // modificata
145: int controlla_riga(char s[NROWS][NCOLS], char simbolo_giocatore, int riga)
146: {
147: // questa variabile la incremento ogni volta che incontro il simbolo passato
148: // e la rimetto a 0 ogni volta che incontro un simbolo differente o una cella vuota
149: // se raggiungo 4 ho inanellato almeno 4 simbolo_giocatore di fila e posso terminare la ricerca
150: int sequenza = 0;
151: for(int c=0; c<NCOLS; ++c)
152: {
153: if(s[riga][c] != simbolo_giocatore)
154: {
155: sequenza = 0; // sequenza interrotta (o mai iniziata) riporto il mio contatore a 0
156: }
157: else
158: {
159: ++sequenza; // incremento il numero di simbolo_giocatore di seguito
160: if(sequenza == 4) // Bingo! Ho trovato almeno 4 simboli di seguito nella stessa riga, mi posso fermare qui
161: return 1;
162: }
163: }
164:
165: return 0; // niente, nessua riga aveva almeno 4 pedine in fila
166: }
167:
168: int controlla_colonna(char s[NROWS][NCOLS], char simbolo_giocatore, int colonna)
169: {
170: int sequenza = 0;
171: for(int r=0; r<NROWS; ++r)
172: {
173: if(s[r][colonna] != simbolo_giocatore)
174: {
175: sequenza = 0;
176: }
177: else
178: {
179: ++sequenza;
180: if(sequenza == 4)
181: return 1;
182: }
183: }
184:
185: return 0;
186: }
187:
188: int controlla_diagonale_dx(char s[NROWS][NCOLS], char simbolo_giocatore, int riga, int colonna)
189: {
190: // leggermente piu' complicato
191: // il meccanismo e' quello gia' visto nelle due sopra ma devo spostarmi sia di riga che di colonna
192: // per muovermi in diagonale
193: // quindi uso un singolo ciclo in cui ogni volta aggiorno entrambe le coordinate
194:
195: int sequenza = 0;
196: while(riga < NROWS && colonna < NCOLS)
197: {
198: if(s[riga][colonna] != simbolo_giocatore)
199: {
200: sequenza = 0;
201: }
202: else
203: {
204: ++sequenza;
205: if(sequenza == 4)
206: return 1;
207: }
208:
209: ++riga;
210: ++colonna;
211: }
212:
213: return 0;
214: }
215:
216: // come la precedente, cambia solo come mi sposto (questo codice si potrebbe effettivamente fattorizzare)
217: int controlla_diagonale_sx(char s[NROWS][NCOLS], char simbolo_giocatore, int riga, int colonna)
218: {
219: int sequenza = 0;
220: while(riga < NROWS && colonna > 0)
221: {
222: if(s[riga][colonna] != simbolo_giocatore)
223: {
224: sequenza = 0;
225: }
226: else
227: {
228: ++sequenza;
229: if(sequenza == 4)
230: return 1;
231: }
232:
233: ++riga;
234: --colonna;
235: }
236:
237: return 0;
238: }
239:
240: // questa funzione controlla se il giocatore con il simbolo passato ha vinto la partita
241: // restituendo vero o falso in base a questo
242: // mi avvalgo di funzioni che verificano righe, colonne e diagonali
243: int vinto(char s[NROWS][NCOLS], char simbolo_giocatore, int riga, int colonna)
244: {
245:
246: // controlliamo la riga modificata
247: // la funziona chiamata restituisce 1 se nella colonna con indice r ci sono almeno 4 pedine in fila di tipo "simbolo_giocatore"
248: if(controlla_riga(s, simbolo_giocatore, riga))
249: return VINTO_RIGA;
250:
251: // controlliamo la colonna, stesso meccanismo di prima
252: if(controlla_colonna(s, simbolo_giocatore, colonna))
253: return VINTO_COL;
254:
255: // PER SEMPLICITA' USO APPROCCIO A FORZA BRUTA
256: // controllo tutte le diagonali che hanno almeno 4 celle
257: // quindi mi limito alle diagonali che hanno almeno 4 celle
258:
259: // diagonali che, partendo dal basso, si spostano verso destra
260: // quelle che partono dalla prima riga in basso
261: for(int c=0; c<NCOLS-3; ++c)
262: if(controlla_diagonale_dx(s, simbolo_giocatore, 0, c))
263: return VINTO_DIAG;
264: // quelle che partono dalla prima colonna a sinistra
265: for(int r=1; r<NROWS-3; ++r)
266: if(controlla_diagonale_dx(s, simbolo_giocatore, r, 0))
267: return VINTO_DIAG;
268:
269: // DIAGONALI CHE PARTENDO DAL BASSO SI SPOSTANO VERSO SINISTRA
270: // quelle che partono dalla prima riga in basso
271: for(int c=3; c<NCOLS; ++c)
272: if(controlla_diagonale_sx(s, simbolo_giocatore, 0, c))
273: return VINTO_DIAG;
274: // quelle che partono dalla prima colonna a destra
275: for(int r=0; r<NROWS-3; ++r)
276: if(controlla_diagonale_dx(s, simbolo_giocatore, r, NCOLS - 1))
277: return VINTO_DIAG;
278:
279:
280: return VINTO_NO; // e niente, nessuno ha ancora vinto
281: }
282: