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