Subversion Repositories Games.Chess Giants

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 pmbaty 1
/*
2
    Texel - A UCI chess engine.
3
    Copyright (C) 2012-2014  Peter Ă–sterlund, peterosterlund2@gmail.com
4
 
5
    This program is free software: you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License as published by
7
    the Free Software Foundation, either version 3 of the License, or
8
    (at your option) any later version.
9
 
10
    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    GNU General Public License for more details.
14
 
15
    You should have received a copy of the GNU General Public License
16
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18
 
19
/*
20
 * moveGen.hpp
21
 *
22
 *  Created on: Feb 25, 2012
23
 *      Author: petero
24
 */
25
 
26
#ifndef MOVEGEN_HPP_
27
#define MOVEGEN_HPP_
28
 
29
#include "move.hpp"
30
#include "position.hpp"
31
#include "util/util.hpp"
32
 
33
#include <cassert>
34
 
35
//#define MOVELIST_DEBUG
36
 
37
#ifdef MOVELIST_DEBUG
38
# include <set>
39
# include "textio.hpp"
40
#endif
41
 
42
/** A stack-allocated move list object. */
43
class MoveList {
44
public:
45
    MoveList();
46
 
47
    void clear();
48
 
49
          Move& operator[](int i);
50
    const Move& operator[](int i) const;
51
 
52
    void addMove(int from, int to, int promoteTo);
53
 
54
    /** Remove all moves that are not included in searchMoves. */
55
    void filter(const std::vector<Move>& searchMoves);
56
 
57
    int size;
58
 
59
private:
60
    static const int MAX_MOVES = 256;
61
    int buf[sizeof(Move[MAX_MOVES])/sizeof(int)];
62
};
63
 
64
/**
65
 * Generates move lists (pseudo-legal, legal, check evasions, captures).
66
 */
67
class MoveGen {
68
public:
69
    MoveGen() = delete;
70
 
71
    /**
72
     * Generate and return a list of pseudo-legal moves.
73
     * Pseudo-legal means that the moves don't necessarily defend from check threats.
74
     */
75
    template <bool wtm>
76
    static void pseudoLegalMoves(const Position& pos, MoveList& moveList);
77
    static void pseudoLegalMoves(const Position& pos, MoveList& moveList);
78
 
79
    /**
80
     * Generate and return a list of pseudo-legal check evasion moves.
81
     * Pseudo-legal means that the moves don't necessarily defend from check threats.
82
     */
83
    template <bool wtm>
84
    static void checkEvasions(const Position& pos, MoveList& moveList);
85
    static void checkEvasions(const Position& pos, MoveList& moveList);
86
 
87
    /** Generate captures, checks, and possibly some other moves that are too hard to filter out. */
88
    template <bool wtm>
89
    static void pseudoLegalCapturesAndChecks(const Position& pos, MoveList& moveList);
90
    static void pseudoLegalCapturesAndChecks(const Position& pos, MoveList& moveList);
91
 
92
    /** Generate and return a list of pseudo-legal capture moves. */
93
    template <bool wtm>
94
    static void pseudoLegalCaptures(const Position& pos, MoveList& moveList);
95
    static void pseudoLegalCaptures(const Position& pos, MoveList& moveList);
96
 
97
    /** Return true if the side to move is in check. */
98
    static bool inCheck(const Position& pos);
99
 
100
    /** Return true if making a move delivers check to the opponent */
101
    static bool givesCheck(const Position& pos, const Move& m);
102
 
103
    /** Return true if the side to move can take the opponents king. */
104
    static bool canTakeKing(Position& pos);
105
 
106
    /** Return true if a square is attacked by the opposite side. */
107
    static bool sqAttacked(const Position& pos, int sq);
108
    static bool sqAttacked(const Position& pos, int sq, U64 occupied);
109
    template <bool wtm> static bool sqAttacked(const Position& pos, int sq, U64 occupied);
110
 
111
    /**
112
     * Remove all illegal moves from moveList.
113
     * "moveList" is assumed to be a list of pseudo-legal moves.
114
     * This function removes the moves that don't defend from check threats.
115
     */
116
    static void removeIllegal(Position& pos, MoveList& moveList);
117
 
118
    /** Return true if the pseudo-legal move "move" is legal is position "pos".
119
     * isInCheck must be equal to inCheck(pos). */
120
    static bool isLegal(Position& pos, const Move& move, bool isInCheck);
121
 
122
private:
123
    /** Return the next piece in a given direction, starting from sq. */
124
    static int nextPiece(const Position& pos, int sq, int delta);
125
 
126
    /** Like nextPiece(), but handles board edges. */
127
    static int nextPieceSafe(const Position& pos, int sq, int delta);
128
 
129
    template <bool wtm>
130
    static void addPawnMovesByMask(MoveList& moveList, U64 mask, int delta, bool allPromotions);
131
 
132
    static void addPawnDoubleMovesByMask(MoveList& moveList, U64 mask, int delta);
133
 
134
    static void addMovesByMask(MoveList& moveList, int sq0, U64 mask);
135
};
136
 
137
 
138
inline
139
MoveList::MoveList()
140
    : size(0) {
141
}
142
 
143
inline void
144
MoveList::clear() {
145
    size = 0;
146
}
147
 
148
inline Move&
149
MoveList::operator[](int i) {
150
    return ((Move*)&buf[0])[i];
151
}
152
inline const Move&
153
MoveList::operator[](int i) const {
154
    return ((Move*)&buf[0])[i];
155
}
156
 
157
inline void
158
MoveList::addMove(int from, int to, int promoteTo) {
159
    Move& m = (*this)[size++];
160
    new (&m) Move(from, to, promoteTo, 0);
161
}
162
 
163
inline void
164
MoveGen::pseudoLegalMoves(const Position& pos, MoveList& moveList) {
165
    if (pos.isWhiteMove())
166
        pseudoLegalMoves<true>(pos, moveList);
167
    else
168
        pseudoLegalMoves<false>(pos, moveList);
169
}
170
 
171
inline void
172
MoveGen::checkEvasions(const Position& pos, MoveList& moveList) {
173
    if (pos.isWhiteMove())
174
        checkEvasions<true>(pos, moveList);
175
    else
176
        checkEvasions<false>(pos, moveList);
177
}
178
 
179
inline void
180
MoveGen::pseudoLegalCapturesAndChecks(const Position& pos, MoveList& moveList) {
181
    if (pos.isWhiteMove())
182
        pseudoLegalCapturesAndChecks<true>(pos, moveList);
183
    else
184
        pseudoLegalCapturesAndChecks<false>(pos, moveList);
185
}
186
 
187
inline void
188
MoveGen::pseudoLegalCaptures(const Position& pos, MoveList& moveList) {
189
    if (pos.isWhiteMove())
190
        pseudoLegalCaptures<true>(pos, moveList);
191
    else
192
        pseudoLegalCaptures<false>(pos, moveList);
193
}
194
 
195
inline bool
196
MoveGen::inCheck(const Position& pos) {
197
    int kingSq = pos.getKingSq(pos.isWhiteMove());
198
    return sqAttacked(pos, kingSq);
199
}
200
 
201
inline bool
202
MoveGen::canTakeKing(Position& pos) {
203
    pos.setWhiteMove(!pos.isWhiteMove());
204
    bool ret = inCheck(pos);
205
    pos.setWhiteMove(!pos.isWhiteMove());
206
    return ret;
207
}
208
 
209
inline bool
210
MoveGen::sqAttacked(const Position& pos, int sq) {
211
    const U64 occupied = pos.occupiedBB();
212
    return sqAttacked(pos, sq, occupied);
213
}
214
 
215
inline bool
216
MoveGen::sqAttacked(const Position& pos, int sq, U64 occupied) {
217
    return pos.isWhiteMove() ? sqAttacked<true>(pos, sq, occupied)
218
                             : sqAttacked<false>(pos, sq, occupied);
219
}
220
 
221
template <bool wtm>
222
inline bool
223
MoveGen::sqAttacked(const Position& pos, int sq, U64 occupied) {
224
    using OtherColor = ColorTraits<!wtm>;
225
    if ((BitBoard::knightAttacks[sq] & pos.pieceTypeBB(OtherColor::KNIGHT)) != 0)
226
        return true;
227
    if ((BitBoard::kingAttacks[sq] & pos.pieceTypeBB(OtherColor::KING)) != 0)
228
        return true;
229
    if (wtm) {
230
        if ((BitBoard::wPawnAttacks[sq] & pos.pieceTypeBB(OtherColor::PAWN)) != 0)
231
            return true;
232
    } else {
233
        if ((BitBoard::bPawnAttacks[sq] & pos.pieceTypeBB(OtherColor::PAWN)) != 0)
234
            return true;
235
    }
236
    U64 bbQueen = pos.pieceTypeBB(OtherColor::QUEEN);
237
    if ((BitBoard::bishopAttacks(sq, occupied) & (pos.pieceTypeBB(OtherColor::BISHOP) | bbQueen)) != 0)
238
        return true;
239
    if ((BitBoard::rookAttacks(sq, occupied) & (pos.pieceTypeBB(OtherColor::ROOK) | bbQueen)) != 0)
240
        return true;
241
    return false;
242
}
243
 
244
inline int
245
MoveGen::nextPiece(const Position& pos, int sq, int delta) {
246
    while (true) {
247
        sq += delta;
248
        int p = pos.getPiece(sq);
249
        if (p != Piece::EMPTY)
250
            return p;
251
    }
252
    assert(false);
253
    return -1;
254
}
255
 
256
inline int
257
MoveGen::nextPieceSafe(const Position& pos, int sq, int delta) {
258
    int dx = 0, dy = 0;
259
    switch (delta) {
260
    case 1: dx=1; dy=0; break;
261
    case 9: dx=1; dy=1; break;
262
    case 8: dx=0; dy=1; break;
263
    case 7: dx=-1; dy=1; break;
264
    case -1: dx=-1; dy=0; break;
265
    case -9: dx=-1; dy=-1; break;
266
    case -8: dx=0; dy=-1; break;
267
    case -7: dx=1; dy=-1; break;
268
    }
269
    int x = Position::getX(sq);
270
    int y = Position::getY(sq);
271
    while (true) {
272
        x += dx;
273
        y += dy;
274
        if ((x < 0) || (x > 7) || (y < 0) || (y > 7)) {
275
            return Piece::EMPTY;
276
        }
277
        int p = pos.getPiece(Position::getSquare(x, y));
278
        if (p != Piece::EMPTY)
279
            return p;
280
    }
281
    assert(false);
282
    return -1;
283
}
284
 
285
template <bool wtm>
286
inline void
287
MoveGen::addPawnMovesByMask(MoveList& moveList, U64 mask, int delta, bool allPromotions) {
288
    using MyColor = ColorTraits<wtm>;
289
    if (mask == 0)
290
        return;
291
    U64 promMask = mask & BitBoard::maskRow1Row8;
292
    mask &= ~promMask;
293
    while (promMask != 0) {
294
        int sq = BitBoard::extractSquare(promMask);
295
        int sq0 = sq + delta;
296
        moveList.addMove(sq0, sq, MyColor::QUEEN);
297
        moveList.addMove(sq0, sq, MyColor::KNIGHT);
298
        if (allPromotions) {
299
            moveList.addMove(sq0, sq, MyColor::ROOK);
300
            moveList.addMove(sq0, sq, MyColor::BISHOP);
301
        }
302
    }
303
    while (mask != 0) {
304
        int sq = BitBoard::extractSquare(mask);
305
        moveList.addMove(sq + delta, sq, Piece::EMPTY);
306
    }
307
}
308
 
309
inline void
310
MoveGen::addPawnDoubleMovesByMask(MoveList& moveList, U64 mask, int delta) {
311
    while (mask != 0) {
312
        int sq = BitBoard::extractSquare(mask);
313
        moveList.addMove(sq + delta, sq, Piece::EMPTY);
314
    }
315
}
316
 
317
inline void
318
MoveGen::addMovesByMask(MoveList& moveList, int sq0, U64 mask) {
319
    while (mask != 0) {
320
        int sq = BitBoard::extractSquare(mask);
321
        moveList.addMove(sq0, sq, Piece::EMPTY);
322
    }
323
}
324
 
325
#endif /* MOVEGEN_HPP_ */