diff options
Diffstat (limited to 'src/ChessArbiter.cpp')
| -rw-r--r-- | src/ChessArbiter.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/src/ChessArbiter.cpp b/src/ChessArbiter.cpp new file mode 100644 index 0000000..37dd5e2 --- /dev/null +++ b/src/ChessArbiter.cpp @@ -0,0 +1,309 @@ +#include "ChessArbiter.hpp" + +namespace chessarbiter { +ChessArbiter::ChessArbiter() + : wPawn(1), wRook(5), wKnight(3), wBishop(3), wQueen(9), wKing(0) {} + +void ChessArbiter::Setup(std::string fen) { + SetFEN(fen); + fen_last = this->fen; +} + +void ChessArbiter::SetFEN(FEN fen) { SetFEN(FENParser::Serialize(fen)); } + +void ChessArbiter::SetFEN(std::string newfen) { + fen = FENParser::Parse(newfen); + + board.Clear(); + for (int i = 0; i < 64; i++) { + if (fen.board[i] != ' ') { + char f = 'a' + ((i) % 8); + char r = '8' - ((i) / 8); + board.AddPiece(fen.board[i], f + std::string() + r); + } + } +} + +std::string ChessArbiter::GetFEN() { return (FENParser::Serialize(fen)); } + +std::string ChessArbiter::GetBoard() { return (fen.board); } + +bool ChessArbiter::IsBlackTurn() { return (fen.player == 'b'); } + +bool ChessArbiter::IsCheck(bool isBlack) { + std::string kingloc = board.GetKingLocation(isBlack); + return (IsAttacked(kingloc, !isBlack)); +} + +bool ChessArbiter::Play(std::string move) { + std::vector<std::string> moves = ListLegalMoves(fen.player); + if (find(moves.begin(), moves.end(), move) != moves.end()) { + Piece moved = board.GetPieceAt(move.substr(0, 2)); // This call never fail + std::string src = move.substr(0, 2); + std::string dst = move.substr(2, 2); + bool IsCapture = !board.IsEmpty(dst); + FEN newFen = fen; + + // Perform the move + if (move == "O-O" || move == "O-O-O") { + if (fen.player && move == "O-O") { + board.Move("e8g8"); + board.Move("h8e8"); + } else if (fen.player && move == "O-O") { + board.Move("e8c8"); + board.Move("a8d8"); + } else if (!fen.player && move == "O-O") { + board.Move("e1g1"); + board.Move("h1e1"); + } else { + board.Move("e1c1"); + board.Move("a1d1"); + } + } else { + board.Move(move); + } + + // Update halfmove + newFen.halfmove++; + // Check enpassant + newFen.en_passant = "-"; + if (moved.piece == 'p' || moved.piece == 'P') { + if (fen.player && (dst[1] - src[1] == 2)) { + newFen.en_passant = src[0] + std::string() + (char)(src[1] - 1); + } else if (!fen.player && (dst[1] - src[1] == 2)) { + newFen.en_passant = src[0] + std::string() + (char)(src[1] + 1); + } + newFen.halfmove = 0; // Pawn moves reset half moves + } + // Captures reset half moves + if (IsCapture) { + newFen.halfmove = 0; + } + if (newFen.player) { + newFen.move++; + } + newFen.board = board.Serialize(); + newFen.player = !newFen.player; + // Castle update if one is true + if (newFen.white_castle_long || newFen.white_castle_short || + newFen.black_castle_long || newFen.black_castle_short) { + if (moved.piece == 'R' && src == "a1") { + newFen.white_castle_long = false; + } else if (moved.piece == 'R' && src == "h1") { + newFen.white_castle_short = false; + } else if (moved.piece == 'r' && src == "a8") { + newFen.black_castle_long = false; + } else if (moved.piece == 'r' && src == "h8") { + newFen.black_castle_short = false; + } else if (moved.piece == 'K' || (!fen.player && src == "O-")) { + newFen.white_castle_long = false; + newFen.white_castle_short = false; + } else if (moved.piece == 'k' || (fen.player && src == "O-")) { + newFen.black_castle_long = false; + newFen.black_castle_short = false; + } + } + + // Update fen! + fen_last = fen; + fen = newFen; + + // Check for illegal move + if (IsCheck(!fen.player)) { + SetFEN(fen_last); + return (false); + } + + return (true); + } + return (false); +} + +bool ChessArbiter::IsAttacked(std::string square, bool by) { + std::vector<std::string> moves = board.ListPossibleMoves(by); + for (std::string &m : moves) { + std::string src = m.substr(0, 2); + std::string dst = m.substr(2, 2); + + if (dst == square) { + // Pawn do not attack forward + Piece p = board.GetPieceAt(src); + if (p.piece == 'p' || p.piece == 'P') { + if (src[0] != dst[0]) { + return (true); + } + } else { + return (true); + } + } + } + return (false); +} + +bool ChessArbiter::IsCastlePossible(bool isBlack, bool isLong) { + + if (isBlack && isLong && fen.black_castle_long) { + if (board.IsEmpty("d8") && board.IsEmpty("c8") && board.IsEmpty("b8")) { + if (!IsAttacked("d8", false) && !IsAttacked("c8", false)) { + return (true); + } + } + } else if (isBlack && !isLong && fen.black_castle_short) { + if (board.IsEmpty("f8") && board.IsEmpty("g8")) { + if (!IsAttacked("f8", false) && !IsAttacked("g8", false)) { + return (true); + } + } + } else if (!isBlack && isLong && fen.white_castle_long) { + if (board.IsEmpty("d1") && board.IsEmpty("c1") && board.IsEmpty("b1")) { + if (!IsAttacked("d1", true) && !IsAttacked("c1", true)) { + return (true); + } + } + } else if (!isBlack && !isLong && fen.white_castle_short) { + if (board.IsEmpty("f1") && board.IsEmpty("g1")) { + if (!IsAttacked("f1", true) && !IsAttacked("g1", true)) { + return (true); + } + } + } + + return (false); +} + +int ChessArbiter::GetMaterialScore() { + int whiteScore = 0; + int blackScore = 0; + for (char i = 0; i < 2; i++) { + int *score = &whiteScore; + if (i > 0) { + score = &blackScore; + } + for (Piece &p : board.GetPlayerPieces((bool)i)) { + switch (tolower(p.piece)) { + case 'p': + (*score) += wPawn; + break; + case 'r': + (*score) += wRook; + break; + case 'n': + (*score) += wKnight; + break; + case 'b': + (*score) += wBishop; + break; + case 'q': + (*score) += wQueen; + break; + default: + (*score) += wKing; + } + } + } + return (whiteScore - blackScore); +} + +std::string ChessArbiter::GetCaptures(bool isBlack) { + std::string captures; + // Pawn + char p = 'P'; + if (!isBlack) + p = 'p'; + for (char i = 8 - board.CountPiece(p); i > 0; i--) { + captures += p; + } + // Rook + p = 'R'; + if (!isBlack) + p = 'r'; + for (char i = 2 - board.CountPiece(p); i > 0; i--) { + captures += p; + } + // Knight + p = 'N'; + if (!isBlack) + p = 'n'; + for (char i = 2 - board.CountPiece(p); i > 0; i--) { + captures += p; + } + // Bishop + p = 'B'; + if (!isBlack) + p = 'b'; + for (char i = 2 - board.CountPiece(p); i > 0; i--) { + captures += p; + } + // Queen + p = 'Q'; + if (!isBlack) + p = 'q'; + for (char i = 1 - board.CountPiece(p); i > 0; i--) { + captures += p; + } + // King :D + p = 'K'; + if (!isBlack) + p = 'k'; + for (char i = 1 - board.CountPiece(p); i > 0; i--) { + captures += p; + } + return (captures); +} + +std::vector<std::string> ChessArbiter::ListLegalMoves(bool isBlack) { + std::vector<std::string> moves; + for (std::string &move : board.ListPossibleMoves(isBlack)) { + std::string src = move.substr(0, 2); + std::string dst = move.substr(2, 2); + Piece srcp = board.GetPieceAt(src); // This call never fail + bool IsDstEmpty = board.IsEmpty(dst); + + // Pawns side moves + if ((srcp.piece == 'p' || srcp.piece == 'P') && (src[0] != dst[0])) { + if (!IsDstEmpty) { + Piece attacked = board.GetPieceAt(dst); + if (srcp.isBlack != attacked.isBlack) + moves.push_back(move); + } else if (dst == fen.en_passant) { + moves.push_back(move); + } + } else { + moves.push_back(move); + } + } + + // Casling + if (IsCastlePossible(isBlack, false)) + moves.push_back("O-O"); + if (IsCastlePossible(isBlack, true)) + moves.push_back("O-O-O"); + + return (moves); +} + +bool ChessArbiter::IsPlayable() { + char nK = board.CountPiece('K'); + if (nK == 1 && nK == board.CountPiece('k')) { + if (!IsCheck(!fen.player)) { + return (true); + } + } + return (false); +} + +bool ChessArbiter::IsCheckMate() { + if (IsCheck(fen.player)) { + std::vector<std::string> moves = ListLegalMoves(fen.player); + for(std::string &move: moves){ + if(Play(move)){ + SetFEN(fen_last); + return(false); + } + } + return(true); + } + return (false); +} + +} // namespace chessarbiter
\ No newline at end of file |
