Subversion Repositories Games.Chess Giants

Rev

Rev 154 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
96 pmbaty 1
/*
2
  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3
  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
4
  Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
5
  Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
6
 
7
  Stockfish is free software: you can redistribute it and/or modify
8
  it under the terms of the GNU General Public License as published by
9
  the Free Software Foundation, either version 3 of the License, or
10
  (at your option) any later version.
11
 
12
  Stockfish is distributed in the hope that it will be useful,
13
  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
  GNU General Public License for more details.
16
 
17
  You should have received a copy of the GNU General Public License
18
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
*/
20
 
21
#include <cassert>
22
 
23
#include "movegen.h"
24
#include "position.h"
25
 
26
namespace {
27
 
28
  template<CastlingRight Cr, bool Checks, bool Chess960>
29
  ExtMove* generate_castling(const Position& pos, ExtMove* moveList, Color us, const CheckInfo* ci) {
30
 
31
    static const bool KingSide = (Cr == WHITE_OO || Cr == BLACK_OO);
32
 
33
    if (pos.castling_impeded(Cr) || !pos.can_castle(Cr))
34
        return moveList;
35
 
36
    // After castling, the rook and king final positions are the same in Chess960
37
    // as they would be in standard chess.
38
    Square kfrom = pos.square<KING>(us);
39
    Square rfrom = pos.castling_rook_square(Cr);
40
    Square kto = relative_square(us, KingSide ? SQ_G1 : SQ_C1);
41
    Bitboard enemies = pos.pieces(~us);
42
 
43
    assert(!pos.checkers());
44
 
45
    const Square K = Chess960 ? kto > kfrom ? DELTA_W : DELTA_E
46
                              : KingSide    ? DELTA_W : DELTA_E;
47
 
48
    for (Square s = kto; s != kfrom; s += K)
49
        if (pos.attackers_to(s) & enemies)
50
            return moveList;
51
 
52
    // Because we generate only legal castling moves we need to verify that
53
    // when moving the castling rook we do not discover some hidden checker.
54
    // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
55
    if (Chess960 && (attacks_bb<ROOK>(kto, pos.pieces() ^ rfrom) & pos.pieces(~us, ROOK, QUEEN)))
56
        return moveList;
57
 
58
    Move m = make<CASTLING>(kfrom, rfrom);
59
 
60
    if (Checks && !pos.gives_check(m, *ci))
61
        return moveList;
62
    else
63
        (void)ci; // Silence a warning under MSVC
64
 
65
    *moveList++ = m;
66
    return moveList;
67
  }
68
 
69
 
70
  template<GenType Type, Square Delta>
71
  ExtMove* make_promotions(ExtMove* moveList, Square to, const CheckInfo* ci) {
72
 
73
    if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
74
        *moveList++ = make<PROMOTION>(to - Delta, to, QUEEN);
75
 
76
    if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
77
    {
78
        *moveList++ = make<PROMOTION>(to - Delta, to, ROOK);
79
        *moveList++ = make<PROMOTION>(to - Delta, to, BISHOP);
80
        *moveList++ = make<PROMOTION>(to - Delta, to, KNIGHT);
81
    }
82
 
83
    // Knight promotion is the only promotion that can give a direct check
84
    // that's not already included in the queen promotion.
85
    if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ci->ksq))
86
        *moveList++ = make<PROMOTION>(to - Delta, to, KNIGHT);
87
    else
88
        (void)ci; // Silence a warning under MSVC
89
 
90
    return moveList;
91
  }
92
 
93
 
94
  template<Color Us, GenType Type>
95
  ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList,
96
                               Bitboard target, const CheckInfo* ci) {
97
 
98
    // Compute our parametrized parameters at compile time, named according to
99
    // the point of view of white side.
100
    const Color    Them     = (Us == WHITE ? BLACK    : WHITE);
101
    const Bitboard TRank8BB = (Us == WHITE ? Rank8BB  : Rank1BB);
102
    const Bitboard TRank7BB = (Us == WHITE ? Rank7BB  : Rank2BB);
103
    const Bitboard TRank3BB = (Us == WHITE ? Rank3BB  : Rank6BB);
104
    const Square   Up       = (Us == WHITE ? DELTA_N  : DELTA_S);
105
    const Square   Right    = (Us == WHITE ? DELTA_NE : DELTA_SW);
106
    const Square   Left     = (Us == WHITE ? DELTA_NW : DELTA_SE);
107
 
108
    Bitboard emptySquares;
109
 
110
    Bitboard pawnsOn7    = pos.pieces(Us, PAWN) &  TRank7BB;
111
    Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
112
 
113
    Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target:
114
                        Type == CAPTURES ? target : pos.pieces(Them));
115
 
116
    // Single and double pawn pushes, no promotions
117
    if (Type != CAPTURES)
118
    {
119
        emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
120
 
121
        Bitboard b1 = shift_bb<Up>(pawnsNotOn7)   & emptySquares;
122
        Bitboard b2 = shift_bb<Up>(b1 & TRank3BB) & emptySquares;
123
 
124
        if (Type == EVASIONS) // Consider only blocking squares
125
        {
126
            b1 &= target;
127
            b2 &= target;
128
        }
129
 
130
        if (Type == QUIET_CHECKS)
131
        {
132
            b1 &= pos.attacks_from<PAWN>(ci->ksq, Them);
133
            b2 &= pos.attacks_from<PAWN>(ci->ksq, Them);
134
 
135
            // Add pawn pushes which give discovered check. This is possible only
136
            // if the pawn is not on the same file as the enemy king, because we
137
            // don't generate captures. Note that a possible discovery check
138
            // promotion has been already generated amongst the captures.
139
            if (pawnsNotOn7 & ci->dcCandidates)
140
            {
141
                Bitboard dc1 = shift_bb<Up>(pawnsNotOn7 & ci->dcCandidates) & emptySquares & ~file_bb(ci->ksq);
142
                Bitboard dc2 = shift_bb<Up>(dc1 & TRank3BB) & emptySquares;
143
 
144
                b1 |= dc1;
145
                b2 |= dc2;
146
            }
147
        }
148
 
149
        while (b1)
150
        {
151
            Square to = pop_lsb(&b1);
152
            *moveList++ = make_move(to - Up, to);
153
        }
154
 
155
        while (b2)
156
        {
157
            Square to = pop_lsb(&b2);
158
            *moveList++ = make_move(to - Up - Up, to);
159
        }
160
    }
161
 
162
    // Promotions and underpromotions
163
    if (pawnsOn7 && (Type != EVASIONS || (target & TRank8BB)))
164
    {
165
        if (Type == CAPTURES)
166
            emptySquares = ~pos.pieces();
167
 
168
        if (Type == EVASIONS)
169
            emptySquares &= target;
170
 
171
        Bitboard b1 = shift_bb<Right>(pawnsOn7) & enemies;
172
        Bitboard b2 = shift_bb<Left >(pawnsOn7) & enemies;
173
        Bitboard b3 = shift_bb<Up   >(pawnsOn7) & emptySquares;
174
 
175
        while (b1)
176
            moveList = make_promotions<Type, Right>(moveList, pop_lsb(&b1), ci);
177
 
178
        while (b2)
179
            moveList = make_promotions<Type, Left >(moveList, pop_lsb(&b2), ci);
180
 
181
        while (b3)
182
            moveList = make_promotions<Type, Up   >(moveList, pop_lsb(&b3), ci);
183
    }
184
 
185
    // Standard and en-passant captures
186
    if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
187
    {
188
        Bitboard b1 = shift_bb<Right>(pawnsNotOn7) & enemies;
189
        Bitboard b2 = shift_bb<Left >(pawnsNotOn7) & enemies;
190
 
191
        while (b1)
192
        {
193
            Square to = pop_lsb(&b1);
194
            *moveList++ = make_move(to - Right, to);
195
        }
196
 
197
        while (b2)
198
        {
199
            Square to = pop_lsb(&b2);
200
            *moveList++ = make_move(to - Left, to);
201
        }
202
 
203
        if (pos.ep_square() != SQ_NONE)
204
        {
205
            assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6));
206
 
207
            // An en passant capture can be an evasion only if the checking piece
208
            // is the double pushed pawn and so is in the target. Otherwise this
209
            // is a discovery check and we are forced to do otherwise.
210
            if (Type == EVASIONS && !(target & (pos.ep_square() - Up)))
211
                return moveList;
212
 
213
            b1 = pawnsNotOn7 & pos.attacks_from<PAWN>(pos.ep_square(), Them);
214
 
215
            assert(b1);
216
 
217
            while (b1)
218
                *moveList++ = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square());
219
        }
220
    }
221
 
222
    return moveList;
223
  }
224
 
225
 
226
  template<PieceType Pt, bool Checks>
227
  ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us,
228
                          Bitboard target, const CheckInfo* ci) {
229
 
230
    assert(Pt != KING && Pt != PAWN);
231
 
232
    const Square* pl = pos.squares<Pt>(us);
233
 
234
    for (Square from = *pl; from != SQ_NONE; from = *++pl)
235
    {
236
        if (Checks)
237
        {
238
            if (    (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
239
                && !(PseudoAttacks[Pt][from] & target & ci->checkSquares[Pt]))
240
                continue;
241
 
242
            if (ci->dcCandidates && (ci->dcCandidates & from))
243
                continue;
244
        }
245
 
246
        Bitboard b = pos.attacks_from<Pt>(from) & target;
247
 
248
        if (Checks)
249
            b &= ci->checkSquares[Pt];
250
 
251
        while (b)
252
            *moveList++ = make_move(from, pop_lsb(&b));
253
    }
254
 
255
    return moveList;
256
  }
257
 
258
 
259
  template<Color Us, GenType Type>
260
  ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target,
261
                        const CheckInfo* ci = nullptr) {
262
 
263
    const bool Checks = Type == QUIET_CHECKS;
264
 
265
    moveList = generate_pawn_moves<Us, Type>(pos, moveList, target, ci);
266
    moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target, ci);
267
    moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target, ci);
268
    moveList = generate_moves<  ROOK, Checks>(pos, moveList, Us, target, ci);
269
    moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target, ci);
270
 
271
    if (Type != QUIET_CHECKS && Type != EVASIONS)
272
    {
273
        Square ksq = pos.square<KING>(Us);
274
        Bitboard b = pos.attacks_from<KING>(ksq) & target;
275
        while (b)
276
            *moveList++ = make_move(ksq, pop_lsb(&b));
277
    }
278
 
279
    if (Type != CAPTURES && Type != EVASIONS && pos.can_castle(Us))
280
    {
281
        if (pos.is_chess960())
282
        {
283
            moveList = generate_castling<MakeCastling<Us,  KING_SIDE>::right, Checks, true>(pos, moveList, Us, ci);
284
            moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, true>(pos, moveList, Us, ci);
285
        }
286
        else
287
        {
288
            moveList = generate_castling<MakeCastling<Us,  KING_SIDE>::right, Checks, false>(pos, moveList, Us, ci);
289
            moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, false>(pos, moveList, Us, ci);
290
        }
291
    }
292
 
293
    return moveList;
294
  }
295
 
296
} // namespace
297
 
298
 
299
/// generate<CAPTURES> generates all pseudo-legal captures and queen
300
/// promotions. Returns a pointer to the end of the move list.
301
///
302
/// generate<QUIETS> generates all pseudo-legal non-captures and
303
/// underpromotions. Returns a pointer to the end of the move list.
304
///
305
/// generate<NON_EVASIONS> generates all pseudo-legal captures and
306
/// non-captures. Returns a pointer to the end of the move list.
307
 
308
template<GenType Type>
309
ExtMove* generate(const Position& pos, ExtMove* moveList) {
310
 
311
  assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS);
312
  assert(!pos.checkers());
313
 
314
  Color us = pos.side_to_move();
315
 
316
  Bitboard target =  Type == CAPTURES     ?  pos.pieces(~us)
317
                   : Type == QUIETS       ? ~pos.pieces()
318
                   : Type == NON_EVASIONS ? ~pos.pieces(us) : 0;
319
 
320
  return us == WHITE ? generate_all<WHITE, Type>(pos, moveList, target)
321
                     : generate_all<BLACK, Type>(pos, moveList, target);
322
}
323
 
324
// Explicit template instantiations
325
template ExtMove* generate<CAPTURES>(const Position&, ExtMove*);
326
template ExtMove* generate<QUIETS>(const Position&, ExtMove*);
327
template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
328
 
329
 
330
/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight
331
/// underpromotions that give check. Returns a pointer to the end of the move list.
332
template<>
333
ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
334
 
335
  assert(!pos.checkers());
336
 
337
  Color us = pos.side_to_move();
338
  CheckInfo ci(pos);
339
  Bitboard dc = ci.dcCandidates;
340
 
341
  while (dc)
342
  {
343
     Square from = pop_lsb(&dc);
344
     PieceType pt = type_of(pos.piece_on(from));
345
 
346
     if (pt == PAWN)
347
         continue; // Will be generated together with direct checks
348
 
349
     Bitboard b = pos.attacks_from(Piece(pt), from) & ~pos.pieces();
350
 
351
     if (pt == KING)
352
         b &= ~PseudoAttacks[QUEEN][ci.ksq];
353
 
354
     while (b)
355
         *moveList++ = make_move(from, pop_lsb(&b));
356
  }
357
 
358
  return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList, ~pos.pieces(), &ci)
359
                     : generate_all<BLACK, QUIET_CHECKS>(pos, moveList, ~pos.pieces(), &ci);
360
}
361
 
362
 
363
/// generate<EVASIONS> generates all pseudo-legal check evasions when the side
364
/// to move is in check. Returns a pointer to the end of the move list.
365
template<>
366
ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* moveList) {
367
 
368
  assert(pos.checkers());
369
 
370
  Color us = pos.side_to_move();
371
  Square ksq = pos.square<KING>(us);
372
  Bitboard sliderAttacks = 0;
373
  Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN);
374
 
375
  // Find all the squares attacked by slider checkers. We will remove them from
376
  // the king evasions in order to skip known illegal moves, which avoids any
377
  // useless legality checks later on.
378
  while (sliders)
379
  {
380
      Square checksq = pop_lsb(&sliders);
381
      sliderAttacks |= LineBB[checksq][ksq] ^ checksq;
382
  }
383
 
384
  // Generate evasions for king, capture and non capture moves
385
  Bitboard b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
386
  while (b)
387
      *moveList++ = make_move(ksq, pop_lsb(&b));
388
 
389
  if (more_than_one(pos.checkers()))
390
      return moveList; // Double check, only a king move can save the day
391
 
392
  // Generate blocking evasions or captures of the checking piece
393
  Square checksq = lsb(pos.checkers());
394
  Bitboard target = between_bb(checksq, ksq) | checksq;
395
 
396
  return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, moveList, target)
397
                     : generate_all<BLACK, EVASIONS>(pos, moveList, target);
398
}
399
 
400
 
401
/// generate<LEGAL> generates all the legal moves in the given position
402
 
403
template<>
404
ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
405
 
406
  Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
407
  Square ksq = pos.square<KING>(pos.side_to_move());
408
  ExtMove* cur = moveList;
409
 
410
  moveList = pos.checkers() ? generate<EVASIONS    >(pos, moveList)
411
                            : generate<NON_EVASIONS>(pos, moveList);
412
  while (cur != moveList)
413
      if (   (pinned || from_sq(*cur) == ksq || type_of(*cur) == ENPASSANT)
414
          && !pos.legal(*cur, pinned))
415
          *cur = (--moveList)->move;
416
      else
417
          ++cur;
418
 
419
  return moveList;
420
}