Belofte version 2.2.0
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
10namespace belofte {
11 extern bWhiteKing const* cWhiteKingClass;
12 extern bBlackKing const* cBlackKingClass;
13}
14
15namespace belofteeval {
16
17 static constexpr uint8_t fieldcolours[64] = { // 1 = white, 2 = black
18 1, 2, 1, 2, 1, 2, 1, 2,
19 2, 1, 2, 1, 2, 1, 2, 1,
20 1, 2, 1, 2, 1, 2, 1, 2,
21 2, 1, 2, 1, 2, 1, 2, 1,
22 1, 2, 1, 2, 1, 2, 1, 2,
23 2, 1, 2, 1, 2, 1, 2, 1,
24 1, 2, 1, 2, 1, 2, 1, 2,
25 2, 1, 2, 1, 2, 1, 2, 1
26 };
27
28 extern bScore piecevalues[];
29 extern const 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 (insufficientMaterial(b)) return GR_DRAW_LACKMATERIAL;
46
47 if (b.getPly50Moves() >= 100) return GR_DRAW_50;
48
49 bBasicBoard bb(b);
50 bMoveList ml;
51 if (!ml.atLeastOneMovePossible(bb)) {
52 if (b.whiteToMove()) {
53 if (belofte::cWhiteKingClass->isAttacked(bb, bb.getWhiteKingPos())) {
54 return GR_BLACKMATES;
55 }
56 return GR_DRAW_STALEMATE;
57 } else {
58 if (belofte::cBlackKingClass->isAttacked(bb, bb.getBlackKingPos())) {
59 return GR_WHITEMATES;
60 }
61 return GR_DRAW_STALEMATE;
62 }
63 }
64 if (threeFoldRepetition(b)) return GR_DRAW_THREEFOLD;
65
66 return GR_UNKNOWN;
67}
68
69/**
70 * @static Class static function
71 * convert all draw scores to SCORE_THEORETIC_DRAW
72 * @return -SCORE_MATE, SCORE_MATE or SCORE_THEORETIC_DRAW
73 */
75{
76 if (gr == GR_BLACKMATES) return -SCORE_MATE;
77 else if (gr == GR_WHITEMATES) return SCORE_MATE;
79}
80
81/**
82 * @static Class static function
83 * test if draw by insufficient material, 2 pieces or 3-4 pieces
84 * other >3 pieces, never material draw ("KNKN", "KNKB", "KBKN" are not draws by FIDE rule)
85 * @return true if insufficient material to mate
86 */
87bool bPositionEvaluation::insufficientMaterial(bBoard const& b)
88{
89 if (b.pieceCount() > 4) return false;
90 if (b.pieceCount() == 2) return true; // only KK, so always draw
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 |= belofteeval::fieldcolours[iCase];
129 break;
130 case tPiece::B_BISHOP:
131 ++blackbishop;
132 blackmask |= belofteeval::fieldcolours[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
223namespace belofteeval {
224
226 // empty, king, pawn, knight, bishop, rook queen
227 // black pieces have negative score
228 0, 0, 100, 300, 300, 500, 900
229};
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// bottom left position is a8, then b8, topmost a1 - h1
240// score for black pieces is inverted
242 // empty
243 {},
244 // White King
245 {
246 5, 6, 8, 0, 0, 2, 10, 5,
247 0, 0, 1, -2, -3, -1, 2, 0,
248 -2, -3, -5, -5, -5, -5, -2, 0,
249 -6, -6, -6, -6, -6, -6, -6, -6,
250 -5, -2, -5, -5, -5, -5, -2, -5,
251 -5, 0, 0, 0, 0, 0, 0, -5,
252 -15, -10, -10, -10, -10, -10, -10, -15,
253 -20, -15, -10, -10, -10, -10, -15, -20
254 },
255 // White Pawn
256 {
257 0, 0, 0, 0, 0, 0, 0, 0,
258 5, 10, 10, -30, -30, 10, 10, 5,
259 5, 5, 0, 10, 10, 0, 5, 5,
260 0, 0, 10, 20, 20, 0, 0, 0,
261 0, 0, 0, 10, 10, 0, 0, 0,
262 20, 50, 60, 80, 80, 60, 50, 20,
263 80, 80, 100, 100, 100, 100, 80, 80,
264 0, 0, 0, 0, 0, 0, 0, 0
265 },
266 // White Knight
267 {
268 -40, -10, -5, -5, -5, -5, -10, -40,
269 -10, -5, 0, 0, 0, 0, -5, -10,
270 -5, 0, 5, 5, 5, 5, 0, -5,
271 0, 5, 5, 5, 5, 5, 5, 0,
272 2, 8, 8, 8, 8, 8, 8, 2,
273 0, 2, 5, 5, 5, 5, 2, 0,
274 -5, -5, 2, 5, 5, 2, -5, -5,
275 -20, -10, -5, 0, 0, -5, -10, -20
276 },
277 // White Bishop
278 {
279 -10, -8, -4, -6, -6, -4, 0, -10,
280 -6, 6, -2, 4, 4, 0, 6, -6,
281 -4, 0, 0, 2, 4, 0, -2, 0,
282 0, 4, 8, 4, 4, 8, 4, 0,
283 2, 6, 4, 2, 2, 4, 6, 4,
284 2, 0, 6, 4, 4, 4, 0, 0,
285 2, 0, 2, 0, -2, -2, -2, -4,
286 -10, -8, -6, -4, -4, -6, -8, -10
287 },
288 // White Rook
289 {
290 0, -6, 8, 20, 20, 2, -6, 0,
291 -5, -2, -2, 4, 4, -2, -8, -5,
292 -3, 0, 1, 2, 2, 2, 0, -3,
293 -1, 0, 0, 0, 0, 0, 0, -1,
294 0, 1, 0, 2, 2, 0, 1, 0,
295 2, 1, 1, 3, 3, 1, 1, 1,
296 6, 8, 10, 10, 10, 10, 8, 6,
297 3, 3, 5, 5, 5, 3, 3, 2
298 },
299 // White Queen
300 {
301 -3, -5, -3, -1, 0, -2, -5, -1,
302 -5, -2, 2, 3, 3, 2, -2, -5,
303 -2, 1, 1, 3, 3, 2, 3, -2,
304 0, 0, 0, 0, 0, 0, 0, 0,
305 0, 0, 0, 0, 0, 0, 0, 0,
306 2, 3, 4, 4, 3, 3, 2, 0,
307 -2, 3, 3, 4, 3, 3, 1, -2,
308 0, 2, 2, 0, -1, -1, -5, -1
309 },
310};
311
312// score for black pieces is inverted
314 // empty
315 {},
316 // White King
317 {
318 -30, -20, -15, -15, -15, -15, -20, -30,
319 -20, -10, -5, -5, -5, -5, -10, -20,
320 -15, -5, 0, 0, 0, 0, -5, -15,
321 -15, -5, 0, 5, 5, 0, -5, -15,
322 -15, -5, 0, 5, 5, 0, -5, -15,
323 -15, -5, 0, 0, 0, 0, -5, -15,
324 -20, -10, -5, -5, -5, -5, -10, -20,
325 -30, -20, -15, -15, -15, -15, -20, -30
326 },
327 // White Pawn
328 {
329 0, 0, 0, 0, 0, 0, 0, 0,
330 0, 0, 0, -30, -30, 0, 0, 0,
331 0, 0, 0, 0, 0, 0, 0, 0,
332 0, 0, 0, 0, 0, 0, 0, 0,
333 20, 20, 30, 30, 30, 20, 20, 20,
334 40, 50, 60, 80, 80, 60, 50, 40,
335 80, 80, 100, 100, 100, 100, 80, 80,
336 0, 0, 0, 0, 0, 0, 0, 0
337 },
338 // White Knight
339 {
340 -20, -10, -5, 0, 0, -5, -10, -20,
341 -10, -5, 0, 0, 0, 0, -5, -10,
342 -5, 0, 5, 5, 5, 5, 0, -5,
343 0, 0, 5, 20, 20, 5, 0, 0,
344 0, 0, 5, 20, 20, 5, 0, 0,
345 -5, 0, 5, 5, 5, 5, 0, -5,
346 -10, -5, 0, 0, 0, 0, -5, -10,
347 -20, -10, -5, 0, 0, -5, -10, -20
348 },
349 // White Bishop
350 {
351 -20, -10, -5, 0, 0, -5, -10, -20,
352 -10, -5, 0, 0, 0, 0, -5, -10,
353 -5, 0, 5, 5, 5, 5, 0, -5,
354 0, 0, 5, 20, 20, 5, 0, 0,
355 0, 0, 5, 20, 20, 5, 0, 0,
356 -5, 0, 5, 5, 5, 5, 0, -5,
357 -10, -5, 0, 0, 0, 0, -5, -10,
358 -20, -10, -5, 0, 0, -5, -10, -20
359 },
360 // White Rook
361 {
362 -20, 10, 0, 0, 0, 0, 10, -20,
363 10, 10, 10, 10, 10, 10, 10, 10,
364 0, 10, 0, 0, 0, 0, 10, 0,
365 0, 10, 0, 0, 0, 0, 10, 0,
366 0, 10, 0, 0, 0, 0, 10, 0,
367 0, 10, 0, 0, 0, 0, 10, 0,
368 10, 10, 10, 10, 10, 10, 10, 10,
369 -20, 10, 0, 0, 0, 0, 10, -20
370 },
371 // White Queen
372 {
373 -20, -10, -5, 0, 0, -5, -10, -20,
374 -10, -5, 0, 0, 0, 0, -5, -10,
375 -5, 0, 5, 5, 5, 5, 0, -5,
376 0, 0, 5, 20, 20, 5, 0, 0,
377 0, 0, 5, 20, 20, 5, 0, 0,
378 -5, 0, 5, 5, 5, 5, 0, -5,
379 -10, -5, 0, 0, 0, 0, -5, -10,
380 -20, -10, -5, 0, 0, -5, -10, -20
381 },
382};
383
385 0, 1, 2, 3, 3, 2, 1, 0,
386 1, 2, 4, 5, 5, 4, 2, 1,
387 2, 4, 6, 7, 7, 6, 4, 2,
388 3, 5, 7, 9, 9, 7, 5, 3,
389 3, 5, 7, 9, 9, 7, 5, 3,
390 2, 4, 6, 7, 7, 6, 4, 2,
391 1, 2, 4, 5, 5, 4, 2, 1,
392 0, 1, 2, 3, 3, 2, 1, 0
393};
394
395}
396
397//-----------------------------------------------------------------------
398
399/**
400 * Store black piece and field values as negative of whites view
401 */
403 : m_name{std::move(s)}
404{
405 for (int i = 7; i < tPiece::P_SIZE; ++i) {
408 for (column_t iCol = 0; iCol < 8; ++iCol) {
409 for (rank_t iRank = 0; iRank < 8; ++iRank) {
410 if (belofteeval::positionvalues[i - 6][bCase::coordToCase(iCol, 7 - iRank)] != 0) {
412 = -belofteeval::positionvalues[i - 6][bCase::coordToCase(iCol, 7 - iRank)];
413 }
414 if (belofteeval::endgamevalues[i - 6][bCase::coordToCase(iCol, 7 - iRank)] != 0) {
416 = -belofteeval::endgamevalues[i - 6][bCase::coordToCase(iCol, 7 - iRank)];
417 }
418 }
419 }
420 }
421 for (int i = 0; i < tPiece::P_SIZE; ++i)
424}
425
426/**
427 * get final score (+-SCORE_MATE, SCORE_THEORETIC_DRAW) or 0
428 */
430{
431 if (gr == GR_UNSET) gr = gameEndedResult(b);
432 if (gr != GR_UNKNOWN) return resultToScoreFlag(gr);
433
434 return 0;
435}
436
437//-----------------------------------------------------------------------
438
439/**
440 * get pure material evaluation of score from whites view
441 */
443{
444 if (gr == GR_UNSET) gr = gameEndedResult(b);
445 if (gr != GR_UNKNOWN) return resultToScoreFlag(gr);
446
447 bScore value = static_cast<bScore>(belofte::getRandomRange(-5, 5));
448 for (case_t iCase = 0; iCase < 64; ++iCase) {
449 int piece = b.getPiece(iCase);
450 if (piece) {
451 value += belofteeval::roundedpiecevalues[piece];
452 }
453 }
454 return value;
455}
456
457//-----------------------------------------------------------------------
458
459/**
460 * get material and case related modification of score from whites view
461 */
463{
464 if (gr == GR_UNSET) gr = gameEndedResult(b);
465 if (gr != GR_UNKNOWN) return resultToScoreFlag(gr);
466
468 return getEndgameEvaluation(b);
469
471 return getPawnEndingEvaluation(b);
472
474 return getMatingEvaluation(b);
475
476 return getRelativeBoardEval(b);
477}
478
480{
481 bScore value = static_cast<bScore>(belofte::getRandomRange(-5, 5));
482 bScore white = 0;
483 bScore black = 0;
484 for (case_t iCase = 0; iCase < 64; ++iCase) {
485 int piece = b.getPiece(iCase);
486 if (piece >= tPiece::B_KING) {
487 black += belofteeval::piecevalues[piece];
488 value += belofteeval::positionvalues[piece][iCase];
489 } else if (piece) {
490 white += belofteeval::piecevalues[piece];
491 value += belofteeval::positionvalues[piece][iCase];
492 }
493 }
494 return value + (white - black) + ((white - black) / (white + black));
495}
496
498{
499 bScore value = static_cast<bScore>(belofte::getRandomRange(-5, 5));
500 for (case_t iCase = 0; iCase < 64; ++iCase) {
501 int piece = b.getPiece(iCase);
502 if (piece >= tPiece::B_KING) {
503 value -= belofteeval::piecevalues[piece];
504 value -= belofteeval::centerplayvalues[iCase];
505 } else if (piece) {
506 value += belofteeval::piecevalues[piece];
507 value += belofteeval::centerplayvalues[iCase];
508 }
509 }
510 return value;
511}
512
514{
515 bScore value = static_cast<bScore>(belofte::getRandomRange(-5, 5));
516 for (case_t iCase = 0; iCase < 64; ++iCase) {
517 int piece = b.getPiece(iCase);
518 if (piece >= tPiece::B_KING) {
519 value -= belofteeval::piecevalues[piece];
520 } else if (piece) {
521 value += belofteeval::piecevalues[piece];
522 }
523 }
524 return value;
525}
526
528{
529 bScore value = static_cast<bScore>(belofte::getRandomRange(-2, 2));
530 for (case_t iCase = 0; iCase < 64; ++iCase) {
531 int piece = b.getPiece(iCase);
532 if (piece >= tPiece::B_KING) {
533 value -= belofteeval::piecevalues[piece];
534 } else if (piece) {
535 value += belofteeval::piecevalues[piece];
536 }
537 value += belofteeval::endgamevalues[piece][iCase];
538 }
539 return value;
540}
541
542//-----------------------------------------------------------------------
543
544/**
545 * get positional evaluation from whites view
546 */
548{
549 if (gr == GR_UNSET) gr = gameEndedResult(b);
550 if (gr != GR_UNKNOWN) return resultToScoreFlag(gr);
551
552 bScore value;
554 value = getEndgameEvaluation(b);
556 return getPawnEndingEvaluation(b);
557 else if (b.getGameStage() == bGameStage::ST_MATING)
558 return getMatingEvaluation(b);
559 else
560 value = getRelativeBoardEval(b);
561
562 value += getKingEvaluation(b);
563 value += getPawnEvaluation(b);
564 value += getRookEvaluation(b);
565 value += getBishopEvaluation(b);
566 value += getQueenEvaluation(b);
567
568 return value;
569}
570
571bScore PosEvalPositionalBoard::getKingEvaluation(bBoard const& b)
572{
573 bScore value = 0;
574
576 // add up to 30 centipoints for castle ability, 30 if castled { }
577 if (b.whiteHasCastled()) { value += 30; }
579 // has short or long rights
582 value += 30; // short and long castle rights
583 } else {
584 value += 25; // short only
585 }
586 } else {
587 value += 20; // long only
588 }
589 }
590
591 if (b.blackHasCastled()) { value -= 30; }
593 // has short or long rights
596 value -= 30; // short and long castle rights
597 } else {
598 value -= 25; // short only
599 }
600 } else {
601 value -= 20; // long only
602 }
603 }
604 }
605
606 return value;
607}
608
609bScore PosEvalPositionalBoard::getPawnEvaluation(bBoard const& b)
610{
611 bScore value = 0;
612 /// @todo move pawn column occupation to calcMinorPieces
613 uint8_t whitePawns[8] = {};
614 uint8_t blackPawns[8] = {};
615 uint8_t whiteIslands = 0, blackIslands = 0;
616
617 /// @todo iterate through whitePieces[] instead
618 for (rank_t iRank = 1; iRank < 7; ++iRank) {
619 for (column_t iCol = 0; iCol < 8; ++iCol) {
620 piece_t piece = b.getPiece(iCol, iRank);
621 if (piece == tPiece::W_PAWN) {
622 whitePawns[iCol]++;
623 } else if (piece == tPiece::B_PAWN) {
624 blackPawns[iCol]++;
625 }
626 }
627 }
628
629 // malus for 25 for double pawn, 50 for triple pawn or border double pawn
630 for (column_t iCol = 0; iCol < 8; ++iCol) {
631 if (whitePawns[iCol] > 1) value -= 25 * whitePawns[iCol];
632 if (blackPawns[iCol] > 1) value += 25 * blackPawns[iCol];
633 }
634 if (whitePawns[0] > 1) value -= 25;
635 if (whitePawns[7] > 1) value -= 25;
636 if (blackPawns[0] > 1) value += 25;
637 if (blackPawns[7] > 1) value += 25;
638
639 // count adjacent pawn groups, 15 malus for isolated pawn
640 // 20 malus for more islands than opponent
641 uint8_t bGroup = 0;
642 for (column_t iCol = 0; iCol < 8; ++iCol) {
643 if (whitePawns[iCol]) {
644 if (!blackPawns[iCol]) {
645 if (whitePassed(b, iCol)) value += 30;
646 }
647 if (!bGroup) { ++whiteIslands; ++bGroup; }
648 } else {
649 if (bGroup == 1) value -= 15; // isolated pawn found
650 bGroup = 0;
651 }
652 }
653 // test same for last column
654 if (bGroup == 1) value -= 15; // isolated pawn found
655 bGroup = 0;
656 for (column_t iCol = 0; iCol < 8; ++iCol) {
657 if (blackPawns[iCol]) {
658 if (!whitePawns[iCol]) {
659 if (blackPassed(b, iCol)) value -= 30;
660 }
661 if (!bGroup) { ++blackIslands; ++bGroup; }
662 } else {
663 if (bGroup == 1) value += 15; // isolated pawn found
664 bGroup = 0;
665 }
666 }
667 // test same for last column
668 if (bGroup == 1) value += 15; // isolated pawn found
669 if (whiteIslands > blackIslands) value -= 10;
670 else if (whiteIslands < blackIslands) value += 10;
671
672 return value;
673}
674
675/**
676 * @static Class static function
677 * see if pawn has passed, we are only interested in frontmost pawn
678 * function assumes that there is at least a pawn on rank, no checks
679 */
680bool PosEvalPositionalBoard::whitePassed(bBoard const& b, column_t const iCol)
681{
682 bool passed = true;
683 rank_t iRank = 6;
684 while (iRank) {
685 if (b.getPiece(iCol, iRank) == tPiece::W_PAWN) break;
686 --iRank;
687 }
688 if (iCol) {
689 for (rank_t i = iRank + 1; i < 7; ++i) {
690 if (b.getPiece(iCol - 1, i) == tPiece::B_PAWN) return false;
691 }
692 }
693 if (iCol < 7) {
694 for (rank_t i = iRank + 1; i < 7; ++i) {
695 if (b.getPiece(iCol + 1, i) == tPiece::B_PAWN) return false;
696 }
697 }
698 return passed;
699}
700
701bool PosEvalPositionalBoard::blackPassed(bBoard const& b, column_t const iCol)
702{
703 bool passed = true;
704 rank_t iRank = 1;
705 while (iRank < 6) {
706 if (b.getPiece(iCol, iRank) == tPiece::B_PAWN) break;
707 ++iRank;
708 }
709 if (iCol) {
710 for (rank_t i = iRank - 1; i > 0; i--) {
711 if (b.getPiece(iCol - 1, i) == tPiece::W_PAWN) return false;
712 }
713 }
714 if (iCol < 7) {
715 for (rank_t i = iRank - 1; i > 0; i--) {
716 if (b.getPiece(iCol + 1, i) == tPiece::W_PAWN) return false;
717 }
718 }
719 return passed;
720}
721
722bScore PosEvalPositionalBoard::getRookEvaluation(bBoard const& b)
723{
724 bScore value = 0;
725
726 if (b.m_whitePieces[STAT_ROOK].size()) {
727 for (unsigned int i=0; i < b.m_whitePieces[STAT_ROOK].size(); ++i) {
728 rank_t iRank = bCase::rank(b.m_whitePieces[STAT_ROOK][i]);
729 column_t iCol = bCase::column(b.m_whitePieces[STAT_ROOK][i]);
730 // we need at least 2 to get linked values
731 if (i && seesHorVer(b, iCol, iRank, tPiece::W_ROOK)) value += 20;
732 if (blackKingSameRankCol(b, iCol, iRank)) value += 25;
733 if (sameCol(b, iCol, iRank, tPiece::B_QUEEN)) value += 15;
734 else if (sameRank(b, iCol, iRank, tPiece::B_QUEEN)) value += 15;
735 value += openLineValWhite(b, iCol, iRank);
736 value += rookRankValWhite(b, iRank);
737 }
738 }
739
740 if (b.m_blackPieces[STAT_ROOK].size()) {
741 for (unsigned int i=0; i < b.m_blackPieces[STAT_ROOK].size(); ++i) {
742 rank_t iRank = bCase::rank(b.m_blackPieces[STAT_ROOK][i]);
743 column_t iCol = bCase::column(b.m_blackPieces[STAT_ROOK][i]);
744 if (i && seesHorVer(b, iCol, iRank, tPiece::B_ROOK)) value -= 20;
745 if (whiteKingSameRankCol(b, iCol, iRank)) value -= 25;
746 if (sameCol(b, iCol, iRank, tPiece::W_QUEEN)) value -= 15;
747 else if (sameRank(b, iCol, iRank, tPiece::W_QUEEN)) value -= 15;
748 value -= openLineValBlack(b, iCol, iRank);
749 value -= rookRankValBlack(b, iRank);
750 }
751 }
752
753 return value;
754}
755
756/**
757 * @static Class static function
758 * check if we see a rook in any direction from this case on
759 * @todo allow to have indirect match of second rook on same column/rank
760 */
761bool PosEvalPositionalBoard::seesHorVer(bBoard const& b,
762 column_t iCol, rank_t iRank, piece_t const matchPiece)
763{
764 column_t c = iCol - 1;
765 while (c > 0) {
766 if (b.getPiece(c, iRank) == matchPiece) return true;
767 if (!b.isFieldEmpty(c, iRank)) break;
768 --c;
769 }
770 c = iCol + 1;
771 while (c < 8) {
772 if (b.getPiece(c, iRank) == matchPiece) return true;
773 if (!b.isFieldEmpty(c, iRank)) break;
774 ++c;
775 }
776
777 rank_t r = iRank - 1;
778 while (r > 0) {
779 if (b.getPiece(iCol, r) == matchPiece) return true;
780 if (!b.isFieldEmpty(iCol, r)) break;
781 --r;
782 }
783 r = iRank + 1;
784 while (r < 8) {
785 if (b.getPiece(iCol, r) == matchPiece) return true;
786 if (!b.isFieldEmpty(iCol, r)) break;
787 ++r;
788 }
789 return false;
790}
791
792/**
793 * @static Class static function
794 * Check if certain piece is on same rank
795 * Used to verify rook on Queen rank
796 * @return true if yes
797 */
798bool PosEvalPositionalBoard::sameRank(bBoard const& b, column_t const iCol,
799 rank_t const iRank, piece_t const matchPiece)
800{
801 column_t c = 0;
802 while (c < iCol) {
803 if (b.getPiece(c, iRank) == matchPiece) return true;
804 ++c;
805 }
806 c = iCol + 1;
807 while (c < 8) {
808 if (b.getPiece(c, iRank) == matchPiece) return true;
809 ++c;
810 }
811 return false;
812}
813
814/**
815 * @static Class static function
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)
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 * @static Class static function
838 * Check if Queen or Rook is on same rank or column as king
839 * @return true if yes
840 */
841bool PosEvalPositionalBoard::whiteKingSameRankCol(bBoard const& b,
842 column_t const iCol, rank_t const iRank)
843{
844 if (bCase::column(b.getWhiteKingPos()) == iCol) return true;
845 return bCase::rank(b.getWhiteKingPos()) == iRank;
846}
847
848bool PosEvalPositionalBoard::blackKingSameRankCol(bBoard const& b,
849 column_t const iCol, rank_t const iRank)
850{
851 if (bCase::column(b.getBlackKingPos()) == iCol) return true;
852 return bCase::rank(b.getBlackKingPos()) == iRank;
853}
854
855/**
856 * @static Class static function
857 * see if rook is on open or semi-open line
858 */
859bScore PosEvalPositionalBoard::openLineValWhite(bBoard const& b, column_t const iCol,
860 rank_t iRank)
861{
862 while (++iRank < 7) {
863 piece_t piece = b.getPiece(iCol, iRank);
864 if (piece == tPiece::W_PAWN) return 0;
865 if (piece == tPiece::B_PAWN) return 5;
866 }
867 return 10;
868}
869
870/**
871 * @static Class static function
872 * see if rook is on open or semi-open line
873 */
874bScore PosEvalPositionalBoard::openLineValBlack(bBoard const& b, column_t const iCol,
875 rank_t iRank)
876{
877 while (--iRank > 0) {
878 piece_t piece = b.getPiece(iCol, iRank);
879 if (piece == tPiece::B_PAWN) return 0;
880 if (piece == tPiece::W_PAWN) return 5;
881 }
882 return 10;
883}
884
885bScore PosEvalPositionalBoard::rookRankValWhite(bBoard const& b,
886 rank_t const iRank)
887{
888 if ((iRank == 0) || (iRank == 7)) return 0;
889 bScore value = 0;
890 for (column_t iCol = 0; iCol < 8; ++iCol) {
891 if (b.getPiece(iCol, iRank) == tPiece::B_PAWN) value += 2;
892 }
893 return value;
894}
895
896bScore PosEvalPositionalBoard::rookRankValBlack(bBoard const& b,
897 rank_t const iRank)
898{
899 if ((iRank == 0) || (iRank == 7)) return 0;
900 bScore value = 0;
901 for (column_t iCol = 0; iCol < 8; ++iCol) {
902 if (b.getPiece(iCol, iRank) == tPiece::W_PAWN) value += 2;
903 }
904 return value;
905}
906
907bScore PosEvalPositionalBoard::getBishopEvaluation(bBoard const& b)
908{
909 bScore value = 0;
910
911 if (b.m_whitePieces[STAT_BISHOP].size()) {
912 for (auto const& v : b.m_whitePieces[STAT_BISHOP]) {
913 rank_t iRank = bCase::rank(v);
914 column_t iCol = bCase::column(v);
915 if (sameColourBlackKing(b, v)) {
916 value += 3;
917 if (sameDiagonal(b, iCol, iRank, tPiece::B_KING)) value += 7;
918 }
919 if (sameDiagonal(b, iCol, iRank, tPiece::B_QUEEN)) value += 5;
920 else if (sameColour(b, v, tPiece::B_QUEEN)) value += 2;
921 }
922 }
923
924 if (b.m_blackPieces[STAT_BISHOP].size()) {
925 for (auto const& v : b.m_blackPieces[STAT_BISHOP]) {
926 rank_t iRank = bCase::rank(v);
927 column_t iCol = bCase::column(v);
928 if (sameColourWhiteKing(b, v)) {
929 value -= 3;
930 if (sameDiagonal(b, iCol, iRank, tPiece::W_KING)) value -= 7;
931 }
932 if (sameDiagonal(b, iCol, iRank, tPiece::W_QUEEN)) value -= 5;
933 else if (sameColour(b, v, tPiece::W_QUEEN)) value -= 2;
934 }
935 }
936
937 return value;
938}
939
940/**
941 * @static Class static function
942 */
943bool PosEvalPositionalBoard::sameDiagonal(bBoard const& b, column_t const iCol,
944 rank_t const iRank, piece_t const matchPiece)
945{
946 int8_t nMax = iCol;
947 for (int8_t i = 1; i <= nMax; ++i) {
948 if (b.getPieceCtl(iCol - i, iRank - i) == matchPiece) return true;
949 if (b.getPieceCtl(iCol - i, iRank + i) == matchPiece) return true;
950 }
951 nMax = 7 - iCol;
952 for (int8_t i = 1; i <= nMax; ++i) {
953 if (b.getPieceCtl(iCol + i, iRank - i) == matchPiece) return true;
954 if (b.getPieceCtl(iCol + i, iRank + i) == matchPiece) return true;
955 }
956 return false;
957}
958
959/**
960 * @static Class static function
961 * see if matching piece is of same colour as original piece
962 * @todo loop through piecelist instead of 64 fields
963 */
964bool PosEvalPositionalBoard::sameColour(bBoard const& b, case_t const c,
965 piece_t const matchPiece)
966{
967 uint8_t pieceColour = belofteeval::fieldcolours[c];
968 for (case_t iCase = 0; iCase < 64; iCase++) {
969 if (b.getPiece(iCase) == matchPiece) {
970 return belofteeval::fieldcolours[iCase] == pieceColour;
971 }
972 }
973 return false;
974}
975
976/**
977 * @static Class static function
978 * see if matching king is of same colour as original piece
979 */
980bool PosEvalPositionalBoard::sameColourWhiteKing(bBoard const& b,
981 case_t const iCol)
982{
984}
985
986/**
987 * @static Class static function
988 * see if matching king is of same colour as original piece
989 */
990bool PosEvalPositionalBoard::sameColourBlackKing(bBoard const& b,
991 case_t const iCol)
992{
994}
995
996bScore PosEvalPositionalBoard::getQueenEvaluation(bBoard const& b)
997{
998 bScore value = 0;
999
1000 if (b.m_whitePieces[STAT_QUEEN].size()) {
1001 for (auto const& v : b.m_whitePieces[STAT_QUEEN]) {
1002 rank_t iRank = bCase::rank(v);
1003 column_t iCol = bCase::column(v);
1004 if (PosEvalPositionalBoard::sameDiagonal(b, iCol, iRank, tPiece::B_KING)) value += 5;
1005 if (blackKingSameRankCol(b, iCol, iRank)) value += 5;
1006 }
1007 }
1008
1009 if (b.m_blackPieces[STAT_QUEEN].size()) {
1010 for (auto const& v : b.m_blackPieces[STAT_QUEEN]) {
1011 rank_t iRank = bCase::rank(v);
1012 column_t iCol = bCase::column(v);
1013 if (PosEvalPositionalBoard::sameDiagonal(b, iCol, iRank, tPiece::W_KING)) value -= 5;
1014 if (whiteKingSameRankCol(b, iCol, iRank)) value -= 5;
1015 }
1016 }
1017
1018 return value;
1019}
1020
1021// 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:253
This is the main include file, needs to be included before any other include.
int8_t rank_t
Definition belofte.h:97
int8_t column_t
Definition belofte.h:98
uint8_t case_t
Definition belofte.h:99
@ 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, gameResult_t gr) const override
get pure material evaluation of score from whites view
Definition eval.cpp:442
bScore getEvaluation(bBoard const &b, gameResult_t gr) const override
get positional evaluation from whites view
Definition eval.cpp:547
static bScore getMatingEvaluation(bBoard const &b)
Definition eval.cpp:527
static bScore getEndgameEvaluation(bBoard const &b)
Definition eval.cpp:497
static bScore getPawnEndingEvaluation(bBoard const &b)
Definition eval.cpp:513
static bScore getRelativeBoardEval(bBoard const &b)
Definition eval.cpp:479
bScore getEvaluation(bBoard const &b, gameResult_t gr) const override
get material and case related modification of score from whites view
Definition eval.cpp:462
constexpr piece_t getPiece(case_t const cf) const
Definition basicboard.h:178
constexpr bool whiteToMove() const
Definition basicboard.h:162
constexpr bool isFieldEmpty(case_t const cf) const
Definition basicboard.h:207
constexpr bool blackHasCastled() const
Definition basicboard.h:131
constexpr bool whiteHasCastled() const
Definition basicboard.h:129
constexpr bool hasCastleRights(uint8_t const f) const
Definition basicboard.h:119
constexpr case_t getBlackKingPos() const
Definition basicboard.h:214
constexpr hashkey_t getHash() const
Definition basicboard.h:231
constexpr case_t getWhiteKingPos() const
Definition basicboard.h:212
constexpr movenum50_t getPly50Moves() const
Definition basicboard.h:109
constexpr int8_t pieceCount() const
Definition basicboard.h:227
piece_t getPieceCtl(column_t const iColumn, rank_t const iRank) const
Definition basicboard.h:182
board
Definition board.h:45
constexpr bGameStage getGameStage() const
Definition board.h:68
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:481
static bScore resultToScoreFlag(gameResult_t const gr)
Class static function convert all draw scores to SCORE_THEORETIC_DRAW.
Definition eval.cpp:74
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, gameResult_t gr) const
get final score (+-SCORE_MATE, SCORE_THEORETIC_DRAW) or 0
Definition eval.cpp:429
@ GR_DRAW_50
Definition eval.h:34
@ GR_UNSET
Definition eval.h:32
@ GR_DRAW_STALEMATE
Definition eval.h:34
@ GR_UNKNOWN
Definition eval.h:33
@ GR_WHITEMATES
Definition eval.h:36
@ GR_BLACKMATES
Definition eval.h:37
@ GR_DRAW_LACKMATERIAL
Definition eval.h:34
@ GR_DRAW_THREEFOLD
Definition eval.h:34
constexpr bScore SCORE_MATE
Definition eval.h:19
enum gameResult gameResult_t
Definition eval.h:40
int16_t bScore
Definition eval.h:11
constexpr bScore SCORE_THEORETIC_DRAW
Definition eval.h:16
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:10
int getRandomRange(int const nStart, int const nMax)
Definition util.cpp:242
bBlackKing const * cBlackKingClass
Definition movelist.cpp:16
bWhiteKing const * cWhiteKingClass
Definition movelist.cpp:15
const bScore centerplayvalues[]
Definition eval.cpp:384
static bScore roundedpiecevalues[tPiece::P_SIZE]
Definition eval.cpp:225
bScore piecevalues[]
Definition eval.cpp:231
static bScore endgamevalues[tPiece::P_SIZE][64]
Definition eval.cpp:313
static constexpr uint8_t fieldcolours[64]
Definition eval.cpp:17
bScore piecevalues_movepenalty[]
Definition eval.cpp:237
static bScore positionvalues[tPiece::P_SIZE][64]
Definition eval.cpp:241
@ 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