drake14w
drake14w

Reputation: 197

How to make a deep copy of an array of pointers

I am in the process of creating a chess engine and I am using a chess engine that can be found here for it's ChessBoard and Piece classes. as part of the engine I have to make a deep copy of an instance of the ChessBoard class and and I am having a great deal of difficulty doing this. I have tried editing the copy constructor in the class in multiple ways and changing the my own code but to no avail.

Here is the problematic part of my code:

move_list = j->data().board->getPossibleMoves(board->flip(colour));
for (auto k : move_list) {
    print_board(j->data().board);
    current_node.board = j->data().board;
    current_node.board->moveTo(std::tuple<char, char>(std::get<0>(k), std::get<1>(k)), std::tuple<char, char>(std::get<2>(k), std::get<3>(k)));
    std::cout << "After :" << std::endl;
    print_board(j->data().board);
    j->insert(current_node);

//"j" is a node in a tree class
//"k" is structured like this: std::vector<std::tuple<char, char, char, char>>
//"MoveTo" moves a chess piece to a location on the chess board

This yields an output like this:

Before :
 R  N  B  Q  K  B  N  R
 P  P  P  P  P  P  P  P
                        



 p  p  p  p  p  p  p  p
 R  N  B  Q  K  B  N  R
After :
 R  N  B  Q  K  B  N  R
 P  P  P  P  P  P  P  P
                        


 p
    p  p  p  p  p  p  p
 R  N  B  Q  K  B  N  R

As you can see, the value of "j->data()" changes even though I change the new "ChessBoard" therefore "j->data()" and the new board are pointing to the same location in memory.

Here are the copy constructors of ChessBoard and Piece:

//board.h
ChessBoard(const ChessBoard& rhs) { //Copy constructor
        //This is the section that I'm concerned about ↓ (Until the other comment)
        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 8; y++) {
                Piece* piece = new Piece(rhs.squares[x][y]->colour);
                piece->value = rhs.squares[x][y]->value;
                piece->symbol = rhs.squares[x][y]->symbol;
                piece->pieceType = rhs.squares[x][y]->pieceType;
                piece->moveCount = rhs.squares[x][y]->moveCount;
                ChessBoard::squares[x][y] = piece;
            }
        }
        //This is the section that I'm concerned about ↑ (Until the other comment)
        for (auto itr = rhs.promotedQueens.begin(); itr != promotedQueens.end(); ++itr) {
            Piece piece = **(itr);
            promotedQueens.push_back(&piece);
        }
        whiteCastled = rhs.whiteCastled;
        blackCastled = rhs.blackCastled;
        plyCount = rhs.plyCount;
        allowIllegalMoves = rhs.allowIllegalMoves;
        improvedDrawDetection = rhs.improvedDrawDetection;
        ChessBoard::transpos_table.initializeHash(this, Colour::White);
        initializeOriginalSquares();
    }

//Pieces.h
Piece(const Piece& rhs) { //Copy constructor
        value = rhs.value;
        symbol = rhs.symbol;
        pieceType = rhs.pieceType;
        moveCount = rhs.moveCount;
        colour = rhs.colour;
    };

To summarize, how could I make a copy constructor that makes a deep copy of the ChessBoard class or create a deep copy of it in some other way?

Upvotes: 0

Views: 607

Answers (1)

rturrado
rturrado

Reputation: 8064

You are using runtime polymorphism for your pieces. I.e. you have a chess board of pointers to Piece, which can be of different types (Horse, Bishop and so on). And your problem is that, when you copy construct your chess board, you need to copy construct each piece, but you only hold a Piece* to a polymorphic object. You need a virtual copy constructor. As suggested in the link, you can:

  • add a pure virtual clone method to your Piece base class, and
  • override that method for each of your final classes, doing the copy construction there.

The code below uses smart pointers instead of raw pointers. Notice *this is passed to std::make_unique to invoke the copy constructor. If you passed nothing, you would be invoking the default constructor. The same applies when using raw pointers and new.

[Demo]

class Piece {
public:
    virtual std::unique_ptr<Piece> clone() = 0;
};

class Horse : public Piece {
public:
    virtual std::unique_ptr<Piece> clone() override {
        return std::make_unique<Horse>(*this);
    };
};

ChessBoard(const ChessBoard& cb) {
    for (size_t x{0}; x < board_size; ++x) {
        for (size_t y{0}; y < board_size; ++y) {
            squares[x][y] = cb.squares[x][y]->clone();
        }
    }
}

Some other related links: another question asking about virtual copy constructors. And two useful answers to that question, 1, and 2.

Upvotes: 1

Related Questions