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
 * endGameEval.cpp
21
 *
22
 *  Created on: Dec 26, 2014
23
 *      Author: petero
24
 */
25
 
26
#include "endGameEval.hpp"
27
#include "position.hpp"
28
#include "piece.hpp"
29
#include "parameters.hpp"
30
 
31
const int EndGameEval::distToH1A8[8][8] = { { 0, 1, 2, 3, 4, 5, 6, 7 },
32
                                            { 1, 2, 3, 4, 5, 6, 7, 6 },
33
                                            { 2, 3, 4, 5, 6, 7, 6, 5 },
34
                                            { 3, 4, 5, 6, 7, 6, 5, 4 },
35
                                            { 4, 5, 6, 7, 6, 5, 4, 3 },
36
                                            { 5, 6, 7, 6, 5, 4, 3, 2 },
37
                                            { 6, 7, 6, 5, 4, 3, 2, 1 },
38
                                            { 7, 6, 5, 4, 3, 2, 1, 0 } };
39
 
40
const int EndGameEval::winKingTable[64] = {
41
    0,   4,  10,  10,  10,  10,   4,   0,
42
    4,  15,  19,  20,  20,  19,  15,   4,
43
   10,  19,  25,  25,  25,  25,  19,  10,
44
   10,  20,  25,  25,  25,  25,  20,  10,
45
   10,  20,  25,  25,  25,  25,  20,  10,
46
   10,  19,  25,  25,  25,  25,  19,  10,
47
    4,  15,  19,  20,  20,  19,  15,   4,
48
    0,   4,  10,  10,  10,  10,   4,   0
49
};
50
 
51
 
52
template int EndGameEval::endGameEval<false>(const Position&, U64, int);
53
template int EndGameEval::endGameEval<true>(const Position&, U64, int);
54
 
55
/** Implements special knowledge for some endgame situations. */
56
template <bool doEval>
57
int
58
EndGameEval::endGameEval(const Position& pos, U64 passedPawns, int oldScore) {
59
    int score = oldScore;
60
    const int wMtrlPawns = pos.wMtrlPawns();
61
    const int bMtrlPawns = pos.bMtrlPawns();
62
    const int wMtrlNoPawns = pos.wMtrl() - wMtrlPawns;
63
    const int bMtrlNoPawns = pos.bMtrl() - bMtrlPawns;
64
 
65
    // Handle special endgames
66
    using MI = MatId;
67
    switch (pos.materialId()) {
68
    case 0:
69
    case MI::WN: case MI::BN: case MI::WB: case MI::BB:
70
    case MI::WN + MI::BN: case MI::WN + MI::BB:
71
    case MI::WB + MI::BN: case MI::WB + MI::BB:
72
        if (!doEval) return 1;
73
        return 0; // King + minor piece vs king + minor piece is a draw
74
    case MI::WQ + MI::BP: {
75
        if (!doEval) return 1;
76
        int wk = pos.getKingSq(true);
77
        int wq = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WQUEEN));
78
        int bk = pos.getKingSq(false);
79
        int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
80
        return kqkpEval(wk, wq, bk, bp, pos.isWhiteMove(), score);
81
    }
82
    case MI::BQ + MI::WP: {
83
        if (!doEval) return 1;
84
        int bk = pos.getKingSq(false);
85
        int bq = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BQUEEN));
86
        int wk = pos.getKingSq(true);
87
        int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
88
        return -kqkpEval(63-bk, 63-bq, 63-wk, 63-wp, !pos.isWhiteMove(), -score);
89
    }
90
    case MI::WQ: {
91
        if (!doEval) return 1;
92
        if (!pos.isWhiteMove() &&
93
            (pos.pieceTypeBB(Piece::BKING) & BitBoard::maskCorners) &&
94
            (pos.pieceTypeBB(Piece::WQUEEN) & BitBoard::sqMask(C2,B3,F2,G3,B6,C7,G6,F7)) &&
95
            (BitBoard::getTaxiDistance(pos.getKingSq(false),
96
                                       BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WQUEEN))) == 3))
97
            return 0;
98
        break;
99
    }
100
    case MI::BQ: {
101
        if (!doEval) return 1;
102
        if (pos.isWhiteMove() &&
103
            (pos.pieceTypeBB(Piece::WKING) & BitBoard::maskCorners) &&
104
            (pos.pieceTypeBB(Piece::BQUEEN) & BitBoard::sqMask(C2,B3,F2,G3,B6,C7,G6,F7)) &&
105
            (BitBoard::getTaxiDistance(pos.getKingSq(true),
106
                                       BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BQUEEN))) == 3))
107
            return 0;
108
        break;
109
    }
110
    case MI::WR + MI::BP: {
111
        if (!doEval) return 1;
112
        int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
113
        return krkpEval(pos.getKingSq(true), pos.getKingSq(false),
114
                        bp, pos.isWhiteMove(), score);
115
    }
116
    case MI::BR + MI::WP: {
117
        if (!doEval) return 1;
118
        int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
119
        return -krkpEval(63-pos.getKingSq(false), 63-pos.getKingSq(true),
120
                         63-wp, !pos.isWhiteMove(), -score);
121
    }
122
    case MI::WR + MI::BB: {
123
        if (!doEval) return 1;
124
        score /= 8;
125
        const int kSq = pos.getKingSq(false);
126
        const int x = Position::getX(kSq);
127
        const int y = Position::getY(kSq);
128
        if ((pos.pieceTypeBB(Piece::BBISHOP) & BitBoard::maskDarkSq) != 0)
129
            score += (7 - distToH1A8[7-y][7-x]) * 7;
130
        else
131
            score += (7 - distToH1A8[7-y][x]) * 7;
132
        return score;
133
    }
134
    case MI::BR + MI::WB: {
135
        if (!doEval) return 1;
136
        score /= 8;
137
        const int kSq = pos.getKingSq(true);
138
        const int x = Position::getX(kSq);
139
        const int y = Position::getY(kSq);
140
        if ((pos.pieceTypeBB(Piece::WBISHOP) & BitBoard::maskDarkSq) != 0)
141
            score -= (7 - distToH1A8[7-y][7-x]) * 7;
142
        else
143
            score -= (7 - distToH1A8[7-y][x]) * 7;
144
        return score;
145
    }
146
    case MI::WR + MI::WP + MI::BR: {
147
        if (!doEval) return 1;
148
        int wk = pos.getKingSq(true);
149
        int bk = pos.getKingSq(false);
150
        int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
151
        int wr = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WROOK));
152
        int br = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BROOK));
153
        return krpkrEval(wk, bk, wp, wr, br, pos.isWhiteMove());
154
    }
155
    case MI::BR + MI::BP + MI::WR: {
156
        if (!doEval) return 1;
157
        int wk = pos.getKingSq(true);
158
        int bk = pos.getKingSq(false);
159
        int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
160
        int wr = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WROOK));
161
        int br = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BROOK));
162
        return -krpkrEval(63-bk, 63-wk, 63-bp, 63-br, 63-wr, !pos.isWhiteMove());
163
    }
164
    case MI::WR + MI::WP + MI::BR + MI::BP: {
165
        if (!doEval) return 1;
166
        int wk = pos.getKingSq(true);
167
        int bk = pos.getKingSq(false);
168
        int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
169
        int wr = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WROOK));
170
        int br = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BROOK));
171
        int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
172
        return krpkrpEval(wk, bk, wp, wr, br, bp, pos.isWhiteMove(), score);
173
    }
174
    case MI::WN * 2:
175
    case MI::BN * 2:
176
        if (!doEval) return 1;
177
        return 0; // KNNK is a draw
178
    case MI::WN + MI::WB: {
179
        if (!doEval) return 1;
180
        bool darkBishop = (pos.pieceTypeBB(Piece::WBISHOP) & BitBoard::maskDarkSq) != 0;
181
        return kbnkEval(pos.getKingSq(true), pos.getKingSq(false), darkBishop);
182
    }
183
    case MI::BN + MI::BB: {
184
        if (!doEval) return 1;
185
        bool darkBishop = (pos.pieceTypeBB(Piece::BBISHOP) & BitBoard::maskDarkSq) != 0;
186
        return -kbnkEval(63-pos.getKingSq(false), 63-pos.getKingSq(true), darkBishop);
187
    }
188
    case MI::WP: {
189
        if (!doEval) return 1;
190
        int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
191
        return kpkEval(pos.getKingSq(true), pos.getKingSq(false),
192
                       wp, pos.isWhiteMove());
193
    }
194
    case MI::BP: {
195
        if (!doEval) return 1;
196
        int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
197
        return -kpkEval(63-pos.getKingSq(false), 63-pos.getKingSq(true),
198
                        63-bp, !pos.isWhiteMove());
199
    }
200
    case MI::WP + MI::BP: {
201
        if (!doEval) return 1;
202
        int wk = pos.getKingSq(true);
203
        int bk = pos.getKingSq(false);
204
        int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
205
        int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
206
        if (kpkpEval(wk, bk, wp, bp, score))
207
            return score;
208
        break;
209
    }
210
    case MI::WB + MI::WP + MI::BB: {
211
        if (!doEval) return 1;
212
        int wb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WBISHOP));
213
        int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
214
        int bb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BBISHOP));
215
        return kbpkbEval(pos.getKingSq(true), wb, wp, pos.getKingSq(false), bb, score);
216
    }
217
    case MI::BB + MI::BP + MI::WB: {
218
        if (!doEval) return 1;
219
        int bb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BBISHOP));
220
        int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
221
        int wb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WBISHOP));
222
        return -kbpkbEval(63-pos.getKingSq(false), 63-bb, 63-bp, 63-pos.getKingSq(true), 63-wb, -score);
223
    }
224
    case MI::WB + MI::WP + MI::BN: {
225
        if (!doEval) return 1;
226
        int wb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WBISHOP));
227
        int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
228
        int bn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BKNIGHT));
229
        return kbpknEval(pos.getKingSq(true), wb, wp, pos.getKingSq(false), bn, score);
230
    }
231
    case MI::BB + MI::BP + MI::WN: {
232
        if (!doEval) return 1;
233
        int bb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BBISHOP));
234
        int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
235
        int wn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WKNIGHT));
236
        return -kbpknEval(63-pos.getKingSq(false), 63-bb, 63-bp, 63-pos.getKingSq(true), 63-wn, -score);
237
    }
238
    case MI::WN + MI::WP + MI::BB: {
239
        if (!doEval) return 1;
240
        int wn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WKNIGHT));
241
        int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
242
        int bb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BBISHOP));
243
        return knpkbEval(pos.getKingSq(true), wn, wp, pos.getKingSq(false), bb,
244
                         score, pos.isWhiteMove());
245
    }
246
    case MI::BN + MI::BP + MI::WB: {
247
        if (!doEval) return 1;
248
        int bn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BKNIGHT));
249
        int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
250
        int wb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WBISHOP));
251
        return -knpkbEval(63-pos.getKingSq(false), 63-bn, 63-bp, 63-pos.getKingSq(true), 63-wb,
252
                          -score, !pos.isWhiteMove());
253
    }
254
    case MI::WN + MI::WP: {
255
        if (!doEval) return 1;
256
        int wn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WKNIGHT));
257
        int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
258
        return knpkEval(pos.getKingSq(true), wn, wp, pos.getKingSq(false),
259
                        score, pos.isWhiteMove());
260
    }
261
    case MI::BN + MI::BP: {
262
        if (!doEval) return 1;
263
        int bn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BKNIGHT));
264
        int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
265
        return -knpkEval(63-pos.getKingSq(false), 63-bn, 63-bp, 63-pos.getKingSq(true),
266
                         -score, !pos.isWhiteMove());
267
    }
268
    }
269
 
270
    // QvsRP fortress detection
271
    if (pos.pieceTypeBB(Piece::WQUEEN) && (pos.wMtrl() == qV) &&
272
        pos.pieceTypeBB(Piece::BROOK) && pos.pieceTypeBB(Piece::BPAWN) &&
273
        (pos.bMtrl() - pos.bMtrlPawns() < rV * 2)) {
274
        if (!doEval) return 1;
275
        if (score > 0) {
276
            int wk = pos.getKingSq(true);
277
            int wq = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WQUEEN));
278
            int bk = pos.getKingSq(false);
279
            int br = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BROOK));
280
            U64 m = pos.pieceTypeBB(Piece::BPAWN);
281
            int newScore = score;
282
            while (m) {
283
                int bp = BitBoard::extractSquare(m);
284
                int s2 = kqkrpEval(wk, wq, bk, br, bp, pos.isWhiteMove(), score);
285
                newScore = std::min(newScore, s2);
286
            }
287
            if (newScore < score)
288
                return newScore;
289
        }
290
    }
291
    if (pos.pieceTypeBB(Piece::BQUEEN) && (pos.bMtrl() == qV) &&
292
        pos.pieceTypeBB(Piece::WROOK) && pos.pieceTypeBB(Piece::WPAWN) &&
293
        (pos.wMtrl() - pos.wMtrlPawns() < rV * 2)) {
294
        if (!doEval) return 1;
295
        if (score < 0) {
296
            int bk = pos.getKingSq(false);
297
            int bq = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BQUEEN));
298
            int wk = pos.getKingSq(true);
299
            int wr = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WROOK));
300
            U64 m = pos.pieceTypeBB(Piece::WPAWN);
301
            int newScore = score;
302
            while (m) {
303
                int wp = BitBoard::extractSquare(m);
304
                int s2 = -kqkrpEval(63-bk, 63-bq, 63-wk, 63-wr, 63-wp, !pos.isWhiteMove(), -score);
305
                newScore = std::max(newScore, s2);
306
            }
307
            if (newScore > score)
308
                return newScore;
309
        }
310
    }
311
 
312
    const int nWN = BitBoard::bitCount(pos.pieceTypeBB(Piece::WKNIGHT));
313
    const int nBN = BitBoard::bitCount(pos.pieceTypeBB(Piece::BKNIGHT));
314
    const int nWB1 = BitBoard::bitCount(pos.pieceTypeBB(Piece::WBISHOP) & BitBoard::maskLightSq);
315
    const int nWB2 = BitBoard::bitCount(pos.pieceTypeBB(Piece::WBISHOP) & BitBoard::maskDarkSq);
316
    const int nBB1 = BitBoard::bitCount(pos.pieceTypeBB(Piece::BBISHOP) & BitBoard::maskLightSq);
317
    const int nBB2 = BitBoard::bitCount(pos.pieceTypeBB(Piece::BBISHOP) & BitBoard::maskDarkSq);
318
    const int qV = ::qV;
319
 
320
    if (pos.materialId() == MI::WB * 2 + MI::BN) {
321
        if (!doEval) return 1;
322
        if (nWB1 == 1)
323
            return 100 + mateEval(pos.getKingSq(true), pos.getKingSq(false));
324
    }
325
    if (pos.materialId() == MI::BB * 2 + MI::WN) {
326
        if (!doEval) return 1;
327
        if (nBB1 == 1)
328
            return -(100 + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
329
    }
330
 
331
    // Bonus for K[BN][BN]KQ
332
    if ((pos.bMtrl() == qV) && pos.pieceTypeBB(Piece::BQUEEN) && ((nWN >= 2) || (nWB1 + nWB2 >= 2))) {
333
        if (!doEval) return 1;
334
        if ((score < 0) && ((nWN >= 2) || ((nWB1 >= 1) && (nWB2 >= 1))))
335
            return -((pos.bMtrl() - pos.wMtrl()) / 8 + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
336
    }
337
    if ((pos.wMtrl() == qV) && pos.pieceTypeBB(Piece::WQUEEN) && ((nBN >= 2) || (nBB1 + nBB2 >= 2))) {
338
        if (!doEval) return 1;
339
        if ((score > 0) && ((nBN >= 2) || ((nBB1 >= 1) && (nBB2 >= 1))))
340
            return (pos.wMtrl() - pos.bMtrl()) / 8 + mateEval(pos.getKingSq(true), pos.getKingSq(false));
341
    }
342
    if ((pos.bMtrl() == qV) && pos.pieceTypeBB(Piece::BQUEEN) && ((nWN >= 1) && (nWB1 + nWB2 >= 1))) {
343
        if (!doEval) return 1;
344
        if (score < 0)
345
            return -((pos.bMtrl() - pos.wMtrl()) / 2 + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
346
    }
347
    if ((pos.wMtrl() == qV) && pos.pieceTypeBB(Piece::WQUEEN) && ((nBN >= 1) && (nBB1 + nBB2 >= 1))) {
348
        if (!doEval) return 1;
349
        if (score > 0)
350
            return (pos.wMtrl() - pos.bMtrl()) / 2 + mateEval(pos.getKingSq(true), pos.getKingSq(false));
351
    }
352
 
353
    // Bonus for KRK
354
    if ((pos.bMtrl() == 0) && pos.pieceTypeBB(Piece::WROOK)) {
355
        if (!doEval) return 1;
356
        return 400 + pos.wMtrl() - pos.bMtrl() + mateEval(pos.getKingSq(true), pos.getKingSq(false));
357
    }
358
    if ((pos.wMtrl() == 0) && pos.pieceTypeBB(Piece::BROOK)) {
359
        if (!doEval) return 1;
360
        return -(400 + pos.bMtrl() - pos.wMtrl() + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
361
    }
362
 
363
    // Bonus for KQK[BN]
364
    const int bV = ::bV;
365
    const int nV = ::nV;
366
    if (pos.pieceTypeBB(Piece::WQUEEN) && (bMtrlPawns == 0) && (pos.bMtrl() <= std::max(bV,nV))) {
367
        if (!doEval) return 1;
368
        return 200 + pos.wMtrl() - pos.bMtrl() + mateEval(pos.getKingSq(true), pos.getKingSq(false));
369
    }
370
    if (pos.pieceTypeBB(Piece::BQUEEN) && (wMtrlPawns == 0) && (pos.wMtrl() <= std::max(bV,nV))) {
371
        if (!doEval) return 1;
372
        return -(200 + pos.bMtrl() - pos.wMtrl() + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
373
    }
374
 
375
    // Bonus for KQK
376
    if ((pos.bMtrl() == 0) && pos.pieceTypeBB(Piece::WQUEEN)) {
377
        if (!doEval) return 1;
378
        return 100 + pos.wMtrl() - pos.bMtrl() + mateEval(pos.getKingSq(true), pos.getKingSq(false));
379
    }
380
    if ((pos.wMtrl() == 0) && pos.pieceTypeBB(Piece::BQUEEN)) {
381
        if (!doEval) return 1;
382
        return -(100 + pos.bMtrl() - pos.wMtrl() + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
383
    }
384
 
385
    if (pos.pieceTypeBB(Piece::WROOK, Piece::WKNIGHT, Piece::WQUEEN) == 0) {
386
        if (!doEval) return 1;
387
        if ((score > 0) && isBishopPawnDraw<true>(pos))
388
            return 0;
389
    }
390
    if (pos.pieceTypeBB(Piece::BROOK, Piece::BKNIGHT, Piece::BQUEEN) == 0) {
391
        if (!doEval) return 1;
392
        if ((score < 0) && isBishopPawnDraw<false>(pos))
393
            return 0;
394
    }
395
 
396
    // Give bonus/penalty if advantage is/isn't large enough to win
397
    if ((wMtrlPawns == 0) && (wMtrlNoPawns <= bMtrlNoPawns + bV)) {
398
        if (!doEval) return 1;
399
        if (score > 0) {
400
            if (wMtrlNoPawns < rV)
401
                return -pos.bMtrl() / 50;
402
            else
403
                return score / 8;        // Too little excess material, probably draw
404
        }
405
    }
406
    if ((bMtrlPawns == 0) && (bMtrlNoPawns <= wMtrlNoPawns + bV)) {
407
        if (!doEval) return 1;
408
        if (score < 0) {
409
            if (bMtrlNoPawns < rV)
410
                return pos.wMtrl() / 50;
411
            else
412
                return score / 8;        // Too little excess material, probably draw
413
        }
414
    }
415
 
416
    if ((bMtrlPawns == 0) && (wMtrlNoPawns - bMtrlNoPawns > bV)) {
417
        if (!doEval) return 1;
418
        return score + 300;       // Enough excess material, should win
419
    }
420
    if ((wMtrlPawns == 0) && (bMtrlNoPawns - wMtrlNoPawns > bV)) {
421
        if (!doEval) return 1;
422
        return score - 300;       // Enough excess material, should win
423
    }
424
 
425
    // Give bonus for advantage larger than KRKP, to avoid evaluation discontinuity
426
    if ((pos.bMtrl() == pV) && pos.pieceTypeBB(Piece::WROOK) && (pos.wMtrl() > rV)) {
427
        if (!doEval) return 1;
428
        return score + krkpBonus;
429
    }
430
    if ((pos.wMtrl() == pV) && pos.pieceTypeBB(Piece::BROOK) && (pos.bMtrl() > rV)) {
431
        if (!doEval) return 1;
432
        return score - krkpBonus;
433
    }
434
 
435
    // Bonus for KRPKN
436
    if (pos.pieceTypeBB(Piece::WROOK) && pos.pieceTypeBB(Piece::WPAWN) &&
437
        !pos.pieceTypeBB(Piece::BBISHOP) && (pos.bMtrl() == nV)  && (bMtrlPawns == 0)) {
438
        if (!doEval) return 1;
439
        return score + krpknBonus;
440
    }
441
    if (pos.pieceTypeBB(Piece::BROOK) && pos.pieceTypeBB(Piece::BPAWN) &&
442
        !pos.pieceTypeBB(Piece::WBISHOP) && (pos.wMtrl() == nV)  && (wMtrlPawns == 0)) {
443
        if (!doEval) return 1;
444
        return score - krpknBonus;
445
    }
446
 
447
    // Bonus for KRPKB
448
    int krpkbAdjustment = 0;
449
    if (pos.pieceTypeBB(Piece::WROOK) && pos.pieceTypeBB(Piece::WPAWN) &&
450
        !pos.pieceTypeBB(Piece::BKNIGHT) && (pos.bMtrl() == bV)  && (bMtrlPawns == 0)) {
451
        if (!doEval) return 1;
452
        score += krpkbBonus;
453
        krpkbAdjustment += krpkbBonus;
454
    }
455
    if (pos.pieceTypeBB(Piece::BROOK) && pos.pieceTypeBB(Piece::BPAWN) &&
456
        !pos.pieceTypeBB(Piece::WKNIGHT) && (pos.wMtrl() == bV)  && (wMtrlPawns == 0)) {
457
        if (!doEval) return 1;
458
        score -= krpkbBonus;
459
        krpkbAdjustment += krpkbBonus;
460
    }
461
 
462
    // Penalty for KRPKB when pawn is on a/h file
463
     if ((wMtrlNoPawns == rV) && (wMtrlPawns <= pV) && pos.pieceTypeBB(Piece::BBISHOP)) {
464
        if (!doEval) return 1;
465
        if (score - krpkbAdjustment > 0) {
466
            U64 pMask = pos.pieceTypeBB(Piece::WPAWN);
467
            U64 bMask = pos.pieceTypeBB(Piece::BBISHOP);
468
            if (((pMask & BitBoard::maskFile[0]) && (bMask & BitBoard::maskDarkSq)) ||
469
                ((pMask & BitBoard::maskFile[7]) && (bMask & BitBoard::maskLightSq))) {
470
                score = (score - krpkbAdjustment) * krpkbPenalty / 128;
471
                return score;
472
            }
473
        }
474
    }
475
    if ((bMtrlNoPawns == rV) && (bMtrlPawns <= pV) && pos.pieceTypeBB(Piece::WBISHOP)) {
476
        if (!doEval) return 1;
477
        if (score + krpkbAdjustment < 0) {
478
            U64 pMask = pos.pieceTypeBB(Piece::BPAWN);
479
            U64 bMask = pos.pieceTypeBB(Piece::WBISHOP);
480
            if (((pMask & BitBoard::maskFile[0]) && (bMask & BitBoard::maskLightSq)) ||
481
                ((pMask & BitBoard::maskFile[7]) && (bMask & BitBoard::maskDarkSq))) {
482
                score = (score + krpkbAdjustment) * krpkbPenalty / 128;
483
                return score;
484
            }
485
        }
486
    }
487
 
488
    auto getPawnAsymmetry = [passedPawns, &pos]() {
489
        int f1 = BitBoard::southFill(pos.pieceTypeBB(Piece::WPAWN)) & 0xff;
490
        int f2 = BitBoard::southFill(pos.pieceTypeBB(Piece::BPAWN)) & 0xff;
491
        int asymmetry = BitBoard::bitCount((f1 & ~f2) | (f2 & ~f1));
492
        U64 passedPawnsW = passedPawns & pos.pieceTypeBB(Piece::WPAWN);
493
        U64 passedPawnsB = passedPawns & pos.pieceTypeBB(Piece::BPAWN);
494
        asymmetry += BitBoard::bitCount(passedPawnsW) + BitBoard::bitCount(passedPawnsB);
495
        return asymmetry;
496
    };
497
 
498
    // Account for draw factor in rook endgames
499
    if ((BitBoard::bitCount(pos.pieceTypeBB(Piece::WROOK)) == 1) &&
500
        (BitBoard::bitCount(pos.pieceTypeBB(Piece::BROOK)) == 1) &&
501
        (pos.pieceTypeBB(Piece::WQUEEN, Piece::WBISHOP, Piece::WKNIGHT,
502
                         Piece::BQUEEN, Piece::BBISHOP, Piece::BKNIGHT) == 0) &&
503
        (BitBoard::bitCount(pos.pieceTypeBB(Piece::WPAWN, Piece::BPAWN)) > 1)) {
504
        if (!doEval) return 1;
505
        int asymmetry = getPawnAsymmetry();
506
        score = score * rookEGDrawFactor[std::min(asymmetry, 6)] / 128;
507
        return score;
508
    }
509
 
510
    // Correction for draw factor in RvsB endgames
511
    if ((BitBoard::bitCount(pos.pieceTypeBB(Piece::WROOK)) == 1) &&
512
        (BitBoard::bitCount(pos.pieceTypeBB(Piece::BBISHOP)) == 1) &&
513
        (pos.pieceTypeBB(Piece::WQUEEN, Piece::WBISHOP, Piece::WKNIGHT,
514
                         Piece::BQUEEN, Piece::BROOK, Piece::BKNIGHT) == 0) &&
515
        (wMtrlPawns - bMtrlPawns == -pV)) {
516
        if (!doEval) return 1;
517
        int asymmetry = getPawnAsymmetry();
518
        score = score * RvsBPDrawFactor[std::min(asymmetry, 6)] / 128;
519
        return score;
520
    }
521
    // Correction for draw factor in RvsB endgames
522
    if ((BitBoard::bitCount(pos.pieceTypeBB(Piece::BROOK)) == 1) &&
523
        (BitBoard::bitCount(pos.pieceTypeBB(Piece::WBISHOP)) == 1) &&
524
        (pos.pieceTypeBB(Piece::BQUEEN, Piece::BBISHOP, Piece::BKNIGHT,
525
                         Piece::WQUEEN, Piece::WROOK, Piece::WKNIGHT) == 0) &&
526
        (wMtrlPawns - bMtrlPawns == pV)) {
527
        if (!doEval) return 1;
528
        int asymmetry = getPawnAsymmetry();
529
        score = score * RvsBPDrawFactor[std::min(asymmetry, 6)] / 128;
530
        return score;
531
    }
532
 
533
    if (!doEval) return 0;
534
    return score;
535
}
536
 
537
int
538
EndGameEval::mateEval(int k1, int k2) {
539
    static const int loseKingTable[64] = {
540
        0,   4,   8,  12,  12,   8,   4,   0,
541
        4,   8,  12,  16,  16,  12,   8,   4,
542
        8,  12,  16,  20,  20,  16,  12,   8,
543
       12,  16,  20,  24,  24,  20,  16,  12,
544
       12,  16,  20,  24,  24,  20,  16,  12,
545
        8,  12,  16,  20,  20,  16,  12,   8,
546
        4,   8,  12,  16,  16,  12,   8,   4,
547
        0,   4,   8,  12,  12,   8,   4,   0
548
    };
549
    return winKingTable[k1] - loseKingTable[k2];
550
}
551
 
552
template <bool whiteBishop>
553
bool
554
EndGameEval::isBishopPawnDraw(const Position& pos) {
555
    const Piece::Type bishop = whiteBishop ? Piece::WBISHOP : Piece::BBISHOP;
556
    const bool darkBishop  = (pos.pieceTypeBB(bishop) & BitBoard::maskDarkSq) != 0;
557
    const bool lightBishop = (pos.pieceTypeBB(bishop) & BitBoard::maskLightSq) != 0;
558
    if (darkBishop && lightBishop)
559
        return false; // No draw against proper bishop pair
560
 
561
    const Piece::Type pawn = whiteBishop ? Piece::WPAWN : Piece::BPAWN;
562
    if (pos.pieceTypeBB(pawn) == 0)
563
        return true; // Only bishops on same color can not win
564
 
565
    // Check for rook pawn + wrong color bishop
566
    if (whiteBishop) {
567
        if (((pos.pieceTypeBB(pawn) & BitBoard::maskBToHFiles) == 0) &&
568
            !lightBishop &&
569
            ((pos.pieceTypeBB(Piece::BKING) & BitBoard::sqMask(A8,B8,A7,B7)) != 0)) {
570
            return true;
571
        } else
572
        if (((pos.pieceTypeBB(pawn) & BitBoard::maskAToGFiles) == 0) &&
573
            !darkBishop &&
574
            ((pos.pieceTypeBB(Piece::BKING) & BitBoard::sqMask(G8,H8,G7,H7)) != 0)) {
575
            return true;
576
        }
577
    } else {
578
        if (((pos.pieceTypeBB(pawn) & BitBoard::maskBToHFiles) == 0) &&
579
            !darkBishop &&
580
            ((pos.pieceTypeBB(Piece::WKING) & BitBoard::sqMask(A1,B1,A2,B2)) != 0)) {
581
            return true;
582
        } else
583
        if (((pos.pieceTypeBB(pawn) & BitBoard::maskAToGFiles) == 0) &&
584
            !lightBishop &&
585
            ((pos.pieceTypeBB(Piece::WKING) & BitBoard::sqMask(G1,H1,G2,H2)) != 0)) {
586
            return true;
587
        }
588
    }
589
 
590
    // Check for fortress containing WPb6, BPb7, white bishop on dark square
591
    const Piece::Type king = whiteBishop ? Piece::WKING : Piece::BKING;
592
    const Piece::Type oPawn = whiteBishop ? Piece::BPAWN : Piece::WPAWN;
593
    const Piece::Type oKnight = whiteBishop ? Piece::BKNIGHT : Piece::WKNIGHT;
594
    const int b7 = whiteBishop ? (darkBishop ? B7 : G7) : (lightBishop ? B2 : G2);
595
    const int b6 = whiteBishop ? (darkBishop ? B6 : G6) : (lightBishop ? B3 : G3);
596
    const int c7 = whiteBishop ? (darkBishop ? C7 : F7) : (lightBishop ? C2 : F2);
597
    const int a8 = whiteBishop ? (darkBishop ? A8 : H8) : (lightBishop ? A1 : H1);
598
    const int b8 = whiteBishop ? (darkBishop ? B8 : G8) : (lightBishop ? B1 : G1);
599
    const int c8 = whiteBishop ? (darkBishop ? C8 : F8) : (lightBishop ? C1 : F1);
600
    const int d8 = whiteBishop ? (darkBishop ? D8 : E8) : (lightBishop ? D1 : E1);
601
    const int d7 = whiteBishop ? (darkBishop ? D7 : E7) : (lightBishop ? D2 : E2);
602
    const U64 bFile = (whiteBishop == darkBishop) ? 0x0202020202020202ULL : 0x4040404040404040ULL;
603
    const U64 acFile = (whiteBishop == darkBishop) ? 0x0505050505050505ULL : 0xA0A0A0A0A0A0A0A0ULL;
604
    const U64 corner = whiteBishop ? (darkBishop ? BitBoard::sqMask(A8,B8,A7) : BitBoard::sqMask(G8,H8,H7))
605
                                   : (lightBishop ? BitBoard::sqMask(A1,B1,A2) : BitBoard::sqMask(G1,H1,H2));
606
 
607
    if ((pos.getPiece(b7) == oPawn) && (pos.getPiece(b6) == pawn) &&
608
        (pos.getPiece(a8) != oKnight) && ((pos.pieceTypeBB(king) & corner) == 0) &&
609
        (BitBoard::bitCount(pos.pieceTypeBB(oPawn) & acFile) <= 1)) {
610
        if (pos.getPiece(c7) == pawn) {
611
            if (BitBoard::bitCount(pos.pieceTypeBB(pawn) & ~bFile) == 1) {
612
                int oKingSq = pos.getKingSq(!whiteBishop);
613
                if ((oKingSq == c8) || (oKingSq == d7))
614
                    return true;
615
            }
616
        } else {
617
            int oKingSq = pos.getKingSq(!whiteBishop);
618
            if ((pos.pieceTypeBB(pawn) & ~bFile) == 0) {
619
                if ((oKingSq == a8) || (oKingSq == b8) || (oKingSq == c8) ||
620
                    (oKingSq == d8) || (oKingSq == d7))
621
                    return true;
622
            } else if (pos.isWhiteMove() != whiteBishop) { // Test if stale-mate
623
                int oMtrl = whiteBishop ? pos.bMtrl() : pos.wMtrl();
624
                U64 bShift = whiteBishop ? (pos.pieceTypeBB(bishop) << 8) : (pos.pieceTypeBB(bishop) >> 8);
625
                U64 kShift = whiteBishop ? (pos.pieceTypeBB(king) << 8) : (pos.pieceTypeBB(king) >> 8);
626
                const U64 md6_h2 = whiteBishop ?
627
                        (darkBishop  ? BitBoard::sqMask(D6,E5,F4,G3,H2) : BitBoard::sqMask(E6,D5,C4,B3,A2)) :
628
                        (lightBishop ? BitBoard::sqMask(D3,E4,F5,G6,H7) : BitBoard::sqMask(E3,D4,C5,B6,A7));
629
                if ((oMtrl == pV) ||
630
                    ((oMtrl == 2*pV) && ((bShift & pos.pieceTypeBB(oPawn)) ||
631
                                         ((kShift & pos.pieceTypeBB(oPawn)) &&
632
                                          ((pos.pieceTypeBB(oPawn) & md6_h2) == 0))))) {
633
                    const U64 mc7c8 = whiteBishop ?
634
                            (darkBishop  ? BitBoard::sqMask(C7,C8) : BitBoard::sqMask(F7,F8)) :
635
                            (lightBishop ? BitBoard::sqMask(C2,C1) : BitBoard::sqMask(F2,F1));
636
                    const U64 md6e6e7e8 = whiteBishop ?
637
                            (darkBishop  ? BitBoard::sqMask(D6,E6,E7,E8) : BitBoard::sqMask(E6,D6,D7,D8)) :
638
                            (lightBishop ? BitBoard::sqMask(D3,E3,E2,E1) : BitBoard::sqMask(E3,D3,D2,D1));
639
                    const U64 me7e8 = whiteBishop ?
640
                            (darkBishop  ? BitBoard::sqMask(E7,E8) : BitBoard::sqMask(D7,D8)) :
641
                            (lightBishop ? BitBoard::sqMask(E2,E1) : BitBoard::sqMask(D2,D1));
642
                    if (oKingSq == a8) {
643
                        if ((pos.pieceTypeBB(king) & mc7c8) ||
644
                                (pos.pieceTypeBB(bishop) & (md6_h2 | (1ULL << c7))))
645
                            return true;
646
                    } else if (oKingSq == c8) {
647
                        if (pos.getPiece(c7) == bishop) {
648
                            if (pos.pieceTypeBB(king) & md6e6e7e8)
649
                                return true;
650
                        } else {
651
                            if ((pos.pieceTypeBB(bishop) & md6_h2) && (pos.pieceTypeBB(king) & me7e8))
652
                                return true;
653
                        }
654
                    }
655
                }
656
            }
657
        }
658
    }
659
 
660
    // Check for fortress when all pawns are on the B file and there is no bishop
661
    if (whiteBishop) {
662
        if (pos.pieceTypeBB(Piece::WBISHOP) == 0) {
663
            if ((pos.pieceTypeBB(Piece::WPAWN,Piece::BPAWN) & ~BitBoard::maskFileB) == 0) {
664
                if ((pos.getPiece(B7) == Piece::BPAWN) &&
665
                    (pos.pieceTypeBB(Piece::BKING) & BitBoard::sqMask(A7,A8,B8)))
666
                    return true;
667
            }
668
            if ((pos.pieceTypeBB(Piece::WPAWN,Piece::BPAWN) & ~BitBoard::maskFileG) == 0) {
669
                if ((pos.getPiece(G7) == Piece::BPAWN) &&
670
                    (pos.pieceTypeBB(Piece::BKING) & BitBoard::sqMask(H7,H8,G8)))
671
                    return true;
672
            }
673
        }
674
    } else {
675
        if (pos.pieceTypeBB(Piece::BBISHOP) == 0) {
676
            if ((pos.pieceTypeBB(Piece::WPAWN,Piece::BPAWN) & ~BitBoard::maskFileB) == 0) {
677
                if ((pos.getPiece(B2) == Piece::WPAWN) &&
678
                    (pos.pieceTypeBB(Piece::WKING) & BitBoard::sqMask(A2,A1,B1)))
679
                    return true;
680
            }
681
            if ((pos.pieceTypeBB(Piece::WPAWN,Piece::BPAWN) & ~BitBoard::maskFileG) == 0) {
682
                if ((pos.getPiece(G2) == Piece::WPAWN) &&
683
                    (pos.pieceTypeBB(Piece::WKING) & BitBoard::sqMask(H2,H1,G1)))
684
                    return true;
685
            }
686
        }
687
    }
688
 
689
    return false;
690
}
691
 
692
int
693
EndGameEval::kqkpEval(int wKing, int wQueen, int bKing, int bPawn, bool whiteMove, int score) {
694
    bool canWin = false;
695
    if (((1ULL << bKing) & 0xFFFF) == 0) {
696
        canWin = true; // King doesn't support pawn
697
    } else if (std::abs(Position::getX(bPawn) - Position::getX(bKing)) > 2) {
698
        canWin = true; // King doesn't support pawn
699
    } else {
700
        switch (bPawn) {
701
        case A2:
702
            canWin = ((1ULL << wKing) & 0x0F1F1F1F1FULL) != 0;
703
            if (canWin && (bKing == A1) && (Position::getX(wQueen) == 1) && !whiteMove)
704
                canWin = false; // Stale-mate
705
            break;
706
        case C2:
707
            canWin = ((1ULL << wKing) & 0x071F1F1FULL) != 0;
708
            break;
709
        case F2:
710
            canWin = ((1ULL << wKing) & 0xE0F8F8F8ULL) != 0;
711
            break;
712
        case H2:
713
            canWin = ((1ULL << wKing) & 0xF0F8F8F8F8ULL) != 0;
714
            if (canWin && (bKing == H1) && (Position::getX(wQueen) == 6) && !whiteMove)
715
                canWin = false; // Stale-mate
716
            break;
717
        default:
718
            canWin = true;
719
            break;
720
        }
721
    }
722
 
723
    const int dist = BitBoard::getKingDistance(wKing, bPawn);
724
    score = score - 20 * (dist - 4);
725
    if (!canWin)
726
        score /= 50;
727
    return score;
728
}
729
 
730
int
731
EndGameEval::kqkrpEval(int wKing, int wQueen, int bKing, int bRook, int bPawn, bool whiteMove, int score) {
732
    if (!(BitBoard::bPawnAttacks[bPawn] & (1ULL << bRook)))
733
        return score; // Rook not protected by pawn, no fortress
734
    if ((1ULL << bPawn) & (BitBoard::maskFileE | BitBoard::maskFileF |
735
                           BitBoard::maskFileG | BitBoard::maskFileH)) { // Mirror X
736
        wKing ^= 7;
737
        wQueen ^= 7;
738
        bKing ^= 7;
739
        bRook ^= 7;
740
        bPawn ^= 7;
741
    }
742
    bool drawish = false;
743
    switch (bPawn) {
744
    case A6:
745
        drawish = ((1ULL << bKing) & BitBoard::sqMask(A8,B8,A7,B7)) &&
746
                  (Position::getX(wKing) >= 2) &&
747
                  (Position::getY(wKing) <= 3);
748
        break;
749
    case A2:
750
        drawish = (((1ULL << bKing) & BitBoard::sqMask(A4,B4,A3,B3)) != 0); // Pierre-Marie Baty -- boolean conversion fix
751
        break;
752
    case B7:
753
        drawish = ((1ULL << bKing) & BitBoard::sqMask(A8,B8,C8,A7,C7)) &&
754
                  (Position::getY(wKing) <= 4);
755
        break;
756
    case B6:
757
        if (bRook == C5) {
758
            drawish = ((1ULL << bKing) & BitBoard::sqMask(A7,B7)) ||
759
                      (((1ULL << bKing) & BitBoard::sqMask(A8,B8)) &&
760
                       ((Position::getX(wKing) >= 3) || (Position::getY(wKing) <= 3)) &&
761
                       (((1ULL << wQueen) & BitBoard::maskRow7) ||
762
                        (!whiteMove && (wQueen != A6)) ||
763
                        (whiteMove && !((1ULL << wQueen) & BitBoard::sqMask(A6,A5,A4,A3,A2,A1,B5,B4,B3,B2,B1,C4,D3,E2,F1)))));
764
        }
765
        break;
766
    case B5:
767
        drawish = ((1ULL << bKing) & BitBoard::sqMask(A6,B6,C6,A5)) &&
768
                  (Position::getY(wKing) <= 2);
769
        break;
770
    case B4:
771
        drawish = ((1ULL << bKing) & BitBoard::sqMask(A6,B6,C6,A5,B5,C5)) &&
772
                  ((Position::getY(wKing) <= 2) || (Position::getX(wKing) >= 4));
773
        break;
774
    case B3:
775
        drawish = (((1ULL << bKing) & BitBoard::sqMask(A4,B4,C4,A3)) &&
776
                   ((1ULL << wKing) & BitBoard::maskRow1Row8)) ||
777
                  (((1ULL << bKing) & BitBoard::sqMask(A5,B5)) &&
778
                   ((1ULL << wQueen) & BitBoard::maskRow4) &&
779
                   ((1ULL << wKing) & BitBoard::maskRow1));
780
        break;
781
    case B2:
782
        drawish = ((1ULL << bKing) & BitBoard::sqMask(A4,B4,C4,A3,B3,C3,A2,C2)) &&
783
                  ((1ULL << wKing) & BitBoard::sqMask(A4,B4,C4,A3,B3,C3,A2,C2)) == 0;
784
        break;
785
    case C7:
786
        drawish = ((1ULL << bKing) & BitBoard::sqMask(B8,C8,D8,B7,D7)) &&
787
                  (Position::getY(wKing) <= 4);
788
        break;
789
    case C3:
790
        drawish = (((1ULL << bKing) & BitBoard::sqMask(B4,C4,D4)) &&
791
                   ((1ULL << wKing) & BitBoard::maskRow1Row8)) ||
792
                  (((1ULL << bKing) & BitBoard::sqMask(B5,C5)) &&
793
                   (((1ULL << wQueen) & BitBoard::maskRow4) || !whiteMove) &&
794
                   ((1ULL << wKing) & BitBoard::maskRow1)) ||
795
                  ((((bKing == B3) && (wQueen != B5)) || ((bKing == D3) && (wQueen != D5))) &&
796
                   ((1ULL << wKing) & BitBoard::maskRow1));
797
 
798
        break;
799
    case C2:
800
        drawish = ((1ULL << bKing) & BitBoard::sqMask(B3,C3,D3,B2,D2)) &&
801
                  ((Position::getX(wKing) == 0) || (Position::getX(wKing) >= 4));
802
        break;
803
    case D7:
804
        drawish = ((1ULL << bKing) & BitBoard::sqMask(C8,D8,E8,C7,E7)) &&
805
                  (Position::getY(wKing) <= 4);
806
        break;
807
    case D3:
808
        drawish = (((1ULL << bKing) & BitBoard::sqMask(C4,D4,E4)) &&
809
                   ((1ULL << wKing) & BitBoard::maskRow1Row8)) ||
810
                  (((1ULL << bKing) & BitBoard::sqMask(C5,D5,E5)) &&
811
                   (((1ULL << wQueen) & BitBoard::maskRow4) || !whiteMove) &&
812
                   ((1ULL << wKing) & BitBoard::maskRow1)) ||
813
                  ((((bKing == C3) && (wQueen != C5)) || ((bKing == E3) && (wQueen != E5))) &&
814
                   ((1ULL << wKing) & BitBoard::maskRow1));
815
        break;
816
    case D2:
817
        drawish = ((1ULL << bKing) & BitBoard::sqMask(C4,D4,E4,C3,D3,E3,C2,E2)) &&
818
                  ((1ULL << wKing) & BitBoard::sqMask(C4,D4,E4,C3,D3,E3,C2,E2)) == 0;
819
        break;
820
    default:
821
        drawish = false;
822
        break;
823
    }
824
    return drawish ? score / 16 : score;
825
}
826
 
827
int
828
EndGameEval::kpkEval(int wKing, int bKing, int wPawn, bool whiteMove) {
829
    if (Position::getX(wKing) >= 4) { // Mirror X
830
        wKing ^= 7;
831
        bKing ^= 7;
832
        wPawn ^= 7;
833
    }
834
    int index = whiteMove ? 0 : 1;
835
    index = index * 32 + Position::getY(wKing)*4+Position::getX(wKing);
836
    index = index * 64 + bKing;
837
    index = index * 48 + wPawn - 8;
838
 
839
    int bytePos = index / 8;
840
    int bitPos = index % 8;
841
    bool draw = (((int)kpkTable[bytePos]) & (1 << bitPos)) == 0;
842
    if (draw)
843
        return 0;
844
    return qV - pV / 4 * (7-Position::getY(wPawn));
845
}
846
 
847
bool
848
EndGameEval::kpkpEval(int wKing, int bKing, int wPawn, int bPawn, int& score) {
849
    const U64 wKingMask = 1ULL << wKing;
850
    const U64 bKingMask = 1ULL << bKing;
851
    if (wPawn == B6 && bPawn == B7) {
852
        if ((bKingMask & BitBoard::sqMask(A8,B8,C8,D8,D7)) &&
853
            ((wKingMask & BitBoard::sqMask(A8,B8,A7)) == 0)) {
854
            score = 0;
855
            return true;
856
        }
857
    } else if (wPawn == G6 && bPawn == G7) {
858
        if ((bKingMask & BitBoard::sqMask(E8,F8,G8,H8,E7)) &&
859
            ((wKingMask & BitBoard::sqMask(G8,H8,H7)) == 0)) {
860
            score = 0;
861
            return true;
862
        }
863
    } else if (wPawn == B2 && bPawn == B3) {
864
        if ((wKingMask & BitBoard::sqMask(A1,B1,C1,D1,D2)) &&
865
            ((bKingMask & BitBoard::sqMask(A1,B1,A2)) == 0)) {
866
            score = 0;
867
            return true;
868
        }
869
    } else if (wPawn == G2 && bPawn == G3) {
870
        if ((wKingMask & BitBoard::sqMask(E1,F1,G1,H1,E2)) &&
871
            ((bKingMask & BitBoard::sqMask(G1,H1,H2)) == 0)) {
872
            score = 0;
873
            return true;
874
        }
875
    }
876
    return false;
877
}
878
 
879
int
880
EndGameEval::krkpEval(int wKing, int bKing, int bPawn, bool whiteMove, int score) {
881
    if (Position::getX(bKing) >= 4) { // Mirror X
882
        wKing ^= 7;
883
        bKing ^= 7;
884
        bPawn ^= 7;
885
    }
886
    int index = whiteMove ? 0 : 1;
887
    index = index * 32 + Position::getY(bKing)*4+Position::getX(bKing);
888
    index = index * 48 + bPawn - 8;
889
    index = index * 8 + Position::getY(wKing);
890
    U8 mask = krkpTable[index];
891
    bool canWin = (mask & (1 << Position::getX(wKing))) != 0;
892
 
893
    score = score + Position::getY(bPawn) * pV / 4;
894
    if (!canWin)
895
        score /= 50;
896
    else
897
        score += krkpBonus;
898
    return score;
899
}
900
 
901
int
902
EndGameEval::krpkrEval(int wKing, int bKing, int wPawn, int wRook, int bRook, bool whiteMove) {
903
    if (Position::getX(wPawn) >= 4) { // Mirror X
904
        wKing ^= 7;
905
        bKing ^= 7;
906
        wPawn ^= 7;
907
        wRook ^= 7;
908
        bRook ^= 7;
909
    }
910
    int index = whiteMove ? 0 : 1;
911
    index = index * 24 + (Position::getY(wPawn)-1)*4+Position::getX(wPawn);
912
    index = index * 64 + wKing;
913
    const U64 kMask = krpkrTable[index];
914
    const bool canWin = (kMask & (1ULL << bKing)) != 0;
915
    U64 kingNeighbors = BitBoard::kingAttacks[bKing];
916
    const U64 occupied = (1ULL<<wKing) | (1ULL<<bKing) | (1ULL<<wPawn) | (1ULL<<bRook);
917
    const U64 rAtk = BitBoard::rookAttacks(wRook, occupied);
918
    kingNeighbors &= ~(BitBoard::kingAttacks[wKing] | BitBoard::wPawnAttacks[wPawn] | rAtk);
919
    bool close;
920
    if (canWin) {
921
        close = (kMask & kingNeighbors) != kingNeighbors;
922
    } else {
923
        close = (kMask & kingNeighbors) != 0;
924
    }
925
    int score = pV + Position::getY(wPawn) * pV / 4;
926
    if (canWin) {
927
        if (!close)
928
            score += pV;
929
    } else {
930
        if (close)
931
            score /= 2;
932
        else
933
            score /= 4;
934
    }
935
    return score;
936
}
937
 
938
int
939
EndGameEval::krpkrpEval(int wKing, int bKing, int wPawn, int wRook, int bRook, int bPawn, bool whiteMove, int score) {
940
    int hiScore = krpkrEval(wKing, bKing, wPawn, wRook, bRook, whiteMove);
941
    if (score > hiScore * 14 / 16)
942
        return hiScore * 14 / 16;
943
    int loScore = -krpkrEval(63-bKing, 63-wKing, 63-bPawn, 63-bRook, 63-wRook, !whiteMove);
944
    if (score < loScore * 14 / 16)
945
        return loScore * 14 / 16;
946
    return score;
947
}
948
 
949
int
950
EndGameEval::kbnkEval(int wKing, int bKing, bool darkBishop) {
951
    int score = 600;
952
    if (darkBishop) { // Mirror X
953
        wKing ^= 7;
954
        bKing ^= 7;
955
    }
956
    static const int bkTable[64] = { 17, 15, 12,  9,  7,  4,  2,  0,
957
                                     15, 20, 17, 15, 12,  9,  4,  2,
958
                                     12, 17, 22, 20, 17, 15,  9,  4,
959
                                      9, 15, 20, 25, 22, 17, 12,  7,
960
                                      7, 12, 17, 22, 25, 20, 15,  9,
961
                                      4,  9, 15, 17, 20, 22, 17, 12,
962
                                      2,  4,  9, 12, 15, 17, 20, 15,
963
                                      0,  2,  4,  7,  9, 12, 15, 17 };
964
 
965
    score += winKingTable[wKing] - bkTable[bKing];
966
    score -= std::min(0, BitBoard::getTaxiDistance(wKing, bKing) - 3);
967
    return score;
968
}
969
 
970
int
971
EndGameEval::kbpkbEval(int wKing, int wBish, int wPawn, int bKing, int bBish, int score) {
972
    U64 wPawnMask = 1ULL << wPawn;
973
    U64 pawnPath = BitBoard::northFill(wPawnMask);
974
    U64 bKingMask = 1ULL << bKing;
975
    U64 wBishMask = 1ULL << wBish;
976
    U64 wBishControl = (wBishMask & BitBoard::maskDarkSq) ? BitBoard::maskDarkSq : BitBoard::maskLightSq;
977
    if ((bKingMask & pawnPath) && ((bKingMask & wBishControl) == 0))
978
        return 0;
979
 
980
    U64 bBishMask = 1ULL << bBish;
981
    if (((wBishMask & BitBoard::maskDarkSq) == 0) != ((bBishMask & BitBoard::maskDarkSq) == 0)) { // Different color bishops
982
        if (((bBishMask | BitBoard::bishopAttacks(bBish, bKingMask)) & pawnPath & ~wPawnMask) != 0)
983
            if (!(wPawn == A6 && bBish == B8) && !(wPawn == H6 && bBish == G8))
984
                return 0;
985
    }
986
 
987
    if (bKingMask & BitBoard::wPawnBlockerMask[wPawn])
988
        return score / 4;
989
    return score;
990
}
991
 
992
int
993
EndGameEval::kbpknEval(int wKing, int wBish, int wPawn, int bKing, int bKnight, int score) {
994
    U64 wPawnMask = 1ULL << wPawn;
995
    U64 pawnPath = BitBoard::northFill(wPawnMask);
996
    U64 bKingMask = 1ULL << bKing;
997
    U64 wBishMask = 1ULL << wBish;
998
    U64 wBishControl = (wBishMask & BitBoard::maskDarkSq) ? BitBoard::maskDarkSq : BitBoard::maskLightSq;
999
 
1000
    U64 edges = 0xff818181818181ffULL;
1001
    U64 bKnightMask = 1ULL << bKnight;
1002
    if ((bKnightMask & edges & ~wBishControl) != 0) // Knight on edge square where it can be trapped
1003
        return score;
1004
 
1005
    if ((bKingMask & pawnPath) && ((bKingMask & wBishControl) == 0))
1006
        return 0;
1007
 
1008
    if (bKingMask & BitBoard::wPawnBlockerMask[wPawn])
1009
        return score / 4;
1010
    return score;
1011
}
1012
 
1013
int
1014
EndGameEval::knpkbEval(int wKing, int wKnight, int wPawn, int bKing, int bBish, int score, bool wtm) {
1015
    U64 wPawnMask = 1ULL << wPawn;
1016
    U64 bBishMask = 1ULL << bBish;
1017
    U64 bBishControl = (bBishMask & BitBoard::maskDarkSq) ? BitBoard::maskDarkSq : BitBoard::maskLightSq;
1018
 
1019
    U64 p = wPawnMask;
1020
    if (bBishControl & wPawnMask) {
1021
        U64 bKingMask = 1ULL << bKing;
1022
        U64 wKnightMask = 1ULL << wKnight;
1023
        if (!wtm && (BitBoard::bishopAttacks(bBish, bKingMask | wKnightMask) & wPawnMask))
1024
            return 0;
1025
        p <<= 8;
1026
    }
1027
    U64 pawnDrawishMask = 0x183c7e7e7e7eULL;
1028
    if (p & pawnDrawishMask)
1029
        return score / 32;
1030
 
1031
    return score;
1032
}
1033
 
1034
int
1035
EndGameEval::knpkEval(int wKing, int wKnight, int wPawn, int bKing, int score, bool wtm) {
1036
    if (Position::getX(wPawn) >= 4) { // Mirror X
1037
        wKing ^= 7;
1038
        wKnight ^= 7;
1039
        wPawn ^= 7;
1040
        bKing ^= 7;
1041
    }
1042
    if (wPawn == A7) {
1043
        if (bKing == A8 || bKing == B7) // Fortress
1044
            return 0;
1045
        if (wKing == A8 && (bKing == C7 || bKing == C8)) {
1046
            bool knightDark = Position::darkSquare(Position::getX(wKnight), Position::getY(wKnight));
1047
            bool kingDark = Position::darkSquare(Position::getX(bKing), Position::getY(bKing));
1048
            if (wtm == (knightDark == kingDark)) // King trapped
1049
                return 0;
1050
        }
1051
    }
1052
    return score;
1053
}