Line data Source code
1 : #pragma once
2 :
3 : #include "attack.hpp"
4 : #include "bitboardTools.hpp"
5 : #include "definition.hpp"
6 : #include "dynamicConfig.hpp"
7 : #include "hash.hpp"
8 : #include "logging.hpp"
9 : #include "movePseudoLegal.hpp"
10 : #include "positionTools.hpp"
11 : #include "timers.hpp"
12 : #include "tools.hpp"
13 :
14 : struct Searcher;
15 :
16 : template<MType MT>
17 : struct CastlingTraits{
18 : };
19 :
20 : template<>
21 : struct CastlingTraits<T_wqs>{
22 : static constexpr CastlingTypes ct = CT_OOO;
23 : static constexpr MType mt = T_wqs;
24 : static constexpr CastlingRights cr = C_wqs;
25 : static constexpr Color c = Co_White;
26 : static constexpr Square kingLanding = Sq_c1;
27 : static constexpr Square rookLanding = Sq_d1;
28 : static constexpr BitBoard kingLandingBB = BB::BBSq_c1;
29 : static constexpr BitBoard rookLandingBB = BB::BBSq_d1;
30 : static constexpr Piece fromP = P_wk;
31 : static constexpr Piece toP = P_wr;
32 : };
33 :
34 : template<>
35 : struct CastlingTraits<T_wks>{
36 : static constexpr CastlingTypes ct = CT_OO;
37 : static constexpr MType mt = T_wks;
38 : static constexpr CastlingRights cr = C_wks;
39 : static constexpr Color c = Co_White;
40 : static constexpr Square kingLanding = Sq_g1;
41 : static constexpr Square rookLanding = Sq_f1;
42 : static constexpr BitBoard kingLandingBB = BB::BBSq_g1;
43 : static constexpr BitBoard rookLandingBB = BB::BBSq_f1;
44 : static constexpr Piece fromP = P_wk;
45 : static constexpr Piece toP = P_wr;
46 : };
47 :
48 : template<>
49 : struct CastlingTraits<T_bqs>{
50 : static constexpr CastlingTypes ct = CT_OOO;
51 : static constexpr MType mt = T_bqs;
52 : static constexpr CastlingRights cr = C_bqs;
53 : static constexpr Color c = Co_Black;
54 : static constexpr Square kingLanding = Sq_c8;
55 : static constexpr Square rookLanding = Sq_d8;
56 : static constexpr BitBoard kingLandingBB = BB::BBSq_c8;
57 : static constexpr BitBoard rookLandingBB = BB::BBSq_d8;
58 : static constexpr Piece fromP = P_bk;
59 : static constexpr Piece toP = P_br;
60 : };
61 :
62 : template<>
63 : struct CastlingTraits<T_bks>{
64 : static constexpr CastlingTypes ct = CT_OO;
65 : static constexpr MType mt = T_bks;
66 : static constexpr CastlingRights cr = C_bks;
67 : static constexpr Color c = Co_Black;
68 : static constexpr Square kingLanding = Sq_g8;
69 : static constexpr Square rookLanding = Sq_f8;
70 : static constexpr BitBoard kingLandingBB = BB::BBSq_g8;
71 : static constexpr BitBoard rookLandingBB = BB::BBSq_f8;
72 : static constexpr Piece fromP = P_bk;
73 : static constexpr Piece toP = P_br;
74 : };
75 :
76 : [[nodiscard]] ScoreType randomMover(const Position& p, PVList& pv, const bool isInCheck);
77 :
78 : namespace MoveGen {
79 :
80 : enum GenPhase { GP_all = 0, GP_cap = 1, GP_quiet = 2, GP_evasion = 3 };
81 :
82 : FORCE_FINLINE void addMove(const Square from, const Square to, const MType type, MoveList& moves) {
83 0 : assert(isValidSquare(from));
84 4339414 : assert(isValidSquare(to));
85 194631767 : moves.emplace_back(ToMove(from, to, type, 0));
86 190432344 : }
87 :
88 : template<GenPhase phase = GP_all>
89 129641277 : void generateSquare(const Position& p, MoveList& moves, const Square from) {
90 129641277 : assert(isValidSquare(from));
91 : #ifdef DEBUG_GENERATION
92 : if (from == INVALIDSQUARE) Logging::LogIt(Logging::logFatal) << "invalid square";
93 : #endif
94 129641277 : const Color side = p.c;
95 129641277 : const BitBoard& myPieceBB = p.allPieces[side];
96 129641277 : const BitBoard& oppPieceBB = p.allPieces[~side];
97 129641277 : const Piece piece = p.board_const(from);
98 129641277 : const Piece ptype = Abs(piece);
99 0 : assert(isValidPieceNotNone(ptype));
100 : #ifdef DEBUG_GENERATION
101 : if (!isValidPieceNotNone(ptype)) {
102 : Logging::LogIt(Logging::logWarn) << ToString(myPieceBB);
103 : Logging::LogIt(Logging::logWarn) << ToString(oppPieceBB);
104 : Logging::LogIt(Logging::logWarn) << "piece " << static_cast<int>(piece);
105 : Logging::LogIt(Logging::logWarn) << SquareNames[from];
106 : Logging::LogIt(Logging::logWarn) << ToString(p);
107 : Logging::LogIt(Logging::logWarn) << ToString(p.lastMove);
108 : Logging::LogIt(Logging::logFatal) << "invalid type " << ptype;
109 : }
110 : #endif
111 102507048 : const BitBoard occupancy = p.occupancy();
112 6298971 : BitBoard sliderRay = emptyBitBoard;
113 : BitBoard attacker = emptyBitBoard;
114 : if (phase == GP_evasion){
115 6298971 : const Square kingSq = kingSquare(p);
116 12597942 : const BitBoard slider = BBTools::attack<P_wb>(kingSq, p.pieces_const<P_wb>(~p.c) | p.pieces_const<P_wq>(~p.c), occupancy)|
117 6298971 : BBTools::attack<P_wr>(kingSq, p.pieces_const<P_wr>(~p.c) | p.pieces_const<P_wq>(~p.c), occupancy);
118 : attacker = slider;
119 : BB::applyOn(slider, [&](const Square & k){
120 5731042 : sliderRay |= BBTools::between(k, kingSq);
121 : });
122 12597942 : attacker |= BBTools::attack<P_wn>(kingSq, p.pieces_const<P_wn>(~p.c));
123 6298971 : attacker |= BBTools::attack<P_wp>(kingSq, p.pieces_const<P_wp>(~p.c), occupancy, p.c);
124 6298971 : if (!attacker){
125 : std::cout << "Error ! no attaker but evasion requested !" << std::endl;
126 0 : std::cout << ToString(p) << std::endl;
127 : }
128 : //std::cout << ToString(attacker) << std::endl;
129 : //std::cout << ToString(sliderRay) << std::endl;
130 : }
131 129641277 : if (ptype != P_wp) {
132 59225849 : BitBoard bb = BBTools::pfCoverage[ptype - 1](from, occupancy, p.c) & ~myPieceBB;
133 : if (phase == GP_cap){
134 : // only target opponent piece
135 6770902 : bb &= oppPieceBB;
136 : }
137 : else if (phase == GP_quiet){
138 : // do not target opponent piece
139 6446 : bb &= ~oppPieceBB;
140 : }
141 : else if (phase == GP_evasion){
142 : // king don't want to stay in check
143 2530326 : if ( ptype == P_wk )
144 695993 : bb &= ~sliderRay;
145 : // other pieces only target king attakers and sliders path
146 : else
147 1834333 : bb &= attacker | sliderRay;
148 : }
149 273558017 : BB::applyOn(bb, [&](const Square & to){
150 107166084 : const bool isCap = (phase == GP_cap) || ((oppPieceBB & SquareToBitboard(to)) != emptyBitBoard);
151 110936491 : if (isCap) addMove(from, to, T_capture, moves);
152 : else
153 100051192 : addMove(from, to, T_std, moves);
154 : });
155 :
156 : // attack on castling king destination square will be checked by applyMove
157 49924621 : if (phase != GP_cap && phase != GP_evasion && ptype == P_wk) { // add castling
158 : // Be carefull, here rooksInit are only accessed if the corresponding p.castling is set
159 : // This way rooksInit is not INVALIDSQUARE, and thus mask[] is not out of bound
160 : // Moreover, king[] also is assumed to be not INVALIDSQUARE which is verified in readFen
161 : /*
162 : std::cout << int(p.rootInfo().kingInit[Co_White]) << std::endl;
163 : std::cout << int(p.rootInfo().kingInit[Co_Black]) << std::endl;
164 : std::cout << int(p.rootInfo().rooksInit[Co_White][CT_OOO]) << std::endl;
165 : std::cout << int(p.rootInfo().rooksInit[Co_White][CT_OO]) << std::endl;
166 : std::cout << int(p.rootInfo().rooksInit[Co_Black][CT_OOO]) << std::endl;
167 : std::cout << int(p.rootInfo().rooksInit[Co_Black][CT_OO]) << std::endl;
168 : */
169 :
170 36132180 : auto addIfCastlingOk = [&]<MType mt>() mutable {
171 : const Color c = CastlingTraits<mt>::c;
172 14452872 : const Square to = p.rootInfo().rooksInit[c][CastlingTraits<mt>::ct];
173 14452872 : if (p.castling & CastlingTraits<mt>::cr) {
174 10433855 : const BitBoard kingPath = BBTools::between(p.king[c], CastlingTraits<mt>::kingLanding) | CastlingTraits<mt>::kingLandingBB;
175 10433855 : const BitBoard pathOccupancy = (kingPath | BBTools::between(to, CastlingTraits<mt>::rookLanding) | CastlingTraits<mt>::rookLandingBB)
176 10433855 : & ~BBTools::mask[to].bbsquare & ~BBTools::mask[p.king[c]].bbsquare;
177 10595888 : if ((pathOccupancy & occupancy) == emptyBitBoard && !isAttacked(p, kingPath | SquareToBitboard(p.king[c]))){
178 139991 : addMove(from, to, mt, moves);
179 : }
180 : }
181 : };
182 :
183 7226436 : if (side == Co_White) {
184 1259301 : addIfCastlingOk.template operator()<T_wqs>();
185 1259301 : addIfCastlingOk.template operator()<T_wks>();
186 : }
187 : else {
188 5967135 : addIfCastlingOk.template operator()<T_bqs>();
189 5967135 : addIfCastlingOk.template operator()<T_bks>();
190 : }
191 : }
192 : }
193 : else {
194 : BitBoard pawnmoves = emptyBitBoard;
195 70403528 : if (phase != GP_quiet) pawnmoves = BBTools::mask[from].pawnAttack[p.c] & ~myPieceBB & oppPieceBB;
196 3768645 : if (phase == GP_evasion) pawnmoves &= attacker;
197 76627584 : BB::applyOn(pawnmoves, [&](const Square & to){
198 3112028 : if ((SquareToBitboard(to) & BB::rank1_or_rank8) == emptyBitBoard) addMove(from, to, T_capture, moves);
199 : else {
200 31183 : addMove(from, to, T_cappromq, moves); // pawn capture with promotion
201 31183 : addMove(from, to, T_cappromr, moves); // pawn capture with promotion
202 31183 : addMove(from, to, T_cappromb, moves); // pawn capture with promotion
203 31183 : addMove(from, to, T_cappromn, moves); // pawn capture with promotion
204 : }
205 : });
206 :
207 : pawnmoves = emptyBitBoard;
208 56351072 : if (phase != GP_cap) pawnmoves |= BBTools::mask[from].push[p.c] & ~occupancy;
209 56351072 : if ((phase != GP_cap) && (BBTools::mask[from].push[p.c] & occupancy) == emptyBitBoard) pawnmoves |= BBTools::mask[from].dpush[p.c] & ~occupancy;
210 3768645 : if (phase == GP_evasion) pawnmoves &= sliderRay;
211 216379554 : BB::applyOn(pawnmoves, [&](const Square & to){
212 80014241 : if ((SquareToBitboard(to) & BB::rank1_or_rank8) == emptyBitBoard) addMove(from, to, T_std, moves);
213 : else {
214 79993 : addMove(from, to, T_promq, moves); // promotion Q
215 79993 : addMove(from, to, T_promr, moves); // promotion R
216 79993 : addMove(from, to, T_promb, moves); // promotion B
217 79993 : addMove(from, to, T_promn, moves); // promotion N
218 : }
219 : });
220 :
221 : ///@todo evasion ep special case ?
222 : pawnmoves = emptyBitBoard;
223 70403528 : if (p.ep != INVALIDSQUARE && phase != GP_quiet) pawnmoves = BBTools::mask[from].pawnAttack[p.c] & ~myPieceBB & SquareToBitboard(p.ep);
224 70411458 : BB::applyOn(pawnmoves, [&](const Square & to){
225 95488 : addMove(from, to, T_ep, moves);
226 : });
227 : }
228 129641277 : }
229 :
230 : template<GenPhase phase = GP_all>
231 10357044 : void generate(const Position& p, MoveList& moves, const bool doNotClear = false) {
232 : START_TIMER
233 10357044 : if (!doNotClear) moves.clear();
234 10357044 : BitBoard myPieceBBiterator = p.allPieces[p.c];
235 129641277 : BB::applyOn(myPieceBBiterator, [&](const Square & k){ generateSquare<phase>(p, moves, k); });
236 : #ifdef DEBUG_GENERATION_LEGAL
237 : for (auto m : moves) {
238 : if (!isPseudoLegal(p, m)) {
239 : Logging::LogIt(Logging::logError) << "Generation error, move not legal " << ToString(p);
240 : Logging::LogIt(Logging::logError) << "move " << ToString(m);
241 : Logging::LogIt(Logging::logFatal) << "previous " << ToString(p.lastMove);
242 : assert(false);
243 : }
244 : }
245 : #endif
246 : // in anarchy chess, EP is mandatory
247 10357044 : if ( DynamicConfig::anarchy && p.ep != INVALIDSQUARE ){ // will be slow ... ///@todo better
248 : bool foundEP = false;
249 0 : MoveList eps;
250 0 : for (auto m : moves){
251 0 : if ( Move2Type(m) == T_ep ){
252 : foundEP = true;
253 0 : eps.emplace_back(m);
254 : }
255 : }
256 0 : if ( foundEP ){
257 : moves = eps;
258 : }
259 : }
260 : // in antichess, capture is mandatory
261 10357044 : if ( DynamicConfig::antichess ){
262 : bool foundCap = false;
263 0 : MoveList caps;
264 0 : for (auto m : moves){
265 0 : if ( isCapture(m) ){
266 : foundCap = true;
267 0 : caps.emplace_back(m);
268 : }
269 : }
270 0 : if ( foundCap ){
271 : moves = caps;
272 : }
273 : }
274 : STOP_AND_SUM_TIMER(Generate)
275 10357044 : }
276 :
277 : } // namespace MoveGen
|