if语句-缩短C++if条件

if statement - Shortening C++ If condition

本文关键字:C++if 条件 缩短 语句 if      更新时间:2023-10-16

我有一个很长的if语句,用于检查井字游戏板的获胜条件:

if 
((tttPositions[i][j][0] && tttPositions[i][j][1] && tttPositions[i][j][2] == 1) 
|| (tttPositions[i][j][3] && tttPositions[i][j][4] && tttPositions[i][j][5] == 1) 
|| (tttPositions[i][j][6] && tttPositions[i][j][7] && tttPositions[i][j][8] == 1) 
|| (tttPositions[i][j][0] && tttPositions[i][j][3] && tttPositions[i][j][6] == 1) 
|| (tttPositions[i][j][1] && tttPositions[i][j][4] && tttPositions[i][j][7] == 1) 
|| (tttPositions[i][j][2] && tttPositions[i][j][5] && tttPositions[i][j][8] == 1) 
|| (tttPositions[i][j][0] && tttPositions[i][j][4] && tttPositions[i][j][8] == 1) 
|| (tttPositions[i][j][2] && tttPositions[i][j][4] && tttPositions[i][j][6] == 1))
{
    if (j = 0)
        cout << "x wins" << endl;
    if (j = 1)
        cout << "o wins" << endl;
}   

这看起来真的很难看。。有没有一种方法可以单独跟踪获胜条件,从而大大缩短if语句的长度?

我把多个井字板放在一个3D矢量中,每个盒子是2x9,第一行代表"x"位置,第二行代表"o"位置,就像:

110000011
001110000

表示:

x x o
o o _
_ x x

您可以创建一个接受3个整数的lambda,并检查它们是否在数组中设置。您还可以将tttPositions[i][j]绑定到引用,这样键入它就不那么麻烦了。

auto& pos = tttPositions[i][j];
auto check = [&pos](int a, int b, int c) {
    return (pos[a] == 1) && (pos[b] == 1) && (pos[c] == 1);
};
// these three lines don't shorten the code, but
// they do make the if statememt more readable, imo
bool horizontal = check(0, 1, 2) || check(3, 4, 5) || check(6, 7, 8);
bool vertical = check(0, 3, 6) || check(1, 4, 7) || check(2, 5, 8);
bool diagonal = check(0, 4, 8) || check(2, 4, 6);

有了这一点,if就变得简单多了(由于变量名的原因,它可以自我记录(:

if (horizontal || vertical || diagonal)

进一步的简化(同样,不是在代码大小上,而是在可读性上(是将所有这些因素考虑到一个函数中。我不确定tttPositions[i][j]是什么类型,但假设它是一个9 int的数组,您可以这样做:

bool check_win_condition(int const (&pos)[9]) {
    // all the stuff I did before, except instead of an if statement, just return    
    return horizontal || vertical || diagonal;
}

然后在你的另一个函数中,if变成了简单的:

if (check_win_condition(tttPositions[i][j]))

您可能需要考虑在编译时创建一个数据结构来存储获胜线,然后在运行时遍历该数据结构,以检查玩家位置是否包括获胜线而不是大量if s。

我注意到你的身体状况有很多重复检查。例如,您要检查tttPositions[i][j][4]四次。成本可能微不足道,但如果能降低成本就好了。

一种可以用来存储获胜线的数据结构是一种树。在树的顶部将是一个精心选择的位置,这些位置包括在所有获胜线中,对于作为孩子的每个父位置,你都有包括这些位置的获胜线。

树只需要有两个级别,我曾将其命名为ParentChild,并存储在一个平面阵列中。Parent存储其子级的开始索引和结束索引。Child存储获胜线上的另外两个位置:

struct Parent {
  int pos;
  int children_start;
  int children_end;
};
using Child = std::pair<int, int>;
using Parents = std::array<Parent, 4>;
using Children = std::array<Child, 8>;
// Position indexes:
// 0 | 1 | 2 
// ----------
// 3 | 4 | 5
// ----------
// 6 | 7 | 8
//                                       centre            top-left  bottom-right
constexpr Parents parents =   {{         {4,0,4},          {0,4,6},    {8,6,8}   }};
//                                          |                 |           |
//                                 +-----+--+--+-----+     +--+--+     +--+--+
//                                 |     |     |     |     |     |     |     |
constexpr Children children = {{ {0,8},{2,6},{1,7},{3,5},{1,2},{3,6},{2,5},{7,6} }};

添加几个beginend函数,这样我们就可以在Parent:上进行基于范围的循环

Children::const_iterator begin(const Parent& p) {
  return children.begin() + p.children_start;
}
Children::const_iterator end(const Parent& p) {
  return children.begin() + p.children_end;
}

有了这个,我们就可以编写一个函数来检查一个位置是否是一个胜利:

using PlayerPositions = std::array<int, 9>;
bool isWin(const PlayerPositions& pos) {
  for (auto& parent : parents) {
    if (pos[parent.pos]) {
      for (auto& child : parent) {
        if (pos[child.first] && pos[child.second])
          return true;
      }
    }
  }
  return false;
}

现场演示。

在这种情况下,这是否会让事情变得更简单,这是有争议的,但更容易概括为更复杂的游戏规则。你甚至可以在运行时加载你的获胜位置。