3 Copyright (c) Scott Gasch
11 Chess-board related functions.
19 $Id: board.c 345 2007-12-02 22:56:42Z scott $
26 SetRootToInitialPosition(void)
31 Sets the root position to the initial position.
47 (void)SetRootPosition(STARTING_POSITION_IN_FEN);
49 pos = GetRootPosition();
52 // Sanity check the sig system. Note: if this changes then any
53 // opening books need to be reconstructed.
55 ASSERT(pos->u64NonPawnSig == 0xd46f3e84d897a443ULL);
56 ASSERT(pos->u64PawnSig == 0xa9341a54d7352d3cULL);
58 ASSERT_ASM_ASSUMPTIONS;
64 DrawTextBoardFromPosition(POSITION *pos)
69 Draw a text-based representation of the board configuration in
70 POSITION pos and returned it as a string. Note: this function is
75 POSITION *pos : position to draw
79 static char * : my drawing
83 static char buf[MEDIUM_STRING_LEN_CHAR];
86 memset(buf, 0, sizeof(buf));
87 strcpy(buf, " 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07\n");
88 strcat(buf, " +---------------------------------------+\n");
89 for (r = 8; r >= 1; r--)
91 sprintf(buf, "%s %u |", buf, r);
93 for (f = A; f <= H; f++)
95 if (IS_WHITE_SQUARE_FR(f, r))
97 if (IS_EMPTY(pos->rgSquare[FILE_RANK_TO_COOR(f,r)].pPiece))
99 sprintf(buf, "%s%s", buf, " |");
103 sprintf(buf, "%s %2s |", buf,
104 PieceAbbrev(pos->rgSquare[FILE_RANK_TO_COOR(f,r)].pPiece));
109 if (IS_EMPTY(pos->rgSquare[FILE_RANK_TO_COOR(f,r)].pPiece))
111 sprintf(buf, "%s%s", buf, "::::|");
115 sprintf(buf, "%s:%2s:|", buf,
116 PieceAbbrev(pos->rgSquare[FILE_RANK_TO_COOR(f,r)].pPiece));
120 sprintf(buf, "%s 0x%x0\n", buf, (8 - r));
122 strcat(buf, " +---------------------------------------+\n");
123 strcat(buf, " A B C D E F G H\n\n");
129 VerifyPositionConsistency(POSITION *pos,
135 Verifies the internal consistency of a POSITION structure. Looks
136 for defects like bad piece lists, bad piece counts, bad material
141 POSITION *pos : the position to verify
145 FLAG : TRUE if consistent, FALSE otherwise
149 static char *szExplainations[] = {
150 "Pawn signature mismatch",
151 "Main signature mismatch",
152 "Invalid enpassant square",
153 "Material balance for white != -Material balance for black",
154 "White castled already and can still castle",
155 "Black castled already and can still castle",
156 "Pawn list points to non-pawn square on board",
157 "Square pointed to by pawn list doesn't point back",
158 "Piece list points to non-piece square on board",
159 "Square pointed to by the non-piece list doesn't point back",
160 "Non-king piece in 0th position of list",
161 "Invalid piece sitting in non-pawn list entry",
162 "Counted pawn material != expected material sum",
163 "Counted piece material != expected material sum",
164 "Total army material != expected material sum",
165 "More white square bishops than total bishop count",
166 "Strange bits flipped in board square",
167 "More pawns on board than accounted for in pawn material",
168 "More pieces on board than accounted for in piece material",
169 "Extra pieces on board that are not accounted for",
170 "Fifty move counter is too high",
174 ULONG uPawnMaterial[2] = {0, 0};
175 ULONG uPawnCount[2] = {0, 0};
176 ULONG uNonPawnMaterial[2] = {0, 0};
177 ULONG uNonPawnCount[2][7];
178 ULONG uSigmaNonPawnCount[2] = {0, 0};
179 ULONG uWhiteSqBishopCount[2] = {0, 0};
183 ULONG uReason = (ULONG)-1;
185 memset(uNonPawnCount, 0, sizeof(uNonPawnCount));
186 u64Computed = ComputeSig(pos);
187 if (pos->u64NonPawnSig != u64Computed)
193 u64Computed = ComputePawnSig(pos);
194 if (pos->u64PawnSig != u64Computed)
200 if (!VALID_EP_SQUARE(pos->cEpSquare))
206 if (pos->iMaterialBalance[WHITE] != -pos->iMaterialBalance[BLACK])
212 if (pos->iMaterialBalance[WHITE] !=
213 ((SCORE)(pos->uPawnMaterial[WHITE] + pos->uNonPawnMaterial[WHITE]) -
214 (SCORE)(pos->uPawnMaterial[BLACK] + pos->uNonPawnMaterial[BLACK])))
223 // If a side has already castled it shouldn't have legal castling
226 if (TRUE == pos->fCastled[u])
230 if (pos->bvCastleInfo & WHITE_CAN_CASTLE)
239 if (pos->bvCastleInfo & BLACK_CAN_CASTLE)
248 // Make sure the pawns are where they should be
250 for (v = 0; v < pos->uPawnCount[u]; v++)
252 c = pos->cPawns[u][v];
255 if (pos->rgSquare[c].pPiece != ((PAWN << 1) | u))
261 if (pos->rgSquare[c].uIndex != v)
266 uPawnMaterial[u] += VALUE_PAWN;
272 // Make sure the non-pawns are where they should be
274 for (v = 0; v < 16; v++)
276 c = pos->cNonPawns[u][v];
277 if (v < pos->uNonPawnCount[u][0])
286 p = pos->rgSquare[c].pPiece;
287 if (pos->rgSquare[c].uIndex != v)
294 // 0th spot must be a king
296 if ((v == 0) && (!IS_KING(p)))
302 if ((!IS_VALID_PIECE(p)) || (PIECE_COLOR(p) != u))
307 uNonPawnCount[u][PIECE_TYPE(p)]++;
308 uNonPawnMaterial[u] += PIECE_VALUE(p);
309 if ((IS_BISHOP(p)) &&
310 (IS_WHITE_SQUARE_COOR(c)))
312 uWhiteSqBishopCount[u]++;
319 // The first off-board is the last, the list must not
320 // have gaps in it followed by good piece data again.
330 // Make sure the materials and counts match up with what we
331 // got when walking the piece lists
333 if ((pos->uPawnMaterial[u] != uPawnMaterial[u]) ||
334 (pos->uPawnCount[u] != uPawnCount[u]) ||
335 (pos->uPawnMaterial[u] != pos->uPawnCount[u] * VALUE_PAWN))
341 for (v = KNIGHT; v <= KING; v++)
343 if (pos->uNonPawnCount[u][v] != uNonPawnCount[u][v])
348 uSigmaNonPawnCount[u] += pos->uNonPawnCount[u][v];
352 // Note: the 0th spot in the array is the sum of all non pawns
354 if (uSigmaNonPawnCount[u] != pos->uNonPawnCount[u][0])
361 // You can't have more white-square bishops than you have
364 if (pos->uWhiteSqBishopCount[u] > pos->uNonPawnCount[u][BISHOP])
372 // Now walk the actual board and reduce the material counts we got
373 // by walking the piece lists. If everything is ok then the
374 // material counts will end up at 0. If there are pieces on the
375 // board that are not on a list or pieces in a list that are not
376 // on the board this will catch it.
382 p = pos->rgSquare[c].pPiece;
387 // Make sure none of these have strange bits flipped
398 uPawnMaterial[u] -= VALUE_PAWN;
399 if (pos->rgSquare[c].uIndex > pos->uPawnCount[u])
407 uNonPawnMaterial[u] -= PIECE_VALUE(p);
408 if (pos->rgSquare[c].uIndex > pos->uNonPawnCount[u][0])
418 if ((uPawnMaterial[WHITE] + uPawnMaterial[BLACK] +
419 uNonPawnMaterial[WHITE] + uNonPawnMaterial[BLACK]) != 0)
425 // if (pos->uFifty > 101)
439 if (FALSE == fContinue)
441 UtilPanic(INCONSISTENT_POSITION,
442 pos, szExplainations[uReason], NULL, NULL,
453 PositionsAreEquivalent(POSITION *p1,
459 Compare two positions and decide whether they are the same
460 position. Note: this code is meant to be accessed from test code
461 or from non-speed critical codepaths. Comparing their signatures
462 should be sufficient to determine whether they are the same in
467 POSITION *p1 : first position to compare
468 POSITION *p2 : second position to compare
472 FLAG : TRUE if they are the same position, FALSE otherwise
479 if ((p1->u64NonPawnSig != p2->u64NonPawnSig) ||
480 (p1->u64PawnSig != p2->u64PawnSig) ||
481 (p1->uToMove != p2->uToMove) ||
482 (p1->uFifty != p2->uFifty) ||
483 (p1->bvCastleInfo != p2->bvCastleInfo) ||
484 (p1->cEpSquare != p2->cEpSquare))
491 if ((p1->fCastled[u] != p2->fCastled[u]) ||
492 (p1->uWhiteSqBishopCount[u] != p2->uWhiteSqBishopCount[u]))
500 if (!IS_ON_BOARD(c)) continue;
502 if (p1->rgSquare[c].pPiece != p2->rgSquare[c].pPiece)
508 VerifyPositionConsistency(p1, FALSE);
509 VerifyPositionConsistency(p2, FALSE);
515 CastleInfoString(BITV bv)
520 Generate and returns a small string describing the possible
521 castling choices in the bitvector passed in for use in a friandly
522 display or in a FEN string representing a position. This function
523 is _NOT_ thread safe.
527 BITV bv : the castling bitvector
531 char * : the string, either '-' signifying none possible or some
534 K = white kingside possible
535 Q = white queenside possibe
536 k = black kingside possible
537 q = black queenside possible
544 memset(buf, 0, sizeof(buf));
545 ASSERT((bv & ~CASTLE_ALL_POSSIBLE) == 0);
553 if (bv & CASTLE_WHITE_SHORT)
558 if (bv & CASTLE_WHITE_LONG)
563 if (bv & CASTLE_BLACK_SHORT)
568 if (bv & CASTLE_BLACK_LONG)
578 DumpPosition(POSITION *pos)
583 Dump an ASCII representation of POSITION pos on stdout.
598 if (!VerifyPositionConsistency(pos, TRUE))
600 Bug("===========================================================================\n"
601 " WARNING: The following position seems to be inconsistent. I'll do my best\n"
602 " to render it but this may not be such a good idea...\n"
603 "===========================================================================\n\n");
606 p = PositionToFen(pos);
607 if (g_Options.fRunningUnderXboard)
609 Trace("; PositionToFen(pos): %s\n", p);
614 Trace("FEN: %s\n\n", p);
618 Trace("--------------------------------------------------------------------------------\n"
619 "PositionToFen(pos): %s\n\n"
622 " +0x%03x u64NonPawnSig : %"
623 COMPILER_LONGLONG_HEX_FORMAT "\n"
624 " +0x%03x u64PawnSig : %"
625 COMPILER_LONGLONG_HEX_FORMAT "\n"
626 " u64NonPawnSig ^ u64PawnSig: %"
627 COMPILER_LONGLONG_HEX_FORMAT "\n"
628 " +0x%03x pSquare[128] : \n\n"
630 " +0x%03x uToMove : 0x%02x (%s)\n"
631 " +0x%03x uFifty : 0x%02x (%u moves)\n"
632 " +0x%03x fCastled[2] : W:0x%02x B:0x%02x\n"
633 " +0x%03x bvCastleInfo : 0x%02x (%s)\n"
634 " +0x%03x cEpSquare : 0x%02x (%s)\n"
635 " +0x%03x cPawns[2][8] : \n",
638 OFFSET_OF(u64PawnSig, POSITION), pos->u64PawnSig,
639 OFFSET_OF(u64NonPawnSig, POSITION), pos->u64NonPawnSig,
640 pos->u64NonPawnSig ^ pos->u64PawnSig,
641 OFFSET_OF(rgSquare, POSITION), DrawTextBoardFromPosition(pos),
642 OFFSET_OF(uToMove, POSITION), pos->uToMove, ColorToString(pos->uToMove),
643 OFFSET_OF(uFifty, POSITION), pos->uFifty, pos->uFifty,
644 OFFSET_OF(fCastled, POSITION), pos->fCastled[WHITE], pos->fCastled[BLACK],
645 OFFSET_OF(bvCastleInfo, POSITION), pos->bvCastleInfo, CastleInfoString(pos->bvCastleInfo),
646 OFFSET_OF(cEpSquare, POSITION), pos->cEpSquare, (IS_ON_BOARD(pos->cEpSquare) ? CoorToString(pos->cEpSquare) : "none"),
647 OFFSET_OF(cPawns, POSITION));
650 for (u = 0; u < pos->uPawnCount[WHITE]; u++)
653 pos->cPawns[WHITE][u],
654 CoorToString(pos->cPawns[WHITE][u]));
655 ASSERT(IS_ON_BOARD(pos->cPawns[WHITE][u]));
660 for (u = 0; u < pos->uPawnCount[BLACK]; u++)
663 pos->cPawns[BLACK][u],
664 CoorToString(pos->cPawns[BLACK][u]));
665 ASSERT(IS_ON_BOARD(pos->cPawns[BLACK][u]));
669 " +0x%03x uPawnMaterial[2] : W:0x%02x (%u, pawn=%u)\n"
670 " : B:0x%02x (%u, pawn=%u)\n"
671 " +0x%03x uPawnCount[2] : W:%1u pawns B:%1u pawns\n",
672 OFFSET_OF(uPawnMaterial, POSITION),
673 pos->uPawnMaterial[WHITE], pos->uPawnMaterial[WHITE], VALUE_PAWN,
674 pos->uPawnMaterial[BLACK], pos->uPawnMaterial[BLACK], VALUE_PAWN,
675 OFFSET_OF(uPawnCount, POSITION),
676 pos->uPawnCount[WHITE], pos->uPawnCount[BLACK]);
678 Trace(" +0x%03x cNonPawns[2][16] : \n"
679 " W: ", OFFSET_OF(cNonPawns, POSITION));
680 for (u = 0; u < pos->uNonPawnCount[WHITE][0]; u++)
683 pos->cNonPawns[WHITE][u],
684 CoorToString(pos->cNonPawns[WHITE][u]));
685 ASSERT(IS_ON_BOARD(pos->cNonPawns[WHITE][u]));
689 for (u = 0; u < pos->uNonPawnCount[BLACK][0]; u++)
692 pos->cNonPawns[BLACK][u],
693 CoorToString(pos->cNonPawns[BLACK][u]));
694 ASSERT(IS_ON_BOARD(pos->cNonPawns[BLACK][u]));
697 " +0x%03x uNonPawnMaterial[2] : W: 0x%02x (%u, pawn=%u)\n"
698 " : B: 0x%02x (%u, pawn=%u)\n"
699 " +0x%03x uNonPawnCount[2][7] : WHITE BLACK\n"
702 " WHITE SQUARE BISHOP : %u %u\n"
706 OFFSET_OF(uNonPawnMaterial, POSITION),
707 pos->uNonPawnMaterial[WHITE], pos->uNonPawnMaterial[WHITE],
709 pos->uNonPawnMaterial[BLACK], pos->uNonPawnMaterial[BLACK],
711 OFFSET_OF(uNonPawnCount, POSITION),
712 pos->uNonPawnCount[WHITE][KNIGHT], pos->uNonPawnCount[BLACK][KNIGHT],
713 pos->uNonPawnCount[WHITE][BISHOP], pos->uNonPawnCount[BLACK][BISHOP],
714 pos->uWhiteSqBishopCount[WHITE], pos->uWhiteSqBishopCount[BLACK],
715 pos->uNonPawnCount[WHITE][ROOK], pos->uNonPawnCount[BLACK][ROOK],
716 pos->uNonPawnCount[WHITE][QUEEN], pos->uNonPawnCount[BLACK][QUEEN],
717 pos->uNonPawnCount[WHITE][0], pos->uNonPawnCount[BLACK][0]);
719 Trace("\n%s\n", DrawTextBoardFromPosition(pos));