【问题标题】:Automatic vector boundary checking without crashing my program自动矢量边界检查而不会使我的程序崩溃
【发布时间】:2017-05-30 04:52:02
【问题描述】:

我正在创建一个有效的国际象棋游戏

我的国际象棋引擎有一个棋盘。棋盘是 2D 棋盘[Y][X],里面是棋子。 Pieces 是枚举,它代表黑色的部分、白色的部分和 NONE。

class ChessBoard
{
   vector<vector<Piece>> board(); //I made it 8*8 in the constructor
   enum Piece{NONE, white pieces, black pieces etc..}
}

我的问题是验证一个正方形是否在我的棋盘内。请让我详细说明。例如,在查看 A2 pawn 的可能移动时,pawn 可以向上移动 1 2 或捕获左右,或从左到右:

(X,Y+1), (X,Y+2), (X+1,Y+1), (X-1,Y+1), (X+1,Y+2), (X-1,Y-2)

但是,如您所知,X-1 会导致棋子出界。

是的,我可以实现一个简单的 bool isSquareValid() 函数。但这意味着,无论我在哪里尝试访问或设置board[][],我都需要调用此函数。

有没有办法实现 Board[][] 以便当我尝试访问超出范围的索引时,它会抛出错误消息或其他内容而不会导致我的程序崩溃?

谢谢

【问题讨论】:

  • 没有办法实现operator[][],除非同时使用两个operator[]std::vector 提供了一个 at() 成员函数来检查有效索引,但必须捕获异常以防止程序终止。请注意,vector&lt;vector&lt;Piece&gt;&gt; board(8*8) 指定了一个包含 64 个vector&lt;Piece&gt;vector,每个都没有元素。它不会创建任何形式的 8x8 数组。
  • 当然,在国际象棋中,棋子不能穿过其他棋子,即使目标方格在棋盘上。
  • 是的,我知道,我写了一些伪代码只是为了显示板是 8*8... 无论如何,我真的不想做 if(isValidSquare(x,y)) 每次我尝试查看或访问板.... 有没有聪明的方法来做到这一点?我想也许可以把它做成一个外层为 10*10 的板,因为 ERROR 可能会有所帮助。
  • 这部分很容易检查,我只在 board[y][x] == NONE 或者它可以捕获的情况下移动棋子。
  • 只需使用向量的at() 而不是[] 语法编写代码(例如,一次移动),就好像数组索引是正确的一样。然后将其包装在 try/catch 块中。如果任何索引无效,则会抛出异常。

标签: c++ vector chess


【解决方案1】:

你混淆了两个不同的问题。

首先是如何确保游戏防止棋子出现在棋盘之外。这是不是错误处理;你必须首先确保这件作品永远不会在那里结束。换句话说,您必须将程序逻辑限制为在选择呈现给用户之前(或人工智能组件,就此而言)。如果您想捕获从at 引发的异常,然后将板恢复到有效状态,请停在那里,不要这样做。这将是最好的异常滥用。

第二个是如何处理由代码中的错误导致的错误。您可能编写了代码来防止游戏将棋子放在棋盘外,但您可能犯了一个错误,因为我们都这样做了,所以您最终会得到非法的向量索引。在这种情况下,operator[] 导致的崩溃实际上是一件好事,因为立即终止有缺陷的程序通常是发生在你身上的最好的事情。另一种选择是“以某种方式继续”并继续处理损坏的数据和破坏的游戏规则,甚至可能没有足够快地注意到错误。

因为不能保证错误的operator[] 调用会导致崩溃,并且强制运行时库执行检查可能有点麻烦(当然,错误的operator[] 索引是形式上未定义的行为),您可能想要添加一些您自己的 assert 语句,并确保 NDEBUG 不会妨碍他们完成工作。

如果您将std::vector 包装在您自己的类中,这会变得相当容易。当您使用它时,您可以使用operator() 简化元素访问:

class Board
{
public:
    Piece& operator()(int x, int y)
    {
        assert(x >= 0);
        assert(x < 16);
        assert(y >= 0);
        assert(y < 16);
        return data[y][x];
    }

    Piece operator()(int x, int y) const
    {
        assert(x >= 0);
        assert(x < 16);
        assert(y >= 0);
        assert(y < 16);
        return data[y][x];
    }

    Board()
    {
        for (int row_index = 0; row_index < 16; ++row_index)
        {
            data.emplace_back(16, Piece::None);
        }
    }

private:
    std::vector<std::vector<Piece>> data;
};

还要注意std::vector 不是棋盘的最佳选择,因为棋盘不会缩小或增长。考虑改用std::array

【讨论】:

  • 好的,所以当我尝试访问棋盘位置时,我只需执行 if(board(x,y)).. 我真的很喜欢这个解决方案……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多