lbragile
lbragile

Reputation: 8122

C++ Store class objects which contain polymorphic properties in a stack

I am attempting to make a chess game from scratch and made significant progress over the past couple of months. However, I recently got stuck on a problem that I just cannot figure out how to solve.

CODE (UPDATED)

Since the source code is too large to post here, I think it is best to leave a link to my GitHub account where it can be found: https://github.com/lbragile/chessCAMO

DESCRIPTION

Chess

Contains relevant game flags and turn tracking, as well as keeps a stack of the board positions to allow a player to undo moves.

Piece

Contains the piece's:

Piece Type classes

Includes:

These inherit from the base class (Piece)

QUESTION

With this set up, Chess and Piece are separate classes (one is not derived from the other). However, to keep track of the board positions in a stack, the Chess class uses the member variable:

stack<vector<Piece*>> board_positions;

This does in fact allow me to undo the position and even make moves afterwards. However, after running my algorithm through my test cases, I noticed that it fails the cases involving flags for check, double check, checkmate, and stalemate. When I checked with my GUI, this was confirmed. For example, making a move which causes a check, then "undoing" that move, and repeating the move again. This fails since the check flag of the previous position is not stored.

This leads to the obvious conclusion that I must store the entire Chess object at each move so that I get both the board representation and the corresponding necessary flags. I just cannot figure out how to have a member variable in the class Chess that can store Chess objects in a stack. The main reason is that Chess itself contains Piece objects in it which are polymorphic (virtual functions) and the two classes are separate.

Any suggestions or helpful tips as to how to proceed would be much appreciated.

EDIT #1

I updated the code using the suggestions provided. However, my current problem is that the board flags do not seem to update on the stack. This seems to stem from the ~Chess(). I think it is not actually destroying the object pointers but rather simply popping them. I attempted using std::move() to move the resources in makeMove(int src, int dest, istream &in) from temp_chess in the pushInfo() function of the if statement and deleting the game_info pointer in the destructor, however this doesn't seem to fix the issue.

EDIT #2

See my answer below, I solved the problem using serialization/de-serialization of the Chess object.

Upvotes: 2

Views: 460

Answers (1)

lbragile
lbragile

Reputation: 8122

I managed to solve the problem by serializing/de-serializing the Chess object's private members to a file.

The way I did this was by making a separate folder which stores these files and added a move counting private member to Chess. Then I added the serializing functionality using the overloaded extraction and insertion operators:

chess.h

class Chess
{
public:
    // previous functions
    
    // Accessor/mutator functions for number of moves made
    int getNumMoves() { return num_moves;}
    void setNumMoves(int num_moves) {this->num_moves = num_moves;}        

    // to serialize (write the object to a file)
    friend ostream & operator << (ostream &out, const Chess &chess_object);

    // to de-serialize (read in the object from a file)
    friend istream & operator >> (istream &in, Chess &chess_object);

private:
    // previous members
    
    int num_moves;
};

chess.cpp

// puts each member field on a new line
ostream & operator << (ostream &out, const Chess &chess_object)
{
    for(const auto & elem : chess_object.getBoard())
        out << elem->getPieceType() << endl << elem->getPieceSquare() << endl << elem->getPieceColor() << endl
            << elem->getPieceMoveInfo() << endl << elem->getEnPassantLeft() << endl << elem->getEnPassantRight() << endl;

    out << chess_object.getCheck() << endl << chess_object.getDoubleCheck() << endl << chess_object.getCheckmate() << endl << chess_object.getStalemate() << endl;

    out << chess_object.getTurn() << endl;

    return out;
}


istream & operator >> (istream &in, Chess &chess_object)
{
    // delete the allocated memory and restore new data
    vector<Piece*> board = chess_object.getBoard();
    for(unsigned int i = 0; i < board.size(); i++)
        delete board[i];
    // board.clear();

    string input;
    for(auto & elem : board)
    {
        in >> input;
        switch(input[0] - '0')
        {
            case 0:
                elem = new Pawn(0, PAWN, NEUTRAL);
                break;
            case 1:
                elem = new Knight(0, KNIGHT, NEUTRAL);
                break;
            case 2:
                elem = new Bishop(0, BISHOP, NEUTRAL);
                break;
            case 3:
                elem = new Rook(0, ROOK, NEUTRAL);
                break;
            case 4:
                elem = new Queen(0, QUEEN, NEUTRAL);
                break;
            case 5:
                elem = new King(0, KING, NEUTRAL);
                break;
            default:
                elem = new Empty(0, EMPTY, NEUTRAL);    
        }

        in >> input;
        elem->setPieceSquare(stoi(input));
        in >> input;
        elem->setPieceColor((pieceColor) (input[0] - '0'));
        in >> input;
        elem->setPieceMoveInfo(input == "1");
        in >> input;
        elem->setEnPassantLeft(input == "1");
        in >> input;
        elem->setEnPassantRight(input == "1");
    }

    chess_object.setBoard(board);

    in >> input;
    chess_object.setCheck(input == "1");
    in >> input;
    chess_object.setDoubleCheck(input == "1");
    in >> input;
    chess_object.setCheckmate(input == "1");
    in >> input;
    chess_object.setStalemate(input == "1");

    in >> input;
    chess_object.setTurn((pieceColor) (input[0] - '0'));

    return in;
}

Thank you to all for the help you provided!

Upvotes: 2

Related Questions