Belofte version 2.1.8
A promising chess program using the UCI or Winboard interface
eval.cpp
Go to the documentation of this file.
1/*---------------------------------------------------------------------+
2 * File: eval.cpp
3 * Project: part of belofte - A Promising Chess Program
4 * Author: yves
5 * SPDX-License-Identifier: GPL-2.0-only
6+----------------------------------------------------------------------*/
7
8#include "belofte.h"
9
10static uint8_t whitefields[64] = { // 1 = white, 2 = black
11 1, 2, 1, 2, 1, 2, 1, 2,
12 2, 1, 2, 1, 2, 1, 2, 1,
13 1, 2, 1, 2, 1, 2, 1, 2,
14 2, 1, 2, 1, 2, 1, 2, 1,
15 1, 2, 1, 2, 1, 2, 1, 2,
16 2, 1, 2, 1, 2, 1, 2, 1,
17 1, 2, 1, 2, 1, 2, 1, 2,
18 2, 1, 2, 1, 2, 1, 2, 1
19};
20
21//-----------------------------------------------------------------------
22
24{
27 return sc;
28}
29
30//-----------------------------------------------------------------------
31
32/**
33 * See if board is in finite state, meaning game is ended
34 * @param b board is a reference, if no moves have been generated, a
35 * copy is created, moves are generated and a recursive call is done
36 * @return mate, stalemate, draw or further evaluation required
37 */
39{
40 if (!b.atLeastOneMovePossible()) {
41 if (b.whiteToMove()) {
42 bWhiteKing const* king = static_cast<bWhiteKing *>(bPiece::getPieceClass(tPiece::W_KING));
43 if (king->isAttacked(b, b.getWhiteKingPos())) {
44 return GR_BLACKMATES;
45 }
46 return GR_DRAW_STALEMATE;
47 } else {
48 bBlackKing const* king = static_cast<bBlackKing *>(bPiece::getPieceClass(tPiece::B_KING));
49 if (king->isAttacked(b, b.getBlackKingPos())) {
50 return GR_WHITEMATES;
51 }
52 return GR_DRAW_STALEMATE;
53 }
54 }
55 if (b.getPly50Moves() >= 100) return GR_DRAW_50;
56 if (insufficientMaterial(b)) return GR_DRAW_LACKMATERIAL;
57 if (threeFoldRepetition(b)) return GR_DRAW_THREEFOLD;
58
59 return GR_UNKNOWN;
60}
61
62/** convert all draw scores to SCORE_THEORETIC_DRAW
63 */
65{
66 if (sc == GR_BLACKMATES) return -SCORE_MATE;
67 else if (sc == GR_WHITEMATES) return SCORE_MATE;
69}
70
71/**
72 * Get piecelist in normalized form (all uppercase)
73 * @param b board
74 * @return piecelist in form K+whitepieces+K+blackpieces in uppercase
75 */
76std::string bPositionEvaluation::getPieceList(bBoard const& b)
77 const
78{
79 return "K" + std::string((b.m_whitePieces[tStatPiece::STAT_ROOK]).size(), 'R')
80 + std::string((b.m_whitePieces[tStatPiece::STAT_KNIGHT]).size(), 'N')
81 + std::string((b.m_whitePieces[tStatPiece::STAT_BISHOP]).size(), 'B')
82 + std::string((b.m_whitePieces[tStatPiece::STAT_QUEEN]).size(), 'Q')
83 + std::string((b.m_whitePieces[tStatPiece::STAT_PAWN]).size(), 'P')
84 + "K" + std::string((b.m_blackPieces[tStatPiece::STAT_ROOK]).size(), 'R')
85 + std::string((b.m_blackPieces[tStatPiece::STAT_KNIGHT]).size(), 'N')
86 + std::string((b.m_blackPieces[tStatPiece::STAT_BISHOP]).size(), 'B')
87 + std::string((b.m_blackPieces[tStatPiece::STAT_QUEEN]).size(), 'Q')
88 + std::string((b.m_blackPieces[tStatPiece::STAT_PAWN]).size(), 'P');
89}
90
91bool bPositionEvaluation::insufficientMaterial(bBoard const& b) const
92{
93 if (b.m_piecesonboard > 4) return false; // >4 pieces, never theoretic draw
94 std::string mat = getPieceList(b);
95
96 // "KBKB" is draw only with opposite colour bishops by FIDE rule
97 if (mat == "KBKB") return sameColorBishops(b);
98
99 // other >3 pieces, never material draw ("KNKN", "KNKB", "KBKN" are not draws by FIDE rule)
100 if (mat.size() > 3) return false;
101
102 if (mat.find('P') < mat.length()) return false; // with pawn, no material draw
103 if (mat.find('Q') < mat.length()) return false; // with queen, no material draw
104 if (mat.find('R') < mat.length()) return false; // with rook, no material draw
105 std::string const nullpositions[] = {"KK", "KNK", "KKN", "KBK", "KKB"};
106 auto it = std::find(std::begin(nullpositions), std::end(nullpositions), mat);
107 return it != std::end(nullpositions);
108}
109
110bool bPositionEvaluation::sameColorBishops(bBoard const& b) const
111{
112 uint8_t whitemask = 0;
113 uint8_t blackmask = 0;
114
115 if (b.m_whitePieces[STAT_BISHOP].size()) {
116 for (unsigned int i=0; i < b.m_whitePieces[STAT_BISHOP].size(); i++) {
117 whitemask |= whitefields[b.m_whitePieces[STAT_BISHOP][i]];
118 }
119 }
120
121 if (b.m_blackPieces[STAT_BISHOP].size()) {
122 for (unsigned int i=0; i < b.m_blackPieces[STAT_BISHOP].size(); i++) {
123 blackmask |= whitefields[b.m_blackPieces[STAT_BISHOP][i]];
124 }
125 }
126
127 return whitemask == blackmask;
128}
129
130int8_t bPositionEvaluation::nFoldRepetition(bBoard const& b) const
131{
132 int8_t nRepetitionCount = 1;
133 int16_t nMovesSinceLastPawnMove = b.getPly50Moves();
134 hashkey_t currentHash = b.getHash();
135 hashkey_t nPieceCnt = currentHash & HASH_ODDMATERIAL;
136
137 // TODO: we need to iterate through positions to get here,
138 // and not only on gamehistory
139 positions_t& positions = Game()->getPositions();
140
141 std::vector<bBoard>::reverse_iterator it = positions.rbegin();
142
143 // if first position is same as board, do not count it but skip
144 // this in case if evaluation is called on current game stack only
145 if ((it != positions.rend())) if ((*it).getHash() == currentHash) ++it;
146
147 while (it != positions.rend()) {
148 if ((*it).getHash() == currentHash) ++nRepetitionCount;
149 // should not go any further, 3 times already
150 if (nRepetitionCount > 2) break;
151 // we are nMoves since last pawn/capture move, and still no repetition
152 if (!(nMovesSinceLastPawnMove--)) break;
153 // capture move, so no threefold repetition
154 if (((*it).getHash() & HASH_ODDMATERIAL) != nPieceCnt) break;
155 ++it;
156 }
157
158 return nRepetitionCount;
159}
160
161bool bPositionEvaluation::twoFoldRepetition(bBoard const& b) const
162{
163 if (b.getPly50Moves() < 4) return false;
164 return (nFoldRepetition(b) > 1);
165}
166
167bool bPositionEvaluation::threeFoldRepetition(bBoard const& b) const
168{
169 if (b.getPly50Moves() < 6) return false;
170 return (nFoldRepetition(b) > 2);
171}
172
173//-----------------------------------------------------------------------
174
176 // empty, king, pawn, knight, bishop, rook queen
177 // black pieces have negative score
178 0, 0, 100, 300, 300, 500, 900
179};
180
182 // empty, king, pawn, knight, bishop, rook queen
183 // black pieces have positive score as well
184 0, 2000, 100, 340, 360, 525, 950
185};
186
188
189// bottom left position is a8, then b8, topmost a1 - h1
190// score for black pieces is inverted
192 // empty
193 {},
194 // White King
195 {
196 5, 6, 8, 0, 0, 2, 10, 5,
197 0, 0, 1, -2, -3, -1, 2, 0,
198 -2, -3, -5, -5, -5, -5, -2, 0,
199 -6, -6, -6, -6, -6, -6, -6, -6,
200 -5, -2, -5, -5, -5, -5, -2, -5,
201 -5, 0, 0, 0, 0, 0, 0, -5,
202 -15, -10, -10, -10, -10, -10, -10, -15,
203 -20, -15, -10, -10, -10, -10, -15, -20
204 },
205 // White Pawn
206 {
207 0, 0, 0, 0, 0, 0, 0, 0,
208 5, 10, 10, -30, -30, 10, 10, 5,
209 5, 5, 0, 10, 10, 0, 5, 5,
210 0, 0, 10, 20, 20, 0, 0, 0,
211 0, 0, 0, 10, 10, 0, 0, 0,
212 20, 50, 60, 80, 80, 60, 50, 20,
213 80, 80, 100, 100, 100, 100, 80, 80,
214 0, 0, 0, 0, 0, 0, 0, 0
215 },
216 // White Knight
217 {
218 -40, -10, -5, -5, -5, -5, -10, -40,
219 -10, -5, 0, 0, 0, 0, -5, -10,
220 -5, 0, 5, 5, 5, 5, 0, -5,
221 0, 5, 5, 5, 5, 5, 5, 0,
222 2, 8, 8, 8, 8, 8, 8, 2,
223 0, 2, 5, 5, 5, 5, 2, 0,
224 -5, -5, 2, 5, 5, 2, -5, -5,
225 -20, -10, -5, 0, 0, -5, -10, -20
226 },
227 // White Bishop
228 {
229 -10, -8, -4, -6, -6, -4, 0, -10,
230 -6, 6, -2, 4, 4, 0, 6, -6,
231 -4, 0, 0, 2, 4, 0, -2, 0,
232 0, 4, 8, 4, 4, 8, 4, 0,
233 2, 6, 4, 2, 2, 4, 6, 4,
234 2, 0, 6, 4, 4, 4, 0, 0,
235 2, 0, 2, 0, -2, -2, -2, -4,
236 -10, -8, -6, -4, -4, -6, -8, -10
237 },
238 // White Rook
239 {
240 0, -6, 8, 20, 20, 2, -6, 0,
241 -5, -2, -2, 4, 4, -2, -8, -5,
242 -3, 0, 1, 2, 2, 2, 0, -3,
243 -1, 0, 0, 0, 0, 0, 0, -1,
244 0, 1, 0, 2, 2, 0, 1, 0,
245 2, 1, 1, 3, 3, 1, 1, 1,
246 6, 8, 10, 10, 10, 10, 8, 6,
247 3, 3, 5, 5, 5, 3, 3, 2
248 },
249 // White Queen
250 {
251 -3, -5, -3, -1, 0, -2, -5, -1,
252 -5, -2, 2, 3, 3, 2, -2, -5,
253 -2, 1, 1, 3, 3, 2, 3, -2,
254 0, 0, 0, 0, 0, 0, 0, 0,
255 0, 0, 0, 0, 0, 0, 0, 0,
256 2, 3, 4, 4, 3, 3, 2, 0,
257 -2, 3, 3, 4, 3, 3, 1, -2,
258 0, 2, 2, 0, -1, -1, -5, -1
259 },
260};
261
262// score for black pieces is inverted
264 // empty
265 {},
266 // White King
267 {
268 -30, -20, -15, -15, -15, -15, -20, -30,
269 -20, -10, -5, -5, -5, -5, -10, -20,
270 -15, -5, 0, 0, 0, 0, -5, -15,
271 -15, -5, 0, 5, 5, 0, -5, -15,
272 -15, -5, 0, 5, 5, 0, -5, -15,
273 -15, -5, 0, 0, 0, 0, -5, -15,
274 -20, -10, -5, -5, -5, -5, -10, -20,
275 -30, -20, -15, -15, -15, -15, -20, -30
276 },
277 // White Pawn
278 {
279 0, 0, 0, 0, 0, 0, 0, 0,
280 0, 0, 0, -30, -30, 0, 0, 0,
281 0, 0, 0, 0, 0, 0, 0, 0,
282 0, 0, 0, 0, 0, 0, 0, 0,
283 20, 20, 30, 30, 30, 20, 20, 20,
284 40, 50, 60, 80, 80, 60, 50, 40,
285 80, 80, 100, 100, 100, 100, 80, 80,
286 0, 0, 0, 0, 0, 0, 0, 0
287 },
288 // White Knight
289 {
290 -20, -10, -5, 0, 0, -5, -10, -20,
291 -10, -5, 0, 0, 0, 0, -5, -10,
292 -5, 0, 5, 5, 5, 5, 0, -5,
293 0, 0, 5, 20, 20, 5, 0, 0,
294 0, 0, 5, 20, 20, 5, 0, 0,
295 -5, 0, 5, 5, 5, 5, 0, -5,
296 -10, -5, 0, 0, 0, 0, -5, -10,
297 -20, -10, -5, 0, 0, -5, -10, -20
298 },
299 // White Bishop
300 {
301 -20, -10, -5, 0, 0, -5, -10, -20,
302 -10, -5, 0, 0, 0, 0, -5, -10,
303 -5, 0, 5, 5, 5, 5, 0, -5,
304 0, 0, 5, 20, 20, 5, 0, 0,
305 0, 0, 5, 20, 20, 5, 0, 0,
306 -5, 0, 5, 5, 5, 5, 0, -5,
307 -10, -5, 0, 0, 0, 0, -5, -10,
308 -20, -10, -5, 0, 0, -5, -10, -20
309 },
310 // White Rook
311 {
312 -20, 10, 0, 0, 0, 0, 10, -20,
313 10, 10, 10, 10, 10, 10, 10, 10,
314 0, 10, 0, 0, 0, 0, 10, 0,
315 0, 10, 0, 0, 0, 0, 10, 0,
316 0, 10, 0, 0, 0, 0, 10, 0,
317 0, 10, 0, 0, 0, 0, 10, 0,
318 10, 10, 10, 10, 10, 10, 10, 10,
319 -20, 10, 0, 0, 0, 0, 10, -20
320 },
321 // White Queen
322 {
323 -20, -10, -5, 0, 0, -5, -10, -20,
324 -10, -5, 0, 0, 0, 0, -5, -10,
325 -5, 0, 5, 5, 5, 5, 0, -5,
326 0, 0, 5, 20, 20, 5, 0, 0,
327 0, 0, 5, 20, 20, 5, 0, 0,
328 -5, 0, 5, 5, 5, 5, 0, -5,
329 -10, -5, 0, 0, 0, 0, -5, -10,
330 -20, -10, -5, 0, 0, -5, -10, -20
331 },
332};
333
335 0, 1, 2, 3, 3, 2, 1, 0,
336 1, 2, 4, 5, 5, 4, 2, 1,
337 2, 4, 6, 7, 7, 6, 4, 2,
338 3, 5, 7, 9, 9, 7, 5, 3,
339 3, 5, 7, 9, 9, 7, 5, 3,
340 2, 4, 6, 7, 7, 6, 4, 2,
341 1, 2, 4, 5, 5, 4, 2, 1,
342 0, 1, 2, 3, 3, 2, 1, 0
343};
344
345//-----------------------------------------------------------------------
346
351
356
361
362//-----------------------------------------------------------------------
363
364/**
365 * Store black piece and field values as negative of whites view
366 */
368 : m_name{n}
369{
370 for (int i = 7; i < tPiece::P_SIZE; i++) {
371 piecevalues[i] = piecevalues[i - 6];
373 for (column_t iCol = 0; iCol < 8; iCol++) {
374 for (rank_t iRank = 0; iRank < 8; iRank++) {
375 if (positionvalues[i - 6][bCase::coordToCase(iCol, 7 - iRank)] != 0) {
376 positionvalues[i][bCase::coordToCase(iCol, iRank)]
377 = -positionvalues[i - 6][bCase::coordToCase(iCol, 7 - iRank)];
378 }
379 if (endgamevalues[i - 6][bCase::coordToCase(iCol, 7 - iRank)] != 0) {
380 endgamevalues[i][bCase::coordToCase(iCol, iRank)]
381 = -endgamevalues[i - 6][bCase::coordToCase(iCol, 7 - iRank)];
382 }
383 }
384 }
385 }
386 for (int i = 0; i < tPiece::P_SIZE; i++)
388}
389
393
394//-----------------------------------------------------------------------
395
400
404
405/** get pure material evaluation of score
406 */
408{
410 if (ge != GR_UNKNOWN) return resultToScoreFlag(ge);
411
412 bScore value = static_cast<bScore>(belofte::getRandomRange(-5, 5));
413 for (case_t iCase = 0; iCase < 64; iCase++) {
414 int piece = b.getPiece(iCase);
415 if (piece) {
416 value += roundedpiecevalues[piece];
417 }
418 }
419 return value;
420}
421
422//-----------------------------------------------------------------------
423
428
431{
432}
433
437
438/** get material and case related modification of score
439 */
441{
443 if (ge != GR_UNKNOWN) return resultToScoreFlag(ge);
444
446 return getEndgameEvaluation(b);
447
449 return getPawnEndingEvaluation(b);
450
452 return getMatingEvaluation(b);
453
454 return getRelativeBoardEval(b);
455}
456
458{
459 bScore value = static_cast<bScore>(belofte::getRandomRange(-5, 5));
460 bScore white = 0;
461 bScore black = 0;
462 for (case_t iCase = 0; iCase < 64; iCase++) {
463 int piece = b.getPiece(iCase);
464 if (piece >= tPiece::B_KING) {
465 black += piecevalues[piece];
466 value += positionvalues[piece][iCase];
467 } else if (piece) {
468 white += piecevalues[piece];
469 value += positionvalues[piece][iCase];
470 }
471 }
472 return value + (white - black) + (white - black) / (white + black);
473}
474
476{
477 bScore value = static_cast<bScore>(belofte::getRandomRange(-5, 5));
478 for (case_t iCase = 0; iCase < 64; iCase++) {
479 int piece = b.getPiece(iCase);
480 if (piece >= tPiece::B_KING) {
481 value -= piecevalues[piece];
482 value -= centerplayvalues[iCase];
483 } else if (piece) {
484 value += piecevalues[piece];
485 value += centerplayvalues[iCase];
486 }
487 }
488 return value;
489}
490
492{
493 bScore value = static_cast<bScore>(belofte::getRandomRange(-5, 5));
494 for (case_t iCase = 0; iCase < 64; iCase++) {
495 int piece = b.getPiece(iCase);
496 if (piece >= tPiece::B_KING) {
497 value -= piecevalues[piece];
498 } else if (piece) {
499 value += piecevalues[piece];
500 }
501 }
502 return value;
503}
504
506{
507 bScore value = static_cast<bScore>(belofte::getRandomRange(-2, 2));
508 for (case_t iCase = 0; iCase < 64; iCase++) {
509 int piece = b.getPiece(iCase);
510 if (piece >= tPiece::B_KING) {
511 value -= piecevalues[piece];
512 } else if (piece) {
513 value += piecevalues[piece];
514 }
515 value += endgamevalues[piece][iCase];
516 }
517 return value;
518}
519
520//-----------------------------------------------------------------------
521
526
530
531/** get positional evaluation
532 */
534{
536 if (ge != GR_UNKNOWN) return resultToScoreFlag(ge);
537
538 bScore value;
540 value = getEndgameEvaluation(b);
541 else if (b.getStage() == bGameStage::ST_PAWNENDING)
542 return getPawnEndingEvaluation(b);
543 else if (b.getStage() == bGameStage::ST_MATING)
544 return getMatingEvaluation(b);
545 else
546 value = getRelativeBoardEval(b);
547
548 value += getKingEvaluation(b);
549 value += getPawnEvaluation(b);
550 value += getRookEvaluation(b);
551 value += getBishopEvaluation(b);
552 value += getQueenEvaluation(b);
553
554 return value;
555}
556
557bScore PosEvalPositionalBoard::getKingEvaluation(bBoard const& b) const
558{
559 bScore value = 0;
560
561 if (b.getStage() == bGameStage::ST_OPENING) {
562 // add up to 30 centipoints for castle ability, 30 if castled
563 if (b.canCastle(tCFlags::WCASTLE_S)) value += 5;
566 if (b.canCastle(tCFlags::BCASTLE_S)) value -= 5;
569 if (b.castleDoneWhite()) value += 30;
570 if (b.castleDoneBlack()) value -= 30;
571 }
572
573 return value;
574}
575
576bScore PosEvalPositionalBoard::getPawnEvaluation(bBoard const& b) const
577{
578 bScore value = 0;
579 // TODO: move pawn column occupation to calcPieces
580 uint8_t whitePawns[8] = {};
581 uint8_t blackPawns[8] = {};
582 uint8_t whiteIslands = 0, blackIslands = 0;
583
584 // TODO: iterate through whitePieces[] instead
585 for (rank_t iRank = 1; iRank < 7; iRank++) {
586 for (column_t iCol = 0; iCol < 8; iCol++) {
587 piece_t piece = b.getPiece(iCol, iRank);
588 if (piece == tPiece::W_PAWN) {
589 whitePawns[iCol]++;
590 } else if (piece == tPiece::B_PAWN) {
591 blackPawns[iCol]++;
592 }
593 }
594 }
595
596 // malus for 25 for double pawn, 50 for triple pawn or border double pawn
597 for (column_t iCol = 0; iCol < 8; iCol++) {
598 if (whitePawns[iCol] > 1) value -= 25 * whitePawns[iCol];
599 if (blackPawns[iCol] > 1) value += 25 * blackPawns[iCol];
600 }
601 if (whitePawns[0] > 1) value -= 25;
602 if (whitePawns[7] > 1) value -= 25;
603 if (blackPawns[0] > 1) value += 25;
604 if (blackPawns[7] > 1) value += 25;
605
606 // count adjacent pawn groups, 15 malus for isolated pawn
607 // 20 malus for more islands than opponent
608 uint8_t bGroup = 0;
609 for (column_t iCol = 0; iCol < 8; iCol++) {
610 if (whitePawns[iCol]) {
611 if (!blackPawns[iCol]) {
612 if (whitePassed(b, iCol)) value += 30;
613 }
614 if (!bGroup) { whiteIslands++; bGroup++; }
615 } else {
616 if (bGroup == 1) value -= 15; // isolated pawn found
617 bGroup = 0;
618 }
619 }
620 // test same for last column
621 if (bGroup == 1) value -= 15; // isolated pawn found
622 bGroup = 0;
623 for (column_t iCol = 0; iCol < 8; iCol++) {
624 if (blackPawns[iCol]) {
625 if (!whitePawns[iCol]) {
626 if (blackPassed(b, iCol)) value -= 30;
627 }
628 if (!bGroup) { blackIslands++; bGroup++; }
629 } else {
630 if (bGroup == 1) value += 15; // isolated pawn found
631 bGroup = 0;
632 }
633 }
634 // test same for last column
635 if (bGroup == 1) value += 15; // isolated pawn found
636 if (whiteIslands > blackIslands) value -= 10;
637 else if (whiteIslands < blackIslands) value += 10;
638
639 return value;
640}
641
642/** see if pawn has passed, we are only interested in frontmost pawn
643 * function assumes that there is at least a pawn on rank, no checks
644 */
645bool PosEvalPositionalBoard::whitePassed(bBoard const& b, column_t const iCol) const
646{
647 bool passed = true;
648 rank_t iRank = 6;
649 while (iRank) {
650 if (b.getPiece(iCol, iRank) == tPiece::W_PAWN) break;
651 iRank--;
652 }
653 if (iCol) {
654 for (rank_t i = iRank + 1; i < 7; i++) {
655 if (b.getPiece(iCol - 1, i) == tPiece::B_PAWN) return false;
656 }
657 }
658 if (iCol < 7) {
659 for (rank_t i = iRank + 1; i < 7; i++) {
660 if (b.getPiece(iCol + 1, i) == tPiece::B_PAWN) return false;
661 }
662 }
663 return passed;
664}
665
666bool PosEvalPositionalBoard::blackPassed(bBoard const& b, column_t const iCol) const
667{
668 bool passed = true;
669 rank_t iRank = 1;
670 while (iRank < 6) {
671 if (b.getPiece(iCol, iRank) == tPiece::B_PAWN) break;
672 iRank++;
673 }
674 if (iCol) {
675 for (rank_t i = iRank - 1; i > 0; i--) {
676 if (b.getPiece(iCol - 1, i) == tPiece::W_PAWN) return false;
677 }
678 }
679 if (iCol < 7) {
680 for (rank_t i = iRank - 1; i > 0; i--) {
681 if (b.getPiece(iCol + 1, i) == tPiece::W_PAWN) return false;
682 }
683 }
684 return passed;
685}
686
687bScore PosEvalPositionalBoard::getRookEvaluation(bBoard const& b) const
688{
689 bScore value = 0;
690
691 if (b.m_whitePieces[STAT_ROOK].size()) {
692 for (unsigned int i=0; i < b.m_whitePieces[STAT_ROOK].size(); i++) {
693 rank_t iRank = bCase::rank(b.m_whitePieces[STAT_ROOK][i]);
694 column_t iCol = bCase::column(b.m_whitePieces[STAT_ROOK][i]);
695 // we need at least 2 to get linked values
696 if (i && seesHorVer(b, iCol, iRank, tPiece::W_ROOK)) value += 20;
697 if (blackKingSameRankCol(b, iCol, iRank)) value += 25;
698 if (sameCol(b, iCol, iRank, tPiece::B_QUEEN)) value += 15;
699 else if (sameRank(b, iCol, iRank, tPiece::B_QUEEN)) value += 15;
700 value += openLineValWhite(b, iCol, iRank);
701 value += rookRankValWhite(b, iRank);
702 }
703 }
704
705 if (b.m_blackPieces[STAT_ROOK].size()) {
706 for (unsigned int i=0; i < b.m_blackPieces[STAT_ROOK].size(); i++) {
707 rank_t iRank = bCase::rank(b.m_blackPieces[STAT_ROOK][i]);
708 column_t iCol = bCase::column(b.m_blackPieces[STAT_ROOK][i]);
709 if (i && seesHorVer(b, iCol, iRank, tPiece::B_ROOK)) value -= 20;
710 if (whiteKingSameRankCol(b, iCol, iRank)) value -= 25;
711 if (sameCol(b, iCol, iRank, tPiece::W_QUEEN)) value -= 15;
712 else if (sameRank(b, iCol, iRank, tPiece::W_QUEEN)) value -= 15;
713 value -= openLineValBlack(b, iCol, iRank);
714 value -= rookRankValBlack(b, iRank);
715 }
716 }
717
718 return value;
719}
720
721/** check if we see a rook in any direction from this case on
722 * TODO: allow to have indirect match of second rook on same column/rank
723 */
724bool PosEvalPositionalBoard::seesHorVer(bBoard const& b,
725 column_t iCol, rank_t iRank, piece_t const matchPiece) const
726{
727 column_t c = iCol - 1;
728 while (c > 0) {
729 if (b.getPiece(c, iRank) == matchPiece) return true;
730 if (!b.isFieldEmpty(c, iRank)) break;
731 c--;
732 }
733 c = iCol + 1;
734 while (c < 8) {
735 if (b.getPiece(c, iRank) == matchPiece) return true;
736 if (!b.isFieldEmpty(c, iRank)) break;
737 c++;
738 }
739
740 rank_t r = iRank - 1;
741 while (r > 0) {
742 if (b.getPiece(iCol, r) == matchPiece) return true;
743 if (!b.isFieldEmpty(iCol, r)) break;
744 r--;
745 }
746 r = iRank + 1;
747 while (r < 8) {
748 if (b.getPiece(iCol, r) == matchPiece) return true;
749 if (!b.isFieldEmpty(iCol, r)) break;
750 r++;
751 }
752 return false;
753}
754
755/**
756 * Check if certain piece is on same rank
757 * Used to verify rook on Queen rank
758 * @return true if yes
759 */
760bool PosEvalPositionalBoard::sameRank(bBoard const& b, column_t const iCol,
761 rank_t const iRank, piece_t const matchPiece) const
762{
763 column_t c = 0;
764 while (c < iCol) {
765 if (b.getPiece(c, iRank) == matchPiece) return true;
766 c++;
767 }
768 c = iCol + 1;
769 while (c < 8) {
770 if (b.getPiece(c, iRank) == matchPiece) return true;
771 c++;
772 }
773 return false;
774}
775
776/**
777 * Check if certain piece is on same column
778 * Used to verify rook on Queen rank
779 * @return true if yes
780 */
781bool PosEvalPositionalBoard::sameCol(bBoard const& b, column_t const iCol,
782 rank_t const iRank, piece_t const matchPiece) const
783{
784 rank_t r = 0;
785 while (r < iRank) {
786 if (b.getPiece(iCol, r) == matchPiece) return true;
787 r++;
788 }
789 r = iRank + r;
790 while (r < 8) {
791 if (b.getPiece(iCol, r) == matchPiece) return true;
792 r++;
793 }
794 return false;
795}
796
797/**
798 * Check if Queen or Rook is on same rank or column as king
799 * @return true if yes
800 */
801bool PosEvalPositionalBoard::whiteKingSameRankCol(bBoard const& b,
802 column_t const iCol, rank_t const iRank) const
803{
804 if (bCase::column(b.getWhiteKingPos()) == iCol) return true;
805 return bCase::rank(b.getWhiteKingPos()) == iRank;
806}
807
808bool PosEvalPositionalBoard::blackKingSameRankCol(bBoard const& b,
809 column_t const iCol, rank_t const iRank) const
810{
811 if (bCase::column(b.getBlackKingPos()) == iCol) return true;
812 return bCase::rank(b.getBlackKingPos()) == iRank;
813}
814
815/** see if rook is on open or semi-open line
816 * @bug does not see if behind piece
817 */
818bScore PosEvalPositionalBoard::openLineValWhite(bBoard const& b, column_t const iCol,
819 rank_t const iRank) const
820{
821 rank_t r = iRank + 1;
822 while (r < 7) {
823 if (b.getPiece(iCol, r) == tPiece::W_PAWN) return 0;
824 if (b.getPiece(iCol, r) == tPiece::B_PAWN) return 5;
825 r++;
826 }
827 return 10;
828}
829
830bScore PosEvalPositionalBoard::openLineValBlack(bBoard const& b, column_t const iCol,
831 rank_t const iRank) const
832{
833 rank_t r = iRank - 1;
834 while (r > 0) {
835 if (b.getPiece(iCol, r) == tPiece::B_PAWN) return 0;
836 if (b.getPiece(iCol, r) == tPiece::W_PAWN) return 5;
837 r--;
838 }
839 return 10;
840}
841
842bScore PosEvalPositionalBoard::rookRankValWhite(bBoard const& b,
843 rank_t const iRank) const
844{
845 if ((iRank == 0) || (iRank == 7)) return 0;
846 bScore value = 0;
847 for (column_t iCol = 0; iCol < 8; iCol++) {
848 if (b.getPiece(iCol, iRank) == tPiece::B_PAWN) value += 2;
849 }
850 return value;
851}
852
853bScore PosEvalPositionalBoard::rookRankValBlack(bBoard const& b,
854 rank_t const iRank) const
855{
856 if ((iRank == 0) || (iRank == 7)) return 0;
857 bScore value = 0;
858 for (column_t iCol = 0; iCol < 8; iCol++) {
859 if (b.getPiece(iCol, iRank) == tPiece::W_PAWN) value += 2;
860 }
861 return value;
862}
863
864bScore PosEvalPositionalBoard::getBishopEvaluation(bBoard const& b) const
865{
866 bScore value = 0;
867
868 if (b.m_whitePieces[STAT_BISHOP].size()) {
869 for (auto const& v : b.m_whitePieces[STAT_BISHOP]) {
870 rank_t iRank = bCase::rank(v);
871 column_t iCol = bCase::column(v);
872 if (sameColourBlackKing(b, v)) {
873 value += 3;
874 if (sameDiagonal(b, iCol, iRank, tPiece::B_KING)) value += 7;
875 }
876 if (sameDiagonal(b, iCol, iRank, tPiece::B_QUEEN)) value += 5;
877 else if (sameColour(b, v, tPiece::B_QUEEN)) value += 2;
878 }
879 }
880
881 if (b.m_blackPieces[STAT_BISHOP].size()) {
882 for (auto const& v : b.m_blackPieces[STAT_BISHOP]) {
883 rank_t iRank = bCase::rank(v);
884 column_t iCol = bCase::column(v);
885 if (sameColourWhiteKing(b, v)) {
886 value -= 3;
887 if (sameDiagonal(b, iCol, iRank, tPiece::W_KING)) value -= 7;
888 }
889 if (sameDiagonal(b, iCol, iRank, tPiece::W_QUEEN)) value -= 5;
890 else if (sameColour(b, v, tPiece::W_QUEEN)) value -= 2;
891 }
892 }
893
894 return value;
895}
896
897bool PosEvalPositionalBoard::sameDiagonal(bBoard const& b, column_t const iCol,
898 rank_t const iRank, piece_t const matchPiece) const
899{
900 for (int8_t i = 1; i < 7; i++) {
901 if (b.getPieceCtl(iCol - i, iRank - i) == matchPiece) return true;
902 if (b.getPieceCtl(iCol - i, iRank + i) == matchPiece) return true;
903 if (b.getPieceCtl(iCol + i, iRank - i) == matchPiece) return true;
904 if (b.getPieceCtl(iCol + i, iRank + i) == matchPiece) return true;
905 }
906 return false;
907}
908
909/** see if matching piece is of same colour as original piece
910 * TODO: loop through piecelist instead of 64 fields
911 */
912bool PosEvalPositionalBoard::sameColour(bBoard const& b, case_t const c,
913 piece_t const matchPiece) const
914{
915 uint8_t pieceColour = whitefields[c];
916 for (case_t iCase = 0; iCase < 64; iCase++) {
917 if (b.getPiece(iCase) == matchPiece) {
918 return whitefields[iCase] == pieceColour;
919 }
920 }
921 return false;
922}
923
924/** see if matching king is of same colour as original piece
925 */
926bool PosEvalPositionalBoard::sameColourWhiteKing(bBoard const& b,
927 case_t const c) const
928{
929 return whitefields[b.getWhiteKingPos()] == whitefields[c];
930}
931
932/** see if matching king is of same colour as original piece
933 */
934bool PosEvalPositionalBoard::sameColourBlackKing(bBoard const& b,
935 case_t const c) const
936{
937 return whitefields[b.getBlackKingPos()] == whitefields[c];
938}
939
940bScore PosEvalPositionalBoard::getQueenEvaluation(bBoard const& b) const
941{
942 bScore value = 0;
943
944 if (b.m_whitePieces[STAT_QUEEN].size()) {
945 for (auto const& v : b.m_whitePieces[STAT_QUEEN]) {
946 rank_t iRank = bCase::rank(v);
947 column_t iCol = bCase::column(v);
948 if (sameDiagonal(b, iCol, iRank, tPiece::B_KING)) value += 5;
949 if (blackKingSameRankCol(b, iCol, iRank)) value += 5;
950 }
951 }
952
953 if (b.m_blackPieces[STAT_QUEEN].size()) {
954 for (auto const& v : b.m_blackPieces[STAT_QUEEN]) {
955 rank_t iRank = bCase::rank(v);
956 column_t iCol = bCase::column(v);
957 if (sameDiagonal(b, iCol, iRank, tPiece::W_KING)) value -= 5;
958 if (whiteKingSameRankCol(b, iCol, iRank)) value -= 5;
959 }
960 }
961
962 return value;
963}
964
965// eof
unsigned long long hashkey_t
Definition bel_hash.h:12
constexpr hashkey_t HASH_ODDMATERIAL
Definition bel_hash.h:16
bGame * Game()
Definition belofte.cpp:491
This is the main include file, needs to be included before any other include.
int8_t rank_t
Definition belofte.h:104
int8_t column_t
Definition belofte.h:105
uint8_t case_t
Definition belofte.h:106
int16_t bScore
@ BCASTLE_L
Definition board.h:11
@ BCASTLE_S
Definition board.h:11
@ WCASTLE_S
Definition board.h:11
@ WCASTLE_L
Definition board.h:11
bScore getEvaluation(bBoard const &b) const override
get pure material evaluation of score
Definition eval.cpp:407
~PosEvalPiecesOnly() override
Definition eval.cpp:401
~PosEvalPositionalBoard() override
Definition eval.cpp:527
bScore getEvaluation(bBoard const &b) const override
get positional evaluation
Definition eval.cpp:533
bScore getMatingEvaluation(bBoard const &b) const
Definition eval.cpp:505
bScore getEndgameEvaluation(bBoard const &b) const
Definition eval.cpp:475
~PosEvalStaticBoard() override
Definition eval.cpp:434
bScore getRelativeBoardEval(bBoard const &b) const
Definition eval.cpp:457
bScore getEvaluation(bBoard const &b) const override
get material and case related modification of score
Definition eval.cpp:440
bScore getPawnEndingEvaluation(bBoard const &b) const
Definition eval.cpp:491
piece_t getPiece(case_t const bc) const
1 for white, 2 for black
Definition board.cpp:157
bool whiteToMove() const
Definition board.h:80
hashkey_t getHash() const
Definition board.h:106
case_t getBlackKingPos() const
Definition board.h:103
case_t getWhiteKingPos() const
Definition board.h:102
movenum50_t getPly50Moves() const
Definition board.h:63
bool canCastle() const
Definition board.cpp:243
piece_t getPieceCtl(column_t const iColumn, rank_t const iRank) const
retrieve piece with bounds checking, return field empty in case of out of bounds
Definition board.cpp:171
bool isFieldEmpty(case_t const bc) const
Definition board.cpp:178
bool isAttacked(bBoard const &b, case_t const &cf) const override
Definition piece.cpp:284
board
Definition board.h:147
bGameStage getStage() const
Definition board.h:177
bool castleDoneWhite() const
-1 black to move, 1 white to move
Definition board.h:181
bool castleDoneBlack() const
Definition board.h:182
uint8_t m_piecesonboard
Definition board.h:212
bool atLeastOneMovePossible() const
see if at least one move can be played e.g.
Definition board.cpp:962
column_t column() const
Definition case.h:37
static constexpr case_t coordToCase(column_t const c, rank_t const r)
Definition case.h:42
rank_t rank() const
Definition case.h:38
positions_t & getPositions()
Definition game.h:54
static bPiece * getPieceClass(piece_t const piece)
static class member function
Definition piece.cpp:130
bPositionEvaluation(std::string const &n)
Store black piece and field values as negative of whites view.
Definition eval.cpp:367
static bScore pieceValue(piece_t const p)
Definition eval.cpp:347
virtual ~bPositionEvaluation()
Definition eval.cpp:390
gameResult_t isGameEnded(bBoard const &b) const
See if board is in finite state, meaning game is ended.
Definition eval.cpp:38
bScore resultToScoreFlag(gameResult_t const sc) const
convert all draw scores to SCORE_THEORETIC_DRAW
Definition eval.cpp:64
static bScore centerplay_pieceValue(case_t const p)
Definition eval.cpp:357
static bScore mymove_pieceValue(piece_t const p)
Definition eval.cpp:352
bool isAttacked(bBoard const &b, case_t const &cf) const override
Check if piece on position is attacked, start with piece always on board and then with pieces with gr...
Definition piece.cpp:237
static bScore mymove_piecevalues[tPiece::P_SIZE]
Definition eval.cpp:187
static uint8_t whitefields[64]
Definition eval.cpp:10
static bScore endgamevalues[tPiece::P_SIZE][64]
Definition eval.cpp:263
static bScore positionvalues[tPiece::P_SIZE][64]
Definition eval.cpp:191
static bScore piecevalues[tPiece::P_SIZE]
Definition eval.cpp:181
static bScore roundedpiecevalues[tPiece::P_SIZE]
Definition eval.cpp:175
static bScore centerplayvalues[64]
Definition eval.cpp:334
@ GR_DRAW_50
Definition eval.h:35
@ GR_DRAW_STALEMATE
Definition eval.h:35
@ GR_UNKNOWN
Definition eval.h:34
@ GR_WHITEMATES
Definition eval.h:37
@ GR_BLACKMATES
Definition eval.h:38
@ GR_DRAW_LACKMATERIAL
Definition eval.h:35
@ GR_DRAW_THREEFOLD
Definition eval.h:35
constexpr bScore SCORE_MATE
Definition eval.h:23
enum gameResult gameResult_t
Definition eval.h:41
constexpr bScore SCORE_PUNDEFINED
Definition eval.h:19
constexpr bScore SCORE_POSITIVE
Definition eval.h:16
constexpr bScore SCORE_UNDEFINED
Definition eval.h:20
constexpr bScore SCORE_DRAW
Definition eval.h:27
constexpr bScore SCORE_THEORETIC_DRAW
Definition eval.h:17
std::vector< bBoard > positions_t
Definition game.h:15
bScore realScore(bScore const sc)
Definition eval.cpp:23
@ W_PAWN
Definition piece.h:39
@ P_SIZE
Definition piece.h:41
@ W_ROOK
Definition piece.h:39
@ B_ROOK
Definition piece.h:40
@ W_QUEEN
Definition piece.h:39
@ B_KING
Definition piece.h:40
@ W_KING
Definition piece.h:39
@ B_PAWN
Definition piece.h:40
@ B_QUEEN
Definition piece.h:40
enum tPiece piece_t
Definition piece.h:44
@ STAT_KNIGHT
Definition piece.h:56
@ STAT_BISHOP
Definition piece.h:56
@ STAT_ROOK
Definition piece.h:56
@ STAT_PAWN
Definition piece.h:55
@ STAT_QUEEN
Definition piece.h:56