Line data Source code
1 : #include "movePseudoLegal.hpp"
2 :
3 : #include "moveGen.hpp"
4 : #include "position.hpp"
5 :
6 : #ifdef DEBUG_PSEUDO_LEGAL
7 : bool isPseudoLegal2(const Position& p, Move m); // forward decl
8 : bool isPseudoLegal(const Position& p, Move m) {
9 : const bool b = isPseudoLegal2(p, m);
10 : if (b) {
11 : MoveList moves;
12 : MoveGen::generate<MoveGen::GP_all>(p, moves);
13 : bool found = false;
14 : for (auto it = moves.begin(); it != moves.end() && !found; ++it)
15 : if (sameMove(*it, m)) found = true;
16 : if (!found) {
17 : std::cout << ToString(p) << "\n" << ToString(m) << "\t" << m << std::endl;
18 : std::cout << SquareNames[Move2From(m)] << std::endl;
19 : std::cout << SquareNames[Move2To(m)] << std::endl;
20 : std::cout << static_cast<int>(Move2Type(m)) << std::endl;
21 : std::cout << Move2Score(m) << std::endl;
22 : std::cout << static_cast<int>(m & 0x0000FFFF) << std::endl;
23 : for (const auto & it : moves) std::cout << ToString(it) << "\t" << *it << "\t";
24 : std::cout << std::endl;
25 : std::cout << "Not a generated move !" << std::endl;
26 : }
27 : }
28 : return b;
29 : }
30 :
31 : bool isPseudoLegal2(const Position& p, const Move m) { // validate TT move
32 : #else
33 1693146 : bool isPseudoLegal(const Position& p, const Move m) { // validate TT move
34 : #endif
35 : #ifdef DEBUG_PSEUDO_LEGAL
36 : #define PSEUDO_LEGAL_RETURN(b, r) \
37 : { \
38 : if (!b) std::cout << "isPseudoLegal2: " << r << std::endl; \
39 : STOP_AND_SUM_TIMER(PseudoLegal) return b; \
40 : }
41 : #else
42 : #define PSEUDO_LEGAL_RETURN(b, r) \
43 : { STOP_AND_SUM_TIMER(PseudoLegal) return b; }
44 : #endif
45 : START_TIMER
46 :
47 : if (!isValidMove(m)) PSEUDO_LEGAL_RETURN(false, -1)
48 1693146 : const MType t = Move2Type(m);
49 :
50 : if (!isValidMoveType(t)) PSEUDO_LEGAL_RETURN(false, -4)
51 1693146 : if (t == T_reserved) PSEUDO_LEGAL_RETURN(false, 3)
52 :
53 1693146 : const Square from = Move2From(m);
54 1693146 : if (!isValidSquare(from)) PSEUDO_LEGAL_RETURN(false, -2)
55 :
56 1693146 : const Piece fromP = p.board_const(from);
57 1693146 : if (fromP == P_none || (fromP > 0 && p.c == Co_Black) || (fromP < 0 && p.c == Co_White)) PSEUDO_LEGAL_RETURN(false, 0)
58 :
59 1693144 : const Square to = Move2To(m);
60 1693144 : if (!isValidSquare(to)) PSEUDO_LEGAL_RETURN(false, -3)
61 :
62 : // cannot capture own piece, except for castling where it is checked later
63 1693144 : const Piece toP = p.board_const(to);
64 1693144 : if ((toP > 0 && p.c == Co_White) || (toP < 0 && p.c == Co_Black)){
65 300 : if(!DynamicConfig::FRC){
66 300 : if (!isCastling(t)) PSEUDO_LEGAL_RETURN(false, 1)
67 : else{
68 : ;// see castling
69 : }
70 : }
71 : else{
72 0 : if (!isCastling(t)) PSEUDO_LEGAL_RETURN(false, 1)
73 : else{
74 : ;// see castling
75 : }
76 : }
77 : }
78 :
79 : // opponent king cannot be captured
80 : ///@todo variant were king can be captured
81 2558421 : if (toP == (p.c == Co_White ? P_bk : P_wk)) PSEUDO_LEGAL_RETURN(false, 2)
82 :
83 : // empty destination square cannot be a capture (except EP)
84 1693143 : if (toP == P_none && isCaptureNoEP(t)) PSEUDO_LEGAL_RETURN(false, 4)
85 :
86 : // none empty destination square must be capture, except for castling where it is checked later
87 : ///@todo variant ?
88 1693143 : if (toP != P_none && !isCapture(t)){
89 299 : if (!DynamicConfig::FRC){
90 299 : if (!isCastling(t)) PSEUDO_LEGAL_RETURN(false, 5)
91 : else{
92 : ;// see castling
93 : }
94 : }
95 : else{
96 0 : if (!isCastling(t)) PSEUDO_LEGAL_RETURN(false, 5)
97 : else{
98 : ;// see castling
99 : }
100 : }
101 : }
102 :
103 1693143 : const Piece fromPieceType = Abs(fromP);
104 :
105 : // EP comes from a pawn
106 1693143 : if (t == T_ep && (p.ep == INVALIDSQUARE || fromPieceType != P_wp)) PSEUDO_LEGAL_RETURN(false, 6)
107 : // EP geometry checks
108 1697109 : if (t == T_ep && p.board_const(static_cast<Square>(p.ep + (p.c == Co_White ? -8 : +8))) != (p.c == Co_White ? P_bp : P_wp)) PSEUDO_LEGAL_RETURN(false, 7)
109 :
110 : // Promotion comes from a pawn
111 1693143 : if (isPromotion(m) && fromPieceType != P_wp) PSEUDO_LEGAL_RETURN(false, 8)
112 :
113 1693143 : const BitBoard occupancy = p.occupancy();
114 :
115 597 : auto isCastlingOk = [&]<MType mt>(){
116 : // Be carefull, here rooksInit are only accessed if the corresponding p.castling is set
117 : // This way rooksInit is not INVALIDSQUARE, and thus mask[] is not out of bound
118 : // Moreover, king[] also is assumed to be not INVALIDSQUARE which is verified in readFen
119 : constexpr Color c = CastlingTraits<mt>::c;
120 299 : return t == mt &&
121 299 : (p.castling & CastlingTraits<mt>::cr) &&
122 299 : from == p.rootInfo().kingInit[c] &&
123 299 : to == p.rootInfo().rooksInit[c][CastlingTraits<mt>::ct] &&
124 299 : fromP == CastlingTraits<mt>::fromP &&
125 299 : (((BBTools::between(p.king[c], CastlingTraits<mt>::kingLanding) | CastlingTraits<mt>::kingLandingBB | BBTools::between(to, CastlingTraits<mt>::rookLanding) | CastlingTraits<mt>::rookLandingBB) &
126 299 : ~BBTools::mask[to].bbsquare & ~BBTools::mask[p.king[c]].bbsquare) &
127 896 : occupancy) == emptyBitBoard &&
128 299 : !isAttacked(p, BBTools::between(p.king[c], CastlingTraits<mt>::kingLanding) | SquareToBitboard(p.king[c]) | CastlingTraits<mt>::kingLandingBB);
129 1693143 : };
130 :
131 1693143 : if (isCastling(t)) {
132 299 : if (p.c == Co_White) {
133 238 : if (isCastlingOk.operator()<T_wqs>()) PSEUDO_LEGAL_RETURN(true, 9)
134 237 : if (isCastlingOk.operator()<T_wks>()) PSEUDO_LEGAL_RETURN(true, 10)
135 : PSEUDO_LEGAL_RETURN(false, 11)
136 : }
137 : else {
138 61 : if (isCastlingOk.operator()<T_bqs>()) PSEUDO_LEGAL_RETURN(true, 12)
139 61 : if (isCastlingOk.operator()<T_bks>()) PSEUDO_LEGAL_RETURN(true, 13)
140 : PSEUDO_LEGAL_RETURN(false, 14)
141 : }
142 : }
143 :
144 1692844 : if (fromPieceType == P_wp) {
145 : // ep must land on good square
146 373942 : if (t == T_ep && to != p.ep) PSEUDO_LEGAL_RETURN(false, 15)
147 :
148 373942 : if (t != T_ep && p.ep != INVALIDSQUARE && to == p.ep) PSEUDO_LEGAL_RETURN(false, 16)
149 : // non promotion pawn move cannot reach 8th rank
150 373942 : if (!isPromotion(m) && SQRANK(to) == PromRank[p.c]) PSEUDO_LEGAL_RETURN(false, 17)
151 : // promotion must be 8th rank
152 373942 : if (isPromotion(m) && SQRANK(to) != PromRank[p.c]) PSEUDO_LEGAL_RETURN(false, 18)
153 :
154 : // (double)pawn push must be legal
155 373942 : BitBoard validPush = BBTools::mask[from].push[p.c] & ~occupancy;
156 373942 : if ((BBTools::mask[from].push[p.c] & occupancy) == emptyBitBoard) validPush |= BBTools::mask[from].dpush[p.c] & ~occupancy;
157 373942 : if (validPush & SquareToBitboard(to)) PSEUDO_LEGAL_RETURN(true, 19)
158 :
159 : // pawn capture (including ep)
160 269067 : const BitBoard validCap = BBTools::mask[from].pawnAttack[p.c] & ~p.allPieces[p.c];
161 269067 : if ((validCap & SquareToBitboard(to)) && ((t != T_ep && toP != P_none) || (t == T_ep && to == p.ep && toP == P_none)))
162 : PSEUDO_LEGAL_RETURN(true, 20)
163 :
164 : PSEUDO_LEGAL_RETURN(false, 21)
165 : }
166 :
167 : // possible piece move (excluding king)
168 1318902 : if (fromPieceType != P_wk) {
169 980582 : if ((BBTools::pfCoverage[fromPieceType - 1](from, occupancy, p.c) & SquareToBitboard(to)) != emptyBitBoard) PSEUDO_LEGAL_RETURN(true, 22)
170 :
171 : PSEUDO_LEGAL_RETURN(false, 23)
172 : }
173 :
174 : // only king moving is not verified yet
175 338320 : if ((BBTools::mask[p.king[p.c]].kingZone & SquareToBitboard(to)) != emptyBitBoard) PSEUDO_LEGAL_RETURN(true, 24)
176 :
177 : PSEUDO_LEGAL_RETURN(false, 25)
178 : }
|