Subversion Repositories Games.Chess Giants

Rev

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