Thread: Chess

  1. #1
    Registered User
    Join Date
    Dec 2007
    Posts
    930

    Chess

    Hi!

    Im trying to understand this chess game and i must have modified something by mistake cause it just exits after asking the second players name.
    I checked the corresponding part but it seems to be ok. I dont understand.
    I put it in red that part. Thank you!

    Code:
    #include <cstdio>
    #include <windows.h>
    #include <string>
    
    class piece
    {
        private:
            char type[2];
            bool owner;
            short x, y;
        public:
            piece(){;}
            ~piece(){;}     
            void SetOwner(bool o) {owner=o;} 
            bool GetOwner() {return owner; }
           
            void  SetX(short i) { x=i; }
            short GetX() { return x; }
            void  SetY(short i) { y=i; }
            short GetY() { return y; }       
            void  SetXY(short a, short b) { x=a; y=b; }
           
            char *GetName(char t);
            void SetType(char t1, char t2) { type[0]=t1; type[1]=t2; } 
            char GetType(int i) {return type[i];}
           
            bool CheckMove(int sx, int sy, int ex, int ey, char t); 
            bool RookMove(int sx, int sy, int ex, int ey);
            bool KnightMove(int sx, int sy, int ex, int ey);
            bool BishopMove(int sx, int sy, int ex, int ey);
            bool QueenMove(int sx, int sy, int ex, int ey);
            bool KingMove(int sx, int sy, int ex, int ey);
            bool PawnMove(int sx, int sy, int ex, int ey);                 
    };     
    
    class player
    {
        private:
            char *name;     
        public:       
            player(){;}
            ~player(){;}
            void SetName(char *s)
            {
                 for(int i=0; i<20; i++)
                 {   
                     name[i] = s[i];
                     if(s[i] == '\0') break; 
                 }
            } 
            char *GetName() {return name;}         
    };
    
    class board
    {
        private:
            piece *cell[8][8];
            player *pl[2];
            short go;//Which players go it is
            short turn;//Turn number
        public:
            player *GetPlayer(int i) { return pl[i]; }     
            piece *GetCell(int x, int y) { return cell[x][y]; }
           
            //Gets the first piece of a given kind that a player owns
            piece *GetPiece(char type, bool player)
            {
                for(int y=0; y<8; y++)
                    for(int x=0; x<8; x++)
                         if(cell[x][y] != NULL)
                            if(cell[x][y]->GetType(1)==type)
                                return cell[x][y];
            }
           
            void NewPiece(int x, int y, bool i)
            {
                cell[x][y] = new piece;
                cell[x][y]->SetOwner(1-i);
                cell[x][y]->SetXY(x, y);
                if(y==0 || y==7)
                    if(x==0 || x==7)      cell[x][y]->SetType('R', 'k');
                    else if(x==1 || x==6) cell[x][y]->SetType('K', 't');
                    else if(x==2 || x==5) cell[x][y]->SetType('B', 's');
                    else if(x==4)         cell[x][y]->SetType('K', 5);
                    else                  cell[x][y]->SetType('Q', 6);
                else                 
                    cell[x][y]->SetType('P', 'n'); 
            }
           
            board()
            {
                int x, y;
                go=0; turn=1;
                for(y=0; y<2; y++) pl[y] = new player;
                for(y=0; y<8; y++) for(x=0; x<8; x++) cell[x][y]=NULL;
                for(y=0; y<2; y++) for(x=0; x<8; x++) NewPiece(x, y, false);
                for(y=6; y<8; y++) for(x=0; x<8; x++) NewPiece(x, y, true);   
            }
            ~board(){;}
           
    
           
            void DrawBoard();   
            void DrawCell(int x, int y);   
            bool GetOwner(int x, int y) { return cell[x][y]->GetOwner(); }   
           
            void PlayerSetup();
            void TurnText()
            {
                    printf("Turn: %i %s\n", turn, GetPlayer(go)->GetName());
            }
           
            bool MakeMove();
            int ValidateLocation(char term_a, char term_b);
           
            void EndGo() { if(go==0){go=1;} else{go=0; turn++;} }
            short GetGo() { return go; }
           
    };     
    
    HANDLE h = GetStdHandle ( STD_OUTPUT_HANDLE );
    WORD wOldColorAttrs;
    CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
    board b;
    
    int main()
    {
        //SetConsoleScreenBufferSize(h 
        GetConsoleScreenBufferInfo(h, &csbiInfo);
        wOldColorAttrs = csbiInfo.wAttributes;
        SetConsoleTextAttribute ( h, 8 );      
       
        bool quit=false;
        bool check;
    
        b.PlayerSetup();
        //MAIN LOOP
        while(quit == false)
        {     
            check=true;
            while(check == true)
            {
                b.DrawBoard();
                b.TurnText();
                check=b.MakeMove();
                getchar();
                system("CLS");
            }
            b.EndGo();
            system("CLS");
        }
    
        return 0;
    }
    
    
    // Get name from second character of type tag
    char* piece::GetName(char t)
    {
         int n=0;
         if(t=='k')      n=1;
         else if(t=='t') n=2;
         else if(t=='s') n=3;
         else if(t==6)   n=4;
         else if(t==5)   n=5;
         else if(t=='n') n=6;
         static char *name[] =
         {
                "Error", "Rook", "Knight", "Bishop", "Queen", "King", "Pawn"
         };
         return name[n];
    }
    
    void board::PlayerSetup()
    {
        char temp[20];
        printf("Enter name for player 1: ");
        gets(temp);
        GetPlayer(0)->SetName(temp);
        printf("Enter name for player 2: ");
        gets(temp);
        GetPlayer(1)->SetName(temp);
        getchar();
        system("CLS");
    }
    
    void board::DrawBoard()
    {
        for(int y=0; y<18; y++)
            for(int x=0; x<26; x++)
                if(y==0)
                    if(x==25)       printf(" \n");
                    else if(x%3==2) putchar(65+(x/3));   
                    else            putchar(' ');
                else if (y==1)
                    if(x==0)        putchar(' ');
                    else if(x==1)   putchar(218);
                    else if(x==25)  printf("%c\n", 191);
                    else if(x%3==1) putchar(194);
                    else            putchar(196);
                else if(y==17)
                    if(x==0)        putchar(' ');
                    else if(x==1)   putchar(192);
                    else if(x==25)  printf("%c\n", 217);
                    else if(x%3==1) putchar(193);
                    else            putchar(196);
                else if(y%2==1)
                    if(x==0)        putchar(' ');
                    else if(x==1)   putchar(195);
                    else if(x==25)  printf("%c\n", 180);
                    else if(x%3==1) putchar(197);
                    else            putchar(196);
                else 
                    if (x==0)       putchar(48+(y/2));
                    else if(x==25)  printf("%c\n", 179);
                    else if(x%3==1) putchar(179);
                    else if(x%3==2) DrawCell(x/3, (y/2)-1);   
    }   
    
    void board::DrawCell(int x, int y)
    { 
        int i;
        bool own;
       
        if(cell[x][y]==NULL) //Empty Cell
        {
            if(x%2==0 && y%2==0 || x%2==1 && y%2==1) SetConsoleTextAttribute ( h, BACKGROUND_BLUE | 0 ); 
            else                                     SetConsoleTextAttribute ( h, BACKGROUND_RED | 0 ); 
            printf("  ");   
        }
        else                 //There is a piece in the Cell
        {
            own=GetOwner(x, y);
            if(own == true)//Check owner colourv
                if(x%2==0 && y%2==0 || x%2==1 && y%2==1)//Check tile colour
                    SetConsoleTextAttribute ( h, BACKGROUND_BLUE | 8 ); 
                else
                    SetConsoleTextAttribute ( h, BACKGROUND_RED | 8 ); 
            else
                if(x%2==0 && y%2==0 || x%2==1 && y%2==1)
                    SetConsoleTextAttribute ( h, BACKGROUND_BLUE | 0 );
                else
                    SetConsoleTextAttribute ( h, BACKGROUND_RED | 0 );
           
            putchar(cell[x][y]->GetType(0));
            putchar(cell[x][y]->GetType(1));
        }
    
        SetConsoleTextAttribute ( h, 8 );
    }
    
    bool board::MakeMove()             
    {
        char temp[100];
        int xa, ya, xb, yb, i;
        char t, t2;
       
        printf("Move Piece From: "); 
        gets(temp);
       
        ya=ValidateLocation(temp[0], temp[1]);
        if(ya==-1)
        {
            printf("Location Not On The Board.");
            return 1;
        }
        xa=ya%8;
        ya=ya/8;
        if(cell[xa][ya]==NULL)
        {
            printf("There is no piece to move there.");
            return 1;
        }
        else if(GetOwner(xa, ya) != go)
        {
            printf("That piece does not belong to you.");
            return 1;   
        }                             
       
        t=cell[xa][ya]->GetType(1);//Get The type
        printf("Move %s to:", cell[xa][ya]->GetName(t));//Get The name
        gets(temp);
       
        yb=ValidateLocation(temp[0], temp[1]);
        if(yb==-1)
        {
            printf("Location Not On The Board.");
            return 1;
        }   
        xb=yb%8;
        yb=yb/8;
        if(cell[xa][ya]->CheckMove(xa, ya, xb, yb, t) == true)
        {
            printf("Invalid Move");
            return 1;
        }
        if(cell[xb][yb] != NULL)
        {
            if(GetOwner(xb, yb) == go)     
            {
                printf("You Cant Take Your Own Piece.");
                return 1;
            } //If Piece belongs to opponent
            t2=cell[xb][yb]->GetType(1);//Get The type
            printf("You take your opponents %s", cell[xb][yb]->GetName(t2));                                         
        }
        delete cell[xb][yb];                    //Delete the taken piece
        cell[xb][yb]=cell[xa][ya];              //Put Piece in Cell Moved To
        cell[xa][ya]=NULL;                      //Clear cell moved from
        cell[xb][yb]->SetXY(xb, yb);            //Set new co-ords for piece
       
        return 0;
    }   
    
    //Returns Y*8 + X, or -1 for invlaid move location
    int board::ValidateLocation(char term_a, char term_b)
    {
         if(term_a > 96 && term_a < 105) term_a-=32;
         if(term_b > 96 && term_b < 105) term_b-=32;
         
         if(term_a > 48 && term_a < 57)
             if(term_b > 64 && term_b < 73)
                 return ((term_a-49)*8)+(term_b-65);     
             else
                 return -1;       
         else if(term_b > 48 && term_b < 57)
             if(term_a > 64 && term_a < 73)
                 return ((term_b-49)*8)+(term_a-65);
             else
                 return -1;
         else
             return -1;
    }   
    
    bool piece::CheckMove(int sx, int sy, int ex, int ey, char tz)
    {
         if(tz=='k' && RookMove(sx, sy, ex, ey)==true)return true;     
         else if(tz=='t' && KnightMove(sx, sy, ex, ey)==true)return true;   
         else if(tz=='s' && BishopMove(sx, sy, ex, ey)==true)return true;   
         else if(tz==6 && QueenMove(sx, sy, ex, ey)==true)return true;   
         else if(tz==5 && KingMove(sx, sy, ex, ey)==true)return true;   
         else if(tz=='n' && PawnMove(sx, sy, ex, ey)==true)return true;       
    }   
    
    bool piece::RookMove(int sx, int sy, int ex, int ey)
    {
        if(sx==ex && sy!=ey)//Moves Y but not X
            if(sy < ey) //Moving Down
                for(int y=sy+1; y<ey; y++)//Check path for obstructions
                    if(b.GetCell(sx, y) != NULL) //If Obstruction on path
                        return 1;
            if(sy > ey) //Moving Up
                for(int y=ey+1; y<sy; y++)//Check path for obstructions
                    if(b.GetCell(sx, y) != NULL) //If Obstruction on path
                        return 1;       
        if(sy==ey && sx!=ex)//Moves X but not Y
            if(sx < ex) //Moving Right
                for(int x=sx+1; x<ex; x++)
                    if(b.GetCell(x, sy) != NULL)
                        return 1;
            if(sx > ex) //Moving Left
                for(int x=ex+1; x<sx; x++)
                    if(b.GetCell(x, sy) != NULL)
                        return 1;               
        if(sx!=ex && sy!=ey || sx==ex && sy==ey)//Moves Both X and Y or neither then Invalid
            return 1;
        return 0;
    }     
    bool piece::KnightMove(int sx, int sy, int ex, int ey)
    {
        if(sx==ex-1 || sx==ex+1)
            if(sy==ey-2 || sy==ey+2)
                return false;
            else
                return true;
        else if(sy==ey-1 || sy==ey+1)
            if(sx==ex-2 || sx==ex+2)
                return false;
            else
                return true;
        else
            return true;
    }     
    bool piece::BishopMove(int sx, int sy, int ex, int ey)
    {
        int dx=sx-ex;
        int dy=sy-ey;
        if(dx < 0)dx=-dx;//Make the difference absolute
        if(dy < 0)dy=-dy;
       
        if(dx != dy) return 1; //If not diagonal then invalid
        if(dx == 0) return 1;  //If not moved then invalid
       
        //Check for obstructions
        if(sx < ex && ey < sy) //Up and Right
            for(int m=1; m<dx; m++)
                if(b.GetCell(sx+m, sy-m) != NULL)
                    //printf("X: %i Y: %i\n", sx+m, sy-m);
                    return 1;
        if(sx < ex && ey > sy)//Down and Right
            for(int m=1; m<dx; m++)
                if(b.GetCell(sx+m, sy+m) != NULL)
                    return 1;
        if(sx > ex && ey < sy)//Up and Left
            for(int m=1; m<dx; m++) 
                if(b.GetCell(sx-m, sy-m) != NULL)
                    return 1; 
        if(sx > ex && ey > sy)//Down and Left
            for(int m=1; m<dx; m++)
                if(b.GetCell(sx-m, sy+m) != NULL)
                    return 1;   
        return 0;
    }     
    
    bool piece::QueenMove(int sx, int sy, int ex, int ey)
    {
        if(RookMove(sx, sy, ex, ey)==true && BishopMove(sx, sy, ex, ey)==true)
            return 1;
        else       
            return 0;
    }
    
    bool piece::KingMove(int sx, int sy, int ex, int ey)
    {
        if(sx==ex-1 || sx==ex+1 || sx==ex)
            if(sy==ey-1 || sy==ey+1 || sy==ey)
                if(sx==ex && sy==ey)//If Not Moved
                    return 1;
                else
                    return 0;
        return 1;
    }     
    
    bool piece::PawnMove(int sx, int sy, int ex, int ey)
    {
        int mod, jmp=0;
        if(b.GetGo()==0) mod= 1;
        else             mod=-1;
       
        if((sy==6 && ey==4) || (sy==1 && ey==3)) jmp=1;
       
        if(sy==ey+mod || (sy=ey+mod+mod && jmp==1)) 
            if(sx==ex)//Move Forward
                if(b.GetCell(ex, ey) != NULL)//If Blocked
                    return 1;
                else
                    return 0;
            else if((sx==ex-1 || sx==ex+1) && jmp==0)
                if(b.GetCell(ex, ey) != NULL)//If Piece to take
                    return 0;
                else
                    return 1;       
            else
                return 1;
        return 1;
    }
    Using Windows 10 with Code Blocks and MingW.

  2. #2
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    what did that section of code look like before you modified it? Did it work before?

  3. #3
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    It crashes for
    Code:
    //in Player::SetName
    name[i] = s[i];
    So I believe you don't allocate memory for name, since you have char* name and probably don't allocate memory, when you should have char name[20].
    Note also if the name is more than 19 characters the program will crash.
    Use fgets() instead of gets(). A simple substitution on these functions and running fgets with the parameter of 19 and taking care of the '\n' character that remains with fgets() will make solve the problem by trancuating(sp?) the name

    EDIT: name[20] fixes the problem. On another note... there is no good way to exit the game

    EDIT2: I forgot to mention that you could easily debug the code. Want I did is this:
    1) Put printf("OK\n") until I find where the code crashes in your red code. I see it crashes at GetPlayer(0)->SetName...
    2) So I look at GetPlayer and SetName.
    3) SetName more easily crashes the program. So I started putting printfs there. Found the above code and could easily guess the problem.
    Try debugging next time. A debugger is really a good idea. But if it is something simple, printfs can do the job
    Last edited by C_ntua; 01-07-2009 at 10:52 AM.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > char *name;
    This is never allocated - memory is trashed.

    > if(term_a > 96 && term_a < 105) term_a-=32;
    Use isupper(), islower(), toupper() etc, and not some magic hard-coded numbers.
    >= 'a' && <= 'z'
    would have been somewhat more readable, if still unportable.

    > printf("You take your opponents %s", cell[xb][yb]->GetName(t2));
    It's C++, where's the iostream?

    > gets(temp);
    Simply unforgivable, read the FAQ

    > cell[xa][ya]=NULL;
    Wouldn't it be better to delete it first, rather than just leaking memory?


    if(t=='k') n=1;
    else if(t=='t') n=2;
    else if(t=='s') n=3;
    else if(t==6) n=4;
    else if(t==5) n=5;
    else if(t=='n') n=6;
    Use an enumeration, not some random mix of 't' and 5
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Thanks for both of you.

    Yes it was working before but i dont remember what i changed.

    I will try to repair all the problem you pointed out and will try to debug it, great idea.
    Using Windows 10 with Code Blocks and MingW.

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Code:
    bool piece::PawnMove(int sx, int sy, int ex, int ey)
    {
        int mod, jmp=0;
        if(b.GetGo()==0) mod= 1;
        else             mod=-1;
       
        if((sy==6 && ey==4) || (sy==1 && ey==3)) jmp=1;
       
        if(sy==ey+mod || (sy=ey+mod+mod && jmp==1)) 
            if(sx==ex)//Move Forward
                if(b.GetCell(ex, ey) != NULL)//If Blocked
                    return 1;
                else
                    return 0;
            else if((sx==ex-1 || sx==ex+1) && jmp==0)
                if(b.GetCell(ex, ey) != NULL)//If Piece to take
                    return 0;
                else
                    return 1;       
            else
                return 1;
        return 1;
    }
    I'm using this function just as an example. The same applies to all functions of this kind...

    1. return true or false, not 0 or 1. Yes, it's the same thing, but you have declared the function to use bool, and if you do that, you should return true or false, not 0, 1, or any other number.

    Code:
                if(b.GetCell(ex, ey) != NULL)//If Piece to take
                    return 0;
                else
                    return 1;
    Is simpler to write:
    Code:
                return b.GetCell(ex, ey) == NULL);
    (Note the change from != to ==).

    I would probably also make a "coord" type that holds a x and y value in a struct, and pass that around instead of one x and one y value for start and end location.

    It also seems like you could simplify the whole process of moving, such that you check if the new x & y coordinate is a valid move from the starting position, and then check do the GetCell() in a common function.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Thank you Mats for the useful help, ill change the code.

    I worked it out by changing char* name; to char name[20]; i dont see the reason for using pointer here, and its working.

    Use fgets() instead of gets().
    fgets() reading from a file so i dont see either why would i need that.

    For the moment im changing all the fprint() to cout<< and it messed up the check board so im
    figuring out how to redraw it correctly.
    Using Windows 10 with Code Blocks and MingW.

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Ducky
    fgets() reading from a file so i dont see either why would i need that.
    fgets() can be used to read from standard input as well. The problem with gets() is detailed in this wiki FAQ on Why gets() is bad.

    EDIT:
    A word on the class design: looking at the piece class, it seems that you are basically relying on a type code, and then providing a bunch of functions (RookMove, KnightMove, etc) of which only one would be valid depending on the type code (which appears to be the purpose of CheckMove()).

    A probably better class design would make use of inheritance and polymorphism, e.g.,
    Code:
    class Piece
    {
    public:
        // ...
        virtual ~Piece() {} // Polymorphic base class should have a virtual destructor.
    
        virtual bool Move(int sx, int sy, int ex, int ey) = 0;
    private:
        bool owner;
        short x, y;
    };
    
    class Rook : public Piece
    {
    public:
        virtual bool Move(int sx, int sy, int ex, int ey);
    };
    
    class Knight : public Piece
    {
    public:
        virtual bool Move(int sx, int sy, int ex, int ey);
    };
    Last edited by laserlight; 01-08-2009 at 01:44 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Thats really awesome! Thank you Laserlight!

    Now i have a lot to learn with all this help from everybody. Highly appreciated.
    Using Windows 10 with Code Blocks and MingW.

  10. #10
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Hi again!

    I would like to get some help please with that function.

    1. Whats the mod =1 or mod=-1 stands for?
    I saw that it changes "go" but why -1?

    2. In the return ; statements is 0=true and 1= false?

    Because if i replace them the program crashes.

    Code:
    bool piece::PawnMove(int sx, int sy, int ex, int ey)
    {
        int mod, jmp=0;
        if(b.GetGo()==0) mod= 1;
        else            mod=-1;
       
        if((sy==6 && ey==4) || (sy==1 && ey==3)) jmp=1;
       
        if(sy==ey+mod || (sy=ey+mod+mod && jmp==1)) 
            if(sx==ex)//Move Forward
                if(b.GetCell(ex, ey) != NULL)//If Blocked
                    return 1;
                else
                    return 0;
            else if((sx==ex-1 || sx==ex+1) && jmp==0)
                if(b.GetCell(ex, ey) != NULL)//If Piece to take
                    return 0;
                else
                    return 1;       
            else
                return 1;
        return 1;
    }
    Last edited by Ducky; 01-14-2009 at 09:23 AM.
    Using Windows 10 with Code Blocks and MingW.

  11. #11
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    0 is false and 1 is true.
    mod=1 and mod=-1 are just assignments (either you are moving up the board or down the board).

  12. #12
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Thank you Tabstop!

    But pawn cant move backwards, so maybe thats wrong there.
    Using Windows 10 with Code Blocks and MingW.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Chess and Heuristics
    By Happy_Reaper in forum A Brief History of Cprogramming.com
    Replies: 9
    Last Post: 11-14-2006, 01:05 PM
  2. chess program.
    By myk_raniu in forum C++ Programming
    Replies: 2
    Last Post: 12-19-2005, 03:32 PM
  3. chess ai contest
    By Raven Arkadon in forum Contests Board
    Replies: 7
    Last Post: 07-09-2005, 06:38 AM
  4. Ultra chess engine contest
    By yodacpp in forum Projects and Job Recruitment
    Replies: 8
    Last Post: 11-21-2004, 07:58 AM
  5. Ultra chess engine
    By yodacpp in forum Game Programming
    Replies: 2
    Last Post: 11-19-2004, 12:33 PM