2010-02-20 18 views
6

Mam tablicę 3 x 3 znaków, która ma reprezentować tablicę typu kółko i krzyżyk, a wcześniej używałbym wielu instrukcji "jeśli", aby sprawdzić, czy były 3 z rzędu.C++ - Sprawdzanie 3 z rzędu

... jeśli ((płyta [0] [0] == płyta [0] [1]) & & (płyta [0] [1] == płyta [0] [2])) { ... } ...

zdałem sobie sprawę, że jest to dużo pisania, i dość podatne na błędy, więc czy istnieje lepszy sposób to zrobić?

+6

9 wartości, po trzy stany, a więc dwa bity na komórkę = 18 bitów. To pasuje do int na każdej przyzwoitej maszynie. Następnie możesz wykonać jeden duży przełącznik lub wykonać operacje bitowe z wcześniej zdefiniowanymi maskami. –

+0

Znacznie lepszy pomysł, Nikolai. +1 –

+0

Niedawno graliśmy w programie na najkrótszą trasę: http://stackoverflow.com/questions/2245801/code-golf-tic-tac-toe/2256299#2256299 – Potatoswatter

Odpowiedz

0

Tak, można to zrobić

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

Może nawet napisać funkcję

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

Posiada ukrytą strony jednak, to nie będzie działać, jeśli tablica [0] [0], deska [0] [0], tablica [0] [1] jest równa 0.

Alternatywą jest pisanie pętli for, ale myślę, że to jeszcze więcej pisania.

+0

Miałem nadzieję na coś, co wymagało mniej pisania. Wciąż potrzebowałbym zrobić "jeśli" dla każdej ważnej trójki. – cornjuliox

+0

Nie jestem całkowicie pewien, że to działa. Powiedz najpierw, że pierwsze "==" jest oceniane najpierw i jest prawdziwe, wtedy dostajesz coś w rodzaju '1 == plansza [0] [2]' co nie jest tym, co OP zamierza. Jeśli pójdzie w drugą stronę, otrzymasz 'board [0] [0] == 1', co również nie jest tym, co OP zamierza. –

+1

Masz rację, wykonałeś test z int, b, c = 50,5050. a == b ocenia na 1, a 1 <> 50. – Tom

1

Można go zapętlić. Na przykład, aby sprawdzić wszystkie wiersze, które możesz wykonać:

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

Zrób coś podobnego dla kolumn. Następnie wystarczy sprawdzić przekątne osobno.

+0

Zobacz komentarz na temat odpowiedzi Toma - nie jestem całkowicie pewny, że 'operator ==' jest dozwolony jak łańcuch 'operator ='. –

+0

Ale +1 "za" sugestia pętli. –

+0

Tak, też nie byłem pewien, ale miałem tylko nadzieję, że ta druga osoba ma tę część. Zmienię to na to, co wiem, że jest właściwe. –

1

można wyjąć nawiasach bo && ma niższy priorytet niż ==

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

Można również zdefiniować funkcję inline (lub makro) czynnik poza równości

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 że a==b==c nie zwraca tego, czego potrzebujesz. Na przykład 0==0==1 jest prawdziwe w wielu językach pochodnych języka C.

3

Można go zmienić, aby sprawdzić tylko od miejsca, w którym wykonano ostatni ruch.

//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 
} 

Albo - Sprawdzanie wszystkie stany:

//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 
} 

Albo jeśli nie przekształcić go w kawałku przez system bit - zachować odrębną X i deski O względu na łatwość aktualizacji. Wtedy potrzebujesz tylko 9 bitów na x, 9 bitów na O, a twoje zwycięskie mecze na desce są znacznie prostsze. (Aby dowiedzieć się otwarte przestrzenie w tym przypadku, po prostu bitowe lub X i O deski)

// 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

Jedyny problem z tą odpowiedzią polega na tym, że nie obsługuje przypadków, w których kwadrat jest pusty. Jeśli rząd jest całkowicie pusty, zgłasza on sukces, mimo że gra się nie skończyła. W przeciwnym razie +1. –

+0

Dobra uwaga - naprawię to. – Jeff

1

nie wiem o „lepsze”, ale można złamać rzeczy seryjnie:

//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

Dopasowanie z zeszłotygodniowej konkurencji Code Golf. Zauważ, że liniowe wzory wzdłuż matrycy planszy zaczynają się od danego indeksu i postępują w równych odstępach.

Jeśli reprezentujesz gracza 1 z 1, a gracza 2 z 2, to są to niezależne bity i możesz przetestować 3 z rzędu z bitowym AND.

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

Raczej przyjemnie! Jednak pytanie dotyczy dwuwymiarowej tablicy, a nie jednowymiarowej. W jaki sposób można uogólnić to podejście? A może najpierw parsując tablicę 2D do postaci 1D? – Morlock

+0

@Mlocklock: Macierze 2D i 1D są gwarantowane równoważne. Wystarczy rzutować, nie trzeba parsować. Edytowano odpowiedź, aby pasowała lepiej. – Potatoswatter

0

Tutaj jest kompleksowe rozwiązanie w postaci funkcji kontroli, która sprawdza, czy gracz (1 lub 2, stały dla X i O) wygrywa:

// 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"; 
    } 
} 

Edycja: kontynuować takie podejście (zwracanie liczby zwycięskich graczy) zamiast po prostu weryfikować, czy był zwycięzca, ponieważ wydawało się bardziej praktyczne w użyciu.

Mam nadzieję, że pomoże!

+0

Po co zawracać sobie głowę definiowaniem makra 'DIM', jeśli masz zamiar po prostu zakodować przekątne czeki na końcu? także, to jest w zasadzie ta sama odpowiedź, którą zamieściłem 39 minut przed tobą. –

+0

Raczej prawdziwe, z wyjątkiem tego, że to rozwiązanie zwraca zwycięzcę, zamiast zwracać "true", jeśli jest zwycięzca. Nie mam żadnych pretensji, że jest to najlepsza możliwa odpowiedź, tym bardziej, że w zeszłym tygodniu zacząłem uczyć się języka C++. Być może dlatego nie zauważyłem podobieństwa w podejściu do twojego rozwiązania, ale w rzeczywistości są do siebie podobne. Pozdrawiam – Morlock

+0

Dlaczego stworzyłeś 'ttt' na świecie? – avakar

0

można przechowywać indeksy, które składają się wygraną wierszy i użyć pojedynczej pętli:

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; 
} 

popieram także sugestii Jeffa przechowywania ruchy zawodników w poszczególnych wartości oraz stosując operacje bitowe.