我写了一个基于多维数组的基本井字游戏。g[3][3]。在我的程序中,我有大约 9 个条件,就像我将要向您展示的那样:
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)
我写了一个基于多维数组的基本井字游戏。g[3][3]。在我的程序中,我有大约 9 个条件,就像我将要向您展示的那样:
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)
你可能走错了路。只有 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.
您甚至可以考虑将网格保持为两个ints,每个玩家一个。位置的位数将是3 * i + j,并测试移动是否合法:
bool
isLegal( int gridX, int gridY, int i, int j )
{
return ((gridX | gridY) & (1 << (3 * i + j))) == 0;
}
处理此类问题的最简单且最强大的方法是将丑陋的代码提取到函数中。如果方便的话,该函数可以是一个类的成员,或者只是一个自由函数。在您的情况下,快速修复可能是
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)) ...
现在我知道了...
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.
您可以编写函数来隐藏复杂性并增强主驱动程序函数的可读性。例如,您可以检查一行或一列以查看它是否都等于 X 或 O。
这应该有效:
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
}
也可能有一种使用 goto 的方法,尽管这些在 c++ 中是非常不鼓励的。如果您一次只想要一行,则只使用 1 个循环。
在这种特殊情况下,还有更简单的比较:
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 ) )
恕我直言,这仍然简单得多。
如果您不能像这样简化,请使用其他人指出的循环。
类型安全的评论!
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) || ...
还有一个选项可供选择。如果存储是连续的,您可以使用 memcmp
if(!memcmp(g[0],"XXX",3) || !memcmp(g[0],"OOO",3))
您可以数 X 或尝试找到它们:
假设 g 是一个 3 x 3 数组,包含字符X或O:
char* end = g + 9;
std::count(g, end, 'X') > 0;
或更有效地:
char* end = g + 9;
std::find(g, end, 'X') != end;