ChessGame.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #include "ChessGame.h"
  2. #include <sstream>
  3. #include <stdexcept>
  4. using namespace chessy;
  5. MoveInfo::MoveInfo(Move move, const ChessGame& cg) :
  6. move{ move }, movedPiece{ cg.getBoard().getAtPosition(move.origin) },
  7. enPassantTarget{ 0 }
  8. {
  9. }
  10. ChessGame::ChessGame(void)
  11. {
  12. board.resetBoard();
  13. }
  14. ChessGame::ChessGame(const std::string& fenString)
  15. {
  16. loadFromFen(fenString);
  17. }
  18. bool ChessGame::isValidMove(const Move& move) const
  19. {
  20. return false;
  21. }
  22. std::vector<Move> ChessGame::getValidMoves(void) const
  23. {
  24. std::vector<Move> ret;
  25. return ret;
  26. }
  27. void ChessGame::move(Move move)
  28. {
  29. MoveInfo mi;
  30. mi.move = move;
  31. mi.movedPiece = board.getAtPosition(move.origin);
  32. doMove(mi);
  33. }
  34. void ChessGame::loadFromFen(const std::string& fenString)
  35. {
  36. using namespace std;
  37. stringstream tokenizer (fenString);
  38. string board;
  39. string turn;
  40. string castling;
  41. string enPassant;
  42. string halfmoves;
  43. string moveCount;
  44. tokenizer >> board;
  45. tokenizer >> turn;
  46. tokenizer >> castling;
  47. tokenizer >> enPassant;
  48. tokenizer >> halfmoves;
  49. tokenizer >> moveCount;
  50. this->board.setBoard(board);
  51. this->enPassant = Index {enPassant};
  52. if (turn == "w"s) this->turn = WHITE_SIDE;
  53. else if (turn == "b"s) this->turn = BLACK_SIDE;
  54. else throw runtime_error("invalid turn "s + turn);
  55. castlingRights = 0;
  56. if (castling != "-")
  57. for (auto character : castling) {
  58. switch (character) {
  59. case 'k':
  60. setCanCastleKingSide(WHITE_SIDE, true);
  61. break;
  62. case 'q':
  63. setCanCastleQueenSide(WHITE_SIDE, true);
  64. break;
  65. case 'K':
  66. setCanCastleKingSide(BLACK_SIDE, true);
  67. break;
  68. case 'Q':
  69. setCanCastleQueenSide(BLACK_SIDE, true);
  70. break;
  71. default:
  72. throw runtime_error("invalid castling right: "s + character);
  73. }
  74. }
  75. if (enPassant == "-"s) {
  76. this->enPassant = -1;
  77. }
  78. else {
  79. if (enPassant.size() != 2 || (enPassant[1] != '3' && enPassant[1] != '6'))
  80. throw runtime_error("invalid en passant string: "s + enPassant);
  81. this->enPassant = Index{ enPassant };
  82. }
  83. try {
  84. reversibleHalfMoves = stoi(halfmoves);
  85. }
  86. catch(...) {
  87. throw runtime_error("invalid number of halfmoves: "s + halfmoves);
  88. }
  89. try {
  90. this->moveCount = stoi(moveCount);
  91. }
  92. catch(...) {
  93. throw runtime_error("invalid number of moves: "s + halfmoves);
  94. }
  95. }
  96. std::string ChessGame::generateFen(void) const
  97. {
  98. using namespace std;
  99. string board = this->board.getFenBoard();
  100. string turn = this->turn == WHITE_SIDE ? "w"s : "b"s;
  101. string castlingRights =
  102. (getCanCastleKingSide(BLACK_SIDE) ? "K"s : ""s) +
  103. (getCanCastleQueenSide(BLACK_SIDE)? "Q"s : ""s) +
  104. (getCanCastleKingSide(WHITE_SIDE) ? "k"s : ""s) +
  105. (getCanCastleQueenSide(WHITE_SIDE) ? "q"s : ""s);
  106. if (castlingRights.empty())
  107. castlingRights = "-"s;
  108. string enPassant;
  109. if (this->enPassant == -1) {
  110. enPassant = "-"s;
  111. }
  112. else {
  113. enPassant = this->enPassant.getName();
  114. }
  115. string halfmoves = to_string(reversibleHalfMoves);
  116. string mCount = to_string(moveCount);
  117. return board + " " + turn + " " + castlingRights + " " + enPassant + " " + halfmoves +
  118. " " + mCount;
  119. }
  120. UndoInfo ChessGame::doMove(const MoveInfo& mi)
  121. {
  122. UndoInfo ui;
  123. ui.castlingRights = castlingRights;
  124. if (mi.movedPiece == KING) {
  125. setCanCastleKingSide(turn, false);
  126. setCanCastleQueenSide(turn, false);
  127. }
  128. ui.type = mi.movedPiece;
  129. Bitboard& b = board.getBitboards(turn)[ui.type];
  130. ui.before = b;
  131. Bitboard target = Bitboard::fromIndex(mi.move.destination);
  132. b &= ~Bitboard::fromIndex(mi.move.origin);
  133. b |= target;
  134. ui.captured = PieceType::EMPTY;
  135. for (int i = 0; i < 6; i++) {
  136. Bitboard& e = board.getBitboards(otherSide(turn))[i];
  137. if (target & e) {
  138. ui.captured = static_cast<PieceType>(i);
  139. ui.beforeCaptured = e;
  140. e ^= target;
  141. break;
  142. }
  143. }
  144. turn = otherSide(turn);
  145. moveCount++;
  146. ui.reversibleHalfMoves = reversibleHalfMoves;
  147. if(mi.movedPiece != PAWN &&
  148. board.getAtPosition(mi.move.destination) != EMPTY) {
  149. reversibleHalfMoves++;
  150. }
  151. return ui;
  152. }
  153. void ChessGame::undoMove(const UndoInfo& ui)
  154. {
  155. turn = otherSide(turn);
  156. Bitboard& b = board.getBitboards(turn)[ui.type];
  157. b = ui.before;
  158. if (ui.captured != PieceType::EMPTY)
  159. board.getBitboards(otherSide(turn))[ui.captured] = ui.beforeCaptured;
  160. moveCount--;
  161. reversibleHalfMoves = ui.reversibleHalfMoves;
  162. castlingRights = ui.castlingRights;
  163. }