【问题标题】:Checking Who Won Tic Tac Toe More Efficient C++检查谁赢得井字游戏更高效的 C++
【发布时间】:2011-07-10 23:29:35
【问题描述】:

我正在编写井字游戏,我想知道如何创建一个有效的函数来检查谁赢了。由 X、O 或空格组成的二维数组代表棋盘。

  char CheckWin(const char board[][NUM_COLS], int& sum) // tic tac toe board - IN
{
    char tmp;
    int lcv;
    tmp = ' ';

    if (sum == 9)
    {
        return 'T';
    }
    else if (sum != 9)
    {
        if (((tmp = board[1][1]) != ' ' && board[0][0] == tmp && board[2][2] == tmp) || (board[2][0] == tmp && board[0][2] == tmp))
        {
            return tmp;
        }

        for (lcv = 0; lcv < 3; lcv++)
        {
            if ((tmp = board[lcv][0]) != ' ' && board[lcv][1] == tmp && board[lcv][2] == tmp)
            {
                return tmp;
            }
            else if ((tmp = board[lcv][0]) != ' ' && board[lcv][1] == tmp && board[lcv][2] == tmp)
            {
                return tmp;
            }
        }
    }

    return 'N';
}

除了一遍又一遍地做类似的事情,我怎么能检查谁赢了,如果 X 赢了,返回 X,如果 O 有一个,返回 O,如果是平局,返回 T,如果没有人有一个,返回 N然而。提前致谢。我仍然在尝试熟悉 C++ 和一般的编程。

编辑:我只是采用了简单的方法,但不知怎么搞砸了,有人知道怎么做吗?看起来它没有返回任何东西,因为当我在玩家选择一行和一列之后在 main 中调用它时(这工作正常),它不输出任何东西

【问题讨论】:

  • 仅供参考:const char board[][3] 不会像您认为的那样做。我想你的意思是const char (&amp;board)[3][3]
  • 只返回最先移动的人:P
  • 还有平局时返回什么???
  • 这只是我正在编写的函数的原型。不就是把二维数组作为常量送入函数,就没有副作用了吗?
  • @Michael const 用于防止被调用者覆盖数据,而不是传值。

标签: c++ if-statement


【解决方案1】:

您可以将数组转换为两个 9 位值,一个用于 O 位置,一个用于 X 位置,以及空格数:

x_mask = 0
y_mask = 0
empty_count = 0
mask = 1
for each square
  if x then x_mask |= mask
  if y then y_mask |= mask
  if empty then empty_count++
  mask <<= 1

然后将 x_mask 和 y_mask 与八种可能的获胜组合进行比较:

for each player
  for each winning combination
    if player_mask & winning_mask == winning_mask then player has won

然后处理双方都没有获胜的情况:

if neither player won
  if empty_count == 0
    its a tie
  else
    moves still available

【讨论】:

    【解决方案2】:

    简单的“结构化”方法

    如果你认为董事会是:

    A  B  C
    D  E  F
    G  H  I
    

    那么任何获胜布局都必须触及的最小选择框是:

    A B C
    D
    G
    

    您可以根据 X 和 Y 方向上的 0、1 或 -1 位置的偏移来设想从获胜线上的任何这些位置开始的移动。我们可以列出您需要检查的动作:

    A: (++x) (++x, ++y) (++y)
    B: (++y)
    C: (++y) (--x, ++y)
    D: (++x)
    E: (++x)
    

    在 C++ 中,您可以创建一个起点的 x/y 坐标和上面显示的 +/-/0 x/y 移动增量的列表/向量,然后使用三个嵌套循环来全面评估每一行.

    这比仅仅在 x 和 y 坐标以及两个对角线(下)上硬编码两个循环要多得多,但它是一种更具算法性的方法,可能会在智力上吸引人:更像是你在处理时可能需要做的事情一块更大的板。


    明显的蛮力方法

    为了记录,更简单的方法如下所示:

    int x;
    for (row = 0; row < 3; ++row)
        if ((x = board[row][0]) != Empty &&
            board[row][1] == x && board[row][2] == x)
            return x;
    // similar loop for columns...
    ...
    // hardcode diagonals...
    if ((x = board[1][1]) != Empty &&
        (board[0][0] == x && board[2][2] == x ||
         board[2][0] == x && board[0][2] == x))
        return x
    

    【讨论】:

    • 我尝试使用您提到的蛮力方法,因为它对我来说最有意义,但看起来我搞砸了。我用我的问题编辑了原始帖子
    【解决方案3】:

    我想您可以为每个获胜的棋盘分配一个数字(基本上是一个哈希值),然后通过生成其哈希值来检查当前棋盘是否与表中的任何值匹配。另一方面,我不建议花太多时间尝试使 CheckWin 功能变得超级高效。除非它被调用了数百万次或需要非常快,否则将时间花在其他事情上——它可能不会成为瓶颈。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多