0

I am trying to write a function that checks if the black king is in check by the white rook. The problem occurs when I try to search if there are any pieces in between the rook and the king.

    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;
    }
}

The function searches where is the king on the x and y axis. It then goes to a specific algorithm (al_1, al_2, ...) in which it searches if there is anything in between the king and the rook.

The input file is something along the lines of this:

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

this shouldn't output nothing, while

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

should output "Black is in check by rook ". (t_i being the number of the board it is being examined on)

A[t_i] is a struct array, the struct pieces consists of char field[8][8].

I use a struct because there is an unlimited number of boards I have to examine.

k_x and k_y are the king coordinates. m_x and m_y are global variables that are transferred from the search function in which a piece is found

here is the program itself with the 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;
}
  • 5
    `goto`... why? Besides, this function doesn't compile (`t_i`, `m_x`, `m_y` and probably more are not declared), and it's missing a `main()`, so we cannot reproduce the problem. You didn't even tell us what the *observed* output is, only the *expected* output. I don't see any debug output in there, which might help you to determine where the actual processing deviates from what you would expect. – DevSolar Oct 22 '15 at 10:45
  • @DevSolar because I can't really think out something else, I need different cycles to call other cycles to finish the check up the int main is just the callings of the function in which it searches. the whole program is already 300+ lines long, I don't want to cluster up everything the observed output is nothing. It outputs nothing, as if there'd be something in between the pieces. But if you remove the piece, it still outputs nothing. –  Oct 22 '15 at 10:47
  • 3
    Well, right now I'm busy *writing* an `int main()`, trying to figure out how to populate `piece A[]`, so I can see what's going on. If you had posted a [minimal, complete, verifyable example](http://stackoverflow.com/help/mcve) (which is a time-honored debugging method when trying to figure out the problem yourself), I'd probably be writing the answer already... – DevSolar Oct 22 '15 at 10:50
  • When checking for empty fields, the rook is only moving in one dimension. So it is either x or y that varies, and either up or down depending on direction. – Bo Persson Oct 22 '15 at 10:55
  • @BoPersson well, yes. I am trying to find out in which direction (L,R,U,D) is the king located from the rook, so I am going by one dimension through all of them to find the direction itself @DevSolar I have included the `int main()` as you requested –  Oct 22 '15 at 10:59
  • Ok, see now that the direction might be taken care of by you using either `+x` or `-x` in the index. However, if you don't find a piece in that direction (so no goto loop_exit), you will fall through to the next test. – Bo Persson Oct 22 '15 at 11:00
  • 2
    Duplicate: http://stackoverflow.com/questions/33268987/beginner-chess-rook-movement-interruption-in-function – Tas Oct 22 '15 at 11:04
  • @BoPersson which is what I want to do, to check through all 4 directions and see if they go through to the king. –  Oct 22 '15 at 11:05
  • Does each piece really have a copy of the chess-board? I would expect there to be a separate 8x8 board and each piece to store its own x, y position. – Galik Oct 22 '15 at 11:09
  • @iamtco - Sorry, I was talking about the code after you have found the king. From `al_1:` and down it's like a `switch`-statement without a `break`. – Bo Persson Oct 22 '15 at 11:14
  • @BoPersson well. I am not really sure what you are asking. Yes, I guess they're similar to `switch` statements, but I just don't understand them and couldn't really wrap my head around on how to write them as `switch` . As for the "copies of the chess-board", I think that they do - the board is not changing in between the functions when searching for the K. This is why I use global variables `m_x`, `k_x`, ... –  Oct 22 '15 at 11:18
  • @iamtco - In a `switch`-statement you use a `break` to exit, so that it doesn't continue with the next alternative. For you this means that if `al_1:` doesn't find anything, it continues with `al_2`, `al_3`, and `al_4`. Perhaps not what you intended? Another more important thing I see now is that right after `loop_exit:` you set `check = false`, always. – Bo Persson Oct 22 '15 at 11:25
  • @BoPersson oh, I thought that it'd not go throught `al_1`, `al_2`, and so on. So how should I go around the `loop_exit:` ? I still have to check if the `check` is `true` or `false`, and then output it. Right now it doesn't even really mean anything I guess, considering it always sets `check = false` ... how could I possibly go around this problem? –  Oct 22 '15 at 11:29
  • @BoPersson I mean it'd only go through when called by `goto al_` ... –  Oct 22 '15 at 11:41
  • @DevSolar this seems to be ["a modern use of goto"](http://stackoverflow.com/a/33270666/5067311). Is that a thing? (BTW I'm not sure which question to close as a dupe.) – Andras Deak -- Слава Україні Oct 22 '15 at 12:19
  • @AndrasDeak: I think I got this one covered. Perhaps the answer below helps the OP. ;-) – DevSolar Oct 22 '15 at 12:48
  • 1
    @AndrasDeak: I strongly disagree with *any* use of `goto` in C++. (`continue` falls in the same category, and `break` outside a `case`.) If you've ever done NSD diagrams of a function's control flow, you know why. I know there are other opinions out there, and I'll accept `goto` in the hands of a real expert looking at a rather special case, but usually the people using `goto` are neither (experts or looking at a special case). ;-) – DevSolar Oct 22 '15 at 13:18

1 Answers1

4

I'll do what I don't usually do -- I'll give you a full round-trip on this one (because I feel like it).


You started with a main() that should read an arbitrary number of fields (but actually crashes on the 11th), and a search() function that is intended to eventually iterate through all possible chess pieces... but your program fails on the check for the very first piece, the white rook.

You also started with C, and then introduced homeopathic doses of C++, actually making things more difficult than necessary.

So let's trim this down. First, we'll get the "minimal" into your example code.


Let's use <vector> instead of a two-dimensional array. Vectors are one of the most useful things in C++, and there is really next to no reason for using C-style arrays anymore (except perhaps for C API compatibility).

#include <vector>
#include <iostream>

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

Field is now an alias for a vector of vectors of chars. That's basically the same as a two-dimensional array (including the [][] addressing), but it has some advantages as you will soon see.


Your rook_white() (as you designed it) needs one field, and the rook's X and Y coordinates. Allow me to tweak your function prototype a bit -- I like more expressive identifier names.

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

Search-and-delete A[t_i]., we only work on that one field for now. Search-and-replace m_x with rook_x and m_y with rook_y. Not too hard. Also replace:

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

With:

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

For now we don't bother with file I/O.


Now, we need to set up a field, but we do not need to read it from file for now. You can expand your code once you got the actual check working.

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

std::vector< char >( 8, '*' ) creates a temporary vector of 8 '8' chars. Field field( 8, /*...*/ ); creates a Field consisting of 8 copies of that temporary vector.

Now let's place your pieces.

    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';

At this point I realized your example code got "X" and "Y" coordinates mixed up in search() (reporting the rook at X = 6, Y = 3), but nevermind. That's not the source of your problems.

We now have field and coordinates to call your function.

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

This way of writing a main() that doesn't really reflect what your final application should do, but rather sets up a test for a specific functionality, is called a test driver. We just shaved over 50 lines of unnecessary code from your example, eliminating all sorts of unrelated potential problems.


Now, let's have a look at rook_white(), shall we?


Since we now have a vector< vector< char > > instead of a "dumb" array, we could do something nifty: Replace [] access with .at(). The reason? If the index to [] is out-of-bounds, it might or might not crash the program. If the index to .at() is out-of-bounds, it will throw an exception.

So,, while .at() is (a bit) slower and usually not used in production code, I recommend it for beginners because it does not allow errors to "hide".

At this point you should be arcing an eyebrow and think to yourself, "why is he suggesting this?". Then you should look at your loops, and...

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;
        }
    }
}

Yes, exactly. You have out of bounds accesses to your field.

rook_x / rook_y is somewhere in the midst of the field, but you insist on accessing anything up to [rook_x - 7][rook_y] if you cannot find the king. That was a negative index in your original code. Since I changed the coordinates to unsigned (which instead overflows and becomes really large) you'll get a segfault crash instead (if you're lucky). That was actually unintentional; I just declare things that cannot be negative unsigned by habbit.

But that's why I suggested using vector<>'s .at() method while you're still learning: Fail as early and as loud as possible. An exception is better than undefined behaviour.


Besides, you do (in all those loops) always loop over x and y, but only use one of the two variables inside the loop. That's a lot of wasted clock cycles. That this doesn't break your logik is mere chance...

At this point you probably want to completely re-work your code. But wait, there is more.


If you "move left" in your first loop, and find the king there, you goto al_1. There you loop (again using only one of the two loop counters) to check for intervening pieces.

The first loop is x == 0, checking [rook_x - 0][rook_y]... well guess what, you find the white rook to be intervening there, since there is no '*' in that field, so you jump to loop_exit...


And even if you wouldn't have made that mistake, you would come out of that loop and enter al_2, checking all remaining directions for the rook as well...


And even if all that wouldn't happen, no matter what happens, you eventually run into this:

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

Well, that check == true is never going to happen, right?


At this point I quote one of your comments...

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

My suggestion? I fully understand why you want to write "something real" as fast as possible. Textbooks are boring. But you really should spend some more time "wrapping your head around" basic concepts. C and C++ are languages that really don't work that well with "trial & error" approaches to learning them. There is simply too much that can, and will, go wrong.

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

And if you try too large things (like a chess program) before you really got the basics right, the answer to any questions you might have will end up being quite a bit longer than comfortable, both to write (if someone feels like it) and for you to digest.


And please:

Don't use goto unless you absolutely, positively, know what you're doing.

Community
  • 1
  • 1
DevSolar
  • 67,862
  • 21
  • 134
  • 209