0

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

    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] 是一个结构体数组,结构体由 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;
}
4

1 回答 1

4

我会做我通常不做的事情——我会给你一个完整的往返旅程(因为我喜欢它)。


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

您还从 C 开始,然后引入了顺势疗法剂量的 C++,实际上使事情变得比必要的更困难。

所以让我们修剪一下。首先,我们将“最小”添加到您的示例代码中。


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

#include <vector>
#include <iostream>

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

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


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

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

Search-and-delete A[t_i].,我们现在只在那个领域工作。m_xrook_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';

在这一点上,我意识到您的示例代码混合了“X”和“Y”坐标search()(报告车在 X = 6,Y = 3),但没关系。这不是你问题的根源。

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

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

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


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


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

所以,虽然.at()(有点)慢并且通常不用于生产代码,但我推荐给初学者,因为它不允许“隐藏”错误。

在这一点上,你应该挑起眉毛,想想自己,“他为什么要建议这个?”。然后你应该看看你的循环,然后......

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我只是宣布习惯不能否定的事情。

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


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

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


如果您在第一个循环中“向左移动”,并在那里找到国王,您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永远不会发生,对吧?


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

...我只是不理解 [switch 语句],也无法真正了解如何将它们写为 switch。

我的建议?我完全理解你为什么要尽快写出“真实的东西”。教科书很无聊。但是你真的应该花更多的时间“围绕”基本概念。C 和 C++ 是真正不能很好地使用“试错”方法来学习它们的语言。有太多的事情可以而且将会出错。

我们有一份推荐的教科书列表,如果你有的不是你的口味。

而且,如果您在真正掌握基础知识之前尝试了太大的东西(例如国际象棋程序),那么您可能遇到的任何问题的答案最终都会比舒适的要长得多,无论是写还是写(如果有人愿意的话)并让你消化。


请:

goto除非您绝对、肯定地知道自己在做什么,否则不要使用。

于 2015-10-22T12:47:27.793 回答