├── .gitignore ├── README.md └── chess ├── chess.cpp ├── chess.h ├── main.cpp ├── variant ├── variant.cpp └── variant.h /.gitignore: -------------------------------------------------------------------------------- 1 | chess/main 2 | .DS_Store 3 | .vscode/settings.json 4 | chess/.vscode/settings.json 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This is a recreation of niklasf's 'python-chess' in C++\ 2 | All credit for the original code and algorithms go to niklasf and his credits\ 3 | His source code can be found here: https://github.com/niklasf/python-chess** 4 | 5 | cpp-chess: a chess library for C++ 6 | ======================================== 7 | 8 | Introduction 9 | ------------ 10 | 11 | cpp-chess is a chess library for C++, with move generation, 12 | move validation, and support for common formats. This is the Scholar's mate in 13 | cpp-chess: 14 | 15 | ```cpp 16 | 17 | >>> #include "chess.cpp" 18 | >>> #include 19 | 20 | >>> chess::Board board; 21 | 22 | >>> std::cout << board.legal_moves(); // doctest: +ELLIPSIS 23 | 24 | >>> chess::LegalMoveGenerator legal_moves = board.legal_moves(); 25 | >>> std::cout << (std::find(std::begin(legal_moves), std::end(legal_moves), chess::Move::from_uci("a8a1")) != std::end(legal_moves)); 26 | 0 27 | 28 | >>> std::cout << board.push_san("e4"); 29 | Move::from_uci("e2e4") 30 | >>> std::cout << board.push_san("e5"); 31 | Move::from_uci("e7e5") 32 | >>> std::cout << board.push_san("Qh5"); 33 | Move::from_uci("d1h5") 34 | >>> std::cout << board.push_san("Nc6"); 35 | Move::from_uci("b8c6") 36 | >>> std::cout << board.push_san("Bc4"); 37 | Move::from_uci("f1c4") 38 | >>> std::cout << board.push_san("Nf6"); 39 | Move::from_uci("g8f6") 40 | >>> std::cout << board.push_san("Qxf7"); 41 | Move::from_uci("h5f7") 42 | 43 | >>> std::cout << board.is_checkmate(); 44 | 1 45 | 46 | >>> std::cout << board; 47 | Board("r1bqkb1r/pppp1Qpp/2n2n2/4p3/2B1P3/8/PPPP1PPP/RNB1K1NR b KQkq - 0 4") 48 | ``` 49 | 50 | Features 51 | -------- 52 | 53 | * Supports C++ 20+. 54 | 55 | * Make and unmake moves. 56 | 57 | ```cpp 58 | 59 | >>> chess::Move Nf3 = chess::Move::from_uci("g1f3"); 60 | >>> board.push(Nf3); // Make the move 61 | 62 | >>> std::cout << board.pop(); // Unmake the last move 63 | Move::from_uci("g1f3") 64 | ``` 65 | 66 | * Show a simple ASCII board. 67 | 68 | ```cpp 69 | 70 | >>> chess::Board board = chess::Board("r1bqkb1r/pppp1Qpp/2n2n2/4p3/2B1P3/8/PPPP1PPP/RNB1K1NR b KQkq - 0 4"); 71 | >>> std::cout << std::string(board); 72 | r . b q k b . r 73 | p p p p . Q p p 74 | . . n . . n . . 75 | . . . . p . . . 76 | . . B . P . . . 77 | . . . . . . . . 78 | P P P P . P P P 79 | R N B . K . N R 80 | ``` 81 | 82 | * Detects checkmates, stalemates and draws by insufficient material. 83 | 84 | ```cpp 85 | 86 | >>> std::cout << board.is_stalemate(); 87 | 0 88 | >>> std::cout << board.is_insufficient_material(); 89 | 0 90 | >>> std::cout << *board.outcome(); 91 | Outcome(termination=Termination::CHECKMATE, winner=true) 92 | ``` 93 | 94 | * Detects repetitions. Has a half-move clock. 95 | 96 | ```cpp 97 | 98 | >>> std::cout << board.can_claim_threefold_repetition(); 99 | 0 100 | >>> std::cout << board.halfmove_clock; 101 | 0 102 | >>> std::cout << board.can_claim_fifty_moves(); 103 | 0 104 | >>> std::cout << board.can_claim_draw(); 105 | 0 106 | ``` 107 | 108 | With the new rules from July 2014, a game ends as a draw (even without a 109 | claim) once a fivefold repetition occurs or if there are 75 moves without 110 | a pawn push or capture. Other ways of ending a game take precedence. 111 | 112 | ```cpp 113 | 114 | >>> std::cout << board.is_fivefold_repetition(); 115 | 0 116 | >>> std::cout << board.is_seventyfive_moves(); 117 | 0 118 | ``` 119 | 120 | * Detects checks and attacks. 121 | 122 | ```cpp 123 | 124 | >>> std::cout << board.is_check(); 125 | 1 126 | >>> std::cout << board.is_attacked_by(chess::WHITE, chess::E8); 127 | 1 128 | 129 | >>> chess::SquareSet attackers = board.attackers(chess::WHITE, chess::F3); 130 | >>> std::cout << attackers; 131 | SquareSet(0x0000'0000'0000'4040) 132 | >>> std::cout << (std::find(std::begin(attackers), std::end(attackers), chess::G2) != std::end(attackers)); 133 | 1 134 | >>> std::cout << std::string(attackers); 135 | . . . . . . . . 136 | . . . . . . . . 137 | . . . . . . . . 138 | . . . . . . . . 139 | . . . . . . . . 140 | . . . . . . . . 141 | . . . . . . 1 . 142 | . . . . . . 1 . 143 | ``` 144 | 145 | * Parses and creates SAN representation of moves. 146 | 147 | ```cpp 148 | 149 | >>> chess::Board board; 150 | >>> std::cout << board.san(chess::Move(chess::E2, chess::E4)); 151 | e4 152 | >>> std::cout << board.parse_san("Nf3"); 153 | Move::from_uci("g1f3") 154 | >>> std::cout << board.variation_san({chess::Move::from_uci("e2e4"), chess::Move::from_uci("e7e5"), chess::Move::from_uci("g1f3")}); 155 | 1. e4 e5 2. Nf3 156 | ``` 157 | 158 | * Parses and creates FENs, extended FENs and Shredder FENs. 159 | 160 | ```cpp 161 | 162 | >>> std::cout << board.fen(); 163 | rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 164 | >>> std::cout << board.shredder_fen(); 165 | rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1 166 | >>> chess::Board board = chess::Board("8/8/8/2k5/4K3/8/8/8 w - - 4 45"); 167 | >>> std::cout << board.piece_at(chess::C5); 168 | Piece::from_symbol('k') 169 | ``` 170 | 171 | * Parses and creates EPDs. 172 | 173 | ```cpp 174 | 175 | >>> chess::Board board; 176 | >>> std::cout << board.epd(false, "legal", std::nullopt, {{"bm", board.parse_uci("d2d4")}}); 177 | rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - bm d4; 178 | 179 | >>> auto ops = board.set_epd("1k1r4/pp1b1R2/3q2pp/4p3/2B5/4Q3/PPP2B2/2K5 b - - bm Qd1+; id \"BK.01\";"); 180 | >>> std::cout << (std::get>(ops.at("bm")) == std::vector({chess::Move::from_uci("d6d1")}) && std::get(ops.at("id")) == "BK.01"); 181 | 1 182 | ``` 183 | -------------------------------------------------------------------------------- /chess/chess.h: -------------------------------------------------------------------------------- 1 | /* 2 | This is a line-for-line remake of niklasf's 'python-chess' in C++ 3 | All credit for the original code and algorithms go to niklasf and his credits 4 | The original source code can be found here: https://github.com/niklasf/python-chess 5 | */ 6 | 7 | /* 8 | A chess library with move generation and validation, 9 | and XBoard/UCI engine communication. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace chess 32 | { 33 | 34 | std::string __author__ = "Patrick Johnson"; 35 | 36 | std::string __email__ = "pjpuzzler@gmail.com"; 37 | 38 | std::string __version__ = "1.0.0"; 39 | 40 | typedef std::string _EnPassantSpec; 41 | 42 | typedef bool Color; 43 | const Color COLORS[] = {true, false}, WHITE = true, BLACK = false; 44 | const std::string COLOR_NAMES[] = {"black", "white"}; 45 | 46 | typedef int PieceType; 47 | const PieceType PIECE_TYPES[] = {1, 2, 3, 4, 5, 6}, PAWN = 1, KNIGHT = 2, BISHOP = 3, ROOK = 4, QUEEN = 5, KING = 6; 48 | const std::optional PIECE_SYMBOLS[] = {std::nullopt, 'p', 'n', 'b', 'r', 'q', 'k'}; 49 | const std::optional PIECE_NAMES[] = {std::nullopt, "pawn", "knight", "bishop", "rook", "queen", "king"}; 50 | 51 | char piece_symbol(PieceType); 52 | 53 | std::string piece_name(PieceType); 54 | 55 | const std::unordered_map UNICODE_PIECE_SYMBOLS = { 56 | {'R', "♖"}, 57 | {'r', "♜"}, 58 | {'N', "♘"}, 59 | {'n', "♞"}, 60 | {'B', "♗"}, 61 | {'b', "♝"}, 62 | {'Q', "♕"}, 63 | {'q', "♛"}, 64 | {'K', "♔"}, 65 | {'k', "♚"}, 66 | {'P', "♙"}, 67 | {'p', "♟"}, 68 | }; 69 | 70 | const char FILE_NAMES[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; 71 | 72 | const char RANK_NAMES[] = {'1', '2', '3', '4', '5', '6', '7', '8'}; 73 | 74 | const std::string STARTING_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; 75 | /* The FEN for the standard chess starting position. */ 76 | 77 | const std::string STARTING_BOARD_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"; 78 | /* The board part of the FEN for the standard chess starting position. */ 79 | 80 | enum class Status 81 | { 82 | VALID = 0, 83 | NO_WHITE_KING = 1 << 0, 84 | NO_BLACK_KING = 1 << 1, 85 | TOO_MANY_KINGS = 1 << 2, 86 | TOO_MANY_WHITE_PAWNS = 1 << 3, 87 | TOO_MANY_BLACK_PAWNS = 1 << 4, 88 | PAWNS_ON_BACKRANK = 1 << 5, 89 | TOO_MANY_WHITE_PIECES = 1 << 6, 90 | TOO_MANY_BLACK_PIECES = 1 << 7, 91 | BAD_CASTLING_RIGHTS = 1 << 8, 92 | INVALID_EP_SQUARE = 1 << 9, 93 | OPPOSITE_CHECK = 1 << 10, 94 | EMPTY = 1 << 11, 95 | RACE_CHECK = 1 << 12, 96 | RACE_OVER = 1 << 13, 97 | RACE_MATERIAL = 1 << 14, 98 | TOO_MANY_CHECKERS = 1 << 15, 99 | IMPOSSIBLE_CHECK = 1 << 16 100 | }; 101 | 102 | const Status STATUS_VALID = Status::VALID; 103 | const Status STATUS_NO_WHITE_KING = Status::NO_WHITE_KING; 104 | const Status STATUS_NO_BLACK_KING = Status::NO_BLACK_KING; 105 | const Status STATUS_TOO_MANY_KINGS = Status::TOO_MANY_KINGS; 106 | const Status STATUS_TOO_MANY_WHITE_PAWNS = Status::TOO_MANY_WHITE_PAWNS; 107 | const Status STATUS_TOO_MANY_BLACK_PAWNS = Status::TOO_MANY_BLACK_PAWNS; 108 | const Status STATUS_PAWNS_ON_BACKRANK = Status::PAWNS_ON_BACKRANK; 109 | const Status STATUS_TOO_MANY_WHITE_PIECES = Status::TOO_MANY_WHITE_PIECES; 110 | const Status STATUS_TOO_MANY_BLACK_PIECES = Status::TOO_MANY_BLACK_PIECES; 111 | const Status STATUS_BAD_CASTLING_RIGHTS = Status::BAD_CASTLING_RIGHTS; 112 | const Status STATUS_INVALID_EP_SQUARE = Status::INVALID_EP_SQUARE; 113 | const Status STATUS_OPPOSITE_CHECK = Status::OPPOSITE_CHECK; 114 | const Status STATUS_EMPTY = Status::EMPTY; 115 | const Status STATUS_RACE_CHECK = Status::RACE_CHECK; 116 | const Status STATUS_RACE_OVER = Status::RACE_OVER; 117 | const Status STATUS_RACE_MATERIAL = Status::RACE_MATERIAL; 118 | const Status STATUS_TOO_MANY_CHECKERS = Status::TOO_MANY_CHECKERS; 119 | const Status STATUS_IMPOSSIBLE_CHECK = Status::IMPOSSIBLE_CHECK; 120 | 121 | enum class Termination 122 | { 123 | /* Enum with reasons for a game to be over. */ 124 | 125 | CHECKMATE, 126 | /* See :func:`chess::Board::is_checkmate()`. */ 127 | STALEMATE, 128 | /* See :func:`chess::Board::is_stalemate()`. */ 129 | INSUFFICIENT_MATERIAL, 130 | /* See :func:`chess::Board::is_insufficient_material()`. */ 131 | SEVENTYFIVE_MOVES, 132 | /* See :func:`chess::Board::is_seventyfive_moves()`. */ 133 | FIVEFOLD_REPETITION, 134 | /* See :func:`chess::Board::is_fivefold_repetition()`. */ 135 | FIFTY_MOVES, 136 | /* See :func:`chess::Board::can_claim_fifty_moves()`. */ 137 | THREEFOLD_REPETITION, 138 | /* See :func:`chess::Board::can_claim_threefold_repetition()`. */ 139 | VARIANT_WIN, 140 | /* See :func:`chess::Board::is_variant_win()`. */ 141 | VARIANT_LOSS, 142 | /* See :func:`chess::Board::is_variant_loss()`. */ 143 | VARIANT_DRAW 144 | /* See :func:`chess::Board::is_variant_draw()`. */ 145 | }; 146 | 147 | std::ostream &operator<<(std::ostream &, Termination); 148 | 149 | class Outcome 150 | { 151 | /* 152 | Information about the outcome of an ended game, usually obtained from 153 | :func:`chess::Board::outcome()`. 154 | */ 155 | 156 | public: 157 | Termination termination; 158 | /* The reason for the game to have ended. */ 159 | 160 | std::optional winner; 161 | /* The winning color or ``std::nullopt`` if drawn. */ 162 | 163 | Outcome(Termination, std::optional); 164 | 165 | std::string result() const; 166 | }; 167 | 168 | std::ostream &operator<<(std::ostream &, const Outcome &); 169 | 170 | typedef int Square; 171 | const Square SQUARES[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, A1 = 0, B1 = 1, C1 = 2, D1 = 3, E1 = 4, F1 = 5, G1 = 6, H1 = 7, A2 = 8, B2 = 9, C2 = 10, D2 = 11, E2 = 12, F2 = 13, G2 = 14, H2 = 15, A3 = 16, B3 = 17, C3 = 18, D3 = 19, E3 = 20, F3 = 21, G3 = 22, H3 = 23, A4 = 24, B4 = 25, C4 = 26, D4 = 27, E4 = 28, F4 = 29, G4 = 30, H4 = 31, A5 = 32, B5 = 33, C5 = 34, D5 = 35, E5 = 36, F5 = 37, G5 = 38, H5 = 39, A6 = 40, B6 = 41, C6 = 42, D6 = 43, E6 = 44, F6 = 45, G6 = 46, H6 = 47, A7 = 48, B7 = 49, C7 = 50, D7 = 51, E7 = 52, F7 = 53, G7 = 54, H7 = 55, A8 = 56, B8 = 57, C8 = 58, D8 = 59, E8 = 60, F8 = 61, G8 = 62, H8 = 63; 172 | 173 | const std::string SQUARE_NAMES[] = {"a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1", "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2", "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3", "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4", "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5", "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6", "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7", "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8"}; 174 | 175 | Square parse_square(const std::string &); 176 | 177 | std::string square_name(Square); 178 | 179 | Square square(int, int); 180 | 181 | int square_file(Square); 182 | 183 | int square_rank(Square); 184 | 185 | int square_distance(Square, Square); 186 | 187 | Square square_mirror(Square); 188 | 189 | const Square SQUARES_180[] = {square_mirror(0), square_mirror(1), square_mirror(2), square_mirror(3), square_mirror(4), square_mirror(5), square_mirror(6), square_mirror(7), square_mirror(8), square_mirror(9), square_mirror(10), square_mirror(11), square_mirror(12), square_mirror(13), square_mirror(14), square_mirror(15), square_mirror(16), square_mirror(17), square_mirror(18), square_mirror(19), square_mirror(20), square_mirror(21), square_mirror(22), square_mirror(23), square_mirror(24), square_mirror(25), square_mirror(26), square_mirror(27), square_mirror(28), square_mirror(29), square_mirror(30), square_mirror(31), square_mirror(32), square_mirror(33), square_mirror(34), square_mirror(35), square_mirror(36), square_mirror(37), square_mirror(38), square_mirror(39), square_mirror(40), square_mirror(41), square_mirror(42), square_mirror(43), square_mirror(44), square_mirror(45), square_mirror(46), square_mirror(47), square_mirror(48), square_mirror(49), square_mirror(50), square_mirror(51), square_mirror(52), square_mirror(53), square_mirror(54), square_mirror(55), square_mirror(56), square_mirror(57), square_mirror(58), square_mirror(59), square_mirror(60), square_mirror(61), square_mirror(62), square_mirror(63)}; 190 | 191 | typedef unsigned long Bitboard; 192 | const Bitboard BB_EMPTY = 0; 193 | const Bitboard BB_ALL = 0xffff'ffff'ffff'ffff; 194 | 195 | const Bitboard BB_SQUARES[] = { 196 | 1UL << 0, 197 | 1UL << 1, 198 | 1UL << 2, 199 | 1UL << 3, 200 | 1UL << 4, 201 | 1UL << 5, 202 | 1UL << 6, 203 | 1UL << 7, 204 | 1UL << 8, 205 | 1UL << 9, 206 | 1UL << 10, 207 | 1UL << 11, 208 | 1UL << 12, 209 | 1UL << 13, 210 | 1UL << 14, 211 | 1UL << 15, 212 | 1UL << 16, 213 | 1UL << 17, 214 | 1UL << 18, 215 | 1UL << 19, 216 | 1UL << 20, 217 | 1UL << 21, 218 | 1UL << 22, 219 | 1UL << 23, 220 | 1UL << 24, 221 | 1UL << 25, 222 | 1UL << 26, 223 | 1UL << 27, 224 | 1UL << 28, 225 | 1UL << 29, 226 | 1UL << 30, 227 | 1UL << 31, 228 | 1UL << 32, 229 | 1UL << 33, 230 | 1UL << 34, 231 | 1UL << 35, 232 | 1UL << 36, 233 | 1UL << 37, 234 | 1UL << 38, 235 | 1UL << 39, 236 | 1UL << 40, 237 | 1UL << 41, 238 | 1UL << 42, 239 | 1UL << 43, 240 | 1UL << 44, 241 | 1UL << 45, 242 | 1UL << 46, 243 | 1UL << 47, 244 | 1UL << 48, 245 | 1UL << 49, 246 | 1UL << 50, 247 | 1UL << 51, 248 | 1UL << 52, 249 | 1UL << 53, 250 | 1UL << 54, 251 | 1UL << 55, 252 | 1UL << 56, 253 | 1UL << 57, 254 | 1UL << 58, 255 | 1UL << 59, 256 | 1UL << 60, 257 | 1UL << 61, 258 | 1UL << 62, 259 | 1UL << 63, 260 | }, 261 | BB_A1 = 1UL << 0, BB_B1 = 1UL << 1, BB_C1 = 1UL << 2, BB_D1 = 1UL << 3, BB_E1 = 1UL << 4, BB_F1 = 1UL << 5, BB_G1 = 1UL << 6, BB_H1 = 1UL << 7, BB_A2 = 1UL << 8, BB_B2 = 1UL << 9, BB_C2 = 1UL << 10, BB_D2 = 1UL << 11, BB_E2 = 1UL << 12, BB_F2 = 1UL << 13, BB_G2 = 1UL << 14, BB_H2 = 1UL << 15, BB_A3 = 1UL << 16, BB_B3 = 1UL << 17, BB_C3 = 1UL << 18, BB_D3 = 1UL << 19, BB_E3 = 1UL << 20, BB_F3 = 1UL << 21, BB_G3 = 1UL << 22, BB_H3 = 1UL << 23, BB_A4 = 1UL << 24, BB_B4 = 1UL << 25, BB_C4 = 1UL << 26, BB_D4 = 1UL << 27, BB_E4 = 1UL << 28, BB_F4 = 1UL << 29, BB_G4 = 1UL << 30, BB_H4 = 1UL << 31, BB_A5 = 1UL << 32, BB_B5 = 1UL << 33, BB_C5 = 1UL << 34, BB_D5 = 1UL << 35, BB_E5 = 1UL << 36, BB_F5 = 1UL << 37, BB_G5 = 1UL << 38, BB_H5 = 1UL << 39, BB_A6 = 1UL << 40, BB_B6 = 1UL << 41, BB_C6 = 1UL << 42, BB_D6 = 1UL << 43, BB_E6 = 1UL << 44, BB_F6 = 1UL << 45, BB_G6 = 1UL << 46, BB_H6 = 1UL << 47, BB_A7 = 1UL << 48, BB_B7 = 1UL << 49, BB_C7 = 1UL << 50, BB_D7 = 1UL << 51, BB_E7 = 1UL << 52, BB_F7 = 1UL << 53, BB_G7 = 1UL << 54, BB_H7 = 1UL << 55, BB_A8 = 1UL << 56, BB_B8 = 1UL << 57, BB_C8 = 1UL << 58, BB_D8 = 1UL << 59, BB_E8 = 1UL << 60, BB_F8 = 1UL << 61, BB_G8 = 1UL << 62, BB_H8 = 1UL << 63; 262 | 263 | const Bitboard BB_CORNERS = BB_A1 | BB_H1 | BB_A8 | BB_H8; 264 | const Bitboard BB_CENTER = BB_D4 | BB_E4 | BB_D5 | BB_E5; 265 | 266 | const Bitboard BB_LIGHT_SQUARES = 0x55aa'55aa'55aa'55aa; 267 | const Bitboard BB_DARK_SQUARES = 0xaa55'aa55'aa55'aa55; 268 | 269 | const Bitboard BB_FILES[] = { 270 | 0x0101'0101'0101'0101UL << 0, 271 | 0x0101'0101'0101'0101UL << 1, 272 | 0x0101'0101'0101'0101UL << 2, 273 | 0x0101'0101'0101'0101UL << 3, 274 | 0x0101'0101'0101'0101UL << 4, 275 | 0x0101'0101'0101'0101UL << 5, 276 | 0x0101'0101'0101'0101UL << 6, 277 | 0x0101'0101'0101'0101UL << 7, 278 | }, 279 | BB_FILE_A = 0x0101'0101'0101'0101UL << 0, BB_FILE_B = 0x0101'0101'0101'0101UL << 1, BB_FILE_C = 0x0101'0101'0101'0101UL << 2, BB_FILE_D = 0x0101'0101'0101'0101UL << 3, BB_FILE_E = 0x0101'0101'0101'0101UL << 4, BB_FILE_F = 0x0101'0101'0101'0101UL << 5, BB_FILE_G = 0x0101'0101'0101'0101UL << 6, BB_FILE_H = 0x0101'0101'0101'0101UL << 7; 280 | 281 | const Bitboard BB_RANKS[] = { 282 | 0xffUL << (8 * 0), 283 | 0xffUL << (8 * 1), 284 | 0xffUL << (8 * 2), 285 | 0xffUL << (8 * 3), 286 | 0xffUL << (8 * 4), 287 | 0xffUL << (8 * 5), 288 | 0xffUL << (8 * 6), 289 | 0xffUL << (8 * 7), 290 | }, 291 | BB_RANK_1 = 0xffUL << (8 * 0), BB_RANK_2 = 0xffUL << (8 * 1), BB_RANK_3 = 0xffUL << (8 * 2), BB_RANK_4 = 0xffUL << (8 * 3), BB_RANK_5 = 0xffUL << (8 * 4), BB_RANK_6 = 0xffUL << (8 * 5), BB_RANK_7 = 0xffUL << (8 * 6), BB_RANK_8 = 0xffUL << (8 * 7); 292 | 293 | const Bitboard BB_BACKRANKS = BB_RANK_1 | BB_RANK_8; 294 | 295 | int lsb(Bitboard); 296 | 297 | std::vector scan_forward(Bitboard); 298 | 299 | int msb(Bitboard); 300 | 301 | std::vector scan_reversed(Bitboard); 302 | 303 | std::function popcount = [](Bitboard bb) -> int 304 | { return std::bitset<64>(bb).count(); }; 305 | 306 | Bitboard flip_vertical(Bitboard); 307 | 308 | Bitboard flip_horizontal(Bitboard); 309 | 310 | Bitboard flip_diagonal(Bitboard); 311 | 312 | Bitboard flip_anti_diagonal(Bitboard); 313 | 314 | Bitboard shift_down(Bitboard); 315 | 316 | Bitboard shift_2_down(Bitboard); 317 | 318 | Bitboard shift_up(Bitboard); 319 | 320 | Bitboard shift_2_up(Bitboard); 321 | 322 | Bitboard shift_right(Bitboard); 323 | 324 | Bitboard shift_2_right(Bitboard); 325 | 326 | Bitboard shift_left(Bitboard); 327 | 328 | Bitboard shift_2_left(Bitboard); 329 | 330 | Bitboard shift_up_left(Bitboard); 331 | 332 | Bitboard shift_up_right(Bitboard); 333 | 334 | Bitboard shift_down_left(Bitboard); 335 | 336 | Bitboard shift_down_right(Bitboard); 337 | 338 | Bitboard _sliding_attacks(Square, Bitboard, const std::vector &); 339 | 340 | Bitboard _step_attacks(Square, const std::vector &); 341 | 342 | const Bitboard BB_KNIGHT_ATTACKS[] = {_step_attacks(0, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(1, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(2, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(3, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(4, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(5, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(6, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(7, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(8, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(9, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(10, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(11, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(12, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(13, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(14, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(15, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(16, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(17, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(18, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(19, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(20, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(21, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(22, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(23, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(24, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(25, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(26, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(27, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(28, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(29, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(30, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(31, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(32, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(33, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(34, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(35, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(36, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(37, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(38, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(39, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(40, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(41, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(42, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(43, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(44, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(45, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(46, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(47, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(48, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(49, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(50, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(51, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(52, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(53, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(54, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(55, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(56, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(57, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(58, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(59, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(60, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(61, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(62, {17, 15, 10, 6, -17, -15, -10, -6}), _step_attacks(63, {17, 15, 10, 6, -17, -15, -10, -6})}; 343 | const Bitboard BB_KING_ATTACKS[] = {_step_attacks(0, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(1, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(2, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(3, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(4, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(5, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(6, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(7, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(8, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(9, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(10, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(11, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(12, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(13, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(14, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(15, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(16, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(17, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(18, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(19, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(20, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(21, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(22, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(23, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(24, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(25, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(26, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(27, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(28, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(29, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(30, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(31, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(32, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(33, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(34, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(35, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(36, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(37, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(38, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(39, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(40, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(41, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(42, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(43, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(44, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(45, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(46, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(47, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(48, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(49, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(50, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(51, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(52, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(53, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(54, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(55, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(56, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(57, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(58, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(59, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(60, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(61, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(62, {9, 8, 7, 1, -9, -8, -7, -1}), _step_attacks(63, {9, 8, 7, 1, -9, -8, -7, -1})}; 344 | const Bitboard BB_PAWN_ATTACKS[][64] = {{_step_attacks(0, {-7, -9}), _step_attacks(1, {-7, -9}), _step_attacks(2, {-7, -9}), _step_attacks(3, {-7, -9}), _step_attacks(4, {-7, -9}), _step_attacks(5, {-7, -9}), _step_attacks(6, {-7, -9}), _step_attacks(7, {-7, -9}), _step_attacks(8, {-7, -9}), _step_attacks(9, {-7, -9}), _step_attacks(10, {-7, -9}), _step_attacks(11, {-7, -9}), _step_attacks(12, {-7, -9}), _step_attacks(13, {-7, -9}), _step_attacks(14, {-7, -9}), _step_attacks(15, {-7, -9}), _step_attacks(16, {-7, -9}), _step_attacks(17, {-7, -9}), _step_attacks(18, {-7, -9}), _step_attacks(19, {-7, -9}), _step_attacks(20, {-7, -9}), _step_attacks(21, {-7, -9}), _step_attacks(22, {-7, -9}), _step_attacks(23, {-7, -9}), _step_attacks(24, {-7, -9}), _step_attacks(25, {-7, -9}), _step_attacks(26, {-7, -9}), _step_attacks(27, {-7, -9}), _step_attacks(28, {-7, -9}), _step_attacks(29, {-7, -9}), _step_attacks(30, {-7, -9}), _step_attacks(31, {-7, -9}), _step_attacks(32, {-7, -9}), _step_attacks(33, {-7, -9}), _step_attacks(34, {-7, -9}), _step_attacks(35, {-7, -9}), _step_attacks(36, {-7, -9}), _step_attacks(37, {-7, -9}), _step_attacks(38, {-7, -9}), _step_attacks(39, {-7, -9}), _step_attacks(40, {-7, -9}), _step_attacks(41, {-7, -9}), _step_attacks(42, {-7, -9}), _step_attacks(43, {-7, -9}), _step_attacks(44, {-7, -9}), _step_attacks(45, {-7, -9}), _step_attacks(46, {-7, -9}), _step_attacks(47, {-7, -9}), _step_attacks(48, {-7, -9}), _step_attacks(49, {-7, -9}), _step_attacks(50, {-7, -9}), _step_attacks(51, {-7, -9}), _step_attacks(52, {-7, -9}), _step_attacks(53, {-7, -9}), _step_attacks(54, {-7, -9}), _step_attacks(55, {-7, -9}), _step_attacks(56, {-7, -9}), _step_attacks(57, {-7, -9}), _step_attacks(58, {-7, -9}), _step_attacks(59, {-7, -9}), _step_attacks(60, {-7, -9}), _step_attacks(61, {-7, -9}), _step_attacks(62, {-7, -9}), _step_attacks(63, {-7, -9})}, {_step_attacks(0, {7, 9}), _step_attacks(1, {7, 9}), _step_attacks(2, {7, 9}), _step_attacks(3, {7, 9}), _step_attacks(4, {7, 9}), _step_attacks(5, {7, 9}), _step_attacks(6, {7, 9}), _step_attacks(7, {7, 9}), _step_attacks(8, {7, 9}), _step_attacks(9, {7, 9}), _step_attacks(10, {7, 9}), _step_attacks(11, {7, 9}), _step_attacks(12, {7, 9}), _step_attacks(13, {7, 9}), _step_attacks(14, {7, 9}), _step_attacks(15, {7, 9}), _step_attacks(16, {7, 9}), _step_attacks(17, {7, 9}), _step_attacks(18, {7, 9}), _step_attacks(19, {7, 9}), _step_attacks(20, {7, 9}), _step_attacks(21, {7, 9}), _step_attacks(22, {7, 9}), _step_attacks(23, {7, 9}), _step_attacks(24, {7, 9}), _step_attacks(25, {7, 9}), _step_attacks(26, {7, 9}), _step_attacks(27, {7, 9}), _step_attacks(28, {7, 9}), _step_attacks(29, {7, 9}), _step_attacks(30, {7, 9}), _step_attacks(31, {7, 9}), _step_attacks(32, {7, 9}), _step_attacks(33, {7, 9}), _step_attacks(34, {7, 9}), _step_attacks(35, {7, 9}), _step_attacks(36, {7, 9}), _step_attacks(37, {7, 9}), _step_attacks(38, {7, 9}), _step_attacks(39, {7, 9}), _step_attacks(40, {7, 9}), _step_attacks(41, {7, 9}), _step_attacks(42, {7, 9}), _step_attacks(43, {7, 9}), _step_attacks(44, {7, 9}), _step_attacks(45, {7, 9}), _step_attacks(46, {7, 9}), _step_attacks(47, {7, 9}), _step_attacks(48, {7, 9}), _step_attacks(49, {7, 9}), _step_attacks(50, {7, 9}), _step_attacks(51, {7, 9}), _step_attacks(52, {7, 9}), _step_attacks(53, {7, 9}), _step_attacks(54, {7, 9}), _step_attacks(55, {7, 9}), _step_attacks(56, {7, 9}), _step_attacks(57, {7, 9}), _step_attacks(58, {7, 9}), _step_attacks(59, {7, 9}), _step_attacks(60, {7, 9}), _step_attacks(61, {7, 9}), _step_attacks(62, {7, 9}), _step_attacks(63, {7, 9})}}; 345 | 346 | Bitboard _edges(Square); 347 | 348 | std::vector _carry_rippler(Bitboard); 349 | 350 | std::tuple, std::vector>> _attack_table(const std::vector &); 351 | 352 | const auto [BB_DIAG_MASKS, BB_DIAG_ATTACKS] = _attack_table({-9, -7, 7, 9}); 353 | const auto [BB_FILE_MASKS, BB_FILE_ATTACKS] = _attack_table({-8, 8}); 354 | const auto [BB_RANK_MASKS, BB_RANK_ATTACKS] = _attack_table({-1, 1}); 355 | 356 | std::vector> _rays(); 357 | 358 | const std::vector> BB_RAYS = _rays(); 359 | 360 | Bitboard ray(Square, Square); 361 | 362 | Bitboard between(Square, Square); 363 | 364 | const std::regex SAN_REGEX(R"(^([NBKRQ])?([a-h])?([1-8])?[\-x]?([a-h][1-8])(=?[nbrqkNBRQK])?[\+#]?$)"); 365 | 366 | const std::regex FEN_CASTLING_REGEX(R"(^(?:-|[KQABCDEFGH]{0,2}[kqabcdefgh]{0,2})$)"); 367 | 368 | class Piece 369 | { 370 | /* A piece with type and color. */ 371 | 372 | public: 373 | PieceType piece_type; 374 | /* The piece type. */ 375 | 376 | Color color; 377 | /* The piece color. */ 378 | 379 | Piece(PieceType, Color); 380 | 381 | Piece(); 382 | 383 | char symbol() const; 384 | 385 | std::string unicode_symbol(bool = false) const; 386 | 387 | operator std::string() const; 388 | 389 | static Piece from_symbol(char); 390 | }; 391 | 392 | std::ostream &operator<<(std::ostream &, const Piece &); 393 | 394 | class Move 395 | { 396 | /* 397 | Represents a move from a square to a square and possibly the promotion 398 | piece type. 399 | 400 | Drops and null moves are supported. 401 | */ 402 | 403 | public: 404 | Square from_square; 405 | /* The source square. */ 406 | 407 | Square to_square; 408 | /* The target square. */ 409 | 410 | std::optional promotion; 411 | /* The promotion piece type or ``std::nullopt``. */ 412 | 413 | std::optional drop; 414 | /* The drop piece type or ``std::nullopt``. */ 415 | 416 | Move(Square, Square, std::optional = std::nullopt, std::optional = std::nullopt); 417 | 418 | std::string uci() const; 419 | 420 | std::string xboard() const; 421 | 422 | operator bool() const; 423 | 424 | operator std::string() const; 425 | 426 | static Move from_uci(const std::string &); 427 | 428 | static Move null(); 429 | }; 430 | 431 | std::ostream &operator<<(std::ostream &, const Move &); 432 | 433 | class SquareSet; 434 | 435 | class BaseBoard 436 | { 437 | /* 438 | A board representing the position of chess pieces. See 439 | :class:`~chess::Board` for a full board with move generation. 440 | 441 | The board is initialized with the standard chess starting position, unless 442 | otherwise specified in the optional *board_fen* argument. If *board_fen* 443 | is ``std::nullopt``, an empty board is created. 444 | */ 445 | 446 | public: 447 | Bitboard occupied_co[2], pawns, knights, bishops, rooks, queens, kings, promoted, occupied; 448 | BaseBoard(const std::optional & = STARTING_BOARD_FEN); 449 | 450 | void reset_board(); 451 | 452 | void clear_board(); 453 | 454 | Bitboard pieces_mask(PieceType, Color) const; 455 | 456 | SquareSet pieces(PieceType, Color) const; 457 | 458 | std::optional piece_at(Square) const; 459 | 460 | std::optional piece_type_at(Square) const; 461 | 462 | std::optional color_at(Square) const; 463 | 464 | std::optional king(Color) const; 465 | 466 | Bitboard attacks_mask(Square) const; 467 | 468 | SquareSet attacks(Square) const; 469 | 470 | Bitboard attackers_mask(Color, Square) const; 471 | 472 | bool is_attacked_by(Color, Square) const; 473 | 474 | SquareSet attackers(Color, Square) const; 475 | 476 | Bitboard pin_mask(Color, Square) const; 477 | 478 | SquareSet pin(Color, Square) const; 479 | 480 | bool is_pinned(Color, Square) const; 481 | 482 | std::optional remove_piece_at(Square); 483 | 484 | void set_piece_at(Square, const std::optional &, bool = false); 485 | 486 | std::string board_fen(std::optional = false) const; 487 | 488 | void set_board_fen(const std::string &); 489 | 490 | std::unordered_map piece_map(Bitboard = BB_ALL) const; 491 | 492 | void set_piece_map(const std::unordered_map &); 493 | 494 | void set_chess960_pos(int); 495 | 496 | std::optional chess960_pos() const; 497 | 498 | operator std::string() const; 499 | 500 | std::string unicode(bool = false, bool = false, const std::string & = "⭘") const; 501 | 502 | bool operator==(const BaseBoard &) const; 503 | 504 | void apply_transform(const std::function &); 505 | 506 | BaseBoard transform(const std::function &) const; 507 | 508 | void apply_mirror(); 509 | 510 | BaseBoard mirror() const; 511 | 512 | BaseBoard copy() const; 513 | 514 | static BaseBoard empty(); 515 | 516 | static BaseBoard from_chess960_pos(int); 517 | 518 | protected: 519 | void _reset_board(); 520 | 521 | void _clear_board(); 522 | 523 | Bitboard _attackers_mask(Color, Square, Bitboard) const; 524 | 525 | std::optional _remove_piece_at(Square); 526 | 527 | void _set_piece_at(Square, PieceType, Color, bool = false); 528 | 529 | void _set_board_fen(std::string); 530 | 531 | void _set_piece_map(const std::unordered_map &); 532 | 533 | void _set_chess960_pos(int); 534 | }; 535 | 536 | std::ostream &operator<<(std::ostream &, const BaseBoard &); 537 | 538 | class Board; 539 | 540 | class _BoardState 541 | { 542 | 543 | public: 544 | Bitboard pawns, knights, bishops, rooks, queens, kings, occupied_w, occupied_b, occupied, promoted; 545 | Color turn; 546 | Bitboard castling_rights; 547 | std::optional ep_square; 548 | int halfmove_clock, fullmove_number; 549 | _BoardState(const Board &); 550 | 551 | void restore(Board &) const; 552 | }; 553 | 554 | class LegalMoveGenerator; 555 | class PseudoLegalMoveGenerator; 556 | 557 | class Board : public BaseBoard 558 | { 559 | /* 560 | A :class:`~chess::BaseBoard`, additional information representing 561 | a chess position, and a :data:`move stack `. 562 | 563 | Provides :func:`move generation `, validation, 564 | :func:`parsing `, attack generation, 565 | :func:`game end detection `, 566 | and the capability to :func:`make ` and 567 | :func:`unmake ` moves. 568 | 569 | The board is initialized to the standard chess starting position, 570 | unless otherwise specified in the optional *fen* argument. 571 | If *fen* is ``std::nullopt``, an empty board is created. 572 | 573 | Optionally supports *chess960*. In Chess960, castling moves are encoded 574 | by a king move to the corresponding rook square. 575 | Use :func:`chess::Board::from_chess960_pos()` to create a board with one 576 | of the Chess960 starting positions. 577 | 578 | It's safe to set :data:`~Board::turn`, :data:`~Board::castling_rights`, 579 | :data:`~Board::ep_square`, :data:`~Board::halfmove_clock` and 580 | :data:`~Board::fullmove_number` directly. 581 | 582 | .. warning:: 583 | It is possible to set up and work with invalid positions. In this 584 | case, :class:`~chess::Board` implements a kind of "pseudo-chess" 585 | (useful to gracefully handle errors or to implement chess variants). 586 | Use :func:`~chess::Board::is_valid()` to detect invalid positions. 587 | */ 588 | 589 | public: 590 | static std::string aliases[]; 591 | static std::optional uci_variant; 592 | static std::optional xboard_variant; 593 | static std::string starting_fen; 594 | 595 | static std::optional tbw_suffix; 596 | static std::optional tbz_suffix; 597 | static std::optional> tbw_magic; 598 | static std::optional> tbz_magic; 599 | static std::optional pawnless_tbw_suffix; 600 | static std::optional pawnless_tbz_suffix; 601 | static std::optional> pawnless_tbw_magic; 602 | static std::optional> pawnless_tbz_magic; 603 | static bool connected_kings; 604 | static bool one_king; 605 | static bool captures_compulsory; 606 | 607 | Color turn; 608 | /* The side to move (``chess::WHITE`` or ``chess::BLACK``). */ 609 | 610 | Bitboard castling_rights; 611 | /* 612 | Bitmask of the rooks with castling rights. 613 | 614 | To test for specific squares: 615 | 616 | >>> #include "chess.cpp" 617 | >>> #include 618 | >>> 619 | >>> chess::Board board; 620 | >>> std::cout << bool(board.castling_rights & chess::BB_H1); // White can castle with the h1 rook 621 | 1 622 | 623 | To add a specific square: 624 | 625 | >>> board.castling_rights |= chess::BB_A1; 626 | 627 | Use :func:`~chess::Board::set_castling_fen()` to set multiple castling 628 | rights. Also see :func:`~chess::Board::has_castling_rights()`, 629 | :func:`~chess::Board::has_kingside_castling_rights()`, 630 | :func:`~chess::Board::has_queenside_castling_rights()`, 631 | :func:`~chess::Board::has_chess960_castling_rights()`, 632 | :func:`~chess::Board::clean_castling_rights()`. 633 | */ 634 | 635 | std::optional ep_square; 636 | /* 637 | The potential en passant square on the third or sixth rank or ``std::nullopt``. 638 | 639 | Use :func:`~chess::Board::has_legal_en_passant()` to test if en passant 640 | capturing would actually be possible on the next move. 641 | */ 642 | 643 | int fullmove_number; 644 | /* 645 | Counts move pairs. Starts at `1` and is incremented after every move 646 | of the black side. 647 | */ 648 | 649 | int halfmove_clock; 650 | /* The number of half-moves since the last capture or pawn move. */ 651 | 652 | bool chess960; 653 | /* 654 | Whether the board is in Chess960 mode. In Chess960 castling moves are 655 | represented as king moves to the corresponding rook square. 656 | */ 657 | 658 | std::vector move_stack; 659 | /* 660 | The move stack. Use :func:`Board::push() `, 661 | :func:`Board::pop() `, 662 | :func:`Board::peek() ` and 663 | :func:`Board::clear_stack() ` for 664 | manipulation. 665 | */ 666 | 667 | Board(const std::optional & = STARTING_FEN, bool = false); 668 | 669 | LegalMoveGenerator legal_moves() const; 670 | 671 | PseudoLegalMoveGenerator pseudo_legal_moves() const; 672 | 673 | void reset(); 674 | 675 | void reset_board(); 676 | 677 | void clear(); 678 | 679 | void clear_board(); 680 | 681 | void clear_stack(); 682 | 683 | Board root() const; 684 | 685 | int ply() const; 686 | 687 | std::optional remove_piece_at(Square); 688 | 689 | void set_piece_at(Square, const std::optional &, bool = false); 690 | 691 | std::vector generate_pseudo_legal_moves(Bitboard = BB_ALL, Bitboard = BB_ALL) const; 692 | 693 | std::vector generate_pseudo_legal_ep(Bitboard = BB_ALL, Bitboard = BB_ALL) const; 694 | 695 | std::vector generate_pseudo_legal_captures(Bitboard = BB_ALL, Bitboard = BB_ALL) const; 696 | 697 | Bitboard checkers_mask() const; 698 | 699 | SquareSet checkers() const; 700 | 701 | bool is_check() const; 702 | 703 | bool gives_check(const Move &); 704 | 705 | bool is_into_check(const Move &) const; 706 | 707 | bool was_into_check() const; 708 | 709 | bool is_pseudo_legal(Move) const; 710 | 711 | bool is_legal(const Move &) const; 712 | 713 | bool is_variant_end() const; 714 | 715 | bool is_variant_loss() const; 716 | 717 | bool is_variant_win() const; 718 | 719 | bool is_variant_draw() const; 720 | 721 | bool is_game_over(bool = false); 722 | 723 | std::string result(bool = false); 724 | 725 | std::optional outcome(bool = false); 726 | 727 | bool is_checkmate() const; 728 | 729 | bool is_stalemate() const; 730 | 731 | bool is_insufficient_material() const; 732 | 733 | bool has_insufficient_material(Color) const; 734 | 735 | bool is_seventyfive_moves() const; 736 | 737 | bool is_fivefold_repetition(); 738 | 739 | bool can_claim_draw(); 740 | 741 | bool is_fifty_moves() const; 742 | 743 | bool can_claim_fifty_moves(); 744 | 745 | bool can_claim_threefold_repetition(); 746 | 747 | bool is_repetition(int = 3); 748 | 749 | void push(Move); 750 | 751 | Move pop(); 752 | 753 | Move peek() const; 754 | 755 | Move find_move(Square, Square, std::optional = std::nullopt); 756 | 757 | std::string castling_shredder_fen() const; 758 | 759 | std::string castling_xfen() const; 760 | 761 | bool has_pseudo_legal_en_passant() const; 762 | 763 | bool has_legal_en_passant() const; 764 | 765 | std::string fen(bool = false, _EnPassantSpec = "legal", std::optional = std::nullopt); 766 | 767 | std::string shredder_fen(_EnPassantSpec = "legal", std::optional = std::nullopt); 768 | 769 | void set_fen(const std::string &); 770 | 771 | void set_castling_fen(const std::string &); 772 | 773 | void set_board_fen(const std::string &); 774 | 775 | void set_piece_map(const std::unordered_map &); 776 | 777 | void set_chess960_pos(int); 778 | 779 | std::optional chess960_pos(bool = false, bool = false, bool = true) const; 780 | 781 | std::string epd(bool = false, const _EnPassantSpec & = "legal", std::optional = std::nullopt, const std::unordered_map>> & = {}); 782 | 783 | std::unordered_map>> set_epd(const std::string &); 784 | 785 | std::string san(const Move &); 786 | 787 | std::string lan(const Move &); 788 | 789 | std::string san_and_push(const Move &); 790 | 791 | std::string variation_san(const std::vector &) const; 792 | 793 | Move parse_san(const std::string &); 794 | 795 | Move push_san(const std::string &); 796 | 797 | std::string uci(Move, std::optional = std::nullopt) const; 798 | 799 | Move parse_uci(const std::string &); 800 | 801 | Move push_uci(const std::string &); 802 | 803 | std::string xboard(const Move &, std::optional = std::nullopt) const; 804 | 805 | Move parse_xboard(const std::string &); 806 | 807 | Move push_xboard(const std::string &); 808 | 809 | bool is_en_passant(const Move &) const; 810 | 811 | bool is_capture(const Move &) const; 812 | 813 | bool is_zeroing(const Move &) const; 814 | 815 | bool is_irreversible(const Move &) const; 816 | 817 | bool is_castling(const Move &) const; 818 | 819 | bool is_kingside_castling(const Move &) const; 820 | 821 | bool is_queenside_castling(const Move &) const; 822 | 823 | Bitboard clean_castling_rights() const; 824 | 825 | bool has_castling_rights(Color) const; 826 | 827 | bool has_kingside_castling_rights(Color) const; 828 | 829 | bool has_queenside_castling_rights(Color) const; 830 | 831 | bool has_chess960_castling_rights(); 832 | 833 | Status status() const; 834 | 835 | bool is_valid() const; 836 | 837 | std::vector generate_legal_moves(Bitboard = BB_ALL, Bitboard = BB_ALL) const; 838 | 839 | std::vector generate_legal_ep(Bitboard = BB_ALL, Bitboard = BB_ALL) const; 840 | 841 | std::vector generate_legal_captures(Bitboard = BB_ALL, Bitboard = BB_ALL) const; 842 | 843 | std::vector generate_castling_moves(Bitboard = BB_ALL, Bitboard = BB_ALL) const; 844 | 845 | bool operator==(const Board &) const; 846 | 847 | void apply_transform(const std::function &); 848 | 849 | Board transform(const std::function &) const; 850 | 851 | void apply_mirror(); 852 | 853 | Board mirror() const; 854 | 855 | Board copy(std::variant = true) const; 856 | 857 | static Board empty(bool = false); 858 | 859 | static std::tuple>>> from_epd(const std::string &, bool = false); 860 | 861 | static Board from_chess960_pos(int); 862 | 863 | private: 864 | std::vector<_BoardState> _stack; 865 | 866 | bool _is_halfmoves(int) const; 867 | 868 | _BoardState _board_state() const; 869 | 870 | void _push_capture(const Move &, Square, PieceType, bool) const; 871 | 872 | void _set_castling_fen(const std::string &); 873 | 874 | std::string _epd_operations(const std::unordered_map>> &); 875 | 876 | std::unordered_map>> _parse_epd_ops(const std::string &, const std::function &) const; 877 | 878 | std::string _algebraic(const Move &, bool = false); 879 | 880 | std::string _algebraic_and_push(const Move &, bool = false); 881 | 882 | std::string _algebraic_without_suffix(const Move &, bool = false); 883 | 884 | bool _reduces_castling_rights(const Move &) const; 885 | 886 | std::optional _valid_ep_square() const; 887 | 888 | bool _ep_skewered(Square, Square) const; 889 | 890 | Bitboard _slider_blockers(Square) const; 891 | 892 | bool _is_safe(Square, Bitboard, const Move &) const; 893 | 894 | std::vector _generate_evasions(Square, Bitboard, Bitboard = BB_ALL, Bitboard = BB_ALL) const; 895 | 896 | bool _attacked_for_king(Bitboard, Bitboard) const; 897 | 898 | Move _from_chess960(bool, Square, Square, std::optional = std::nullopt, std::optional = std::nullopt) const; 899 | 900 | Move _to_chess960(const Move &) const; 901 | 902 | std::tuple _transposition_key() const; 903 | }; 904 | 905 | std::ostream &operator<<(std::ostream &, Board); 906 | 907 | class PseudoLegalMoveGenerator 908 | { 909 | 910 | public: 911 | PseudoLegalMoveGenerator(const Board &); 912 | 913 | operator bool() const; 914 | 915 | int count() const; 916 | 917 | auto begin() const; 918 | 919 | auto end() const; 920 | 921 | Board get_board() const; 922 | 923 | operator std::vector() const; 924 | 925 | private: 926 | Board _board; 927 | std::vector _iter; 928 | }; 929 | 930 | std::ostream &operator<<(std::ostream &, PseudoLegalMoveGenerator); 931 | 932 | class LegalMoveGenerator 933 | { 934 | 935 | public: 936 | LegalMoveGenerator(const Board &); 937 | 938 | operator bool() const; 939 | 940 | int count() const; 941 | 942 | auto begin() const; 943 | 944 | auto end() const; 945 | 946 | Board get_board() const; 947 | 948 | operator std::vector() const; 949 | 950 | private: 951 | Board _board; 952 | std::vector _iter; 953 | }; 954 | 955 | std::ostream &operator<<(std::ostream &, LegalMoveGenerator); 956 | 957 | typedef std::variant> IntoSquareSet; 958 | 959 | class SquareSet 960 | { 961 | /* 962 | A set of squares. 963 | 964 | Square sets are internally represented by 64-bit integer masks of the 965 | included squares. Bitwise operations can be used to compute unions, 966 | intersections and shifts. 967 | 968 | >>> #include "chess.cpp" 969 | >>> #include 970 | >>> 971 | >>> chess::SquareSet squares = chess::SquareSet({chess::A8, chess::A1}); 972 | >>> std::cout << squares; 973 | SquareSet(0x0100_0000_0000_0001) 974 | 975 | >>> squares = chess::SquareSet(chess::BB_A8 | chess::BB_RANK_1); 976 | >>> std::cout << squares; 977 | SquareSet(0x0100_0000_0000_00ff) 978 | 979 | >>> std::cout << std::string(squares); 980 | 1 . . . . . . . 981 | . . . . . . . . 982 | . . . . . . . . 983 | . . . . . . . . 984 | . . . . . . . . 985 | . . . . . . . . 986 | . . . . . . . . 987 | 1 1 1 1 1 1 1 1 988 | 989 | >>> std::cout << std::size(squares); 990 | 9 991 | 992 | >>> std::cout << bool(squares); 993 | 1 994 | 995 | >>> std::cout << (std::find(std::begin(squares), std::end(squares), chess::B1) != std::end(squares)); 996 | 1 997 | 998 | >>> for (chess::Square square : squares) { 999 | ... // 0 -- chess::A1 1000 | ... // 1 -- chess::B1 1001 | ... // 2 -- chess::C1 1002 | ... // 3 -- chess::D1 1003 | ... // 4 -- chess::E1 1004 | ... // 5 -- chess::F1 1005 | ... // 6 -- chess::G1 1006 | ... // 7 -- chess::H1 1007 | ... // 56 -- chess::A8 1008 | ... std::cout << std::string(square); 1009 | >>> } 1010 | 0 1011 | 1 1012 | 2 1013 | 3 1014 | 4 1015 | 5 1016 | 6 1017 | 7 1018 | 56 1019 | 1020 | >>> vector(squares); 1021 | 1022 | Square sets are internally represented by 64-bit integer masks of the 1023 | included squares. Bitwise operations can be used to compute unions, 1024 | intersections and shifts. 1025 | 1026 | >>> std::cout << (unsigned long)(squares); 1027 | 72057594037928191 1028 | 1029 | Also supports common set operations like 1030 | :func:`~chess::SquareSet::issubset()`, :func:`~chess::SquareSet::issuperset()`, 1031 | :func:`~chess::SquareSet::union()`, :func:`~chess::SquareSet::intersection()`, 1032 | :func:`~chess::SquareSet::difference()`, 1033 | :func:`~chess::SquareSet::symmetric_difference()` and 1034 | :func:`~chess::SquareSet::copy()` as well as 1035 | :func:`~chess::SquareSet::update()`, 1036 | :func:`~chess::SquareSet::intersection_update()`, 1037 | :func:`~chess::SquareSet::difference_update()`, 1038 | :func:`~chess::SquareSet::symmetric_difference_update()` and 1039 | :func:`~chess::SquareSet::clear()`. 1040 | */ 1041 | 1042 | public: 1043 | SquareSet(const IntoSquareSet & = BB_EMPTY); 1044 | 1045 | // Set 1046 | 1047 | std::vector::const_iterator begin() const; 1048 | 1049 | std::vector::const_iterator end() const; 1050 | 1051 | size_t size() const; 1052 | 1053 | // MutableSet 1054 | 1055 | void add(Square); 1056 | 1057 | void discard(Square); 1058 | 1059 | // frozenset 1060 | 1061 | bool isdisjoint(const IntoSquareSet &) const; 1062 | 1063 | bool issubset(const IntoSquareSet &) const; 1064 | 1065 | bool issuperset(const IntoSquareSet &) const; 1066 | 1067 | SquareSet union_(const IntoSquareSet &) const; 1068 | 1069 | SquareSet operator|(const IntoSquareSet &) const; 1070 | 1071 | SquareSet intersection(const IntoSquareSet &) const; 1072 | 1073 | SquareSet operator&(const IntoSquareSet &) const; 1074 | 1075 | SquareSet difference(const IntoSquareSet &) const; 1076 | 1077 | SquareSet operator-(const IntoSquareSet &) const; 1078 | 1079 | SquareSet symmetric_difference(const IntoSquareSet &) const; 1080 | 1081 | SquareSet operator^(const IntoSquareSet &) const; 1082 | 1083 | SquareSet copy() const; 1084 | 1085 | // set 1086 | 1087 | void update(const std::initializer_list &); 1088 | 1089 | SquareSet operator|=(const IntoSquareSet &); 1090 | 1091 | void intersection_update(const std::initializer_list &); 1092 | 1093 | SquareSet operator&=(const IntoSquareSet &); 1094 | 1095 | void difference_update(const IntoSquareSet &); 1096 | 1097 | SquareSet operator-=(const IntoSquareSet &); 1098 | 1099 | void symmetric_difference_update(const IntoSquareSet &); 1100 | 1101 | SquareSet operator^=(const IntoSquareSet &); 1102 | 1103 | void remove(Square); 1104 | 1105 | Square pop(); 1106 | 1107 | void clear(); 1108 | 1109 | // SquareSet 1110 | 1111 | std::vector carry_rippler() const; 1112 | 1113 | SquareSet mirror() const; 1114 | 1115 | std::array tolist(); 1116 | 1117 | operator bool() const; 1118 | 1119 | bool operator==(const Bitboard &) const; 1120 | 1121 | bool operator==(const SquareSet &) const; 1122 | 1123 | bool operator==(const std::vector &) const; 1124 | 1125 | SquareSet operator<<(int) const; 1126 | 1127 | SquareSet operator>>(int) const; 1128 | 1129 | SquareSet operator<<=(int); 1130 | 1131 | SquareSet operator>>=(int); 1132 | 1133 | SquareSet operator~() const; 1134 | 1135 | operator unsigned long int() const; 1136 | 1137 | operator std::string() const; 1138 | 1139 | Bitboard get_mask() const; 1140 | 1141 | operator std::vector() const; 1142 | 1143 | static SquareSet ray(Square, Square); 1144 | 1145 | static SquareSet between(Square, Square); 1146 | 1147 | static SquareSet from_square(Square); 1148 | 1149 | private: 1150 | Bitboard _mask; 1151 | std::vector _iter; 1152 | }; 1153 | 1154 | std::ostream &operator<<(std::ostream &, const SquareSet &); 1155 | } 1156 | 1157 | template <> 1158 | struct std::hash 1159 | { 1160 | int operator()(const chess::Piece &piece) const 1161 | { 1162 | return piece.piece_type + (piece.color ? -1 : 5); 1163 | } 1164 | }; -------------------------------------------------------------------------------- /chess/main.cpp: -------------------------------------------------------------------------------- 1 | #include "chess.cpp" 2 | #include 3 | 4 | int main() { 5 | chess::Board board; 6 | 7 | while (!board.is_game_over(true)) { 8 | while (true) { 9 | std::cout << board.unicode(false, true) << std::endl; 10 | 11 | std::string san; 12 | std::cout << board.ply() + 1 << ". " << (board.turn ? "[WHITE] " : "[BLACK] ") << "Enter Move: "; 13 | std::cin >> san; 14 | std::cout << std::endl; 15 | 16 | try { 17 | chess::Move move = board.parse_san(san); 18 | if (!move) { 19 | throw std::invalid_argument(""); 20 | } 21 | board.push(move); 22 | break; 23 | } catch (std::invalid_argument) { 24 | std::cout << "Invalid Move, Try Again..." << std::endl; 25 | } 26 | } 27 | } 28 | 29 | std::cout << "Game Over! Result: " << board.result(true); 30 | } -------------------------------------------------------------------------------- /chess/variant: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjpuzzler/cpp-chess/e39294e257af8a26f0a6d375e88d230d6595be2a/chess/variant -------------------------------------------------------------------------------- /chess/variant.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This is a line-for-line remake of niklasf's 'python-chess' in C++ 3 | All credit for the original code and algorithms go to niklasf and his credits 4 | The original source code can be found here: https://github.com/niklasf/python-chess 5 | */ 6 | 7 | #include "variant.h" 8 | #include 9 | 10 | namespace chess 11 | { 12 | std::string SuicideBoard::aliases[] = {"Suicide", "Suicide chess"}; 13 | std::optional SuicideBoard::uci_variant = "suicide"; 14 | std::optional SuicideBoard::xboard_variant = "suicide"; 15 | 16 | std::optional SuicideBoard::tbw_suffix = ".stbw"; 17 | std::optional SuicideBoard::tbz_suffix = ".stbz"; 18 | std::optional> SuicideBoard::tbw_magic = {{0x7b, 0xf6, 0x93, 0x15}}; 19 | std::optional> SuicideBoard::tbz_magic = {{0xe4, 0xcf, 0xe7, 0x23}}; 20 | std::optional SuicideBoard::pawnless_tbw_suffix = ".gtbw"; 21 | std::optional SuicideBoard::pawnless_tbz_suffix = ".gtbz"; 22 | std::optional> SuicideBoard::pawnless_tbw_magic = {{0xbc, 0x55, 0xbc, 0x21}}; 23 | std::optional> SuicideBoard::pawnless_tbz_magic = {{0xd6, 0xf5, 0x1b, 0x50}}; 24 | bool SuicideBoard::connected_kings = true; 25 | bool SuicideBoard::one_king = false; 26 | bool SuicideBoard::captures_compulsory = true; 27 | 28 | chess::Bitboard SuicideBoard::pin_mask(chess::Color color, chess::Square square) const 29 | { 30 | return chess::BB_ALL; 31 | } 32 | 33 | bool SuicideBoard::_attacked_for_king(chess::Bitboard path, chess::Bitboard occupied) const 34 | { 35 | return false; 36 | } 37 | 38 | chess::Bitboard SuicideBoard::checkers_mask() const 39 | { 40 | return chess::BB_EMPTY; 41 | } 42 | 43 | bool SuicideBoard::gives_check(chess::Move move) const 44 | { 45 | return false; 46 | } 47 | 48 | bool SuicideBoard::is_into_check(chess::Move move) const 49 | { 50 | return false; 51 | } 52 | 53 | bool SuicideBoard::was_into_check() const 54 | { 55 | return false; 56 | } 57 | 58 | int SuicideBoard::_material_balance() const 59 | { 60 | return (chess::popcount(this->occupied_co[this->turn]) - 61 | chess::popcount(this->occupied_co[!this->turn])); 62 | } 63 | 64 | bool SuicideBoard::is_variant_end() const 65 | { 66 | for (chess::Bitboard has_pieces : this->occupied_co) { 67 | if (!has_pieces) { 68 | return true; 69 | } 70 | } 71 | return false; 72 | } 73 | 74 | bool SuicideBoard::is_variant_win() const 75 | { 76 | if (!this->occupied_co[this->turn]) { 77 | return true; 78 | } else { 79 | return this->is_stalemate() && this->_material_balance() < 0; 80 | } 81 | } 82 | 83 | bool SuicideBoard::is_variant_loss() const 84 | { 85 | if (!this->occupied_co[this->turn]) { 86 | return false; 87 | } else { 88 | return this->is_stalemate() && this->_material_balance() > 0; 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /chess/variant.h: -------------------------------------------------------------------------------- 1 | /* 2 | This is a line-for-line remake of niklasf's 'python-chess' in C++ 3 | All credit for the original code and algorithms go to niklasf and his credits 4 | The original source code can be found here: https://github.com/niklasf/python-chess 5 | */ 6 | 7 | #include "chess.cpp" 8 | 9 | namespace chess 10 | { 11 | class SuicideBoard : public chess::Board 12 | { 13 | public: 14 | static std::string aliases[]; 15 | static std::optional uci_variant; 16 | static std::optional xboard_variant; 17 | static std::string starting_fen; 18 | 19 | static std::optional tbw_suffix; 20 | static std::optional tbz_suffix; 21 | static std::optional> tbw_magic; 22 | static std::optional> tbz_magic; 23 | static std::optional pawnless_tbw_suffix; 24 | static std::optional pawnless_tbz_suffix; 25 | static std::optional> pawnless_tbw_magic; 26 | static std::optional> pawnless_tbz_magic; 27 | static bool connected_kings; 28 | static bool one_king; 29 | static bool captures_compulsory; 30 | 31 | chess::Bitboard pin_mask(chess::Color, chess::Square) const; 32 | 33 | bool _attacked_for_king(chess::Bitboard, chess::Bitboard) const; 34 | 35 | chess::Bitboard checkers_mask() const; 36 | 37 | bool gives_check(chess::Move) const; 38 | 39 | bool is_into_check(chess::Move) const; 40 | 41 | bool was_into_check() const; 42 | 43 | int _material_balance() const; 44 | 45 | bool is_variant_end() const; 46 | 47 | bool is_variant_win() const; 48 | 49 | bool is_variant_loss() const; 50 | }; 51 | } --------------------------------------------------------------------------------