2010-02-20 16 views
6

Ho questa matrice di 3 x 3 di caratteri che dovrebbe rappresentare una scheda di tic-tac-toe, e prima, userei un gruppo di istruzioni "if" per vedere se c'erano 3 di fila.C++ - Controllo di 3 di fila

... if ((scheda [0] [0] == bordo [0] [1]) & & (scheda [0] [1] == bordo [0] [2])) { ...} ...

mi sono reso conto che questo è un sacco di battitura, e molto soggetto a errori, per cui c'è un modo migliore per fare questo?

+6

9 valori, tre stati ciascuno, quindi due bit per cella = 18 bit. Ciò si inserisce in un int su qualsiasi macchina decente. Quindi è possibile eseguire un unico grande interruttore o eseguire operazioni bit a bit con maschere predefinite. –

+0

Molto meglio l'idea, Nikolai. +1 –

+0

Abbiamo avuto una gara di short-program tic-tac-toe non molto tempo fa: http://stackoverflow.com/questions/2245801/code-golf-tic-tac-toe/2256299#2256299 – Potatoswatter

risposta

0

Sì, si potrebbe fare questo

if (board[0][0]==board[0][1]==board[0][2]) {...} 

Forse anche scrivere una funzione

inline boolean row_win(int row_num){ 
    return (board[row_num][0]==board[row_num][1]==board[row_num][2]); 
} 

Ha un lato nascosto, però, non funzionerà se la scheda [0] [0], bordo [0] [0], board [0] [1] sono uguali a 0.

Un'alternativa è la scrittura di un ciclo for, ma immagino che sia ancora più digitante.

+0

speravo in qualcosa che implicasse meno digitazione. Avrei ancora bisogno di fare un "se" per ogni tripletta valida. – cornjuliox

+0

Non sono del tutto sicuro che funzioni. Diciamo che il primo '==' viene valutato per primo e valutato come vero, quindi si ottiene qualcosa come '1 == board [0] [2]' che non è ciò che l'OP intende. Se va nella direzione opposta, allora ottieni 'board [0] [0] == 1' che non è nemmeno quello che l'OP intende. –

+1

Hai ragione, hai fatto il test con int a, b, c = 50,50,50. a == b restituisce 1, e 1 <> 50. – Tom

1

Si potrebbe loop it. Per esempio per controllare tutte le righe che potresti fare:

for(int i = 0; i < 3; i++){ 
    if((board[i][0]==board[i][1]) && (board[i][1]==board[i][2])){ 
     .... 
    } 
} 

E fare qualcosa di simile per le colonne. Quindi devi solo controllare le diagonali separatamente.

+0

Vedere il commento sulla risposta di Tom - Non sono del tutto sicuro concatenare che 'operator ==' è permesso come concatenare 'operator =' is. –

+0

Ma +1 'for' suggerimento di loop. –

+0

Sì, non ero nemmeno sicuro, ma speravo solo che l'altra persona avesse ragione. Lo cambierò in quello che so è giusto. –

1

È possibile rimuovere il paranthesis perché && ha priorità inferiore rispetto ==

if (board[0][0] == board[0][1] && board[0][1] == board[0][2]) 

È anche possibile definire una funzione linea (o macro) per scomporre parità

inline bool are_equal(int a, int b, int c) { 
    return a == b && b == c; 
} 
... 
if (are_equal(board[0][0], board[0][1], board[0][2])) 

Note che a==b==c non restituisce quello che ti serve. Ad esempio, 0==0==1 è vero in molti linguaggi derivati ​​da C.

3

È possibile modificarlo per verificare solo da dove è stata effettuata l'ultima mossa.

//lr = lastMoveRow 
//lc = lastMoveCol 

// no need to check blank with last move known 
if (board[0][lc] == board[1][lc] && board[0][lc] == board[2][lc] || 
    board[lr][0] == board[lr][1] && board[lr][0] == board[lr][2]){ 
     // Game over 
} 

// Check diagonals 
if (board[1][1] != blank && 
    (board[0][0] == board[1][1] && board[0][0] == board[2][2] || 
    board[2][0] == board[1][1] && board[2][0] == board[0][2])){ 
    // Game over 
} 

O - Controllo tutti gli stati:

//Check horizontals and verticals at once 
for (int i = 0; i < 3; ++i){ 
    // Check column and row at once 
    if (board[0][i] != blank && board[0][i] == board[1][i] && board[0][i] == board[2][i] || 
     board[i][0] != blank && board[i][0] == board[i][1] && board[i][0] == board[i][2]){ 
     // Game over 
    } 
} 

// Check diagonals 
if (board[1][1] != blank && 
    (board[0][0] == board[1][1] && board[0][0] == board[2][2] || 
    board[2][0] == board[1][1] && board[2][0] == board[0][2])){ 
    // Game over 
} 

o se trasformarlo in un po 'dal sistema bit - mantenere X separato e tavole O per facilità di aggiornamento. Allora hai solo bisogno di 9 bit per x, 9 bit per O, e le tue partite di scacchi vincenti sono molto più semplici. (Per trovare spazi aperti in questo caso, solo bit per bit o le schede X e O)

// winning 9 bit boards 
// int winningBoards[8] 
000000111 
000111000 
111000000 
001001001 
010010010 
100100100 
100010001 
001010100 

//xBoard and yBoard can be ints 
for (int i = 0; i < 8; ++i){ 
    if (xBoard & winningBoards[i] == winningBoards[i]){ 
    //Game over 
    } 
} 
+0

L'unico problema con questa risposta è che non gestisce i casi in cui un quadrato è vuoto. Se una riga è completamente vuota segnalerà il successo, anche se il gioco non è finito. Altrimenti, +1. –

+0

Buon punto - Lo aggiusterò. – Jeff

1

non so di "migliore", ma si potrebbe rompere le cose serie:

//Set empty to whatever value you're using for an empty square. 
#define empty '\0' 

bool thereIsALine(char matrix[3][3]) 
{ 
    char c; 
    //Check all columns: 
    for(int i = 0; i < 3; i++) 
    { 
     c = matrix[i][0]; 
     if (c == empty) 
      break; 
     if (c == matrix[i][1] && c == matrix[i][2]) 
      return true; 
    } 
    //Check all rows: 
    for(int i = 0; i < 3; i++) 
    { 
     c = matrix[0][i]; 
     if (c == empty) 
      break; 
     if (c == matrix[1][i] && c == matrix[2][i]) 
      return true; 
    } 
    //Check diagonals 
    c = matrix[1][1]; 
    if (c == empty) return false; 
    if (c == matrix[0][2] && c == matrix[2][0]) 
     return true; 
    if (c == matrix[0][0] && c == matrix[2][2]) 
     return true; 
    return false; 
} 
1

Adattato dalla competizione Code Golf della scorsa settimana. Si noti che i modelli lineari lungo la matrice della tavola iniziano con un dato indice e progrediscono lungo intervalli uguali.

E se rappresenti il ​​giocatore 1 con un 1 e il giocatore 2 con un 2, allora quelli sono bit indipendenti e puoi testare per 3 di fila con AND bit a bit.

char check_1row(char *board, int base, int stride) { 
    return board[ base ] & board[ base + stride ] & board[ base + 2 * stride ]; 
} 

char check_win(char (&board)[3][3]) { 
    char winner = 0; 
    winner |= check1row(board, 0, 4); // check NW/SE diagonal 
    for (int i = 0; i < 3; i ++) { 
     winner |= check1row(board, i, 3); // check verticals 
    } 
    winner |= check1row(board, 2, 2); // check NE/SW diagonal 
    for (int i = 0; i < 9; i += 3) { 
     winner |= check1row(board, i, 1); // check horizontals 
    } 
    return winner; 
} 
+0

Piuttosto bello! Tuttavia, la domanda richiede una matrice bidimensionale, non una 1-dimensionale. In che modo questo approccio può essere generalizzato? Forse analizzando prima l'array 2D in 1D? – Morlock

+0

@Morlock: gli array 2D e 1D sono garantiti equivalenti. Appena lanciato, non è necessaria alcuna analisi. Risposta modificata per adattarsi meglio. – Potatoswatter

0

Ecco una soluzione completa, sotto forma di una funzione di controllo che verifica se un giocatore (1 o 2, in piedi per la X e O) vince:

// tic tac toe win checker 

#include<iostream> 

using namespace std; 

const int DIM = 3; 

int check (int t[DIM][DIM]) { 
    // 0 is empty, 1 is X, 2 is O 
    // return 1 or 2 if there is a win from either 
    for (int row=0; row<DIM; row++) { 
     if (t[row][0] == t[row][1] && t[row][1] == t[row][2]) { 
      if (t[row][0] != 0) return t[row][0]; 
     } 
    } 
    for (int col=0; col<DIM; col++) { 
     if (t[0][col] == t[1][col] && t[0][col] == t[2][col]) { 
      if (t[0][col] != 0) return t[0][col]; 
     } 
    } 
    if (t[0][0] == t[1][1] && t[1][1] == t[2][2]) { 
     if (t[0][0] != 0) return t[0][0]; 
    } 
    if (t[0][2] == t[1][1] && t[1][1] == t[2][0] != 0) { 
     if (t[0][2] != 0) return t[0][2]; 
    } 
    return 1; 
} 

int main() { 
    int ttt[DIM][DIM]; 
    ttt[1][0] = 2; // Initialyzing row no. 2 to values "2" to test 
    ttt[1][1] = 2; 
    ttt[1][2] = 2; 
    if (check(ttt) != 0) { 
     cout << "Player " << check(ttt) << " wins\n"; 
    } 
    else { 
     cout << "No winner yet\n"; 
    } 
} 

EDIT: ho preferito questo approccio (restituendo il numero del giocatore vincente) piuttosto che semplicemente verificare se ci fosse un vincitore, poiché sembrava più pratico da usare.

Spero che aiuti!

+0

Perché preoccuparsi di definire una macro 'DIM' se stai solo andando a codificare i controlli diagonali alla fine? inoltre, questa è essenzialmente la stessa risposta che ho postato 39 minuti prima di te. –

+0

È vero, tranne che questa soluzione restituisce il vincitore, invece di restituire 'true' se c'è un vincitore. Non ho alcuna pretesa che questa sia la migliore risposta possibile, tanto più che ho iniziato ad imparare il C++ la scorsa settimana. Questo potrebbe essere il motivo per cui non ho notato la somiglianza dell'approccio con la soluzione, tuttavia essi si assomigliano a vicenda, anzi. Cheers – Morlock

+0

Perché hai reso 'ttt' globale? – avakar

0

è possibile memorizzare gli indici che compongono il file vincente, e utilizzare un unico anello:

int win_row[][3] = {{0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}}; 
int win_col[][3] = {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {0, 1, 2}, {2, 1, 0}}; 

bool has_winner(char board[][3]) 
{ 
    //'\0' means unoccupied 
    for (int i = 0; i != 8; ++i) { 
     char c = board[win_row[i][0]][win_col[i][0]]; 
     if (c && c == board[win_row[i][1]][win_col[i][1]] && c == board[win_row[i][2]][win_col[i][2]]) { 
      return true; 
     } 
    } 
    return false; 
} 

Sostengo anche i suggerimenti di Jeff di memorizzazione di mosse dei giocatori nel separare i valori e l'utilizzo di operazioni bit per bit.

Problemi correlati