diff options
| author | Loic Guegan <manzerbredes@mailbox.org> | 2022-01-29 11:52:47 +0100 |
|---|---|---|
| committer | Loic Guegan <manzerbredes@mailbox.org> | 2022-01-29 11:52:47 +0100 |
| commit | e9d328acf4ee45bd8771d422fa4db40298e6e16a (patch) | |
| tree | 68a86c53539fe57b434c49555feafac9081f75e0 /src | |
Init project
Diffstat (limited to 'src')
| -rw-r--r-- | src/Board.cpp | 196 | ||||
| -rw-r--r-- | src/Board.hpp | 44 | ||||
| -rw-r--r-- | src/ChessArbiter.cpp | 309 | ||||
| -rw-r--r-- | src/ChessArbiter.hpp | 40 | ||||
| -rw-r--r-- | src/Fen.cpp | 170 | ||||
| -rw-r--r-- | src/Fen.hpp | 41 | ||||
| -rw-r--r-- | src/Piece.cpp | 103 | ||||
| -rw-r--r-- | src/Piece.hpp | 27 |
8 files changed, 930 insertions, 0 deletions
diff --git a/src/Board.cpp b/src/Board.cpp new file mode 100644 index 0000000..afd32e3 --- /dev/null +++ b/src/Board.cpp @@ -0,0 +1,196 @@ +#include "Board.hpp" + +namespace chessarbiter { + +bool Board::IsEmpty(std::string coord) { + for (Piece &p : pieces) { + if (p.coord == coord) { + return (false); + } + } + return (true); +} + +bool Board::AddPiece(char p, std::string coord) { + if (IsEmpty(coord)) { + Piece piece(p, coord); + pieces.push_back(piece); + return (true); + } + return (false); +} + +bool Board::RemovePiece(std::string coord) { + for (char i = 0; i < pieces.size(); i++) { + if (pieces[i].coord == coord) { + pieces.erase(pieces.begin() + i); + return (true); + } + } + return false; +} + +Piece Board::GetPieceAt(std::string coord) { + for (Piece &p : pieces) { + if (p.coord == coord) + return p; + } + throw NoPieceFound(); +} + +std::vector<Piece> Board::GetPlayerPieces(bool isBlack) { + std::vector<Piece> pp; + for (Piece &p : pieces) { + if (p.isBlack == isBlack) { + pp.push_back(p); + } + } + return (pp); +} + +short Board::CountPiece(char c) { + char count = 0; + for (Piece &p : pieces) { + if (p.piece == c) { + count++; + } + } + return (count); +} + +void Board::Clear() { pieces.clear(); } + +std::string Board::GetKingLocation(bool isBlack) { + for (Piece &p : pieces) { + if (p.isBlack == isBlack) { + if (p.piece == 'k' || p.piece == 'K') { + return (p.coord); + } + } + } + throw NoPieceFound(); +} + +void Board::Move(std::string move) { + std::string src(move.substr(0, 2)); + std::string dst(move.substr(2, 2)); + if (!IsEmpty(src)) { + if (!IsEmpty(dst)) { + RemovePiece(dst); + } + for (Piece &p : pieces) { + if (p.coord == src) { + p.coord = dst; + } + } + } +} + +std::string Board::Serialize() { + std::string s; + for (short i = 0; i < 8; i++) { + for (short j = 0; j < 8; j++) { + try { + Piece p = GetPieceAt((char)('a' + j) + std::string() + (char)('8' - i)); + s += p.piece; + } catch (...) { + s += " "; + } + } + } + return (s); +} + +bool Board::IsMovePossible(std::string move) { + std::string src(move.substr(0, 2)); + std::string dst(move.substr(2, 2)); + if (src == dst) { + return (false); + } + Piece srcp = GetPieceAt(src); + + // Check move is possible + std::vector<std::string> srcm = srcp.GetMoves(); + if (find(srcm.begin(), srcm.end(), dst) == srcm.end()) { + return (false); + } + + // Check colors on dst square + if (!IsEmpty(dst)) { + Piece dstp = GetPieceAt(dst); + if (srcp.isBlack == dstp.isBlack) + return (false); + } + + // Check if no piece in between + if (src[0] == dst[0] || src[1] == dst[1]) { // Rook like moves + if (src[0] == dst[0]) { // Vertical + char side = 1; + if (src[1] > dst[1]) { + side = -1; + } + char r = src[1] + 1 * side; + while (r != dst[1]) { + if (!IsEmpty(src[0] + std::string() + r)) { + return (false); + } + r += 1 * side; + } + } else { // Horizontal + char side = 1; + if (src[0] > dst[0]) { + side = -1; + } + char f = src[0] + 1 * side; + while (f != dst[0]) { + if (!IsEmpty(f + std::string() + src[1])) { + return (false); + } + f += 1 * side; + } + } + } else if ((src[0] - dst[0] == src[1] - dst[1]) || + (dst[0] - src[0] == src[1] - dst[1])) { // Bishop like moves + // That code if for diagonal 1 (bottom left to up right) + // Using the d2 variable allow to reuse the same code for the 2 diagonals + char d2 = 1; // d2 stand for diagonal 2 (bottom right to up left) + if ((dst[0] - src[0] == src[1] - dst[1])) { // If move is for diagonal 2 + d2 = -1; + } + + // Move direction check + char side = 1; + if (src[0] > dst[0]) { + side = -1; + } + + // Setup variables + char f = src[0] + 1 * side; + char r = src[1] + d2 * side; + + // Perform empty square checks + while (f != dst[0], r != dst[1]) { + if (!IsEmpty(f + std::string() + r)) { + return (false); + } + f += 1 * side; + r += d2 * side; + } + } + return (true); +} + +std::vector<std::string> Board::ListPossibleMoves(bool isBlack) { + std::vector<std::string> moves; + for (Piece &p : pieces) { + if (p.isBlack == isBlack) { + for (std::string &m : p.GetMoves()) { + if (IsMovePossible(p.coord + m)) { + moves.push_back(p.coord + m); + } + } + } + } + return (moves); +} +} // namespace chessarbiter
\ No newline at end of file diff --git a/src/Board.hpp b/src/Board.hpp new file mode 100644 index 0000000..aee2e10 --- /dev/null +++ b/src/Board.hpp @@ -0,0 +1,44 @@ +#include "Piece.hpp" +#include <algorithm> +#include <exception> +#include <iostream> +#include <string> + +namespace chessarbiter { + +class Board { + std::vector<Piece> pieces; + +public: + /// @brief Check if a square is empty + bool IsEmpty(std::string); + /// @brief Add a piece (no checks are performed on coord) + bool AddPiece(char p, std::string); + /// @brief Remove a piece from a square + bool RemovePiece(std::string); + /// @brief Get piece at a specific coordinate + Piece GetPieceAt(std::string); + /// @brief Get the pieces of a player + std::vector<Piece> GetPlayerPieces(bool); + /// @brief Count the number of a specific piece on the board + short CountPiece(char); + /// @brief Get the location of the first king found on the board + std::string GetKingLocation(bool); + /// @brief Check if a move is technically possible (does not means it is + /// legal) + bool IsMovePossible(std::string); + /// @brief Clear the board + void Clear(); + /// @brief Move a piece somewhere no matter what + void Move(std::string); + /// @brief Get a serialize version of the board + std::string Serialize(); + /// @brief List all the technically possible moves of a player + std::vector<std::string> ListPossibleMoves(bool); +}; + +struct NoPieceFound : public std::exception { + const char *what() const throw() { return "No piece found"; } +}; + +} // namespace chessarbiter
\ No newline at end of file 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 diff --git a/src/ChessArbiter.hpp b/src/ChessArbiter.hpp new file mode 100644 index 0000000..5739904 --- /dev/null +++ b/src/ChessArbiter.hpp @@ -0,0 +1,40 @@ +#include "Board.hpp" +#include "Fen.hpp" +#include <iostream> + +namespace chessarbiter { +class ChessArbiter { + Board board; + FEN fen; + FEN fen_last; // To undo a move + int wPawn, wRook, wKnight, wBishop, wQueen, wKing; + +public: + ChessArbiter(); + void Setup(std::string); + void SetFEN(std::string); + void SetFEN(FEN); + std::string GetFEN(); + /// @brief Check which player is going to play + bool IsBlackTurn(); + /// @brief Check if a side is in check + bool IsCheck(bool); + /// @brief Play a move (return false if it's illegal) + bool Play(std::string); + /// @brief Check if a square is attacked by a particular player + bool IsAttacked(std::string, bool); + /// @brief Get the serialized board + std::string GetBoard(); + /// @brief Get current position evaluation according to player's material + int GetMaterialScore(); + /// @brief Check if position is legal + bool IsPlayable(); + /// @brief Get pieces captures by a player + std::string GetCaptures(bool); + /// @brief List all the legal moves of a player + std::vector<std::string> ListLegalMoves(bool); + /// @brief Check if a specific castle is possible by a player + bool IsCastlePossible(bool, bool); + bool IsCheckMate(); +}; +} // namespace chessarbiter
\ No newline at end of file diff --git a/src/Fen.cpp b/src/Fen.cpp new file mode 100644 index 0000000..32c66a2 --- /dev/null +++ b/src/Fen.cpp @@ -0,0 +1,170 @@ +#include "Fen.hpp" + +namespace chessarbiter { + +std::string FENParser::normalize_rank(std::string fen_rank) { + std::string normalized; + for (char &c : fen_rank) { + if (IS_DIGIT(c)) { + for (char i = 0; i < (c - '0'); i++) { + normalized += ' '; + } + } else { + normalized += c; + } + } + return (normalized); +} + +char FENParser::NextToken(std::string fen, char loc) { + while (loc < fen.size() && IS_BLANK(fen[loc])) { + loc++; + } + return (loc); +} + +char FENParser::NextRank(std::string fen, char loc) { + loc++; + while (loc < fen.size() && fen[loc] != '/' && fen[loc] != ' ') { + loc++; + } + return (loc); +} + +std::string FENParser::Serialize(FEN fen) { + std::string s; + char skip = 0; + char rank = 0; + for (char &c : fen.board) { + rank++; + if (c == ' ') { + skip++; + } else { + if (skip > 0) { + s += std::to_string(skip); + skip = 0; + } + s += c; + } + if (rank == 8) { + if (skip != 0) { + s += std::to_string(skip); + skip = 0; + } + s += '/'; + rank = 0; + } + } + + // Remove last / + s = s.substr(0, s.size() - 1); + s += " "; + + // Player + if (fen.player) { + s += "b "; + } else { + s += "w "; + } + + // Castle + if (!(fen.white_castle_short || fen.white_castle_long || + fen.black_castle_short || fen.black_castle_long)) { + s += "-"; + } else { + if (fen.white_castle_short) { + s += "K"; + } + if (fen.white_castle_long) { + s += "Q"; + } + if (fen.black_castle_short) { + s += "k"; + } + if (fen.black_castle_long) { + s += "q"; + } + } + + // Remaining + s += " " + fen.en_passant + " " + std::to_string(fen.halfmove) + " " + + std::to_string(fen.move); + + return (s); +} + +FEN FENParser::Parse(std::string fen) { + FEN parsed; + + // Parse board + char loc = 0; + for (char rank = 0; rank < 8; rank++) { + char newloc = NextRank(fen, loc); + parsed.board += normalize_rank(fen.substr(loc, newloc - loc)); + loc = newloc + 1; + } + + // Parse player to move + loc = NextToken(fen, loc); + parsed.player = fen[loc] == 'b'; + + // Parse castling + loc = NextToken(fen, loc + 1); + char length = 0; + char cur_loc = loc; + while (!IS_BLANK(fen[cur_loc])) { + length++; + cur_loc++; + } + parsed.white_castle_short = false; + parsed.white_castle_long = false; + parsed.black_castle_short = false; + parsed.black_castle_long = false; + std::string castle = fen.substr(loc, length); + for (char i = 0; i < length; i++) { + switch (fen[loc + i]) { + case 'K': + parsed.white_castle_short = true; + break; + case 'Q': + parsed.white_castle_long = true; + break; + case 'k': + parsed.black_castle_short = true; + break; + case 'q': + parsed.black_castle_long = true; + break; + } + } + + // Parse en passant + loc = NextToken(fen, loc + length); + if (fen[loc] != '-') { + parsed.en_passant = fen.substr(loc, 2); + loc++; + } + loc++; + + // Parse half move counter + loc = NextToken(fen, loc); + std::string halfmove; + while (!IS_BLANK(fen[loc])) { + halfmove += fen[loc]; + loc++; + } + parsed.halfmove = stoi(halfmove); + + // Parse move counter + loc = NextToken(fen, loc); + std::string move; + while (loc < fen.size() && !IS_BLANK(fen[loc])) { + move += fen[loc]; + loc++; + } + parsed.move = stoi(move); + + return (parsed); +} + +} // namespace chessarbiter
\ No newline at end of file diff --git a/src/Fen.hpp b/src/Fen.hpp new file mode 100644 index 0000000..a477bb0 --- /dev/null +++ b/src/Fen.hpp @@ -0,0 +1,41 @@ +#include <iostream> +#include <sstream> +#include <string> + +#define IS_DIGIT(c) \ + (c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || \ + c == '6' || c == '7' || c == '8' || c == '9') +#define IS_BLANK(c) (c == ' ' || c == '\n' || c == '\t' || c == '\r') + +namespace chessarbiter { + +class FEN { +public: + std::string board; + bool player; + bool white_castle_short; + bool white_castle_long; + bool black_castle_short; + bool black_castle_long; + std::string en_passant; + short halfmove; + short move; + FEN() + : board(""), player(false), white_castle_short(true), + white_castle_long(true), black_castle_short(true), + black_castle_long(true), en_passant("-"), halfmove(0), move(1) {} +}; + +class FENParser { +private: + static std::string normalize_rank(std::string fen_rank); + static char NextToken(std::string fen, char loc); + static char NextRank(std::string fen, char loc); + +public: + /// @brief Parse a FEN from a string + static FEN Parse(std::string); + /// @brief Generate a fen string from the FEN object + static std::string Serialize(FEN fen); +}; +} // namespace chessarbiter diff --git a/src/Piece.cpp b/src/Piece.cpp new file mode 100644 index 0000000..6f9a3be --- /dev/null +++ b/src/Piece.cpp @@ -0,0 +1,103 @@ +#include "Piece.hpp" + +namespace chessarbiter { +Piece::Piece(char c, std::string coord) + : piece(c), isBlack(!isupper(c)), coord(coord) {} + +std::vector<std::string> Piece::GetMoves() { + std::vector<std::string> moves; + char f = coord[0]; // File + char r = coord[1]; // Rank + if (piece == 'p' || piece == 'P') { + char side = 1; + if (piece == 'p') { + side = -1; + } + // First two steps + if ((r == '2' && piece == 'P') || (r == '7' && piece == 'p')) { + moves.push_back(std::string() + f + (char)(r + 2 * side)); + } + if ((piece == 'P' && r < '8') || (piece == 'p' && r > '1')) { + moves.push_back(std::string() + f + (char)(r + 1 * side)); + } + PIECE__ADD_MOVE(f - 1, r + 1 * side); + PIECE__ADD_MOVE(f + 1, r + 1 * side); + } else if (piece == 'k' || piece == 'K') { + PIECE__ADD_MOVE(f, r - 1); + PIECE__ADD_MOVE(f, r + 1); + PIECE__ADD_MOVE(f + 1, r); + PIECE__ADD_MOVE(f - 1, r); + PIECE__ADD_MOVE(f + 1, r + 1); + PIECE__ADD_MOVE(f - 1, r - 1); + PIECE__ADD_MOVE(f + 1, r - 1); + PIECE__ADD_MOVE(f - 1, r + 1); + } else if (piece == 'n' || piece == 'N') { + PIECE__ADD_MOVE(f + 1, r + 2); + PIECE__ADD_MOVE(f - 1, r + 2); + PIECE__ADD_MOVE(f + 1, r - 2); + PIECE__ADD_MOVE(f - 1, r - 2); + PIECE__ADD_MOVE(f + 2, r + 1); + PIECE__ADD_MOVE(f - 2, r + 1); + PIECE__ADD_MOVE(f + 2, r - 1); + PIECE__ADD_MOVE(f - 2, r - 1); + } else { + if (piece == 'b' || piece == 'B' || piece == 'Q' || piece == 'q') { + char rtmp = r; + char ftmp = f; + while (PIECE__IS_VALID(ftmp, rtmp)) { + ftmp++; + rtmp++; + PIECE__ADD_MOVE(ftmp, rtmp); + } + rtmp = r; + ftmp = f; + while (PIECE__IS_VALID(ftmp, rtmp)) { + ftmp--; + rtmp--; + PIECE__ADD_MOVE(ftmp, rtmp); + } + rtmp = r; + ftmp = f; + while (PIECE__IS_VALID(ftmp, rtmp)) { + ftmp--; + rtmp++; + PIECE__ADD_MOVE(ftmp, rtmp); + } + rtmp = r; + ftmp = f; + while (PIECE__IS_VALID(ftmp, rtmp)) { + ftmp++; + rtmp--; + PIECE__ADD_MOVE(ftmp, rtmp); + } + } + if (piece == 'r' || piece == 'R' || piece == 'Q' || piece == 'q') { + char rtmp = r; + char ftmp = f; + while (PIECE__IS_VALID(ftmp, rtmp)) { + rtmp++; + PIECE__ADD_MOVE(ftmp, rtmp); + } + rtmp = r; + ftmp = f; + while (PIECE__IS_VALID(ftmp, rtmp)) { + rtmp--; + PIECE__ADD_MOVE(ftmp, rtmp); + } + rtmp = r; + ftmp = f; + while (PIECE__IS_VALID(ftmp, rtmp)) { + ftmp++; + PIECE__ADD_MOVE(ftmp, rtmp); + } + rtmp = r; + ftmp = f; + while (PIECE__IS_VALID(ftmp, rtmp)) { + ftmp--; + PIECE__ADD_MOVE(ftmp, rtmp); + } + } + } + return (moves); +} +} // namespace chessarbiter
\ No newline at end of file diff --git a/src/Piece.hpp b/src/Piece.hpp new file mode 100644 index 0000000..73791a0 --- /dev/null +++ b/src/Piece.hpp @@ -0,0 +1,27 @@ +#include <string> +#include <vector> + +#define PIECE__IS_VALID(f, r) ((f) >= 'a' && (f) <= 'h' && (r) >= '1' && (r) <= '8') +#define PIECE__ADD_MOVE(f, r) \ + { \ + if (PIECE__IS_VALID(f, r)) { \ + moves.push_back(std::string() + (char)((f)) + (char)((r))); \ + } \ + } + +namespace chessarbiter { + +/** + * Member are public for conveniance + */ +class Piece { +public: + bool isBlack; + std::string coord; + char piece; + Piece(char c, std::string coord); + /// @brief Get all possible moves according to the type of piece and its position + std::vector<std::string> GetMoves(); +}; + +} // namespace chessarbiter
\ No newline at end of file |
