2012-04-16 15 views
2

Я написал основную игру tic-tac-toe, основанную на многомерных массивах. г [3] [3]. В моей программе у меня есть около 9 условий, подобных той, которую я собираюсь вам показать:Есть ли более простой способ представления условий в C++?

if((g[0][0] == X && g[0][1] == X && g[0][2] == X) || (g[0][0] == O && g[0][1] == O && g[0][2] == O)) 

Это совершенно ненормально. Я, вероятно, делаю что-то неправильно, но именно поэтому я обращаюсь к этому вопросу. Есть ли более простой способ представления длинных и сложных условий, подобных этому? Например я не мог как-то сделать:

if(grid.hasXes) 
+5

петли? Таблица поиска? Функция? Возьмите свой выбор ... –

+0

@ Oli Charlesworth, можете ли вы привести несколько примеров каждого из них? – Bugster

ответ

6

Вы, вероятно, будете об этом неправильном пути. Есть только 3^9, или 19683 возможных комбинаций, так что вы можете преобразовать сетку к int, даже на 16 битной машине:

int 
asInt(char const (&grid)[3][3]) 
{ 
    int results = 0; 
    for (int i = 0; i != 3; ++ i) { 
     for (int j = 0; j != 3; ++ j) { 
      results *= 3; 
      switch (grid[i][j]) { 
      case 'X': 
       results += 1; 
       break; 

      case 'Y': 
       results += 2; 
       break; 

      case ' ': 
       break; 

      default: 
       assert(0); 
      } 
     } 
    } 
    return results; 
} 

После этого, вы можете использовать Int для индекса в таблицу указывая, кто выиграл (если кто). Кроме того, вы можете конвертировать только один или позицию другого игрока в 9 битном междунар:

int 
asInt(char const (&grid)[3][3], char who) 
{ 
    int results = 0; 
    for (int i = 0; i != 3; ++ i) { 
     for (int j = 0; j != 3; ++ j) { 
      results *= 2; 
      if (grid[i][j] == who) { 
       ++ results; 
      } 
     } 
    } 
    return results; 
} 

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

static int const wins[] = 
{ 
    0007, 0070, 0700,  // rows 
    0111, 0222, 0444,  // columns 
    0124, 0421    // diagonals 
}; 

class Wins 
{ 
    int myToMatch; 
public: 
    Wins(char const (&grid)[3][3], char who) 
     : myToMatch(asInt(grid, who)) 
    { 
    } 
    bool operator()(int entry) const 
    { 
     return (entry & myToMatch) == entry; 
    } 
}; 

Тогда:

if (std::find_if(begin(wins), end(wins), Wins(grid, 'X')) 
      != end(wins) { 
    // X wins 
else if (std::find_if(begin(wins), end(wins), Wins(grid, 'O')) 
      != end(wins) { 
    // O wins 
else 
    // play another turn. 

Можно даже рассмотреть хранение сетки в виде двух int с, по одному на игрока. Номер бита для позиции будет 3 * i + j, и проверить, если хода является легальным:

bool 
isLegal(int gridX, int gridY, int i, int j) 
{ 
    return ((gridX | gridY) & (1 << (3 * i + j))) == 0; 
} 
+0

Ничего себе этот ответ в значительной степени заставляет меня думать, что мой вопрос был глупым, так как существует так много способов. Этот ответ заставляет меня чувствовать себя настолько маленьким, спасибо! – Bugster

+2

@ ThePlan Совсем нет. Видеть такие возможности во многом зависит от опыта. И единственный способ получить этот опыт и научиться - это задавать такие вопросы. Я думал, что это хороший вопрос; вот почему я приложил некоторые усилия, чтобы понять, что я считаю хорошим ответом. (И техника бит-битби в конце - это не то, что может произойти с вами, если вы в прошлом не сделали что-то подобное). –

3

теперь я получил его ...

bool check(char *g, int x, int y, int moveX, int moveY, char ch) 
{ 
    for (int i(0); i<3; ++i) 
    { 
     if ((g+(y*3)+x) != ch) return false; 
     x += moveX; 
     y += moveY; 
    } 
    return true; 
} 

вы используете его так:

if (check(g, 0, 0, 0, 1, 'O')) //checking O in the first row. 
if (check(g, 0, 0, 0, 1, 'X')) //checking X in the first row. 
if (check(g, 0, 0, 1, 0, 'O')) //checking O in the first column. 
if (check(g, 0, 0, 1, 0, 'X')) //checking X in the first column. 
2

Вы могли бы написать функции, чтобы скрыть сложность и повысить читаемость вашей основной функции драйвера. Например, вы можете проверить строку или столбец, чтобы убедиться, что все это равно X или O.

4

Самый простой и самый мощный способ справиться с этой проблемой - просто извлечь уродливый код в функцию. Эта функция может быть членом класса, если это удобно, или просто свободной функцией. В вашем случае, быстрое исправление может быть

bool hasXes(char[3][3] g) { 
    return (g[0][0] == X && g[0][1] == X && g[0][2] == X) || (g[0][0] == O && g[0][1] == O && g[0][2] == O) 
} 

Тогда вы можете просто написать:

if (hasXes(g)) ... 
+0

вы должны хотя бы передать X функции или принять лямбда-доступность. Или Boost.bind ... – CapelliC

1

Это должно работать:

bool found = false; 
int i, j; 
for(i = 0; i < 3; i++) 
{ 
    for(j = 0; j < 3; j++) 
    { 
     if(g[i][j] == X) 
     { 
      found = true; 
      break; 
     } 
    } 
    if(found == true) 
    { 
     break; 
    } 
} 
if(found == true) 
{ 
    // do something because one of them had X. i, j have the co-ordinates of the first find of it 
} 
else 
{ 
    // none of them had X 
} 

Там может быть способ использовать Гото, как ну, хотя в C++ они сильно обескуражены. Если вам нужна только строка за раз, используйте только 1 цикл.

+0

Я использовал gotos в своем коде, несмотря на то, что это считается плохой практикой, потому что у меня не было терпения думать об альтернативных циклах. – Bugster

0

Еще один вариант на выбор. Вы можете использовать memcmp если хранилище является непрерывным

if(!memcmp(g[0],"XXX",3) || !memcmp(g[0],"OOO",3)) 
+0

+1 умный, -1 ewwww :) –

+0

@ ErnestFriedman-Hill: -1 почему? – Abhijit

+0

Шутка. Я вообще не голосовал. Я дал вам воображаемый +1 для умения и -1 для уродства; они балансируют без голосования. –

0

Вы могли бы посчитать крестики или попытаться найти их:

Предполагая, что г представляет собой массив 3 х 3, содержащие символы X или O:

char* end = g + 9; 
std::count(g, end, 'X') > 0; 

или более эффективно:

char* end = g + 9; 
std::find(g, end, 'X') != end; 
0

В этой спецификации IAL случая есть и несколько проще в сравнении:

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

По крайней мере, предполагая, что возможно только X и O. В противном случае это станет

if(g[0][0] == g[0][1] && g[0][1] == g[0][2] && (g[0][1] == X || g[0][1] == O)) 

Который все еще намного проще ИМХО.

Если вы не можете упростить подобное, используйте петлю, как указывали другие.

0

Typesafe комментарии!

const bool first_is_xful = g[0][0] == X && g[0][1] == X && g[0][2] == X, 
      second_is_xful = ...; 

if (first_is_xful || second_is_xful || ...) ... 

Или функция функция:

bool is_xful (int row, ...) ... 

... 

if (is_ixful(0) || ... 
Смежные вопросы