Reputation: 197
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
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:
clone
method to your Piece
base class, andThe 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
.
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