C ++ - проверка на 3 подряд - PullRequest
6 голосов
/ 20 февраля 2010

У меня есть массив символов 3 x 3, который должен представлять доску в крестики-нолики, и раньше я использовал несколько операторов «если», чтобы увидеть, есть ли 3 в строке. 1001 *

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

Я понял, что это много печатает и довольно подвержено ошибкам, так есть ли лучший способ сделать это?

Ответы [ 8 ]

3 голосов
/ 20 февраля 2010

Вы можете изменить его, чтобы проверять только с того места, где был сделан последний ход.

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

Или - Проверка всех состояний:

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

Или, если вы все-таки превратите ее в побитовую систему - держите отдельные платы X и O для простоты обновления. Тогда вам нужно только 9 бит для x, 9 бит для O, и ваши совпадения на выигрышных досках намного проще. (Чтобы найти открытые пространства в этом случае, просто поразрядно или доски x и 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
  }
}
1 голос
/ 20 февраля 2010

Адаптировано с конкурса Code Golf прошлой недели. Обратите внимание, что линейные шаблоны вдоль матрицы доски начинаются с заданного индекса и развиваются через равные интервалы.

И если вы представляете игрока 1 с 1, а игрока 2 с 2, то это независимые биты, и вы можете проверить на 3 подряд с помощью побитового 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;
}
1 голос
/ 20 февраля 2010

Я не знаю о «лучше», но вы можете разбить все на части:

//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 голос
/ 20 февраля 2010

Вы можете удалить парантез, потому что && имеет более низкий приоритет, чем ==

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

Вы также можете определить встроенную функцию (или макрос ), чтобы выделить равенство

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]))

Обратите внимание, что a==b==c не возвращает то, что вам нужно. Например, 0==0==1 верно для многих языков, производных от C.

1 голос
/ 20 февраля 2010

Вы можете зациклить это. Например, чтобы проверить все строки, которые вы можете сделать:

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

И сделать что-то подобное для столбцов. Тогда вам просто нужно проверить диагонали отдельно.

0 голосов
/ 20 февраля 2010

Вы можете хранить индексы, которые составляют выигрышные строки, и использовать один цикл:

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

Я также поддерживаю предложения Джеффа хранить ходы игроков в отдельных значениях и использовать побитовые операции.

0 голосов
/ 20 февраля 2010

Вот полное решение в виде функции проверки, которая проверяет, выиграл ли игрок (1 или 2, обозначающий Х и О):

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

РЕДАКТИРОВАТЬ: я предпочел этот подход (возвращая номер победившего игрока), а не просто проверить, был ли победитель, так как он казался более практичным для использования.

Надеюсь, это поможет!

0 голосов
/ 20 февраля 2010

Да, вы могли бы сделать это

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

Может быть, даже написать функцию

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

Хотя он имеет скрытую сторону, он не будет работать, если board [0] [0], board [0] [0], board [0] [1] равны 0.

Альтернативой является написание цикла for, но я думаю, это еще больше печатает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...