首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >函数来测试源和目标方格是否代表有效的骑士移动。

函数来测试源和目标方格是否代表有效的骑士移动。
EN

Code Review用户
提问于 2017-10-07 22:25:34
回答 3查看 548关注 0票数 10

以下是我对一个问题的解决办法。虽然它有效--我想学习如何以更好的方式优化它(我是C++新手)。我最初的想法是使用一个map来映射r,c对,然后测试它们,但是希望有人能帮我优化这个。

使用一个字符串网格和两个行/列对(r1,c1) (r2,c2)编写一个函数,如果棋盘广场上有一个骑士(r1,c1)可以移动到空方块(r2,c2),则返回true。要使函数返回true,必须有一个正方形骑士(r1,c1),平方at (r2,c2)必须存储一个空字符串,这两个位置都必须在网格的范围内。一位骑士做出了一个"L“形状的动作,其中一个维度上有两个正方形,另一个维度中有一个正方形。也就是说,如果棋盘(1,2)存储“骑士”,那么knightMoves( board,1,2,2,4)的调用返回true。

这是我目前的解决方案

代码语言:javascript
复制
bool knightMoves(Grid<string>& board, int r1, int c1, int r2, int c2);

int main() {

    //create a fake board
    Grid<string> board(7,7);
    board[1][2] = "knight";
    board[3][1] = "rock";
    board[0][4] = "king";

    //fire the function
    bool result = knightCanMove(board, 1, 2, 2, 4);
    cout << result << endl;

    return 0;
}

bool knightMoves(Grid<string>& board, int r1, int c1, int r2, int c2) {

    bool canMove = false;
    string knight = "knight";

    //within grid bounds
    if(r1 > board.numRows() || c1 > board.numCols()) return false;
    if(r2 > board.numRows() || c2 > board.numCols()) return false;

    //test whether the co-ords match a knight string,
    //if yes, continue
    if (board[r1][c1] == knight) {
        if(board[r1 + 2][c1 + 1] == "" && r1+2 == r2 && c1+1 == c2) {
            canMove = true;
        }
        if(board[r1 + 2][c1 - 1] == "" && r1+2 == r2 && c1-1 == c2) {
            canMove = true;
        }
        if(r1 >= 2 && board[r1 - 2][c1 + 1] == "" && r1-2 == r2 && c1+1 == c2) {
            canMove = true;
        }
        if(r1 >= 2 && board[r1 - 2][c1 - 1] == "" && r1-2 == r2 && c1-1 == c2) {
            canMove = true;
        }
        if(board[r1 + 1][c1 + 2] == "" && r1+1 == r2 && c1+2 == c2) {
            canMove = true;
        }
        if(c1 >= 2 && board[r1 + 1][c1 - 2] == "" && r1+1 == r2 && c1-2 == c2) {
            canMove = true;
        }
        if(board[r1 - 1][c1 + 2] == "" && r1-1 == r2 && c1+2 == c2) {
            canMove = true;
        }
        if(c1 >= 2 && board[r1 - 1][c1 - 2] == "" && r1-1 == r2 && c1-2 == c2) {
            canMove = true;
        }
    }
    return canMove;
}
EN

回答 3

Code Review用户

回答已采纳

发布于 2017-10-07 23:46:23

看来在范围检查方面可能有问题。

  1. 您不检查行和列是否为非负数。( < 0 )类型没有标记为无符号,所以它们可能是负的。
  2. 如果板是基于零的,而且它似乎是,检查与numXYZ应该包括边界.( >= board.numXYZ() )

范围检查如下:

代码语言:javascript
复制
if ( r1 < 0 || r1 >= board.numRows() ||
     r2 < 0 || r2 >= board.numRows() ||
     c1 < 0 || c1 >= board.numCols() ||
     c2 < 0 || c2 >= board.numCols() ) {
  return false;
}

跳转检查可以简化。一个维度的绝对距离必须是一个,而另一个维度的绝对距离必须是两个。

代码语言:javascript
复制
unsigned int rowdiff = abs(r1 - r2);
unsigned int coldiff = abs(c1 - c2);
if ( rowdiff == 1 && coldiff == 2 || rowdiff == 2 && coldiff == 1 )

或者,我们可以注意到,距离的乘积必须是±2,从而导致更简洁的检查,但这可能会模糊根本的目标:

代码语言:javascript
复制
if ( abs((r1 - r2) * (c1 - c2)) != 2 ) return false;

在这一点上,最后的检查是:

代码语言:javascript
复制
return board[r1][c1] == "knight" && board[r2][c2] == "";
票数 7
EN

Code Review用户

发布于 2017-10-08 01:14:16

  • 这不是rock,而是Rook。很抱歉吹毛求疵,我是个棋手。
  • 只测试坐标小于板的大小意味着你假设它们是非负的。确保非否定性的最好方法是声明你的论点unsigned
  • 测试目标方的可用性与源方无关,只需进行一次即可完成。最好将这两个测试都考虑到独立的函数中: if (!knight_can_reach(c1,r1,c2,r2))返回false;如果c1 c2,r2)返回false;//在这里测试引脚,如果您希望返回true;
  • 有些人(包括我)会争辩说,一个非法的来源广场应该导致一个例外。
票数 7
EN

Code Review用户

发布于 2017-10-08 05:16:37

我同意另外两个答案。他们有很好的建议。我想指出的是,您的代码有一些更大的问题。

命名常数

在代码中有几个重要字符串。通过分配一个变量来保存字符串knightMoves(),您在"knight"函数中有了正确的想法。(同时,这个函数的名字也不错!不知道你是不是鲍勃·塞格的粉丝,但这让我笑了起来。)如果要使用字符串来表示所有棋子,则应该将它们定义为命名常量,并且只键入它们一次,这样就不会在某个地方出错。类似于:

代码语言:javascript
复制
const std::string kKing = "king";
const std::string kQueen = "queen";
//... etc.

不过,还有更好的办法。

使用类型

您的代码就是我们所称的粗壮打字。这是一个应该避免的反模式

C++是一种强类型(而不是典型的)语言。也就是说,它允许您为数据创建类型,如果使用不当,可以给出警告或错误。通过使您的board成为一个Grid<string>,任何东西都可以进入它,编译器将无法告诉您它是否是一个错误。例如,与“国王”不同,您可能会意外地将一个"knig“放到板上,而您的代码的其余部分可能会被这一点搞糊涂,并做一些意想不到的事情。(或者你也可以把一只“青蛙”、“挪威”或“埃尔玛·庞贝克”也放进董事会。)

相反,您应该使用命名类型。在这种情况下,您应该使用枚举类型。类似于:

代码语言:javascript
复制
typedef enum ChessPiece {
    kNone,
    kPawn,
    kRook,
    kBishop,
    kKnight,
    kKing,
    kQueen
} ChessPiece;

然后你可以让你的板成为一个Grid<ChessPiece>,如果你输入了一个错误的片段,那么编译器会在它发生时告诉你。

票数 6
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/177432

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档