#include "ChessGame.h" #include #include using namespace chessy; MoveInfo::MoveInfo(Move move, const ChessGame& cg) : move{ move }, movedPiece{ cg.getBoard().getAtPosition(move.origin) }, enPassantTarget{ 0 } { } ChessGame::ChessGame(void) { board.resetBoard(); } ChessGame::ChessGame(const std::string& fenString) { loadFromFen(fenString); } bool ChessGame::isValidMove(const Move& move) const { return false; } std::vector ChessGame::getValidMoves(void) const { std::vector ret; return ret; } void ChessGame::move(Move move) { MoveInfo mi; mi.move = move; mi.movedPiece = board.getAtPosition(move.origin); doMove(mi); } void ChessGame::loadFromFen(const std::string& fenString) { using namespace std; stringstream tokenizer (fenString); string board; string turn; string castling; string enPassant; string halfmoves; string moveCount; tokenizer >> board; tokenizer >> turn; tokenizer >> castling; tokenizer >> enPassant; tokenizer >> halfmoves; tokenizer >> moveCount; this->board.setBoard(board); this->enPassant = Index {enPassant}; if (turn == "w"s) this->turn = WHITE_SIDE; else if (turn == "b"s) this->turn = BLACK_SIDE; else throw runtime_error("invalid turn "s + turn); castlingRights = 0; 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); } } if (enPassant == "-"s) { this->enPassant = -1; } else { if (enPassant.size() != 2 || (enPassant[1] != '3' && enPassant[1] != '6')) throw runtime_error("invalid en passant string: "s + enPassant); this->enPassant = Index{ enPassant }; } try { reversibleHalfMoves = stoi(halfmoves); } catch(...) { throw runtime_error("invalid number of halfmoves: "s + halfmoves); } try { this->moveCount = stoi(moveCount); } catch(...) { throw runtime_error("invalid number of moves: "s + halfmoves); } } std::string ChessGame::generateFen(void) const { using namespace std; string board = this->board.getFenBoard(); string turn = this->turn == WHITE_SIDE ? "w"s : "b"s; string castlingRights = (getCanCastleKingSide(BLACK_SIDE) ? "K"s : ""s) + (getCanCastleQueenSide(BLACK_SIDE)? "Q"s : ""s) + (getCanCastleKingSide(WHITE_SIDE) ? "k"s : ""s) + (getCanCastleQueenSide(WHITE_SIDE) ? "q"s : ""s); if (castlingRights.empty()) castlingRights = "-"s; string enPassant; if (this->enPassant == -1) { enPassant = "-"s; } else { enPassant = this->enPassant.getName(); } string halfmoves = to_string(reversibleHalfMoves); string mCount = to_string(moveCount); return board + " " + turn + " " + castlingRights + " " + enPassant + " " + halfmoves + " " + mCount; } UndoInfo ChessGame::doMove(const MoveInfo& mi) { UndoInfo ui; ui.castlingRights = castlingRights; if (mi.movedPiece == KING) { setCanCastleKingSide(turn, false); setCanCastleQueenSide(turn, false); } ui.type = mi.movedPiece; Bitboard& b = board.getBitboards(turn)[ui.type]; ui.before = b; Bitboard target = Bitboard::fromIndex(mi.move.destination); b &= ~Bitboard::fromIndex(mi.move.origin); b |= target; ui.captured = PieceType::EMPTY; for (int i = 0; i < 6; i++) { Bitboard& e = board.getBitboards(otherSide(turn))[i]; if (target & e) { ui.captured = static_cast(i); ui.beforeCaptured = e; e ^= target; break; } } turn = otherSide(turn); moveCount++; ui.reversibleHalfMoves = reversibleHalfMoves; if(mi.movedPiece != PAWN && board.getAtPosition(mi.move.destination) != EMPTY) { reversibleHalfMoves++; } return ui; } void ChessGame::undoMove(const UndoInfo& ui) { turn = otherSide(turn); Bitboard& b = board.getBitboards(turn)[ui.type]; b = ui.before; if (ui.captured != PieceType::EMPTY) board.getBitboards(otherSide(turn))[ui.captured] = ui.beforeCaptured; moveCount--; reversibleHalfMoves = ui.reversibleHalfMoves; castlingRights = ui.castlingRights; }