@@ -19,13 +19,11 @@ template <typename Piece> struct alignas(64) HistoryEntry {
1919 Color turn; // true if white to move
2020 Move mv;
2121 Key hash;
22- struct {
23- uint8_t halfMoveClock; // Half-move clock for 50/75-move rule
24- uint16_t fullMoveNumber; // Full-move number (starts at 1)
25- bool epIncluded;
26- int8_t repetition = 0 ;
27- uint8_t pliesFromNull = 0 ;
28- };
22+ uint8_t halfMoveClock; // Half-move clock for 50/75-move rule
23+ uint16_t fullMoveNumber; // Full-move number (starts at 1)
24+ bool epIncluded;
25+ int8_t repetition = 0 ;
26+ uint8_t pliesFromNull = 0 ;
2927 Square enPassant = SQ_NONE; // En passant target square
3028 Square kings[COLOR_NB] = { SQ_NONE };
3129 CastlingRights castlingRights; // Castling rights bitmask
@@ -160,9 +158,7 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
160158
161159 // Move history stack
162160 HeapAllocatedValueList<HistoryEntry<PieceC>, 6144 >
163- history; // ahh, but i hope it fulfils before I manages to find the absolute limit of a game
164- // Move generation functions, but INTERNAL. (they're kind of long so i put them into a source
165- // file) Pawns (fully extensively tested)
161+ history;
166162 Bitboard _rook_pin;
167163 Bitboard _bishop_pin;
168164 Bitboard _checkers;
@@ -181,6 +177,12 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
181177 PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE,
182178 PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE, PieceC::NO_PIECE
183179 };
180+ // Castling path, [color][king_side]
181+ static constexpr std::array<std::array<Bitboard, 2 >, 2 > castling_path =
182+ {{
183+ {{ 0xe , 0x60 }},
184+ {{ 0xe00000000000000ULL , 0x6000000000000000ULL }}
185+ }};
184186
185187 public:
186188 // Legal move generation functions
@@ -393,7 +395,7 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
393395 }
394396
395397 [[nodiscard]] __FORCEINLINE Bitboard attackers (Color color, Square square) const { return attackers (color, square, occ ()); }
396- // Compile-time piece type and color, runtime square
398+
397399 template <PieceType pt> __FORCEINLINE void placePiece (Square sq, Color c) {
398400 if constexpr (pt != NO_PIECE_TYPE) {
399401 Bitboard v = 1ULL << sq;
@@ -448,6 +450,7 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
448450 }
449451 __FORCEINLINE Bitboard occ () const { return current_state.occ [0 ] | current_state.occ [1 ]; }
450452 PieceC piece_on (Square s) const {
453+ assert (chess::is_valid (s));
451454#if !defined(_DEBUG) || defined(NDEBUG)
452455 return pieces_list[s];
453456#else
@@ -470,8 +473,7 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
470473 assert (p == _p2 && " Inconsistient piece map" );
471474#else
472475 if (p != _p2)
473- // throw std::invalid_argument("Inconsistient piece map");
474- exit (-1 );
476+ throw std::invalid_argument (" Inconsistient piece map" );
475477#endif
476478 return p;
477479#endif
@@ -504,7 +506,12 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
504506 __FORCEINLINE const HistoryEntry<PieceC> &state () const { return current_state; }
505507 uint64_t zobrist () const ;
506508 __FORCEINLINE PieceC piece_at (Square sq) const { return piece_on (sq); }
507- __FORCEINLINE PieceC at (Square sq) const { return piece_at (sq); }
509+ template <typename T = PieceC>
510+ __FORCEINLINE PieceC at (Square sq) const {
511+ assert (chess::is_valid (sq));
512+ if constexpr (std::is_same_v<T, PieceType>) return piece_of (piece_at (sq));
513+ else return piece_at (sq);
514+ }
508515 __FORCEINLINE Square enpassantSq () const { return ep_square (); }
509516 CastlingRights clean_castling_rights () const ;
510517 void setFEN (const std::string &str);
@@ -524,6 +531,8 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
524531 __FORCEINLINE bool is_insufficient_material () const {
525532 return has_insufficient_material (WHITE) && has_insufficient_material (BLACK);
526533 }
534+ __FORCEINLINE bool isInsufficientMaterial () const { return is_insufficient_material (); }
535+ __FORCEINLINE bool hasNonPawnMaterial (Color c) const { return bool (us (c) ^ (pieces (PAWN, KING) & us (c))); }
527536 __FORCEINLINE bool inCheck () const { return checkers () != 0 ; }
528537 __FORCEINLINE bool is_check () const { return checkers () != 0 ; }
529538 __FORCEINLINE bool has_castling_rights (Color c) const { return castlingRights (c) != 0 ; }
@@ -583,14 +592,33 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
583592 }
584593 return b != 0 ;
585594 }
595+ __FORCEINLINE bool is_checkmate () const {
596+ Movelist moves;
597+ legals (moves);
598+ return inCheck () && !moves.size ();
599+ }
600+ __FORCEINLINE bool is_stalemate () const {
601+ Movelist moves;
602+ legals (moves);
603+ return !inCheck () && !moves.size ();
604+ }
586605 // Material-only key (note: Zobrist=Zpieces^Zep^Zcastling^Zturn, we just XORs the remaining, it's trivial)
587606 __FORCEINLINE Key material_key () const {
588607 return hash () ^ (zobrist::RandomTurn * ~sideToMove ()) ^ (zobrist::RandomCastle[castlingRights ()]) ^
589608 (zobrist::RandomEP[ep_square () == SQ_NONE ? file_of (ep_square ()) : FILE_NB]);
590609 }
591610 template <bool Strict = false > bool is_valid () const ;
592611 CheckType givesCheck (Move move) const ;
593-
612+ /* *
613+ * @brief Checks if the current position is a draw by 50 move rule.
614+ * Keep in mind that by the rules of chess, if the position has 50 half
615+ * moves it's not necessarily a draw, since checkmate has higher priority,
616+ * <del>call getHalfMoveDrawType,
617+ * to determine whether the position is a draw or checkmate.</del>
618+ * @return
619+ */
620+ [[nodiscard]] __FORCEINLINE bool isHalfMoveDraw () const noexcept { return halfmoveClock () >= 100 ; }
621+ [[nodiscard]] __FORCEINLINE Bitboard getCastlingPath (Color c, bool isKingSide) const { return castling_path[c][isKingSide]; }
594622 private:
595623 template <PieceType pt> [[nodiscard]] __FORCEINLINE Bitboard pinMask (Color c, Square sq) const {
596624 static_assert (pt == BISHOP || pt == ROOK, " Only bishop or rook allowed!" );
@@ -684,5 +712,23 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
684712 refresh_attacks ();
685713 }
686714};
687- using Position = _Position<EnginePiece>; // for some fun because I HATE HARDCODING
715+ namespace attacks {
716+ /* *
717+ * @brief Returns the attacks for a given piece on a given square
718+ * @param board
719+ * @param color
720+ * @param square
721+ * @return
722+ */
723+ template <typename T, typename = std::enable_if_t <is_piece_enum<T>::value>>
724+ [[nodiscard]] __FORCEINLINE Bitboard attackers (const _Position<T> &board, Color color, Square square) noexcept {
725+ return board.attackers (color, square);
726+ }
727+ }
728+ // Aliases
729+ using Position = _Position<EnginePiece>;
730+ using Board = _Position<EnginePiece>;
688731}; // namespace chess
732+
733+
734+
0 commit comments