2012-04-16 55 views
2

我写了一个基于多维数组的基本井字棋游戏。克[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

一个循环?查找表?一个函数?拿你的选择... – 2012-04-16 14:01:53

+0

@Oli查尔斯沃思,你可以给每个例子吗? – Bugster 2012-04-16 14:03:36

回答

6

你可能会约了错误的方式。目前只有3^9,或 19683种可能的组合,所以你甚至可以在16位机器上的网格转换为int, :

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:

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 S,每名球员之一。 的位置的位数是3 * i + j,并测试一个 此举是合法的:

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

哇这个答案几乎让我觉得我的问题很愚蠢,因为有很多方法。这个答案让我感觉很小,谢谢! – Bugster 2012-04-16 16:34:54

+2

@ThePlan完全没有。看到这样的可能性很大程度上取决于经验。获得这种经验和学习的唯一方法就是提出这样的问题。我认为这是一个很好的问题;这就是为什么我花了一些精力来思考我认为是一个很好的答案。 (如果你以前没有真正做过类似的事情,那么最后的抨击技巧并不是你可能想到的。) – 2012-04-16 17:23:30

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传递给函数,或者假设lambda可用性。或Boost.bind ... – CapelliC 2012-04-16 14:09:41

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 
} 

有可能是使用goto语句的一种方式好吧,尽管这些在C++中非常令人沮丧。如果您一次只需要一行,则只使用1循环。

+0

尽管事实上它被认为是一种不好的做法,但我在代码中使用了gotos,因为我没有耐心去考虑备用循环。 – Bugster 2012-04-16 14:10:13

0

另有一个选项可供选择。可以使用memcmp如果存储是连续

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

+1聪明,-1 ewwww :) – 2012-04-16 14:12:39

+0

@ ErnestFriedman-Hill:-1为什么? – Abhijit 2012-04-16 14:13:40

+0

笑话。我根本没有投票。我给你一个想象中的聪明+1和丑陋-1;他们平衡到没有投票。 – 2012-04-16 14:14:49

0

你可以计数两个X或试图找到它们:

假设g为3×3阵列,包含字符XO

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

至少假设有只XO可能。否则这将成为

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) || ... 
相关问题