Belofte version 2.1.8
A promising chess program using the UCI or Winboard interface
board.cpp
Go to the documentation of this file.
1/*---------------------------------------------------------------------+
2 * File: board.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//-----------------------------------------------------------------------
11
13 : u_positionFlags{bb.u_positionFlags}
14 , m_hash{bb.m_hash}
15 , m_fields{bb.m_fields}
16{
17}
18
20 : u_positionFlags{std::move(bb.u_positionFlags)}
21 , m_hash{std::move(bb.m_hash)}
22 , m_fields{std::move(bb.m_fields)}
23{
24}
25
29
30#if defined(__GNUC__)
31#pragma GCC diagnostic push
32#pragma GCC diagnostic ignored "-Weffc++"
33#endif
34
36{
37 u_positionFlags = 0ULL;
38 for (case_t iCase = 0; iCase < 64; iCase++) m_fields[iCase] = tPiece::P_EMPTY;
39
40 // parse
41 std::string sFen = belofte::alltrim(fen); // remove leading and trailing space
42 belofte::stringList const fenParts = belofte::stringSplit(sFen, " ");
43 belofte::stringList const rowParts = belofte::stringSplit(fenParts[0], "/");
44
45 // part 1, board filler
46 for (rank_t iRank = 0; iRank < 8; iRank++) {
47 auto initRank = [this](rank_t iR, std::string const& rankdata) -> void {
48 column_t iCol = 0;
49 unsigned int i = 0;
50 while (iCol < 8) {
51 unsigned char c = static_cast<unsigned char>(rankdata[i++]);
52 if (c == 0) {
53 break;
54 } else if ((c >= '1') && (c <= '8')) {
55 iCol += (c - '0');
56 } else {
57 setPieceKU(bCase::coordToCase(iCol, iR), bPiece::getPiece(static_cast<cpiece_t>(c)));
58 iCol++;
59 }
60 }
61 };
62 initRank(7 - iRank, rowParts[static_cast<unsigned long>(iRank)]);
63 }
64
65 if (fenParts.size() > 2) {
66 // part 3, castling rights
67 setCastle(tCFlags::WCASTLE_S, fenParts[2].find('K') != std::string::npos);
68 setCastle(tCFlags::WCASTLE_L, fenParts[2].find('Q') != std::string::npos);
69 setCastle(tCFlags::BCASTLE_S, fenParts[2].find('k') != std::string::npos);
70 setCastle(tCFlags::BCASTLE_L, fenParts[2].find('q') != std::string::npos);
71 }
72
73 if (fenParts.size() > 3) {
74 // part 4, ep case
75 if (fenParts[3] == "-") {
76 clearEp();
77 } else {
78 setEp(bCase(fenParts[3]).getCaseT());
79 }
80 }
81
82 if (fenParts.size() > 4) {
83 // part 5, 50 move number (half-move / ply)
84 setPly50Moves(static_cast<movenum50_t>(atoi(fenParts[4].c_str())));
85 }
86
87 if (fenParts.size() > 5) {
88 // part 6, move number, starting from 1
89 setPly(static_cast<plynum_t>((atoi(fenParts[5].c_str()) - 1) * 2));
90 }
91
92 if (fenParts.size() > 1) {
93 // part 2, side to move
94 if (fenParts[1] == "b") incPly();
95 }
96
97 /**
98 @todo check legality of position: Max number of pieces
99 of each type e.g. K=1, Q=(9 - # pawns), N=(10 - # pawns)
100 colour of bishops, double in-check, in case of ep, adjacent pawn
101 movenumber if not initial position, location of pawns,
102 position of king and rooks in case of castle allowed (att. 960)
103 for each promoted piece, an opponent piece must have been taken
104 */
105 calcHash();
106}
107
108#if defined(__GNUC__)
109#pragma GCC diagnostic pop
110#endif
111
112//-----------------------------------------------------------------------
113
115{
116 std::string strfen;
117 piece_t nPiece;
118 std::string castl;
119
120 // part 1, board filler
121 for (rank_t iRank = 0; iRank < 8; iRank++) {
122 int iBlanks = 0;
123 for (column_t iCol = 0; iCol < 8; iCol++) {
124 nPiece = getPiece(iCol, 7 - iRank);
125 if (nPiece) {
126 if (iBlanks) strfen += static_cast<char>(iBlanks + '0');
127 iBlanks = 0;
128 strfen += static_cast<char>(bPiece::getPieceChar(nPiece));
129 } else {
130 iBlanks++;
131 }
132 }
133 if (iBlanks) strfen += static_cast<char>(iBlanks + '0');
134 if (iRank < 7) strfen += "/";
135 }
136
137 strfen += getColourToMove() == tSide::SIDE_BLACK ? " b " : " w ";
138
139 castl += canCastle(tCFlags::WCASTLE_S) ? "K" : "";
140 castl += canCastle(tCFlags::WCASTLE_L) ? "Q" : "";
141 castl += canCastle(tCFlags::BCASTLE_S) ? "k" : "";
142 castl += canCastle(tCFlags::BCASTLE_L) ? "q" : "";
143 strfen += castl.size() ? castl : "-";
144
145 if (getEp()) {
146 strfen += " " + std::string(bCase(getEp())) + " ";
147 } else {
148 strfen += " - ";
149 }
150 strfen += belofte::to_string(getPly50Moves()) + " " + belofte::to_string(getMoveNumber());
151
152 return bFen(strfen);
153}
154
155//-----------------------------------------------------------------------
156
158{
159 return m_fields[bc];
160}
161
163 rank_t const iRank) const
164{
165 return m_fields[bCase::coordToCase(iColumn, iRank)];
166}
167
168/** retrieve piece with bounds checking, return field empty in case
169 * of out of bounds
170 */
171piece_t bBasicBoard::getPieceCtl(column_t const iColumn, rank_t const iRank) const
172{
173 if ((iColumn < 0) || (iColumn > 7)) return tPiece::P_EMPTY;
174 if ((iRank < 0) || (iRank > 7)) return tPiece::P_EMPTY;
175 return m_fields[bCase::coordToCase(iColumn, iRank)];
176}
177
179{
180 return !m_fields[bc];
181}
182
184 rank_t const iRank) const
185{
186 return !m_fields[bCase::coordToCase(iColumn, iRank)];
187}
188
189/** used for promotion move generation */
190void bBasicBoard::setPiece(case_t const bc, piece_t const piece)
191{
192 m_fields[bc] = piece;
193}
194
195/** used for unMakeBoardMove */
196void bBasicBoard::setPiece(case_t const bc, uint8_t const piece)
197{
198 m_fields[bc] = static_cast<piece_t>(piece);
199}
200
201/** used for makeBoardMove */
203 piece_t const piece)
204{
205 case_t bc = bCase::coordToCase(newcol, newrank);
206 piece_t oldPiece = m_fields[bc];
207 m_fields[bc] = piece;
208 return oldPiece;
209}
210
211/** used for makeBoardMove */
213{
214 case_t bc = bCase::coordToCase(newcol, newrank);
215 piece_t oldPiece = m_fields[bc];
216 m_fields[bc] = tPiece::P_EMPTY;
217 return oldPiece;
218}
219
220/** used for setboard only */
221void bBasicBoard::setPieceKU(case_t const bc, piece_t const piece)
222{
223 m_fields[bc] = piece;
224 if (piece == tPiece::W_KING) m_whiteKing = bc;
225 else if (piece == tPiece::B_KING) m_blackKing = bc;
226}
227
229{
230 m_fields[bc] = tPiece::P_EMPTY;
231}
232
234{
235 if (m_ep != e) {
236 // clear old and set new
239 m_ep = e;
240 }
241}
242
244{
245 if (m_castling & 0x0F) return !isInCheck();
246 return false;
247}
248
249bool bBasicBoard::canCastle(uint8_t const f) const
250{
251 return m_castling & f;
252}
253
254void bBasicBoard::setCastle(uint8_t const f, bool const c)
255{
256 if (c) setCastle(f);
257 else clearCastle(f);
258}
259
260void bBasicBoard::setCastle(uint8_t const f)
261{
262 if (!(m_castling & f)) {
263 m_castling |= f;
264 // there can be (is) a difference in the offsets in the hash table and the castle flags
266 }
267}
268
269void bBasicBoard::clearCastle(uint8_t const f)
270{
271 if (m_castling & f) {
272 m_castling &= 0x0F & ~f; // make sure to align to 4 bits only
273 // there can be (is) a difference in the offsets in the hash table and the castle flags
275 }
276}
277
279{
280 return m_castling & 0x10;
281}
282
284{
285 m_castling |= 0x10;
286}
287
289{
290 m_castling &= ~(0x10);
291}
292
293/**
294 * Clear castle flag if rook captured
295 * update piece counter, update hash, clear field
296 */
298{
300 m_fields[c] = tPiece::P_EMPTY;
302 if (p == tPiece::W_ROOK) {
303 if (c == bCase::coordToCase(7, 0)) {
305 } else if (c == bCase::coordToCase(0, 0)) {
307 }
308 } else if (p == tPiece::B_ROOK) {
309 if (c == bCase::coordToCase(7, 7)) {
311 } else if (c == bCase::coordToCase(0, 7)) {
313 }
314 }
315}
316
317void bBasicBoard::movePiece(case_t const f, case_t const t, piece_t const p)
318{
319 m_fields[f] = tPiece::P_EMPTY;
320 m_fields[t] = p;
321 m_hash ^= hashmultiplexer[p][f] ^ hashmultiplexer[p][t];
322}
323
324void bBasicBoard::swapPiece(case_t const t, piece_t const op, piece_t const np)
325{
326 m_fields[t] = np;
327 m_hash ^= hashmultiplexer[op][t] ^ hashmultiplexer[np][t];
328}
329
331{
332 m_fields[f] = tPiece::P_EMPTY;
333 m_fields[t] = tPiece::W_KING;
335 m_whiteKing = t;
336}
337
339{
340 m_fields[f] = tPiece::P_EMPTY;
341 m_fields[t] = tPiece::B_KING;
343 m_blackKing = t;
344}
345
346//-----------------------------------------------------------------------
347
348/**
349 * Set hash based on board position, also calc pieces
350 * Byte 0: bits 4-6 capture count (masked)
351 * bit 7 player to move
352 * We are using 64 bits for hash
353 * @todo TOCHECK: increase to 64 bits, is there added value
354 */
356{
357 hashkey_t hash = HASH_INIT;
358 uint8_t piecesonboard = 0;
359 for (case_t iCase = 0; iCase < 64; iCase++) {
360 int piece = getPiece(iCase);
361 if (piece) {
362 hash ^= hashmultiplexer[piece][iCase];
363 piecesonboard++;
364 }
365 }
366
375
376 // use hash of field 0 or any of the ep fields
378
379 // set bit 63 (odd material)
380 if (piecesonboard & 0x01) hash |= HASH_ODDMATERIAL;
381
382 // set bit 64 (black to move)
384
385 m_hash = hash;
386}
387
388//-----------------------------------------------------------------------
389
390/** apply move to check if in check only, board to be discarded
391 * as it will be in incomplete state, no hash update
392 * no check flag set, etc.
393 * @param oldcol column from
394 * @param oldrank rank from
395 * @param newcol column to
396 * @param newrank rank to
397 * @param promotion piece
398 * @return captured piece
399 */
401 rank_t const oldrank, column_t const newcol,
402 rank_t const newrank, piece_t const promotion) {
403 // keep old flags
404 u_positionFlags_t oldFlags;
406
407 piece_t piece = removePiece(oldcol, oldrank); // clear from square
408
409 // in case of capture, we return captured piece
410 oldFlags.capturedpiece = setGetPiece(newcol, newrank, piece);
411
413 if (piece == tPiece::W_PAWN) {
414 if (newcol != oldcol) {
415 // this is a column change, so a capture move
416 // check if we need to clear ep case
417 if (getPiece(newcol, newrank) == tPiece::P_EMPTY) {
418 // ep move, clear pawn
419 clearPiece(bCase::coordToCase(newcol, newrank-1));
420 oldFlags.capturedpiece = tPiece::P_SIZE; // this is a special hack to allow
421 // unmake move to restore ep move
422 }
423 }
424 if (newrank == 7) {
425 // override new piece with promotion piece
426 setPiece(bCase::coordToCase(newcol, newrank), promotion);
427 }
428 } else if (piece == tPiece::W_KING) {
429 m_whiteKing = bCase::coordToCase(newcol, newrank);
430 if ((newcol - oldcol) == 2) {
431 // short castle
434 } else if ((newcol - oldcol) == -2) {
435 // long castle
438 }
439 }
440 } else {
441 // tSide::SIDE_BLACK
442 if (piece == tPiece::B_PAWN) {
443 if (newcol != oldcol) {
444 // this is a column change, so a capture move
445 // check if we need to clear ep case
446 if (getPiece(newcol, newrank) == tPiece::P_EMPTY) {
447 // ep move, clear pawn
448 clearPiece(bCase::coordToCase(newcol, newrank+1));
449 oldFlags.capturedpiece = tPiece::P_SIZE; // this is a special hack to allow
450 // unmake move to restore ep move
451 }
452 }
453 if (newrank == 0) {
454 // override new piece with promotion piece
455 setPiece(bCase::coordToCase(newcol, newrank), promotion);
456 }
457 } else if (piece == tPiece::B_KING) {
458 m_blackKing = bCase::coordToCase(newcol, newrank);
459 if ((newcol - oldcol) == 2) {
460 // short castle
463 } else if ((newcol - oldcol) == -2) {
464 // long castle
467 }
468 }
469 }
470 incPly();
471 return oldFlags;
472}
473
474/** undo makeBoardMove, restoring previous situation
475 * @param cf case from
476 * @param newcol column to
477 * @param newrank rank to
478 * @param oldFlags the positionFlags of the old position
479 * @param promotion move signals return to pawn
480 */
481void bBasicBoard::unMakeBoardMove(case_t const& cf, column_t const newcol,
482 rank_t const newrank,
483 u_positionFlags_t const oldFlags,
484 piece_t const promotion)
485{
486 case_t ct = bCase::coordToCase(newcol, newrank);
487 piece_t piece = getPiece(ct);
488
489 setPiece(cf, piece);
490 if (oldFlags.capturedpiece == tPiece::P_SIZE) {
491 // see remark on e.p move, we flag old piece as P_SIZE
492 // to be able to restore board on before ep move
493 clearPiece(ct);
495 setPiece(bCase::coordToCase(newcol, newrank-1), tPiece::W_PAWN);
496 } else {
497 // tSide::SIDE_BLACK
498 setPiece(bCase::coordToCase(newcol, newrank+1), tPiece::B_PAWN);
499 }
500 } else {
501 setPiece(ct, oldFlags.capturedpiece); // can be tPiece::P_EMPTY as well
503 if (piece == tPiece::W_KING) {
504 m_whiteKing = cf;
505 column_t oldcol = bCase::column(cf);
506 if ((newcol - oldcol) == 2) {
507 // short un-castle
510 } else if ((newcol - oldcol) == -2) {
511 // long un-castle
514 }
515 } else if (promotion != tPiece::P_EMPTY) {
517 }
518 } else {
519 // tSide::SIDE_BLACK
520 if (piece == tPiece::B_KING) {
521 m_blackKing = cf;
522 column_t oldcol = bCase::column(cf);
523 if ((newcol - oldcol) == 2) {
524 // short un-castle
527 } else if ((newcol - oldcol) == -2) {
528 // long un-castle
531 }
532 } else if (promotion != tPiece::P_EMPTY) {
534 }
535 }
536 }
538}
539
540//-----------------------------------------------------------------------
541
542std::string bBasicBoard::getHashStr() const
543{
544 std::stringstream ss;
545 ss << std::uppercase << std::setfill('0')
546 << std::setw(16) << std::hex << m_hash;
547 return ss.str();
548}
549
550//-----------------------------------------------------------------------
551
552#if defined(__GNUC__)
553#pragma GCC diagnostic push
554#pragma GCC diagnostic ignored "-Weffc++"
555#endif
556
557/**
558 * Used by bPgnMove ctor, popuplateMoveList, atLeastOneMovePossible
559 * movesinpgnformat
560 * @todo make function obsolete to avoid confusion
561 */
563 : bBasicBoard{std::move(b)}
564 , u_boardFlags1{std::move(b.u_boardFlags1)}
565{
566}
567
568/**
569 * Used when Push board on gamestack (playGameMove)
570 */
572 : bBasicBoard{std::move(b)}
573 , u_boardFlags1{std::move(b.u_boardFlags1)}
574 , m_castledoneWhite{std::move(b.m_castledoneWhite)}
575 , m_castledoneBlack{std::move(b.m_castledoneBlack)}
576 , m_boardeval{std::move(b.m_boardeval)}
577 , m_moves{}
578#if !defined(INCOMPLETE_C11)
579 , m_whitePieces{std::move(b.m_whitePieces)}
580 , m_blackPieces{std::move(b.m_blackPieces)}
581#endif
582 , m_previousmoves{std::move(b.m_previousmoves)}
583{
584#if defined(INCOMPLETE_C11)
585 for (unsigned int i = 0; i < tStatPiece::STAT_SIZE; i++) {
586 m_whitePieces[i] = std::move(b.m_whitePieces[i]);
587 m_blackPieces[i] = std::move(b.m_blackPieces[i]);
588 }
589#endif
590}
591
592/**
593 * Create copy of board with move applied on it, clear fields that reflect
594 * state before move is played
595 * used by CalcBestMove
596 * @param b existing board, moves may not have been generated yet
597 * @param moveid to be applied
598 */
599bBoard::bBoard(bBoard const& b, movenum_t const moveid)
600 : bBasicBoard{std::move(b)}
601 , m_moves{}
602 , m_variation{}
603{
604 bMove m(b.getMove(moveid));
605 m_previousmoves = b.getPreviousMoves();
606 m_previousmoves.emplace_back(m);
607 applyMove(m);
608 calcPieces();
611 m_boardeval = Game()->EvalForPlayer(*this);
612}
613
614/**
615 * Create copy of board with move applied on it, clear fields that reflect
616 * state before move is played, used for playGameMove and applyMove
617 * Signature difference in const only!!
618 * @param b existing board
619 * @param m move to be applied
620 */
622 : bBasicBoard{std::move(b)}
623 , m_previousmoves{b.getPreviousMoves()}
624{
625 m_previousmoves.emplace_back(std::move(m));
626 applyMove(m);
627 calcPieces();
629}
630
631/**
632 * Create copy of board with move applied on it, clear fields that reflect
633 * state before move is played, used for SearchPerft::CalcBestMove, add..MoveIfValid
634 * @param b existing board
635 * @param m move to be applied
636 */
637bBoard::bBoard(bBoard const& b, bMove const& m)
638 : bBasicBoard{std::move(b)}
639{
640 applyMove(m);
641}
642
643/** used by setFENInitialPos
644 */
646 : bBasicBoard(fen)
647 , u_boardFlags1{0ULL}
648 , m_castledoneWhite{false}
649 , m_castledoneBlack{false}
650 , m_moves{}
651 , m_variation{}
652 , m_previousmoves{}
653{
654 calcPieces();
656}
657
658#if defined(__GNUC__)
659#pragma GCC diagnostic pop
660#endif
661
663{
664 for (auto& v : m_whitePieces) v.clear();
665 for (auto& v : m_blackPieces) v.clear();
666 m_variation.clear();
667 m_previousmoves.clear();
668}
669
670//-----------------------------------------------------------------------
671
673{
674 if (m_piecesonboard) return; // void extra calculation cost
675
676 m_piecesonboard = 0;
677 for (auto& v : m_whitePieces) v.clear();
678 for (auto& v : m_blackPieces) v.clear();
679
680 for (case_t iCase = 0; iCase < 64; iCase++) {
681 piece_t piece = getPiece(iCase);
682 if (piece) {
684 switch (piece) {
685 case tPiece::W_PAWN:
686 m_whitePieces[tStatPiece::STAT_PAWN].emplace_back(iCase);
687 break;
688 case tPiece::W_ROOK:
689 m_whitePieces[tStatPiece::STAT_ROOK].emplace_back(iCase);
690 break;
691 case tPiece::W_KNIGHT:
692 m_whitePieces[tStatPiece::STAT_KNIGHT].emplace_back(iCase);
693 break;
694 case tPiece::W_BISHOP:
695 m_whitePieces[tStatPiece::STAT_BISHOP].emplace_back(iCase);
696 break;
697 case tPiece::W_QUEEN:
698 m_whitePieces[tStatPiece::STAT_QUEEN].emplace_back(iCase);
699 break;
700 case tPiece::B_PAWN:
701 m_blackPieces[tStatPiece::STAT_PAWN].emplace_back(iCase);
702 break;
703 case tPiece::B_ROOK:
704 m_blackPieces[tStatPiece::STAT_ROOK].emplace_back(iCase);
705 break;
706 case tPiece::B_KNIGHT:
707 m_blackPieces[tStatPiece::STAT_KNIGHT].emplace_back(iCase);
708 break;
709 case tPiece::B_BISHOP:
710 m_blackPieces[tStatPiece::STAT_BISHOP].emplace_back(iCase);
711 break;
712 case tPiece::B_QUEEN:
713 m_blackPieces[tStatPiece::STAT_QUEEN].emplace_back(iCase);
714 break;
715 //case tPiece::W_KING:
716 //case tPiece::B_KING:
717 // break;
718 //case tPiece::P_EMPTY:
719 //case tPiece::P_SIZE:
720 // break;
721 default:
722 break;
723 }
724 }
725 }
726
727 m_whiteminor = static_cast<uint8_t>(m_whitePieces[tStatPiece::STAT_ROOK].size()
728 + m_whitePieces[tStatPiece::STAT_KNIGHT].size()
729 + m_whitePieces[tStatPiece::STAT_BISHOP].size()
730 + m_whitePieces[tStatPiece::STAT_QUEEN].size());
731 m_blackminor = static_cast<uint8_t>(m_blackPieces[tStatPiece::STAT_ROOK].size()
732 + m_blackPieces[tStatPiece::STAT_KNIGHT].size()
733 + m_blackPieces[tStatPiece::STAT_BISHOP].size()
734 + m_blackPieces[tStatPiece::STAT_QUEEN].size());
735}
736
738{
739 // pre-calculate stage
740 if (m_piecesonboard > 28) {
741 // TODO: take into account actual moves
743 } else if (m_piecesonboard < 14) {
744 if (m_whiteminor && m_blackminor) {
745 if ((m_whiteminor + m_blackminor) < 4)
747 else
749 } else if (m_whiteminor + m_blackminor) {
751 } else {
753 }
754 } else {
756 }
757}
758
759/** invert colours
760 * update kingpos, update colour to move, castle rights, ...
761 * @todo castledone, capturedcase, capturedpiece, moveplayed, eval
762 * @todo epcase
763 */
765{
766 // invert pieces
767 for (column_t iCol = 0; iCol < 8; iCol++) {
768 for (rank_t iRank = 0; iRank < 4; iRank++) {
769 piece_t c0 = getPiece(iCol, iRank);
770 piece_t c1 = getPiece(iCol, 7 - iRank);
771 if (c0) { c0 = static_cast<piece_t>((c0 > W_QUEEN) ? c0 - W_QUEEN : c0 + W_QUEEN); }
772 if (c1) { c1 = static_cast<piece_t>((c1 > W_QUEEN) ? c1 - W_QUEEN : c1 + W_QUEEN); }
773 setPieceKU(bCase::coordToCase(iCol, iRank), c1);
774 setPieceKU(bCase::coordToCase(iCol, 7 - iRank), c0);
775 }
776 }
777 // invert castle rights
784 // invert column
785 if (whiteToMove()) incPly();
786 else decPly();
787 // recalculate board data
788 calcHash();
789 m_piecesonboard = 0; /// force recalculation of pieces
790 calcPieces();
791}
792
793/** set non-silent flag, store captured piece and case (for undo)
794 */
795void bBoard::setCapture(piece_t const p, case_t const c)
796{
798 m_bNonSilent = true;
799 m_capturedpiece = p;
800 m_capturedcase = c;
801}
802
804{
806 m_bNonSilent = true;
807}
808
809
810/** modification of board
811 * TOCHECK: check usage in case of failure, why not return exception?
812 */
813void bBoard::applyMove(bMove const& m)
814{
816 applyWhiteMove(m);
817 m_hash &= ~HASH_BLACKTOMOVE;
818 } else {
819 applyBlackMove(m);
821 }
822
823 // TODO: flag mate/stalemate move, special move, ...
824 if (m.isCheck()) {
825 setInCheck(); // TOCHECK: do we need to look for mate here ?
826 }
828 incPly();
829}
830
831void bBoard::applyWhiteMove(bMove const& m)
832{
833 piece_t piece = getPiece(m.from());
834
835 if (piece == tPiece::W_PAWN) {
836 rank_t iFromRank = m.fromrank();
837 if (m.isEPMove()) {
839 } else if (m.isCapture()) {
840 setCapture(getPiece(m.to()), m.to());
841 } else {
844 }
845 movePiece(m.from(), m.to(), tPiece::W_PAWN);
846 if (m.isPromotion()) {
849 }
850 if (m.isEPPossible()) {
851 // TODO: add functions such as nextrank
852 setEp(bCase::coordToCase(m.tocolumn(), iFromRank + 1));
853 } else {
854 clearEp(); // clear ep flag
855 }
856 } else {
857 // other pieces: King, Queen, Rook, Knight, Bishop
858 clearEp(); // clear ep flag
859 if (m.isCapture()) {
860 setCapture(getPiece(m.to()), m.to());
861 } else {
864 }
865 if (piece == tPiece::W_KING) {
866 moveWhiteKing(m.from(), m.to());
867 if (m.isCastleMove()) {
868 if (m.isLongCastleMove()) {
870 } else {
872 }
873 setCastleDoneWhite(true);
874 }
877 } else {
878 movePiece(m.from(), m.to(), piece);
879 if (piece == tPiece::W_ROOK) {
880 if (m.from() == bCase::coordToCase(0, 0)) {
882 } else if (m.from() == bCase::coordToCase(7, 0)) {
884 }
885 }
886 }
887 }
888}
889
890void bBoard::applyBlackMove(bMove const& m)
891{
892 piece_t piece = getPiece(m.from());
893
894 if (piece == tPiece::B_PAWN) {
895 rank_t iFromRank = m.fromrank();
896 if (m.isEPMove()) {
898 } else if (m.isCapture()) {
899 setCapture(getPiece(m.to()), m.to());
900 } else {
903 }
904 movePiece(m.from(), m.to(), tPiece::B_PAWN);
905 if (m.isPromotion()) {
908 }
909 if (m.isEPPossible()) {
910 // TODO: add functions such as nextrank
911 setEp(bCase::coordToCase(m.tocolumn(), iFromRank - 1));
912 } else {
913 clearEp(); // clear ep flag
914 }
915 } else {
916 // other pieces: King, Queen, Rook, Knight, Bishop
917 clearEp(); // clear ep flag
918 if (m.isCapture()) {
919 setCapture(getPiece(m.to()), m.to());
920 } else {
923 }
924 if (piece == tPiece::B_KING) {
925 moveBlackKing(m.from(), m.to());
926 if (m.isCastleMove()) {
927 if (m.isLongCastleMove()) {
929 } else {
931 }
932 setCastleDoneBlack(true);
933 }
936 } else {
937 movePiece(m.from(), m.to(), piece);
938 if (piece == tPiece::B_ROOK) {
939 if (m.from() == bCase::coordToCase(0, 7)) {
941 } else if (m.from() == bCase::coordToCase(7, 7)) {
943 }
944 }
945 }
946 }
947}
948
949//-----------------------------------------------------------------------
950
951/**
952 * return reference to movelist
953 */
955{
956 return m_moves;
957}
958
959/**
960 * see if at least one move can be played e.g. (stale-)mate eval
961 */
963{
964 return m_moves.atLeastOneMovePossible(*this);
965}
966
967bMove const& bBoard::getMove(movenum_t const moveid) const
968{
969 return m_moves[moveid];
970}
971
972//-----------------------------------------------------------------------
973
975{
976 m_variation = {};
977}
978
979void bBoard::setVariation(bBoard const& chldbrd)
980{
981 m_variation = chldbrd.getVariation();
982 if (chldbrd.getPreviousMoves().back() != "")
983 m_variation.insert(m_variation.begin(), chldbrd.getPreviousMoves().back());
984}
985
986//-----------------------------------------------------------------------
987
988bBoard::operator std::string() const
989{
990 std::stringstream ss;
991
992 for (rank_t iRank = 0; iRank < 8; iRank++) {
993 ss << "+---+---+---+---+---+---+---+---+\n";
994 for (column_t iCol = 0; iCol < 8; iCol++) {
995 ss << "| "
996 << static_cast<char>(bPiece::getPieceChar(getPiece(iCol, 7 - iRank)))
997 << " ";
998 }
999 ss << "|\n";
1000 }
1001 ss << "+---+---+---+---+---+---+---+---+\n";
1002
1003 ss << "Move " << getMoveNumber() << " - "
1004 << (whiteToMove() ? "White" : "Black") << " to move"
1005 << "\n";
1006
1007 ss << "Castling : ";
1008 for (uint8_t i = 0; i < 4; i++) ss << canCastle(static_cast<uint8_t>(1 << i));
1009 if (getEp()) ss << " E.p. " << bCase(getEp());
1010 if (isNonSilent() || isInCheck())
1011 ss << " QS:" << (isInCheck() ? " Check" : "")
1012 << (isCapture() ? " Capture" : "");
1013 if (getStage() == bGameStage::ST_OPENING) ss << " - Opening";
1014 else if (getStage() == bGameStage::ST_ENDGAME) ss << " - Endgame";
1015 else if (getStage() == bGameStage::ST_MATING) ss << " - Mating";
1016 else if (getStage() == bGameStage::ST_PAWNENDING) ss << " - Pawnending";
1017
1018 return ss.str();
1019}
1020
1021/** print board */
1022std::ostream& operator<<(std::ostream& os, bBoard const& bd)
1023{
1024 os << bd.operator std::string();
1025 os << std::endl;
1026 return os;
1027}
1028
1029// eof
hashkey_t hashmultiplexer[tPiece::P_SIZE][64]
Definition bel_hash.cpp:10
unsigned long long hashkey_t
Definition bel_hash.h:12
constexpr hashkey_t HASH_INIT
Definition bel_hash.h:14
constexpr hashkey_t HASH_ODDMATERIAL
Definition bel_hash.h:16
@ HP_CASTLE_FL
Definition bel_hash.h:19
constexpr hashkey_t HASH_BLACKTOMOVE
Definition bel_hash.h:15
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
uint8_t movenum50_t
Definition belofte.h:110
int8_t column_t
Definition belofte.h:105
uint_fast8_t movenum_t
Definition belofte.h:109
uint8_t case_t
Definition belofte.h:106
uint16_t plynum_t
Definition belofte.h:108
std::ostream & operator<<(std::ostream &os, bBoard const &bd)
print board
Definition board.cpp:1022
@ BCASTLE_L
Definition board.h:11
@ BCASTLE_S
Definition board.h:11
@ WCASTLE_S
Definition board.h:11
@ WCASTLE_L
Definition board.h:11
void setPiece(case_t const bc, piece_t const piece)
used for promotion move generation
Definition board.cpp:190
bFen getFEN() const
Definition board.cpp:114
uint8_t m_castling
Definition board.h:129
case_t m_blackKing
Definition board.h:125
void incPly()
Definition board.h:54
piece_t getPiece(case_t const bc) const
1 for white, 2 for black
Definition board.cpp:157
void setCastle(uint8_t const f)
Definition board.cpp:260
int16_t getMoveNumber() const
Definition board.h:81
void setPly50Moves(movenum50_t const p)
Definition board.h:64
hashkey_t m_hash
Definition board.h:133
bool whiteToMove() const
Definition board.h:80
case_t m_whiteKing
Definition board.h:124
u_positionFlags_t makeBoardMove(column_t const oldcol, rank_t const oldrank, column_t const newcol, rank_t const newrank, piece_t const promotion)
apply move to check if in check only, board to be discarded as it will be in incomplete state,...
Definition board.cpp:400
void setEp(case_t const e)
Definition board.cpp:233
void movePiece(case_t const f, case_t const t, piece_t const p)
Definition board.cpp:317
void moveBlackKing(case_t const f, case_t const t)
Definition board.cpp:338
side_t getColourToMove() const
Definition board.h:82
std::string getHashStr() const
Definition board.cpp:542
void setPieceKU(case_t const bc, piece_t const piece)
calculate and set hash
Definition board.cpp:221
void clearPiece(case_t const bc)
Definition board.cpp:228
virtual void setInCheck()
Definition board.cpp:283
void moveWhiteKing(case_t const f, case_t const t)
Definition board.cpp:330
void decPly()
Definition board.h:55
virtual void setCapture(piece_t const p, case_t const c)
Clear castle flag if rook captured update piece counter, update hash, clear field.
Definition board.cpp:297
movenum50_t incPly50Moves()
Definition board.h:65
case_t m_ep
Definition board.h:127
uint64_t u_positionFlags
Definition board.h:122
piece_t m_capturedpiece
4 castling bits as uints as copy ctor stumbles on bool array
Definition board.h:130
void clearInCheck()
Definition board.cpp:288
piece_t setGetPiece(column_t const newcol, rank_t const newrank, piece_t const piece)
used for makeBoardMove
Definition board.cpp:202
piece_t removePiece(column_t const newcol, rank_t const newrank)
used for makeBoardMove
Definition board.cpp:212
void unMakeBoardMove(case_t const &cf, column_t const newcol, rank_t const newrank, u_positionFlags_t const oldFlags, piece_t const promotion)
undo makeBoardMove, restoring previous situation
Definition board.cpp:481
virtual ~bBasicBoard()
Definition board.cpp:26
void swapPiece(case_t const t, piece_t const op, piece_t const np)
Definition board.cpp:324
void clearPly50Moves()
Definition board.h:66
void calcHash()
Set hash based on board position, also calc pieces Byte 0: bits 4-6 capture count (masked) bit 7 play...
Definition board.cpp:355
case_t getEp() const
Definition board.h:58
bool isInCheck() const
Definition board.cpp:278
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
void clearCastle(uint8_t const f)
Definition board.cpp:269
void clearEp()
Definition board.h:60
bool isFieldEmpty(case_t const bc) const
Definition board.cpp:178
void setPly(plynum_t const p)
Definition board.h:53
basicmove_t getBasicMoveT() const
Definition move.h:38
MEMBER_CONSTEXPR case_t to() const
Definition move.h:29
MEMBER_CONSTEXPR case_t from() const
Definition move.h:25
rank_t fromrank() const
Definition move.h:33
column_t tocolumn() const
Definition move.h:36
board
Definition board.h:147
void setCapture(piece_t const p, case_t const c) override
set non-silent flag, store captured piece and case (for undo)
Definition board.cpp:795
void setCastleDoneWhite(bool const c)
Definition board.h:183
void clearVariation()
Definition board.cpp:974
bBoard(bBoard &&b) noexcept
Used when Push board on gamestack (playGameMove)
Definition board.cpp:571
uint8_t m_whiteminor
Definition board.h:213
void invertColours()
invert colours update kingpos, update colour to move, castle rights, ...
Definition board.cpp:764
basicmove_t m_moveplayed
Definition board.h:210
uint8_t m_bNonSilent
Definition board.h:211
bMove const & getMove(movenum_t const moveid) const
Definition board.cpp:967
void setVariation(bBoard const &chldbrd)
Definition board.cpp:979
void setInCheck() final
Definition board.cpp:803
bMoveList & getMoveListRef()
return reference to movelist
Definition board.cpp:954
uint8_t m_blackminor
Definition board.h:214
bScore m_boardeval
Definition board.h:225
bGameStage m_gamestage
Definition board.h:215
movesequence_t const & getPreviousMoves() const
Definition board.h:186
void setCastleDoneBlack(bool const c)
Definition board.h:184
movesequence_t const & getVariation() const
Definition board.h:189
case_t m_capturedcase
Definition board.h:216
uint8_t m_piecesonboard
Definition board.h:212
void calcGameStage()
calculate pieces
Definition board.cpp:737
~bBoard() override
Definition board.cpp:662
void calcPieces()
Definition board.cpp:672
void setNonSilent()
Definition board.h:171
bool atLeastOneMovePossible() const
see if at least one move can be played e.g.
Definition board.cpp:962
position on board, defined as 255 if invalid used primarily to compose a move or a source or destinat...
Definition case.h:17
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
FEN string.
Definition fen.h:14
bScore EvalForPlayer(bBoard const &b)
Definition game.cpp:151
Definition move.h:69
piece_t getBlackPromotionPiece() const
Definition move.cpp:173
bool isCapture() const
Definition move.h:87
bool isMajorPromotion() const
test if major promotion or mating promotion (queen, knight) if minor promotion, move is considered as...
Definition move.cpp:152
bool isCastleMove() const
Definition move.h:91
bool isEPPossible() const
Definition move.h:100
bool isPromotion() const
Definition move.h:83
bool isCheck() const
Definition move.h:95
piece_t getWhitePromotionPiece() const
Definition move.cpp:159
bool isEPMove() const
Definition move.h:102
bool isLongCastleMove() const
Definition move.h:94
movenum_t generateMoves(bBoard const &b)
generate moves if not yet generated
Definition movelist.cpp:259
bool atLeastOneMovePossible(bBoard const &b) const
see if at least one move can be played e.g.
Definition movelist.cpp:296
static cpiece_t getPieceChar(piece_t const p)
static class member function
Definition piece.cpp:178
piece_t getPiece() const
Definition piece.h:99
@ 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
@ P_EMPTY
Definition piece.h:38
@ 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
enum tCPiece cpiece_t
Definition piece.h:35
@ STAT_KNIGHT
Definition piece.h:56
@ STAT_BISHOP
Definition piece.h:56
@ STAT_ROOK
Definition piece.h:56
@ STAT_SIZE
Definition piece.h:57
@ STAT_PAWN
Definition piece.h:55
@ STAT_QUEEN
Definition piece.h:56
@ SIDE_BLACK
@ SIDE_WHITE
uint64_t u_positionFlags
Definition board.h:15
uint8_t capturedpiece
4 castling bits, plus incheck flag and capture move
Definition board.h:31