|
@@ -1,4 +1,7 @@
|
|
|
#include "ChessGame.h"
|
|
|
+
|
|
|
+#include "Util.h"
|
|
|
+
|
|
|
#include <sstream>
|
|
|
#include <stdexcept>
|
|
|
|
|
@@ -14,6 +17,7 @@ MoveInfo::MoveInfo(Move move, const ChessGame& cg) :
|
|
|
ChessGame::ChessGame(void)
|
|
|
{
|
|
|
board.resetBoard();
|
|
|
+ hash = zobrist::getHash(*this);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -23,19 +27,6 @@ ChessGame::ChessGame(const std::string& fenString)
|
|
|
}
|
|
|
|
|
|
|
|
|
-bool ChessGame::isValidMove(const Move& move) const
|
|
|
-{
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-std::vector<Move> ChessGame::getValidMoves(void) const
|
|
|
-{
|
|
|
- std::vector<Move> ret;
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
void ChessGame::move(Move move)
|
|
|
{
|
|
|
MoveInfo mi;
|
|
@@ -73,25 +64,26 @@ void ChessGame::loadFromFen(const std::string& fenString)
|
|
|
else throw runtime_error("invalid turn "s + turn);
|
|
|
|
|
|
castlingRights = 0;
|
|
|
- if (castling != "-")
|
|
|
+ if (castling != "-") {
|
|
|
for (auto character : castling) {
|
|
|
switch (character) {
|
|
|
- case 'k':
|
|
|
- setCanCastleKingSide(WHITE_SIDE, true);
|
|
|
- break;
|
|
|
- case 'q':
|
|
|
- setCanCastleQueenSide(WHITE_SIDE, true);
|
|
|
- break;
|
|
|
- case 'K':
|
|
|
- setCanCastleKingSide(BLACK_SIDE, true);
|
|
|
- break;
|
|
|
- case 'Q':
|
|
|
- setCanCastleQueenSide(BLACK_SIDE, true);
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw runtime_error("invalid castling right: "s + character);
|
|
|
+ case 'k':
|
|
|
+ setCanCastleKingSide(WHITE_SIDE, true);
|
|
|
+ break;
|
|
|
+ case 'q':
|
|
|
+ setCanCastleQueenSide(WHITE_SIDE, true);
|
|
|
+ break;
|
|
|
+ case 'K':
|
|
|
+ setCanCastleKingSide(BLACK_SIDE, true);
|
|
|
+ break;
|
|
|
+ case 'Q':
|
|
|
+ setCanCastleQueenSide(BLACK_SIDE, true);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw runtime_error("invalid castling right: "s + character);
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
if (enPassant == "-"s) {
|
|
|
this->enPassant = -1;
|
|
@@ -99,7 +91,7 @@ void ChessGame::loadFromFen(const std::string& fenString)
|
|
|
else {
|
|
|
if (enPassant.size() != 2 || (enPassant[1] != '3' && enPassant[1] != '6'))
|
|
|
throw runtime_error("invalid en passant string: "s + enPassant);
|
|
|
- this->enPassant = Index{ enPassant };
|
|
|
+ this->enPassant = Index{ enPassant }.getColumn();
|
|
|
}
|
|
|
|
|
|
try {
|
|
@@ -115,6 +107,8 @@ void ChessGame::loadFromFen(const std::string& fenString)
|
|
|
catch(...) {
|
|
|
throw runtime_error("invalid number of moves: "s + halfmoves);
|
|
|
}
|
|
|
+
|
|
|
+ hash = zobrist::getHash(*this);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -139,7 +133,7 @@ std::string ChessGame::generateFen(void) const
|
|
|
enPassant = "-"s;
|
|
|
}
|
|
|
else {
|
|
|
- enPassant = this->enPassant.getName();
|
|
|
+ enPassant = Index{ this->turn == WHITE_SIDE ? 3 : 5, this->enPassant }.getName();
|
|
|
}
|
|
|
|
|
|
string halfmoves = to_string(reversibleHalfMoves);
|
|
@@ -152,68 +146,88 @@ std::string ChessGame::generateFen(void) const
|
|
|
|
|
|
UndoInfo ChessGame::doMove(const MoveInfo& mi)
|
|
|
{
|
|
|
- UndoInfo ui;
|
|
|
+ assert(hash == zobrist::getHash(*this)); // valid zobrist hash
|
|
|
|
|
|
+ UndoInfo ui;
|
|
|
+ ui.hash = hash;
|
|
|
// adjust castling rights
|
|
|
ui.castlingRights = castlingRights;
|
|
|
+ hash ^= zobrist::castlingRights[castlingRights];
|
|
|
if (mi.movedPiece == KING) {
|
|
|
setCanCastleKingSide(turn, false);
|
|
|
setCanCastleQueenSide(turn, false);
|
|
|
}
|
|
|
+ hash ^= zobrist::castlingRights[castlingRights];
|
|
|
|
|
|
// update possible en-passant moves
|
|
|
ui.enPassantBefore = enPassant;
|
|
|
+ if (enPassant != -1)
|
|
|
+ hash ^= zobrist::enPassant[enPassant];
|
|
|
if (mi.movedPiece == PAWN &&
|
|
|
- std::abs(mi.move.destination.getRow() - mi.move.destination.getRow()) == 2) {
|
|
|
+ std::abs(mi.move.origin.getRow() - mi.move.destination.getRow()) == 2) {
|
|
|
enPassant = mi.move.origin.getRow();
|
|
|
}
|
|
|
else {
|
|
|
enPassant = -1;
|
|
|
}
|
|
|
+ if (enPassant != -1)
|
|
|
+ hash ^= zobrist::enPassant[enPassant];
|
|
|
|
|
|
ui.type = mi.movedPiece;
|
|
|
Bitboard& b = board.getBitboards(turn)[ui.type];
|
|
|
ui.before = b;
|
|
|
|
|
|
Bitboard target = Bitboard::fromIndex(mi.move.destination);
|
|
|
+ hash ^= zobrist::get(mi.movedPiece, turn, mi.move.origin);
|
|
|
b ^= Bitboard::fromIndex(mi.move.origin);
|
|
|
if (mi.move.promotion == PAWN) {
|
|
|
b |= target;
|
|
|
+ hash ^= zobrist::get(mi.movedPiece, turn, mi.move.destination);
|
|
|
ui.promotion = PAWN;
|
|
|
}
|
|
|
else {
|
|
|
ui.promotion = mi.move.promotion;
|
|
|
ui.promotionBefore = board.getBitboards(turn)[ui.promotion];
|
|
|
board.getBitboards(turn)[ui.promotion] |= target;
|
|
|
+ hash ^= zobrist::get(ui.promotion, turn, mi.move.destination);
|
|
|
}
|
|
|
+ if (mi.move.isEnPassant)
|
|
|
+ int asas = 4;
|
|
|
|
|
|
ui.captured = PieceType::EMPTY;
|
|
|
if (mi.move.isEnPassant)
|
|
|
target = Bitboard::fromIndex(Index{
|
|
|
- turn == WHITE_SIDE ? 5 : 2, mi.move.destination.getColumn() });
|
|
|
+ turn == WHITE_SIDE ? 4 : 3, mi.move.destination.getColumn() });
|
|
|
for (int i = 0; i < 6; i++) {
|
|
|
Bitboard& e = board.getBitboards(otherSide(turn))[i];
|
|
|
if (target & e) {
|
|
|
ui.captured = static_cast<PieceType>(i);
|
|
|
ui.beforeCaptured = e;
|
|
|
e ^= target;
|
|
|
+ hash ^= zobrist::get(ui.captured, otherSide(turn),
|
|
|
+ target.getLeastSignificantBit());
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
turn = otherSide(turn);
|
|
|
+ hash ^= zobrist::turn;
|
|
|
moveCount++;
|
|
|
ui.reversibleHalfMoves = reversibleHalfMoves;
|
|
|
if(mi.movedPiece != PAWN &&
|
|
|
board.getAtPosition(mi.move.destination) != EMPTY) {
|
|
|
reversibleHalfMoves++;
|
|
|
}
|
|
|
+
|
|
|
+ assert(hash == zobrist::getHash(*this)); // valid zobrist hash
|
|
|
return ui;
|
|
|
}
|
|
|
|
|
|
|
|
|
void ChessGame::undoMove(const UndoInfo& ui)
|
|
|
{
|
|
|
+ assert(hash == zobrist::getHash(*this)); // valid zobrist hash
|
|
|
+
|
|
|
turn = otherSide(turn);
|
|
|
|
|
|
Bitboard& b = board.getBitboards(turn)[ui.type];
|
|
@@ -222,9 +236,13 @@ void ChessGame::undoMove(const UndoInfo& ui)
|
|
|
board.getBitboards(otherSide(turn))[ui.captured] = ui.beforeCaptured;
|
|
|
if (ui.promotion != PieceType::PAWN)
|
|
|
board.getBitboards(turn)[ui.promotion] = ui.promotionBefore;
|
|
|
+
|
|
|
moveCount--;
|
|
|
reversibleHalfMoves = ui.reversibleHalfMoves;
|
|
|
castlingRights = ui.castlingRights;
|
|
|
enPassant = ui.enPassantBefore;
|
|
|
+ hash = ui.hash;
|
|
|
+
|
|
|
+ assert(hash == zobrist::getHash(*this)); // valid zobrist hash
|
|
|
}
|
|
|
|