Line data Source code
1 : #pragma once
2 :
3 : #include "bitboardTools.hpp"
4 : #include "definition.hpp"
5 :
6 : #ifdef __BMI2__
7 : #include <immintrin.h>
8 : #endif
9 :
10 : namespace BBTools {
11 :
12 : /*!
13 : * Two bitboard attack generation tools can be used here (controlled by WITH_MAGIC define from config.hpp):
14 : * - hyperbola quintessence (https://www.chessprogramming.org/Hyperbola_Quintessence)
15 : * - or magic (https://www.chessprogramming.org/Magic_Bitboards) with BMI2 extension if available
16 : */
17 :
18 : // mask variable is filled with many usefull pre-computed bitboard information
19 : // many of then will be usefull during evaluation and move generation
20 : // note that between to not include start and end square
21 : struct Mask {
22 : BitBoard bbsquare {emptyBitBoard};
23 : BitBoard kingZone {emptyBitBoard};
24 : BitBoard knight {emptyBitBoard};
25 : BitBoard king {emptyBitBoard};
26 : BitBoard diagonal {emptyBitBoard};
27 : BitBoard antidiagonal {emptyBitBoard};
28 : BitBoard file {emptyBitBoard};
29 : colored<BitBoard> pawnAttack {{emptyBitBoard, emptyBitBoard}};
30 : colored<BitBoard> push {{emptyBitBoard, emptyBitBoard}};
31 : colored<BitBoard> dpush {{emptyBitBoard, emptyBitBoard}};
32 : #if !defined(WITH_SMALL_MEMORY)
33 : BitBoard enpassant {emptyBitBoard};
34 : colored<BitBoard> frontSpan {{emptyBitBoard, emptyBitBoard}};
35 : colored<BitBoard> rearSpan {{emptyBitBoard, emptyBitBoard}};
36 : colored<BitBoard> passerSpan {{emptyBitBoard, emptyBitBoard}};
37 : colored<BitBoard> attackFrontSpan {{emptyBitBoard, emptyBitBoard}};
38 : array1d<BitBoard, NbSquare> between {emptyBitBoard};
39 : #endif
40 : };
41 :
42 : extern array1d<Mask,NbSquare> mask;
43 : void initMask();
44 :
45 : constexpr auto SquareToBitboardTable(const Square k) { return BBTools::mask[k].bbsquare;}
46 :
47 : #ifndef WITH_MAGIC
48 :
49 : /*!
50 : * This HQ BB implementation is comming from Dumb/Amoeba by Richard Delorme (a.k.a Abulmo)
51 : * after a discussion on talkchess about a small BB implementation
52 : * http://talkchess.com/forum3/viewtopic.php?f=7&t=68741&p=777898#p777682
53 : */
54 :
55 : [[nodiscard]] BitBoard attack (const BitBoard occupancy, const Square x, const BitBoard m);
56 : [[nodiscard]] BitBoard rankAttack (const BitBoard occupancy, const Square x);
57 : [[nodiscard]] BitBoard fileAttack (const BitBoard occupancy, const Square x);
58 : [[nodiscard]] BitBoard diagonalAttack (const BitBoard occupancy, const Square x);
59 : [[nodiscard]] BitBoard antidiagonalAttack(const BitBoard occupancy, const Square x);
60 :
61 : // Next functions define the user API for piece move
62 : template < Piece > [[nodiscard]] FORCE_FINLINE BitBoard coverage (const Square x, const BitBoard occupancy = 0, const Color c = Co_White) { assert(false); return emptyBitBoard; }
63 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wp>(const Square x, const BitBoard , const Color c) { assert(isValidSquare(x)); return mask[x].pawnAttack[c]; }
64 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wn>(const Square x, const BitBoard , const Color ) { assert(isValidSquare(x)); return mask[x].knight; }
65 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wb>(const Square x, const BitBoard occupancy, const Color ) { assert(isValidSquare(x)); return diagonalAttack(occupancy, x) | antidiagonalAttack(occupancy, x); }
66 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wr>(const Square x, const BitBoard occupancy, const Color ) { assert(isValidSquare(x)); return fileAttack (occupancy, x) | rankAttack (occupancy, x); }
67 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wq>(const Square x, const BitBoard occupancy, const Color ) { assert(isValidSquare(x)); return diagonalAttack(occupancy, x) | antidiagonalAttack(occupancy, x) | fileAttack(occupancy, x) | rankAttack(occupancy, x); }
68 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wk>(const Square x, const BitBoard , const Color ) { assert(isValidSquare(x)); return mask[x].king; }
69 :
70 : // Attack function is just coverage interseted with a target bitboard
71 : template<Piece pp>
72 : [[nodiscard]] FORCE_FINLINE BitBoard attack(const Square x, const BitBoard target, const BitBoard occupancy = 0, const Color c = Co_White) {
73 : return coverage<pp>(x, occupancy, c) & target;
74 : }
75 :
76 : #else // MAGIC
77 :
78 : namespace MagicBB {
79 :
80 : /*!
81 : * This compact magic BB implementation is very near the one used
82 : * in RubiChess and Stockfish
83 : * It is not really much faster than HQ BB, maybe around +10%
84 : */
85 :
86 : inline constexpr size_t BISHOP_INDEX_BITS = 9;
87 : inline constexpr size_t ROOK_INDEX_BITS = 12;
88 :
89 : struct SMagic {
90 : BitBoard mask {emptyBitBoard};
91 : BitBoard magic {emptyBitBoard};
92 : };
93 :
94 : extern array1d<SMagic, NbSquare> bishopMagic;
95 : extern array1d<SMagic, NbSquare> rookMagic;
96 :
97 : extern array2d<BitBoard, NbSquare, 1 << BISHOP_INDEX_BITS> bishopAttacks;
98 : extern array2d<BitBoard, NbSquare, 1 << ROOK_INDEX_BITS> rookAttacks;
99 :
100 : #if defined(__BMI2__) && !defined(__znver1) && !defined(__znver2) && !defined(__bdver4) && defined(ENV64BIT)
101 : inline auto MAGICBISHOPINDEX(const BitBoard m, const Square x) { return _pext_u64(m, MagicBB::bishopMagic[x].mask);}
102 : inline auto MAGICROOKINDEX(const BitBoard m, const Square x) { return _pext_u64(m, MagicBB::rookMagic[x].mask);}
103 : #else
104 43396428 : inline auto MAGICBISHOPINDEX(const BitBoard m, const Square x) { return static_cast<int>(((m & MagicBB::bishopMagic[x].mask) * MagicBB::bishopMagic[x].magic) >> (NbSquare - BISHOP_INDEX_BITS));}
105 95032626 : inline auto MAGICROOKINDEX(const BitBoard m, const Square x) { return static_cast<int>(((m & MagicBB::rookMagic[x].mask) * MagicBB::rookMagic[x].magic) >> (NbSquare - ROOK_INDEX_BITS));}
106 : #endif
107 :
108 193009060 : inline auto MAGICBISHOPATTACKS(const BitBoard m, const Square x) { return MagicBB::bishopAttacks[x][MAGICBISHOPINDEX(m, x)];}
109 222992238 : inline auto MAGICROOKATTACKS(const BitBoard m, const Square x) { return MagicBB::rookAttacks [x][MAGICROOKINDEX(m, x)];}
110 :
111 : void initMagic();
112 :
113 : } // namespace MagicBB
114 :
115 : // Next functions define the user API for piece move
116 : template < Piece > [[nodiscard]] FORCE_FINLINE BitBoard coverage (const Square , const BitBoard , const Color ) { assert(false); return emptyBitBoard; }
117 270825320 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wp>(const Square s, const BitBoard , const Color c) { assert(isValidSquare(s)); return mask[s].pawnAttack[c]; }
118 169236630 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wn>(const Square s, const BitBoard , const Color ) { assert(isValidSquare(s)); return mask[s].knight; }
119 19607804 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wb>(const Square s, const BitBoard occupancy, const Color ) { assert(isValidSquare(s)); return MagicBB::MAGICBISHOPATTACKS(occupancy, s); }
120 62030389 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wr>(const Square s, const BitBoard occupancy, const Color ) { assert(isValidSquare(s)); return MagicBB::MAGICROOKATTACKS (occupancy, s); }
121 14394866 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wq>(const Square s, const BitBoard occupancy, const Color ) { assert(isValidSquare(s)); return MagicBB::MAGICBISHOPATTACKS(occupancy, s) | MagicBB::MAGICROOKATTACKS(occupancy, s); }
122 229491438 : template < > [[nodiscard]] FORCE_FINLINE BitBoard coverage<P_wk>(const Square s, const BitBoard , const Color ) { assert(isValidSquare(s)); return mask[s].king; }
123 :
124 : // Attack function is just coverage interseted with a target bitboard
125 : template<Piece pp>
126 : [[nodiscard]] FORCE_FINLINE BitBoard attack(const Square s,
127 : const BitBoard target,
128 : const BitBoard occupancy = 0,
129 : const Color c = Co_White) { // color is only important/needed for pawns
130 248177225 : return target ? target & coverage<pp>(s, occupancy, c) : emptyBitBoard;
131 : }
132 :
133 : #endif // MAGIC
134 :
135 : BitBoard between(const Square sq1, const Square sq2);
136 :
137 : // Those are convenient function pointers for coverage and attack
138 : constexpr BitBoard (*const pfCoverage[])(const Square, const BitBoard, const Color) = {&BBTools::coverage<P_wp>, &BBTools::coverage<P_wn>,
139 : &BBTools::coverage<P_wb>, &BBTools::coverage<P_wr>,
140 : &BBTools::coverage<P_wq>, &BBTools::coverage<P_wk>};
141 : //constexpr BitBoard(*const pfAttack[]) (const Square, const BitBoard, const BitBoard, const Color) = { &BBTools::attack<P_wp>, &BBTools::attack<P_wn>, &BBTools::attack<P_wb>, &BBTools::attack<P_wr>, &BBTools::attack<P_wq>, &BBTools::attack<P_wk> };
142 :
143 : // Convenient function to check is a square is under attack or not
144 : [[nodiscard]] bool isAttackedBB(const Position &p, const Square s, const Color c);
145 :
146 : // Convenient function to return the bitboard of all attacker of a specific square
147 : [[nodiscard]] BitBoard allAttackedBB(const Position &p, const Square s, const Color c);
148 : [[nodiscard]] BitBoard allAttackedBB(const Position &p, const Square s);
149 :
150 : } // namespace BBTools
151 :
152 : // Those are wrapper functions around isAttackedBB
153 : [[nodiscard]] bool isAttacked(const Position &p, const Square s);
154 : [[nodiscard]] bool isAttacked(const Position &p, BitBoard bb);
155 : [[nodiscard]] bool isPosInCheck(const Position& p);
|