车子移动功能没有发现中断

Rook movement function not finding interruptions

我正在尝试编写一个函数来检查黑王是否被白车控制。当我尝试搜索车和王之间是否有棋子时出现问题。

    void rook_white(piece A[])                                      // does WR check BK
{
    cout << "Found White Rook ";
    int k_x;                                                  // BK'S x coordinate
    int k_y;                                                  // BK's y coordinate
    bool check = false;
    for(int x=0; x<8; x++)
    {
        for(int y=0; y<8; y++)
        {
            if(A[t_i].field[m_x-x][m_y] == 'k')                 // Moving Left
            {
                k_x=m_x;
                k_y=m_y;
                goto al_1;
            }
        }
    }
    for(int x=0; x<8; x++)
    {
        for(int y=0; y<8; y++)
        {
            if(A[t_i].field[m_x+x][m_y] == 'k')                 // Moving Right
            {
                k_x=m_x;
                k_y=m_y;
                goto al_2;
            }
        }
    }
    for(int x=0; x<8; x++)
    {
        for(int y=0; y<8; y++)
        {
            if(A[t_i].field[m_x][m_y-y] == 'k')                 // Moving Up
            {
                k_x=m_x;
                k_y=m_y;
                goto al_3;
            }
        }
    }
    for(int x=0; x<8; x++)
    {
        for(int y=0; y<8; y++)
        {
            if(A[t_i].field[m_x][m_y+y] == 'k')                 // Moving Down
            {
                k_x=m_x;
                k_y=m_y;
                goto al_4;
            }
        }
    }
al_1:
    for(int x=0; x<k_x; x++)
    {
        for(int y=0; y<k_y; y++)
        {
            if(!A[t_i].field[m_x-x][m_y] == '*')                   // Checking left
            {
                goto loop_exit;
            }
        }
    }
al_2:
    for(int x=0; x<k_x; x++)
    {
        for(int y=0; y<k_y; y++)
        {
            if(!A[t_i].field[m_x+x][m_y] == '*')                    // Checking Right
            {
                goto loop_exit;
            }
        }
    }
al_3:
    for(int x=0; x<k_x; x++)
    {
        for(int y=0; y<k_y; y++)
        {
            if(!A[t_i].field[m_x][m_y-y] == '*')                    // Checking Up
            {
                goto loop_exit;
            }
        }
    }
al_4:
    for(int x=0; x<k_x; x++)
    {
        for(int y=0; y<k_y; y++)
        {
            if(!A[t_i].field[m_x][m_y+y] == '*')                    // Checking Down
            {
                goto loop_exit;
            }
        }
    }
loop_exit:
    check = false;
    if (check == true)
    {
        ofstream fr(FVR,ios::app);
        fr << "Black is in check by rook " << t_i << endl;
    }
}

该函数在 x 和 y 轴上搜索国王在哪里。然后它进入特定算法(al_1、al_2、...),在该算法中搜索国王和车之间是否有任何东西。

输入文件大致如下:

********
***k****
********
***q****
********
********
***R****
********

这不应该什么都不输出,而

********
***k****
********
********
********
********
***R****
********

应该输出"Black is in check by rook "。 (t_i 是正在检查的板的编号)

A[t_i]是一个struct数组,struct块由char field[8][8]组成。

我使用结构体是因为我要检查的板子数量不受限制。

k_x和k_y是王坐标。 m_x 和 m_y 是全局变量,从找到一个片段的搜索功能中传递过来

这是带有 int main()

的程序本身
#include <iostream>
#include <fstream>                  // chess
#include <cstdlib>
using namespace std;                                                       // PROGRAM CHECKS FOR CHESS CHEKS
const char FVD[]="5_input.txt";                                 // **************************************************
const char FVR[]="5_output.txt";                                // P - white pawn   (WP)      p - black pawn     (BP)
//---                                                           // R - white rook   (WR)      r - black rook     (BR)
//---                                                           // B - white bishop (WB)      b - black bishop   (BB)
int m_i=0;          // max i                                    // N - white knight (WN)      n - black knight   (BN)
int m_x=0;          //                                          // Q - white queen  (WQ)      q - black queen    (BQ)
int m_y=0;          //                                          // K - white king   (WK)      k - black king     (BK)
int t_i=0;          //                                          // **************************************************
struct piece
{
    char field[8][8];
};
void read(piece A[])
{
    ifstream fd(FVD);
    int i=0;
    m_i=0;
    while(!fd.eof())
    {
        for(int x=0; x<8; x++)
        {
            for(int y=0; y<8; y++)
            {
                fd >> A[i].field[x][y];
            }
        }
        fd.ignore();
        i++;
        m_i=i;
    }
    fd.close();
}
///  ----------------------------------------------BLACK KING IS IN CHECK--------------------------------------------------------------
void rook_white(piece A[])                                      // does WR check BK
{
    cout << "Found White Rook ";
    int k_x;                                                  // BK'S x coordinate
    int k_y;                                                  // BK's y coordinate
    bool check = false;
    for(int x=0; x<8; x++)
    {
        for(int y=0; y<8; y++)
        {
            if(A[t_i].field[m_x-x][m_y] == 'k')                 // Moving Left
            {
                k_x=m_x;
                k_y=m_y;
                goto al_1;
            }
        }
    }
    for(int x=0; x<8; x++)
    {
        for(int y=0; y<8; y++)
        {
            if(A[t_i].field[m_x+x][m_y] == 'k')                 // Moving Right
            {
                k_x=m_x;
                k_y=m_y;
                goto al_2;
            }
        }
    }
    for(int x=0; x<8; x++)
    {
        for(int y=0; y<8; y++)
        {
            if(A[t_i].field[m_x][m_y-y] == 'k')                 // Moving Up
            {
                k_x=m_x;
                k_y=m_y;
                goto al_3;
            }
        }
    }
    for(int x=0; x<8; x++)
    {
        for(int y=0; y<8; y++)
        {
            if(A[t_i].field[m_x][m_y+y] == 'k')                 // Moving Down
            {
                k_x=m_x;
                k_y=m_y;
                goto al_4;
            }
        }
    }
al_1:
    for(int x=0; x<k_x; x++)
    {
        for(int y=0; y<k_y; y++)
        {
            if(!A[t_i].field[m_x-x][m_y] == '*')                   // Checking left
            {
                goto loop_exit;
            }
        }
    }
al_2:
    for(int x=0; x<k_x; x++)
    {
        for(int y=0; y<k_y; y++)
        {
            if(!A[t_i].field[m_x+x][m_y] == '*')                    // Checking Right
            {
                goto loop_exit;
            }
        }
    }
al_3:
    for(int x=0; x<k_x; x++)
    {
        for(int y=0; y<k_y; y++)
        {
            if(!A[t_i].field[m_x][m_y-y] == '*')                    // Checking Up
            {
                goto loop_exit;
            }
        }
    }
al_4:
    for(int x=0; x<k_x; x++)
    {
        for(int y=0; y<k_y; y++)
        {
            if(!A[t_i].field[m_x][m_y+y] == '*')                    // Checking Down
            {
                goto loop_exit;
            }
        }
    }
loop_exit:
    check = false;
    if (check == true)
    {
        ofstream fr(FVR,ios::app);
        fr << "Black is in check by rook " << t_i << endl;
    }
}
///-----------------------------------------SEARCHING FOR THE CHECKS // CALLING FUNCTIONS --------------------------------------------
void search(piece A[])                                               // searches for piece and calls a function related to it
{
    for(int i=0; i<m_i-1; i++)
    {
        for(int x=0; x<8; x++)
        {
            for(int y=0; y<8; y++)
            {
        if (A[i].field[x][y]=='R')
                {
                    t_i=i;
                    m_x=x;
                    m_y=y;
                    rook_white(A);
                }

            }
        }
    }
}
int main()
{
    piece A[10];
    remove(FVR);            // clears the output before inputting new data because of ios::app
    read(A);
    search(A);
    ofstream fr(FVR);
    fr << "Done";
    return 0;
}

我会做我平时不做的事情 -- 我会给你一个完整的往返(因为我喜欢)。


你从一个 main() 开始,它应该读取任意数量的字段(但实际上在 11 日崩溃),以及一个 search() 函数,它旨在最终遍历所有可能的棋子...但是您的程序在检查第一块白车时失败了。

您也从 C 开始,然后顺势引入 C++,实际上让事情变得比必要的更困难。

所以让我们trim记下来。 首先,我们会将 "minimal" 放入您的示例代码中。


让我们用<vector>代替二维数组。向量是 C++ 中 最有用的东西之一,几乎没有理由再使用 C 风格的数组(除了 C API 兼容性)。 =64=]

#include <vector>
#include <iostream>

typedef std::vector< std::vector< char > > Field;

Field 现在是 char 向量的向量的别名。这与二维数组(包括 [][] 寻址)基本相同,但它有一些您很快就会看到的优点。


您的 rook_white()(如您设计的那样)需要 一个 字段,以及车的 X 和 Y 坐标。请允许我稍微调整一下您的函数原型——我喜欢更具表现力的标识符名称

void rook_white( Field const & field, unsigned rook_x, unsigned rook_y );

搜索并删除 A[t_i].,我们现在只处理那个字段。将 m_x 搜索并替换为 rook_x,将 m_y 替换为 rook_y。不是太难。同时替换:

        ofstream fr(FVR,ios::app);
        fr << "Black is in check by rook " << t_i << endl;

有:

        std::cout << "Black is in check by rook" endl;

现在我们不用理会文件 I/O.


现在,我们需要设置一个字段,但是我们暂时不需要从文件中读取它。实际检查工作后,您可以扩展代码。

int main()
{
    Field field( 8, std::vector< char >( 8, '*' ) );

std::vector< char >( 8, '*' ) 创建一个 8 '8' 个字符的临时向量。 Field field( 8, /*...*/ ); 创建一个 Field,其中包含该临时向量的 8 个副本。

现在让我们放置你的棋子。

    unsigned rook_x = 3;
    unsigned rook_y = 6;
    field[rook_x][rook_y] = 'R';

    unsigned king_x = 3;
    unsigned king_y = 1;
    field[king_x][king_y] = 'k';

此时我意识到 你的示例代码在 search() 中混淆了 "X" 和 "Y" 坐标(报告 X 处的车= 6,Y = 3),但没关系。那不是你问题的根源。

我们现在有了字段和坐标来调用您的函数。

    rook_white( field, rook_x, rook_y );
    return 0;
}

这种编写 main() 的方式并没有真正反映您的最终应用程序应该做什么,而是为特定功能设置测试,称为 测试驱动程序。我们刚刚从您的示例中删除了 50 多行不必要的代码,消除了各种不相关的潜在问题。


现在,让我们看看 rook_white(),好吗?


因为我们现在有一个 vector< vector< char > > 而不是 "dumb" 数组,我们可以做一些漂亮的事情:用 .at() 替换 [] 访问。原因?如果 [] 的索引越界,它可能会也可能不会使程序崩溃。如果 .at() 的索引越界,它 抛出异常。

所以,虽然 .at()(有点)慢并且通常不在生产代码中使用,但我建议初学者使用它,因为它不允许 "hide".[=64= 的错误]

此时你应该眉头一挑,心想,"why is he suggesting this?"。然后你应该看看你的循环,并且...

for(int x=0; x<8; x++)
{
    for(int y=0; y<8; y++)
    {
        if(field[rook_x-x][rook_y] == 'k')
        {
            k_x=rook_x;
            k_y=rook_y;
            goto al_1;
        }
    }
}

是的,没错。您对您的字段有 越界访问

rook_x / rook_y 在场地中间的某个地方,但如果找不到国王,您坚持访问 [rook_x - 7][rook_y] 之前的任何内容。那是您原始代码中的负索引。由于我将坐标更改为 unsigned(它会溢出并变得 非常大 ),你会遇到段错误崩溃(如果幸运的话)。那实际上是无意的;我只是声明不能为负的东西 unsigned by habbit.

但这就是为什么我建议您在学习期间使用 vector<>.at() 方法:尽早失败并尽可能大声地失败。 异常优于未定义的行为。


此外,你(在所有这些循环中)总是循环xy,但只使用 循环中 两个变量中的一个。这是很多 浪费的时钟周期 。这不会破坏您的逻辑只是偶然...

此时您可能想要完全重新编写代码。但是等等,还有更多。


如果您 "move left" 在您的第一个循环中找到国王,那么您 goto al_1。在那里你循环(再次使用两个循环计数器之一)来检查中间部分。

第一个循环是 x == 0,检查 [rook_x - 0][rook_y]... 猜猜看,你发现白车正在介入,因为那里在该字段中没有 '*',因此您跳转到 loop_exit...


即使你没有犯那个错误,你也会从那个循环中出来并输入 al_2,同时检查车的所有剩余方向...


即使这一切都不会发生,无论发生什么,你最终运行会变成这样:

loop_exit:
    check = false;
    if (check == true)
    {
        std::cout << "Black is in check by rook \n";
    }

嗯,check == true 永远不会发生,对吧?


在这一点上我引用你的评论之一...

...I just don't understand [switch statements] and couldn't really wrap my head around on how to write them as switch.

我的建议?我完全理解你为什么要尽快写 "something real" 。教科书很无聊。但是你真的应该多花一些时间"wrapping your head around"基本概念。 C 和 C++ 是使用 "trial & error" 方法 学习它们的语言。有太多的事情可以而且将会出错。

We have a list of recommended textbooks, if the one you have isn't to your tastes.

如果你在真正掌握正确的基础知识之前尝试了太多的东西(比如国际象棋程序),那么你可能遇到的任何问题的答案最终都会比舒适的时间长很多,无论是写(如果有人喜欢它)并让你消化。


请:

不要使用 goto 除非你绝对肯定地知道你在做什么。