From: H.G. Muller Date: Fri, 6 Nov 2009 03:23:44 +0000 (-0800) Subject: Integrate castling and e.p. rights into board array; bugfix for EditPosition X-Git-Tag: master-20091122~19 X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=91e0735ab1cbc57465e0252bc95b90bc2ab13caa;p=xboard.git Integrate castling and e.p. rights into board array; bugfix for EditPosition A large-scale operation that I have been postponing since the very first 4.4.0: The castling and e.p. rights are now integrated into the board array, as boards[moveNr][CASTLING][i] replacing castlingRights[moveNr][i] and boards[moveNr][EP_STATUS] replacing epStatus[moveNr] These quantities are now automatically copied with the position by CopyBoards (allowing the removal of lots of dedicated copying code), and passed as function arguments with the position (so that the moves.c functions like TestLegality, MateTest, CoordsToAlgebraic, Disambiguate, GenLegal no longer need explicit e.p. and castling parameters. Also fixed a bug introduced by a recent previous fix: by adding fake castling rights to a position set up through the EditPosition menu, I destroyed the castling rights of a pasted FEN. Faking castling rights is now made conditional in EditPositionDone(), depending on the caller. (I had not realized it was also called after FEN pasting, to send the position to the engine.) --- diff --git a/backend.c b/backend.c index 0a51282..7f8db9e 100755 --- a/backend.c +++ b/backend.c @@ -160,7 +160,7 @@ int LoadGameFromFile P((char *filename, int n, char *title, int useList)); int LoadPositionFromFile P((char *filename, int n, char *title)); int SavePositionToFile P((char *filename)); void ApplyMove P((int fromX, int fromY, int toX, int toY, int promoChar, - Board board, char *castle, char *ep)); + Board board)); void MakeMove P((int fromX, int fromY, int toX, int toY, int promoChar)); void ShowMove P((int fromX, int fromY, int toX, int toY)); int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY, @@ -168,7 +168,7 @@ int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY, void BackwardInner P((int target)); void ForwardInner P((int target)); void GameEnds P((ChessMove result, char *resultDetails, int whosays)); -void EditPositionDone P((void)); +void EditPositionDone P((Boolean fakeRights)); void PrintOpponents P((FILE *fp)); void PrintPosition P((FILE *fp, int move)); void StartChessProgram P((ChessProgramState *cps)); @@ -441,47 +441,44 @@ AppData appData; Board boards[MAX_MOVES]; /* [HGM] Following 7 needed for accurate legality tests: */ -signed char epStatus[MAX_MOVES]; -signed char castlingRights[MAX_MOVES][BOARD_SIZE]; // stores files for pieces with castling rights or -1 -signed char castlingRank[BOARD_SIZE]; // and corresponding ranks -signed char initialRights[BOARD_SIZE], FENcastlingRights[BOARD_SIZE], fileRights[BOARD_SIZE]; +signed char castlingRank[BOARD_FILES]; // and corresponding ranks +signed char initialRights[BOARD_FILES]; int nrCastlingRights; // For TwoKings, or to implement castling-unknown status int initialRulePlies, FENrulePlies; -char FENepStatus; FILE *serverMoves = NULL; // next two for broadcasting (/serverMoves option) int loadFlag = 0; int shuffleOpenings; int mute; // mute all sounds -ChessSquare FIDEArray[2][BOARD_SIZE] = { +ChessSquare FIDEArray[2][BOARD_FILES] = { { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteKing, WhiteBishop, WhiteKnight, WhiteRook }, { BlackRook, BlackKnight, BlackBishop, BlackQueen, BlackKing, BlackBishop, BlackKnight, BlackRook } }; -ChessSquare twoKingsArray[2][BOARD_SIZE] = { +ChessSquare twoKingsArray[2][BOARD_FILES] = { { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteKing, WhiteKing, WhiteKnight, WhiteRook }, { BlackRook, BlackKnight, BlackBishop, BlackQueen, BlackKing, BlackKing, BlackKnight, BlackRook } }; -ChessSquare KnightmateArray[2][BOARD_SIZE] = { +ChessSquare KnightmateArray[2][BOARD_FILES] = { { WhiteRook, WhiteMan, WhiteBishop, WhiteQueen, WhiteUnicorn, WhiteBishop, WhiteMan, WhiteRook }, { BlackRook, BlackMan, BlackBishop, BlackQueen, BlackUnicorn, BlackBishop, BlackMan, BlackRook } }; -ChessSquare fairyArray[2][BOARD_SIZE] = { /* [HGM] Queen side differs from King side */ +ChessSquare fairyArray[2][BOARD_FILES] = { /* [HGM] Queen side differs from King side */ { WhiteCannon, WhiteNightrider, WhiteAlfil, WhiteQueen, WhiteKing, WhiteBishop, WhiteKnight, WhiteRook }, { BlackCannon, BlackNightrider, BlackAlfil, BlackQueen, BlackKing, BlackBishop, BlackKnight, BlackRook } }; -ChessSquare ShatranjArray[2][BOARD_SIZE] = { /* [HGM] (movGen knows about Shatranj Q and P) */ +ChessSquare ShatranjArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatranj Q and P) */ { WhiteRook, WhiteKnight, WhiteAlfil, WhiteKing, WhiteFerz, WhiteAlfil, WhiteKnight, WhiteRook }, { BlackRook, BlackKnight, BlackAlfil, BlackKing, @@ -489,36 +486,36 @@ ChessSquare ShatranjArray[2][BOARD_SIZE] = { /* [HGM] (movGen knows about Shatra }; -#if (BOARD_SIZE>=10) -ChessSquare ShogiArray[2][BOARD_SIZE] = { +#if (BOARD_FILES>=10) +ChessSquare ShogiArray[2][BOARD_FILES] = { { WhiteQueen, WhiteKnight, WhiteFerz, WhiteWazir, WhiteKing, WhiteWazir, WhiteFerz, WhiteKnight, WhiteQueen }, { BlackQueen, BlackKnight, BlackFerz, BlackWazir, BlackKing, BlackWazir, BlackFerz, BlackKnight, BlackQueen } }; -ChessSquare XiangqiArray[2][BOARD_SIZE] = { +ChessSquare XiangqiArray[2][BOARD_FILES] = { { WhiteRook, WhiteKnight, WhiteAlfil, WhiteFerz, WhiteWazir, WhiteFerz, WhiteAlfil, WhiteKnight, WhiteRook }, { BlackRook, BlackKnight, BlackAlfil, BlackFerz, BlackWazir, BlackFerz, BlackAlfil, BlackKnight, BlackRook } }; -ChessSquare CapablancaArray[2][BOARD_SIZE] = { +ChessSquare CapablancaArray[2][BOARD_FILES] = { { WhiteRook, WhiteKnight, WhiteAngel, WhiteBishop, WhiteQueen, WhiteKing, WhiteBishop, WhiteMarshall, WhiteKnight, WhiteRook }, { BlackRook, BlackKnight, BlackAngel, BlackBishop, BlackQueen, BlackKing, BlackBishop, BlackMarshall, BlackKnight, BlackRook } }; -ChessSquare GreatArray[2][BOARD_SIZE] = { +ChessSquare GreatArray[2][BOARD_FILES] = { { WhiteDragon, WhiteKnight, WhiteAlfil, WhiteGrasshopper, WhiteKing, WhiteSilver, WhiteCardinal, WhiteAlfil, WhiteKnight, WhiteDragon }, { BlackDragon, BlackKnight, BlackAlfil, BlackGrasshopper, BlackKing, BlackSilver, BlackCardinal, BlackAlfil, BlackKnight, BlackDragon }, }; -ChessSquare JanusArray[2][BOARD_SIZE] = { +ChessSquare JanusArray[2][BOARD_FILES] = { { WhiteRook, WhiteAngel, WhiteKnight, WhiteBishop, WhiteKing, WhiteQueen, WhiteBishop, WhiteKnight, WhiteAngel, WhiteRook }, { BlackRook, BlackAngel, BlackKnight, BlackBishop, BlackKing, @@ -526,7 +523,7 @@ ChessSquare JanusArray[2][BOARD_SIZE] = { }; #ifdef GOTHIC -ChessSquare GothicArray[2][BOARD_SIZE] = { +ChessSquare GothicArray[2][BOARD_FILES] = { { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteMarshall, WhiteKing, WhiteAngel, WhiteBishop, WhiteKnight, WhiteRook }, { BlackRook, BlackKnight, BlackBishop, BlackQueen, BlackMarshall, @@ -537,7 +534,7 @@ ChessSquare GothicArray[2][BOARD_SIZE] = { #endif // !GOTHIC #ifdef FALCON -ChessSquare FalconArray[2][BOARD_SIZE] = { +ChessSquare FalconArray[2][BOARD_FILES] = { { WhiteRook, WhiteKnight, WhiteBishop, WhiteLance, WhiteQueen, WhiteKing, WhiteLance, WhiteBishop, WhiteKnight, WhiteRook }, { BlackRook, BlackKnight, BlackBishop, BlackLance, BlackQueen, @@ -547,23 +544,23 @@ ChessSquare FalconArray[2][BOARD_SIZE] = { #define FalconArray CapablancaArray #endif // !FALCON -#else // !(BOARD_SIZE>=10) +#else // !(BOARD_FILES>=10) #define XiangqiPosition FIDEArray #define CapablancaArray FIDEArray #define GothicArray FIDEArray #define GreatArray FIDEArray -#endif // !(BOARD_SIZE>=10) +#endif // !(BOARD_FILES>=10) -#if (BOARD_SIZE>=12) -ChessSquare CourierArray[2][BOARD_SIZE] = { +#if (BOARD_FILES>=12) +ChessSquare CourierArray[2][BOARD_FILES] = { { WhiteRook, WhiteKnight, WhiteAlfil, WhiteBishop, WhiteMan, WhiteKing, WhiteFerz, WhiteWazir, WhiteBishop, WhiteAlfil, WhiteKnight, WhiteRook }, { BlackRook, BlackKnight, BlackAlfil, BlackBishop, BlackMan, BlackKing, BlackFerz, BlackWazir, BlackBishop, BlackAlfil, BlackKnight, BlackRook } }; -#else // !(BOARD_SIZE>=12) +#else // !(BOARD_FILES>=12) #define CourierArray CapablancaArray -#endif // !(BOARD_SIZE>=12) +#endif // !(BOARD_FILES>=12) Board initialPosition; @@ -646,8 +643,8 @@ InitBackEnd1() for( i=0; i= BlackPawn ) { @@ -2082,7 +2078,8 @@ read_from_ics(isr, closure, data, count, error) if (appData.debugMode) { int f = forwardMostMove; fprintf(debugFP, "ics input %d, castling = %d %d %d %d %d %d\n", f, - castlingRights[f][0],castlingRights[f][1],castlingRights[f][2],castlingRights[f][3],castlingRights[f][4],castlingRights[f][5]); + boards[f][CASTLING][0],boards[f][CASTLING][1],boards[f][CASTLING][2], + boards[f][CASTLING][3],boards[f][CASTLING][4],boards[f][CASTLING][5]); } if (count > 0) { /* If last read ended with a partial line that we couldn't parse, @@ -3307,7 +3304,7 @@ read_from_ics(isr, closure, data, count, error) /* [HGM] copy holdings to board holdings area */ CopyHoldings(boards[forwardMostMove], white_holding, WhitePawn); CopyHoldings(boards[forwardMostMove], black_holding, BlackPawn); - boards[forwardMostMove][BOARD_SIZE-1][BOARD_SIZE-2] = 1; // flag holdings as set + boards[forwardMostMove][HOLDINGS_SET] = 1; // flag holdings as set #if ZIPPY if (appData.zippyPlay && first.initDone) { ZippyHoldings(white_holding, black_holding, @@ -3660,7 +3657,7 @@ ParseBoard12(string) } } CopyBoard(boards[moveNum], board); - boards[moveNum][BOARD_SIZE-1][BOARD_SIZE-2] = 0; // [HGM] indicate holdings not set + boards[moveNum][HOLDINGS_SET] = 0; // [HGM] indicate holdings not set if (moveNum == 0) { startedFromSetupPosition = !CompareBoards(board, initialPosition); @@ -3683,38 +3680,38 @@ ParseBoard12(string) for(i=BOARD_LEFT, j= -1; i=BOARD_LEFT; i--) if(board[0][i] == WhiteRook) j = i; - initialRights[1] = castlingRights[moveNum][1] = (castle_wl == 0 && gameInfo.variant != VariantFischeRandom ? -1 : j); + initialRights[1] = boards[moveNum][CASTLING][1] = (castle_wl == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j); for(i=BOARD_LEFT, j= -1; i=BOARD_LEFT; i--) if(board[BOARD_HEIGHT-1][i] == BlackRook) j = i; - initialRights[4] = castlingRights[moveNum][4] = (castle_bl == 0 && gameInfo.variant != VariantFischeRandom ? -1 : j); + initialRights[4] = boards[moveNum][CASTLING][4] = (castle_bl == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j); if(gameInfo.variant == VariantKnightmate) { wKing = WhiteUnicorn; bKing = BlackUnicorn; } for(k=BOARD_LEFT; k>1; - castlingRights[0][3] = initialRights[3] = BOARD_RGHT-1; - castlingRights[0][4] = initialRights[4] = BOARD_LEFT; - castlingRights[0][5] = initialRights[5] =(BOARD_WIDTH-1)>>1; + initialPosition[CASTLING][0] = initialRights[0] = BOARD_RGHT-1; + initialPosition[CASTLING][1] = initialRights[1] = BOARD_LEFT; + initialPosition[CASTLING][2] = initialRights[2] =(BOARD_WIDTH-1)>>1; + initialPosition[CASTLING][3] = initialRights[3] = BOARD_RGHT-1; + initialPosition[CASTLING][4] = initialRights[4] = BOARD_LEFT; + initialPosition[CASTLING][5] = initialRights[5] =(BOARD_WIDTH-1)>>1; break; case VariantFalcon: pieces = FalconArray; @@ -4705,7 +4704,6 @@ InitPosition(redraw) gameInfo.boardWidth = 12; nrCastlingRights = 0; SetCharTable(pieceToChar, "PNBR.FE..WMKpnbr.fe..wmk"); - for(i=0; i BOARD_SIZE || BOARD_WIDTH > BOARD_SIZE) - DisplayFatalError(_("Recompile to support this BOARD_SIZE!"), 0, 2); + if(BOARD_HEIGHT > BOARD_RANKS || BOARD_WIDTH > BOARD_FILES) + DisplayFatalError(_("Recompile to support this BOARD_RANKS or BOARD_FILES!"), 0, 2); pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */ if(pawnRow < 1) pawnRow = 1; @@ -4810,12 +4807,12 @@ InitPosition(redraw) /* Variants with other castling rights must set them themselves above */ nrCastlingRights = 6; - castlingRights[0][0] = initialRights[0] = BOARD_RGHT-1; - castlingRights[0][1] = initialRights[1] = BOARD_LEFT; - castlingRights[0][2] = initialRights[2] = BOARD_WIDTH>>1; - castlingRights[0][3] = initialRights[3] = BOARD_RGHT-1; - castlingRights[0][4] = initialRights[4] = BOARD_LEFT; - castlingRights[0][5] = initialRights[5] = BOARD_WIDTH>>1; + initialPosition[CASTLING][0] = initialRights[0] = BOARD_RGHT-1; + initialPosition[CASTLING][1] = initialRights[1] = BOARD_LEFT; + initialPosition[CASTLING][2] = initialRights[2] = BOARD_WIDTH>>1; + initialPosition[CASTLING][3] = initialRights[3] = BOARD_RGHT-1; + initialPosition[CASTLING][4] = initialRights[4] = BOARD_LEFT; + initialPosition[CASTLING][5] = initialRights[5] = BOARD_WIDTH>>1; } if(gameInfo.variant == VariantSuper) Prelude(initialPosition); @@ -4836,7 +4833,7 @@ InitPosition(redraw) /* [HGM] loadPos: use PositionFile for every new game */ CopyBoard(initialPosition, filePosition); for(i=0; ialphaRank) AlphaRank(machineMove, 4); if (!ParseOneMove(machineMove, forwardMostMove, &moveType, @@ -5926,12 +5921,11 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h ) { ChessMove moveType; moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove), - epStatus[forwardMostMove], castlingRights[forwardMostMove], fromY, fromX, toY, toX, promoChar); if (appData.debugMode) { int i; for(i=0; i< nrCastlingRights; i++) fprintf(debugFP, "(%d,%d) ", - castlingRights[forwardMostMove][i], castlingRank[i]); + boards[forwardMostMove][CASTLING][i], castlingRank[i]); fprintf(debugFP, "castling rights\n"); } if(moveType == IllegalMove) { @@ -6031,7 +6025,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. if( gameMode == TwoMachinesPlay ) { // [HGM] some adjudications useful with buggy engines - int k, count = 0, epFile = epStatus[forwardMostMove]; static int bare = 1; + int k, count = 0; static int bare = 1; if(gameInfo.holdingsSize == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) { @@ -6093,7 +6087,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. /* Some material-based adjudications that have to be made before stalemate test */ if(gameInfo.variant == VariantAtomic && NrK < 2) { // [HGM] atomic: stm must have lost his King on previous move, as destroying own K is illegal - epStatus[forwardMostMove] = EP_CHECKMATE; // make claimable as if stm is checkmated + boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; // make claimable as if stm is checkmated if(appData.checkMates) { SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets move ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ @@ -6106,7 +6100,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. /* Bare King in Shatranj (loses) or Losers (wins) */ if( NrW == 1 || NrPieces - NrW == 1) { if( gameInfo.variant == VariantLosers) { // [HGM] losers: bare King wins (stm must have it first) - epStatus[forwardMostMove] = EP_WINS; // mark as win, so it becomes claimable + boards[forwardMostMove][EP_STATUS] = EP_WINS; // mark as win, so it becomes claimable if(appData.checkMates) { SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets to see move ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ @@ -6117,7 +6111,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. } else if( gameInfo.variant == VariantShatranj && --bare < 0) { /* bare King */ - epStatus[forwardMostMove] = EP_WINS; // make claimable as win for stm + boards[forwardMostMove][EP_STATUS] = EP_WINS; // make claimable as win for stm if(appData.checkMates) { /* but only adjudicate if adjudication enabled */ SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets move @@ -6131,17 +6125,16 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. // don't wait for engine to announce game end if we can judge ourselves - switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove), epFile, - castlingRights[forwardMostMove]) ) { + switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove)) ) { case MT_CHECK: if(gameInfo.variant == Variant3Check) { // [HGM] 3check: when in check, test if 3rd time int i, checkCnt = 0; // (should really be done by making nr of checks part of game state) for(i=forwardMostMove-2; i>=backwardMostMove; i-=2) { - if(MateTest(boards[i], PosFlags(i), epStatus[i], castlingRights[i]) == MT_CHECK) + if(MateTest(boards[i], PosFlags(i)) == MT_CHECK) checkCnt++; if(checkCnt >= 2) { reason = "Xboard adjudication: 3rd check"; - epStatus[forwardMostMove] = EP_CHECKMATE; + boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; break; } } @@ -6152,25 +6145,25 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. case MT_STALEMATE: case MT_STAINMATE: reason = "Xboard adjudication: Stalemate"; - if(epStatus[forwardMostMove] != EP_CHECKMATE) { // [HGM] don't touch win through baring or K-capt - epStatus[forwardMostMove] = EP_STALEMATE; // default result for stalemate is draw + if((int)boards[forwardMostMove][EP_STATUS] != EP_CHECKMATE) { // [HGM] don't touch win through baring or K-capt + boards[forwardMostMove][EP_STATUS] = EP_STALEMATE; // default result for stalemate is draw if(gameInfo.variant == VariantLosers || gameInfo.variant == VariantGiveaway) // [HGM] losers: - epStatus[forwardMostMove] = EP_WINS; // in these variants stalemated is always a win + boards[forwardMostMove][EP_STATUS] = EP_WINS; // in these variants stalemated is always a win else if(gameInfo.variant == VariantSuicide) // in suicide it depends - epStatus[forwardMostMove] = NrW == NrPieces-NrW ? EP_STALEMATE : + boards[forwardMostMove][EP_STATUS] = NrW == NrPieces-NrW ? EP_STALEMATE : ((NrW < NrPieces-NrW) != WhiteOnMove(forwardMostMove) ? EP_CHECKMATE : EP_WINS); else if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi) - epStatus[forwardMostMove] = EP_CHECKMATE; // and in these variants being stalemated loses + boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; // and in these variants being stalemated loses } break; case MT_CHECKMATE: reason = "Xboard adjudication: Checkmate"; - epStatus[forwardMostMove] = (gameInfo.variant == VariantLosers ? EP_WINS : EP_CHECKMATE); + boards[forwardMostMove][EP_STATUS] = (gameInfo.variant == VariantLosers ? EP_WINS : EP_CHECKMATE); break; } - switch(i = epStatus[forwardMostMove]) { + switch(i = (int)boards[forwardMostMove][EP_STATUS]) { case EP_STALEMATE: result = GameIsDrawn; break; case EP_CHECKMATE: @@ -6195,7 +6188,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. { /* KBK, KNK, KK of KBKB with like Bishops */ /* always flag draws, for judging claims */ - epStatus[forwardMostMove] = EP_INSUF_DRAW; + boards[forwardMostMove][EP_STATUS] = EP_INSUF_DRAW; if(appData.materialDraws) { /* but only adjudicate them if adjudication enabled */ @@ -6228,10 +6221,10 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. if (appData.debugMode) { int i; fprintf(debugFP, "repeat test fmm=%d bmm=%d ep=%d, reps=%d\n", - forwardMostMove, backwardMostMove, epStatus[backwardMostMove], + forwardMostMove, backwardMostMove, boards[backwardMostMove][EP_STATUS], appData.drawRepeats); for( i=forwardMostMove; i>=backwardMostMove; i-- ) - fprintf(debugFP, "%d ep=%d\n", i, epStatus[i]); + fprintf(debugFP, "%d ep=%d\n", i, (int)boards[i][EP_STATUS]); } @@ -6239,26 +6232,26 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. count = 0; for(k = forwardMostMove-2; k>=backwardMostMove && k>=forwardMostMove-100 && - epStatus[k] < EP_UNKNOWN && - epStatus[k+2] <= EP_NONE && epStatus[k+1] <= EP_NONE; + (int)boards[k][EP_STATUS] < EP_UNKNOWN && + (int)boards[k+2][EP_STATUS] <= EP_NONE && (int)boards[k+1][EP_STATUS] <= EP_NONE; k-=2) { int rights=0; if(CompareBoards(boards[k], boards[forwardMostMove])) { /* compare castling rights */ - if( castlingRights[forwardMostMove][2] != castlingRights[k][2] && - (castlingRights[k][0] >= 0 || castlingRights[k][1] >= 0) ) + if( boards[forwardMostMove][CASTLING][2] != boards[k][CASTLING][2] && + (boards[k][CASTLING][0] != NoRights || boards[k][CASTLING][1] != NoRights) ) rights++; /* King lost rights, while rook still had them */ - if( castlingRights[forwardMostMove][2] >= 0 ) { /* king has rights */ - if( castlingRights[forwardMostMove][0] != castlingRights[k][0] || - castlingRights[forwardMostMove][1] != castlingRights[k][1] ) + if( boards[forwardMostMove][CASTLING][2] != NoRights ) { /* king has rights */ + if( boards[forwardMostMove][CASTLING][0] != boards[k][CASTLING][0] || + boards[forwardMostMove][CASTLING][1] != boards[k][CASTLING][1] ) rights++; /* but at least one rook lost them */ } - if( castlingRights[forwardMostMove][5] != castlingRights[k][5] && - (castlingRights[k][3] >= 0 || castlingRights[k][4] >= 0) ) + if( boards[forwardMostMove][CASTLING][5] != boards[k][CASTLING][5] && + (boards[k][CASTLING][3] != NoRights || boards[k][CASTLING][4] != NoRights) ) rights++; - if( castlingRights[forwardMostMove][5] >= 0 ) { - if( castlingRights[forwardMostMove][3] != castlingRights[k][3] || - castlingRights[forwardMostMove][4] != castlingRights[k][4] ) + if( boards[forwardMostMove][CASTLING][5] != NoRights ) { + if( boards[forwardMostMove][CASTLING][3] != boards[k][CASTLING][3] || + boards[forwardMostMove][CASTLING][4] != boards[k][CASTLING][4] ) rights++; } if( rights == 0 && ++count > appData.drawRepeats-2 @@ -6271,11 +6264,9 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. // [HGM] xiangqi: check for forbidden perpetuals int m, ourPerpetual = 1, hisPerpetual = 1; for(m=forwardMostMove; m>k; m-=2) { - if(MateTest(boards[m], PosFlags(m), - EP_NONE, castlingRights[m]) != MT_CHECK) + if(MateTest(boards[m], PosFlags(m)) != MT_CHECK) ourPerpetual = 0; // the current mover did not always check - if(MateTest(boards[m-1], PosFlags(m-1), - EP_NONE, castlingRights[m-1]) != MT_CHECK) + if(MateTest(boards[m-1], PosFlags(m-1)) != MT_CHECK) hisPerpetual = 0; // the opponent did not always check } if(appData.debugMode) fprintf(debugFP, "XQ perpetual test, our=%d, his=%d\n", @@ -6305,21 +6296,21 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. return; } if( rights == 0 && count > 1 ) /* occurred 2 or more times before */ - epStatus[forwardMostMove] = EP_REP_DRAW; + boards[forwardMostMove][EP_STATUS] = EP_REP_DRAW; } } /* Now we test for 50-move draws. Determine ply count */ count = forwardMostMove; /* look for last irreversble move */ - while( epStatus[count] <= EP_NONE && count > backwardMostMove ) + while( (int)boards[count][EP_STATUS] <= EP_NONE && count > backwardMostMove ) count--; /* if we hit starting position, add initial plies */ if( count == backwardMostMove ) count -= initialRulePlies; count = forwardMostMove - count; if( count >= 100) - epStatus[forwardMostMove] = EP_RULE_DRAW; + boards[forwardMostMove][EP_STATUS] = EP_RULE_DRAW; /* this is used to judge if draw claims are legal */ if(appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) { SendToProgram("force\n", cps->other); // suppress reply @@ -6336,11 +6327,11 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. */ if( cps->other->offeredDraw || cps->offeredDraw ) { char *p = NULL; - if(epStatus[forwardMostMove] == EP_RULE_DRAW) + if((int)boards[forwardMostMove][EP_STATUS] == EP_RULE_DRAW) p = "Draw claim: 50-move rule"; - if(epStatus[forwardMostMove] == EP_REP_DRAW) + if((int)boards[forwardMostMove][EP_STATUS] == EP_REP_DRAW) p = "Draw claim: 3-fold repetition"; - if(epStatus[forwardMostMove] == EP_INSUF_DRAW) + if((int)boards[forwardMostMove][EP_STATUS] == EP_INSUF_DRAW) p = "Draw claim: insufficient mating material"; if( p != NULL ) { SendToProgram("force\n", cps->other); // suppress reply @@ -6442,7 +6433,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. * want this, I was asked to put it in, and obliged. */ if (!strncmp(message, "setboard ", 9)) { - Board initial_position; int i; + Board initial_position; GameEnds(GameUnfinished, "Engine aborts game", GE_XBOARD); @@ -6453,9 +6444,6 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. Reset(TRUE, FALSE); CopyBoard(boards[0], initial_position); initialRulePlies = FENrulePlies; - epStatus[0] = FENepStatus; - for( i=0; iBOARD_LEFT && board[toY][toX-1] == BlackPawn && gameInfo.variant != VariantBerolina || toX < fromX) - *ep = toX | berolina; + board[EP_STATUS] = toX | berolina; if(toX fromX) - *ep = toX; + board[EP_STATUS] = toX; } } else if( board[fromY][fromX] == BlackPawn ) { if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers - *ep = EP_PAWN_MOVE; + board[EP_STATUS] = EP_PAWN_MOVE; if( toY-fromY== -2) { if(toX>BOARD_LEFT && board[toY][toX-1] == WhitePawn && gameInfo.variant != VariantBerolina || toX < fromX) - *ep = toX | berolina; + board[EP_STATUS] = toX | berolina; if(toX fromX) - *ep = toX; + board[EP_STATUS] = toX; } } for(i=0; i EP_DRAWS + if( result == GameIsDrawn && (int)boards[forwardMostMove][EP_STATUS] > EP_DRAWS && (forwardMostMove <= backwardMostMove || - epStatus[forwardMostMove-1] > EP_DRAWS || + (int)boards[forwardMostMove-1][EP_STATUS] > EP_DRAWS || (claimer=='b')==(forwardMostMove&1)) ) { /* [HGM] verify: draws that were not flagged are false claims */ @@ -8750,8 +8729,7 @@ LoadGameOneMove(readAhead) case (ChessMove) 0: /* end of file */ if (appData.debugMode) fprintf(debugFP, "Parser hit end of file\n"); - switch (MateTest(boards[currentMove], PosFlags(currentMove), - EP_UNKNOWN, castlingRights[currentMove]) ) { + switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) { case MT_NONE: case MT_CHECK: break; @@ -8786,8 +8764,7 @@ LoadGameOneMove(readAhead) /* Reached start of next game in file */ if (appData.debugMode) fprintf(debugFP, "Parsed start of next game: %s\n", yy_text); - switch (MateTest(boards[currentMove], PosFlags(currentMove), - EP_UNKNOWN, castlingRights[currentMove]) ) { + switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) { case MT_NONE: case MT_CHECK: break; @@ -8946,8 +8923,7 @@ MakeRegisteredMove() MakeMove(fromX, fromY, toX, toY, promoChar); ShowMove(fromX, fromY, toX, toY); - switch (MateTest(boards[currentMove], PosFlags(currentMove), - EP_UNKNOWN, castlingRights[currentMove]) ) { + switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) { case MT_NONE: case MT_CHECK: break; @@ -9317,9 +9293,8 @@ LoadGame(f, gameNumber, title, useList) /* [HGM] copy FEN attributes as well. Bugfix 4.3.14m and 4.3.15e: moved to after 'blackPlaysFirst' */ { int i; initialRulePlies = FENrulePlies; - epStatus[forwardMostMove] = FENepStatus; for( i=0; i< nrCastlingRights; i++ ) - initialRights[i] = castlingRights[forwardMostMove][i] = FENcastlingRights[i]; + initialRights[i] = initial_position[CASTLING][i]; } yyboardindex = forwardMostMove; free(gameInfo.fen); @@ -9668,17 +9643,11 @@ LoadPosition(f, positionNumber, title) currentMove = forwardMostMove = backwardMostMove = 0; DisplayMessage("", _("White to play")); } - /* [HGM] copy FEN attributes as well */ - { int i; - initialRulePlies = FENrulePlies; - epStatus[forwardMostMove] = FENepStatus; - for( i=0; i< nrCastlingRights; i++ ) - castlingRights[forwardMostMove][i] = FENcastlingRights[i]; - } + initialRulePlies = FENrulePlies; /* [HGM] copy FEN attributes as well */ SendBoard(&first, forwardMostMove); if (appData.debugMode) { int i, j; - for(i=0;i<2;i++){for(j=0;j<6;j++)fprintf(debugFP, " %d", castlingRights[i][j]);fprintf(debugFP,"\n");} + for(i=0;i<2;i++){for(j=0;j<6;j++)fprintf(debugFP, " %d", boards[i][CASTLING][j]);fprintf(debugFP,"\n");} for(j=0;j<6;j++)fprintf(debugFP, " %d", initialRights[j]);fprintf(debugFP,"\n"); fprintf(debugFP, "Load Position\n"); } @@ -10090,7 +10059,7 @@ SaveGame(f, dummy, dummy2) int dummy; char *dummy2; { - if (gameMode == EditPosition) EditPositionDone(); + if (gameMode == EditPosition) EditPositionDone(TRUE); lastSavedGame = GameCheckSum(); // [HGM] save: remember ID of last saved game to prevent double saving if (appData.oldSaveStyle) return SaveGameOldStyle(f); @@ -10708,7 +10677,7 @@ MachineWhiteEvent() EditGameEvent(); if (gameMode == EditPosition) - EditPositionDone(); + EditPositionDone(TRUE); if (!WhiteOnMove(currentMove)) { DisplayError(_("It is not White's turn"), 0); @@ -10789,7 +10758,7 @@ MachineBlackEvent() EditGameEvent(); if (gameMode == EditPosition) - EditPositionDone(); + EditPositionDone(TRUE); if (WhiteOnMove(currentMove)) { DisplayError(_("It is not Black's turn"), 0); @@ -10896,7 +10865,7 @@ TwoMachinesEvent P((void)) if (gameMode != EditGame) return; break; case EditPosition: - EditPositionDone(); + EditPositionDone(TRUE); break; case AnalyzeMode: case AnalyzeFile: @@ -11034,7 +11003,7 @@ IcsClientEvent() break; case EditPosition: - EditPositionDone(); + EditPositionDone(TRUE); break; case AnalyzeMode: @@ -11075,7 +11044,7 @@ EditGameEvent() } break; case EditPosition: - EditPositionDone(); + EditPositionDone(TRUE); break; case AnalyzeMode: case AnalyzeFile: @@ -11182,32 +11151,30 @@ ExitAnalyzeMode() } void -EditPositionDone() +EditPositionDone(Boolean fakeRights) { int king = gameInfo.variant == VariantKnightmate ? WhiteUnicorn : WhiteKing; startedFromSetupPosition = TRUE; InitChessProgram(&first, FALSE); - castlingRights[0][2] = castlingRights[0][5] = BOARD_WIDTH>>1; + if(fakeRights) { // [HGM] suppress this if we just pasted a FEN. + boards[0][EP_STATUS] = EP_NONE; + boards[0][CASTLING][2] = boards[0][CASTLING][5] = BOARD_WIDTH>>1; if(boards[0][0][BOARD_WIDTH>>1] == king) { - castlingRights[0][1] = boards[0][0][BOARD_LEFT] == WhiteRook ? 0 : -1; - castlingRights[0][0] = boards[0][0][BOARD_RGHT-1] == WhiteRook ? BOARD_RGHT-1 : -1; - } else castlingRights[0][2] = -1; + boards[0][CASTLING][1] = boards[0][0][BOARD_LEFT] == WhiteRook ? 0 : NoRights; + boards[0][CASTLING][0] = boards[0][0][BOARD_RGHT-1] == WhiteRook ? BOARD_RGHT-1 : NoRights; + } else boards[0][CASTLING][2] = NoRights; if(boards[0][BOARD_HEIGHT-1][BOARD_WIDTH>>1] == WHITE_TO_BLACK king) { - castlingRights[0][4] = boards[0][BOARD_HEIGHT-1][BOARD_LEFT] == BlackRook ? 0 : -1; - castlingRights[0][3] = boards[0][BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook ? BOARD_RGHT-1 : -1; - } else castlingRights[0][5] = -1; + boards[0][CASTLING][4] = boards[0][BOARD_HEIGHT-1][BOARD_LEFT] == BlackRook ? 0 : NoRights; + boards[0][CASTLING][3] = boards[0][BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook ? BOARD_RGHT-1 : NoRights; + } else boards[0][CASTLING][5] = NoRights; + } SendToProgram("force\n", &first); if (blackPlaysFirst) { strcpy(moveList[0], ""); strcpy(parseList[0], ""); currentMove = forwardMostMove = backwardMostMove = 1; CopyBoard(boards[1], boards[0]); - /* [HGM] copy rights as well, as this code is also used after pasting a FEN */ - { int i; - epStatus[1] = epStatus[0]; - for(i=0; iwhich); if(gameInfo.resultDetails==NULL) { /* [HGM] crash: if game in progress, give reason for abort */ - if(epStatus[forwardMostMove] <= EP_DRAWS) { + if((int)boards[forwardMostMove][EP_STATUS] <= EP_DRAWS) { gameInfo.result = GameIsDrawn; /* [HGM] accept exit as draw claim */ sprintf(buf, "%s program exits in draw position (%s)", cps->which, cps->program); } else { @@ -12438,7 +12405,7 @@ ReceiveFromProgram(isr, closure, message, count, error) _("Error: %s chess program (%s) exited unexpectedly"), cps->which, cps->program); if(gameInfo.resultDetails==NULL) { /* [HGM] crash: if game in progress, give reason for abort */ - if(epStatus[forwardMostMove] <= EP_DRAWS) { + if((int)boards[forwardMostMove][EP_STATUS] <= EP_DRAWS) { gameInfo.result = GameIsDrawn; /* [HGM] accept exit as draw claim */ sprintf(buf, _("%s program exits in draw position (%s)"), cps->which, cps->program); } else { @@ -12892,7 +12859,7 @@ PonderNextMoveEvent(newState) int newState; { if (newState == appData.ponderNextMove) return; - if (gameMode == EditPosition) EditPositionDone(); + if (gameMode == EditPosition) EditPositionDone(TRUE); if (newState) { SendToProgram("hard\n", &first); if (gameMode == TwoMachinesPlay) { @@ -12915,7 +12882,7 @@ NewSettingEvent(option, command, value) { char buf[MSG_SIZ]; - if (gameMode == EditPosition) EditPositionDone(); + if (gameMode == EditPosition) EditPositionDone(TRUE); sprintf(buf, "%s%s %d\n", (option ? "option ": ""), command, value); SendToProgram(buf, &first); if (gameMode == TwoMachinesPlay) { @@ -12934,7 +12901,7 @@ ShowThinkingEvent() if (oldState == newState) return; oldState = newState; - if (gameMode == EditPosition) EditPositionDone(); + if (gameMode == EditPosition) EditPositionDone(TRUE); if (oldState) { SendToProgram("post\n", &first); if (gameMode == TwoMachinesPlay) { @@ -13701,30 +13668,30 @@ PositionToFEN(move, overrideCastling) q = p; if(gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) { /* [HGM] write directly from rights */ - if(castlingRights[move][2] >= 0 && - castlingRights[move][0] >= 0 ) - *p++ = castlingRights[move][0] + AAA + 'A' - 'a'; - if(castlingRights[move][2] >= 0 && - castlingRights[move][1] >= 0 ) - *p++ = castlingRights[move][1] + AAA + 'A' - 'a'; - if(castlingRights[move][5] >= 0 && - castlingRights[move][3] >= 0 ) - *p++ = castlingRights[move][3] + AAA; - if(castlingRights[move][5] >= 0 && - castlingRights[move][4] >= 0 ) - *p++ = castlingRights[move][4] + AAA; + if(boards[move][CASTLING][2] != NoRights && + boards[move][CASTLING][0] != NoRights ) + *p++ = boards[move][CASTLING][0] + AAA + 'A' - 'a'; + if(boards[move][CASTLING][2] != NoRights && + boards[move][CASTLING][1] != NoRights ) + *p++ = boards[move][CASTLING][1] + AAA + 'A' - 'a'; + if(boards[move][CASTLING][5] != NoRights && + boards[move][CASTLING][3] != NoRights ) + *p++ = boards[move][CASTLING][3] + AAA; + if(boards[move][CASTLING][5] != NoRights && + boards[move][CASTLING][4] != NoRights ) + *p++ = boards[move][CASTLING][4] + AAA; } else { /* [HGM] write true castling rights */ if( nrCastlingRights == 6 ) { - if(castlingRights[move][0] == BOARD_RGHT-1 && - castlingRights[move][2] >= 0 ) *p++ = 'K'; - if(castlingRights[move][1] == BOARD_LEFT && - castlingRights[move][2] >= 0 ) *p++ = 'Q'; - if(castlingRights[move][3] == BOARD_RGHT-1 && - castlingRights[move][5] >= 0 ) *p++ = 'k'; - if(castlingRights[move][4] == BOARD_LEFT && - castlingRights[move][5] >= 0 ) *p++ = 'q'; + if(boards[move][CASTLING][0] == BOARD_RGHT-1 && + boards[move][CASTLING][2] != NoRights ) *p++ = 'K'; + if(boards[move][CASTLING][1] == BOARD_LEFT && + boards[move][CASTLING][2] != NoRights ) *p++ = 'Q'; + if(boards[move][CASTLING][3] == BOARD_RGHT-1 && + boards[move][CASTLING][5] != NoRights ) *p++ = 'k'; + if(boards[move][CASTLING][4] == BOARD_LEFT && + boards[move][CASTLING][5] != NoRights ) *p++ = 'q'; } } if (q == p) *p++ = '-'; /* No castling rights */ @@ -13751,8 +13718,8 @@ PositionToFEN(move, overrideCastling) } } else if(move == backwardMostMove) { // [HGM] perhaps we should always do it like this, and forget the above? - if(epStatus[move] >= 0) { - *p++ = epStatus[move] + AAA; + if((int)boards[move][EP_STATUS] >= 0) { + *p++ = boards[move][EP_STATUS] + AAA; *p++ = whiteToPlay ? '6'+BOARD_HEIGHT-8 : '3'; } else { *p++ = '-'; @@ -13770,11 +13737,11 @@ PositionToFEN(move, overrideCastling) if (appData.debugMode) { int k; fprintf(debugFP, "write FEN 50-move: %d %d %d\n", initialRulePlies, forwardMostMove, backwardMostMove); for(k=backwardMostMove; k<=forwardMostMove; k++) - fprintf(debugFP, "e%d. p=%d\n", k, epStatus[k]); + fprintf(debugFP, "e%d. p=%d\n", k, (int)boards[k][EP_STATUS]); } - while(j > backwardMostMove && epStatus[j] <= EP_NONE) j--,i++; + while(j > backwardMostMove && (int)boards[j][EP_STATUS] <= EP_NONE) j--,i++; if( j == backwardMostMove ) i += initialRulePlies; sprintf(p, "%d ", i); p += i>=100 ? 4 : i >= 10 ? 3 : 2; @@ -13818,7 +13785,7 @@ ParseFEN(board, blackPlaysFirst, fen) while (emptycount--) board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare; break; -#if(BOARD_SIZE >= 10) +#if(BOARD_FILES >= 10) } else if(*p=='x' || *p=='X') { /* [HGM] X means 10 */ p++; emptycount=10; if (j + emptycount > gameInfo.boardWidth) return FALSE; @@ -13900,17 +13867,17 @@ ParseFEN(board, blackPlaysFirst, fen) /* return the extra info in global variiables */ /* set defaults in case FEN is incomplete */ - FENepStatus = EP_UNKNOWN; + board[EP_STATUS] = EP_UNKNOWN; for(i=0; i=0 && board[castlingRank[0]][initialRights[0]] != WhiteRook) FENcastlingRights[0] = -1; - if(initialRights[1]>=0 && board[castlingRank[1]][initialRights[1]] != WhiteRook) FENcastlingRights[1] = -1; - if(initialRights[2]>=0 && board[castlingRank[2]][initialRights[2]] != WhiteKing) FENcastlingRights[2] = -1; - if(initialRights[3]>=0 && board[castlingRank[3]][initialRights[3]] != BlackRook) FENcastlingRights[3] = -1; - if(initialRights[4]>=0 && board[castlingRank[4]][initialRights[4]] != BlackRook) FENcastlingRights[4] = -1; - if(initialRights[5]>=0 && board[castlingRank[5]][initialRights[5]] != BlackKing) FENcastlingRights[5] = -1; + if(initialRights[0]>=0 && board[castlingRank[0]][initialRights[0]] != WhiteRook) board[CASTLING][0] = NoRights; + if(initialRights[1]>=0 && board[castlingRank[1]][initialRights[1]] != WhiteRook) board[CASTLING][1] = NoRights; + if(initialRights[2]>=0 && board[castlingRank[2]][initialRights[2]] != WhiteKing) board[CASTLING][2] = NoRights; + if(initialRights[3]>=0 && board[castlingRank[3]][initialRights[3]] != BlackRook) board[CASTLING][3] = NoRights; + if(initialRights[4]>=0 && board[castlingRank[4]][initialRights[4]] != BlackRook) board[CASTLING][4] = NoRights; + if(initialRights[5]>=0 && board[castlingRank[5]][initialRights[5]] != BlackKing) board[CASTLING][5] = NoRights; FENrulePlies = 0; while(*p==' ') p++; @@ -13918,7 +13885,7 @@ ParseFEN(board, blackPlaysFirst, fen) if(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') { /* castling indicator present, so default becomes no castlings */ for(i=0; iwhiteKingFile; i--); - FENcastlingRights[0] = i != whiteKingFile ? i : -1; - FENcastlingRights[2] = whiteKingFile; + board[CASTLING][0] = i != whiteKingFile ? i : NoRights; + board[CASTLING][2] = whiteKingFile; break; case'Q': for(i=BOARD_LEFT; board[0][i]!=WhiteRook && iblackKingFile; i--); - FENcastlingRights[3] = i != blackKingFile ? i : -1; - FENcastlingRights[5] = blackKingFile; + board[CASTLING][3] = i != blackKingFile ? i : NoRights; + board[CASTLING][5] = blackKingFile; break; case'q': for(i=BOARD_LEFT; board[BOARD_HEIGHT-1][i]!=BlackRook && i= BlackKing ) break; if(c > i) - FENcastlingRights[3] = c; + board[CASTLING][3] = c; else - FENcastlingRights[4] = c; + board[CASTLING][4] = c; } else { /* white rights */ for(i=BOARD_LEFT; i= WhiteKing) break; if(c > i) - FENcastlingRights[0] = c; + board[CASTLING][0] = c; else - FENcastlingRights[1] = c; + board[CASTLING][1] = c; } } } if (appData.debugMode) { fprintf(debugFP, "FEN castling rights:"); for(i=0; i= BOARD_RGHT) return TRUE; if(*p >= '0' && *p <='9') *p++; - FENepStatus = c; + board[EP_STATUS] = c; } } @@ -14027,14 +13994,8 @@ EditPositionPasteFEN(char *fen) EditPositionEvent(); blackPlaysFirst = savedBlackPlaysFirst; CopyBoard(boards[0], initial_position); - /* [HGM] copy FEN attributes as well */ - { int i; - initialRulePlies = FENrulePlies; - epStatus[0] = FENepStatus; - for( i=0; i= 0) { - if(castlingRights[moveNr][0] >= 0) key^=RandomCastle[0]; - if(castlingRights[moveNr][1] >= 0) key^=RandomCastle[1]; + if(boards[moveNr][CASTLING][2] != NoRights) { + if(boards[moveNr][CASTLING][0] != NoRights) key^=RandomCastle[0]; + if(boards[moveNr][CASTLING][1] != NoRights) key^=RandomCastle[1]; } - if(castlingRights[moveNr][5] >= 0) { - if(castlingRights[moveNr][3] >= 0) key^=RandomCastle[2]; - if(castlingRights[moveNr][4] >= 0) key^=RandomCastle[3]; + if(boards[moveNr][CASTLING][5] != NoRights) { + if(boards[moveNr][CASTLING][3] != NoRights) key^=RandomCastle[2]; + if(boards[moveNr][CASTLING][4] != NoRights) key^=RandomCastle[3]; } - f = epStatus[moveNr]; + f = boards[moveNr][EP_STATUS]; if(f >= 0 && f < 8){ if(!WhiteOnMove(moveNr)){ // the test for neighboring Pawns might not be needed, diff --git a/common.h b/common.h index b184aec..18c3b38 100644 --- a/common.h +++ b/common.h @@ -125,13 +125,17 @@ int pclose(FILE *); outside world in ASCII. In a similar way, the different rank numbering systems (starting at rank 0 or 1) are implemented by redefining '1'. */ -#define BOARD_SIZE 16 /* [HGM] for in declarations */ -#define BOARD_HEIGHT (gameInfo.boardHeight) // [HGM] made user adjustable +#define BOARD_RANKS 11 /* [HGM] for in declarations */ +#define BOARD_FILES 16 /* [HGM] for in declarations */ +#define BOARD_HEIGHT (gameInfo.boardHeight) /* [HGM] made user adjustable */ #define BOARD_WIDTH (gameInfo.boardWidth + 2*gameInfo.holdingsWidth) -#define BOARD_LEFT (gameInfo.holdingsWidth) // [HGM] play-board edges +#define BOARD_LEFT (gameInfo.holdingsWidth) /* [HGM] play-board edges */ #define BOARD_RGHT (gameInfo.boardWidth + gameInfo.holdingsWidth) -#define ONE ('1'-(BOARD_HEIGHT>9)) // [HGM] foremost board rank -#define AAA ('a'-BOARD_LEFT) // [HGM] leftmost board file +#define CASTLING (BOARD_RANKS-1) /* [HGM] hide in upper rank */ +#define EP_STATUS CASTLING][(BOARD_FILES-2) /* [HGM] in upper rank */ +#define HOLDINGS_SET CASTLING][(BOARD_FILES-1) /* [HGM] in upper-right corner*/ +#define ONE ('1'-(BOARD_HEIGHT>9)) /* [HGM] foremost board rank */ +#define AAA ('a'-BOARD_LEFT) /* [HGM] leftmost board file */ #define DROP_RANK -3 #define MAX_MOVES 1000 #define MSG_SIZ 512 @@ -209,6 +213,7 @@ typedef enum { BlackCannon, BlackNightrider, BlackCardinal, BlackDragon, BlackGrasshopper, BlackSilver, BlackFalcon, BlackLance, BlackCobra, BlackUnicorn, BlackKing, EmptySquare, + NoRights, // [HGM] gamestate: for castling rights hidden in board[CASTLING] ClearBoard, WhitePlay, BlackPlay, PromotePiece, DemotePiece /*for use on EditPosition menus*/ } ChessSquare; @@ -220,7 +225,7 @@ typedef enum { #define SHOGI (int)EmptySquare + (int) -typedef ChessSquare Board[BOARD_SIZE][BOARD_SIZE]; +typedef ChessSquare Board[BOARD_RANKS][BOARD_FILES]; typedef enum { WhiteKingSideCastle = 1, WhiteQueenSideCastle, @@ -656,6 +661,7 @@ typedef struct { } GameInfo; /* [AS] Search stats from chessprogram, for the played move */ +// [HGM] moved here from backend.h because it occurs in declarations of front-end functions typedef struct { int score; /* Centipawns */ int depth; /* Plies */ diff --git a/moves.c b/moves.c index 2a017c3..9086a92 100644 --- a/moves.c +++ b/moves.c @@ -69,7 +69,7 @@ int BlackPiece P((ChessSquare)); int SameColor P((ChessSquare, ChessSquare)); int PosFlags(int index); -extern signed char initialRights[BOARD_SIZE]; /* [HGM] all rights enabled, set in InitPosition */ +extern signed char initialRights[BOARD_FILES]; /* [HGM] all rights enabled, set in InitPosition */ int WhitePiece(piece) @@ -227,6 +227,9 @@ void CopyBoard(to, from) for (i = 0; i < BOARD_HEIGHT; i++) for (j = 0; j < BOARD_WIDTH; j++) to[i][j] = from[i][j]; + for (j = 0; j < BOARD_FILES-1; j++) // [HGM] gamestate: copy castling rights and ep status + to[CASTLING][j] = from[CASTLING][j]; + to[HOLDINGS_SET] = 0; // flag used in ICS play } int CompareBoards(board1, board2) @@ -251,15 +254,15 @@ int CompareBoards(board1, board2) EP_UNKNOWN if we don't know and want to allow all e.p. captures. Promotion moves generated are to Queen only. */ -void GenPseudoLegal(board, flags, epfile, callback, closure) +void GenPseudoLegal(board, flags, callback, closure) Board board; int flags; - int epfile; MoveCallback callback; VOIDSTAR closure; { int rf, ff; int i, j, d, s, fs, rs, rt, ft, m; + int epfile = board[EP_STATUS]; // [HGM] gamestate: extract ep status from board for (rf = 0; rf < BOARD_HEIGHT; rf++) for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) { @@ -748,22 +751,20 @@ typedef struct { true if castling is not yet ruled out by a move of the king or rook. Return TRUE if the player on move is currently in check and F_IGNORE_CHECK is not set. [HGM] add castlingRights parameter */ -int GenLegal(board, flags, epfile, castlingRights, callback, closure) +int GenLegal(board, flags, callback, closure) Board board; int flags; - int epfile; - char castlingRights[]; MoveCallback callback; VOIDSTAR closure; { GenLegalClosure cl; int ff, ft, k, left, right; int ignoreCheck = (flags & F_IGNORE_CHECK) != 0; - ChessSquare wKing = WhiteKing, bKing = BlackKing; + ChessSquare wKing = WhiteKing, bKing = BlackKing, *castlingRights = board[CASTLING]; cl.cb = callback; cl.cl = closure; - GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl); + GenPseudoLegal(board, flags, GenLegalCallback, (VOIDSTAR) &cl); if (!ignoreCheck && CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE; @@ -782,7 +783,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) board[0][BOARD_RGHT-3] == EmptySquare && board[0][BOARD_RGHT-2] == EmptySquare && board[0][BOARD_RGHT-1] == WhiteRook && - castlingRights[0] >= 0 && /* [HGM] check rights */ + (int)castlingRights[0] >= 0 && /* [HGM] check rights */ ( castlingRights[2] == ff || castlingRights[6] == ff ) && (ignoreCheck || (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) && @@ -802,7 +803,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) board[0][BOARD_LEFT+2] == EmptySquare && board[0][BOARD_LEFT+1] == EmptySquare && board[0][BOARD_LEFT+0] == WhiteRook && - castlingRights[1] >= 0 && /* [HGM] check rights */ + (int)castlingRights[1] >= 0 && /* [HGM] check rights */ ( castlingRights[2] == ff || castlingRights[6] == ff ) && (ignoreCheck || (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) && @@ -821,7 +822,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) board[BOARD_HEIGHT-1][BOARD_RGHT-3] == EmptySquare && board[BOARD_HEIGHT-1][BOARD_RGHT-2] == EmptySquare && board[BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook && - castlingRights[3] >= 0 && /* [HGM] check rights */ + (int)castlingRights[3] >= 0 && /* [HGM] check rights */ ( castlingRights[5] == ff || castlingRights[7] == ff ) && (ignoreCheck || (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) && @@ -841,7 +842,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) board[BOARD_HEIGHT-1][BOARD_LEFT+2] == EmptySquare && board[BOARD_HEIGHT-1][BOARD_LEFT+1] == EmptySquare && board[BOARD_HEIGHT-1][BOARD_LEFT+0] == BlackRook && - castlingRights[4] >= 0 && /* [HGM] check rights */ + (int)castlingRights[4] >= 0 && /* [HGM] check rights */ ( castlingRights[5] == ff || castlingRights[7] == ff ) && (ignoreCheck || (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) && @@ -999,8 +1000,7 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant) cl.check++; } - GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1, - CheckTestCallback, (VOIDSTAR) &cl); + GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, CheckTestCallback, (VOIDSTAR) &cl); goto undo_move; /* 2-level break */ } } @@ -1043,13 +1043,12 @@ void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure) cl->kind = kind; } -ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, promoChar) +ChessMove LegalityTest(board, flags, rf, ff, rt, ft, promoChar) Board board; - int flags, epfile; + int flags; int rf, ff, rt, ft, promoChar; - char castlingRights[]; { - LegalityTestClosure cl; ChessSquare piece = board[rf][ff]; + LegalityTestClosure cl; ChessSquare piece = board[rf][ff], *castlingRights = board[CASTLING]; if (appData.debugMode) { int i; @@ -1069,7 +1068,7 @@ ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, pro cl.ft = ft; cl.kind = IllegalMove; cl.captures = 0; // [HGM] losers: prepare to count legal captures. - GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl); + GenLegal(board, flags, LegalityTestCallback, (VOIDSTAR) &cl); if((flags & F_MANDATORY_CAPTURE) && cl.captures && board[rt][ft] == EmptySquare && cl.kind != WhiteCapturesEnPassant && cl.kind != BlackCapturesEnPassant) return(IllegalMove); // [HGM] losers: if there are legal captures, non-capts are illegal @@ -1142,10 +1141,9 @@ void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure) } /* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */ -int MateTest(board, flags, epfile, castlingRights) +int MateTest(board, flags) Board board; - int flags, epfile; - char castlingRights[]; + int flags; { MateTestClosure cl; int inCheck, r, f, myPieces=0, hisPieces=0, nrKing=0; @@ -1173,7 +1171,7 @@ int MateTest(board, flags, epfile, castlingRights) if(myPieces == 1) return MT_BARE; } cl.count = 0; - inCheck = GenLegal(board, flags, epfile, castlingRights, MateTestCallback, (VOIDSTAR) &cl); + inCheck = GenLegal(board, flags, MateTestCallback, (VOIDSTAR) &cl); // [HGM] 3check: yet to do! if (cl.count > 0) { return inCheck ? MT_CHECK : MT_NONE; @@ -1230,9 +1228,9 @@ void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure) } } -void Disambiguate(board, flags, epfile, closure) +void Disambiguate(board, flags, closure) Board board; - int flags, epfile; + int flags; DisambiguateClosure *closure; { int illegal = 0; char c = closure->promoCharIn; @@ -1245,12 +1243,11 @@ void Disambiguate(board, flags, epfile, closure) closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn, closure->promoCharIn, closure->promoCharIn >= ' ' ? closure->promoCharIn : '-'); } - GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure); + GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) closure); if (closure->count == 0) { /* See if it's an illegal move due to check */ illegal = 1; - GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights, DisambiguateCallback, - (VOIDSTAR) closure); + GenLegal(board, flags|F_IGNORE_CHECK, DisambiguateCallback, (VOIDSTAR) closure); if (closure->count == 0) { /* No, it's not even that */ if (appData.debugMode) { int i, j; @@ -1380,10 +1377,9 @@ void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure) /* Convert coordinates to normal algebraic notation. promoChar must be NULLCHAR or 'x' if not a promotion. */ -ChessMove CoordsToAlgebraic(board, flags, epfile, - rf, ff, rt, ft, promoChar, out) +ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out) Board board; - int flags, epfile; + int flags; int rf, ff, rt, ft; int promoChar; char out[MOVE_LEN]; @@ -1414,12 +1410,11 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, switch (piece) { case WhitePawn: case BlackPawn: - kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar); + kind = LegalityTest(board, flags, rf, ff, rt, ft, promoChar); if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) { /* Keep short notation if move is illegal only because it leaves the player in check, but still return IllegalMove */ - kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile, initialRights, - rf, ff, rt, ft, promoChar); + kind = LegalityTest(board, flags|F_IGNORE_CHECK, rf, ff, rt, ft, promoChar); if (kind == IllegalMove) break; kind = IllegalMove; } @@ -1463,8 +1458,7 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, if((piece == WhiteKing && board[rt][ft] == WhiteRook) || (piece == BlackKing && board[rt][ft] == BlackRook)) { if(ft > ff) strcpy(out, "O-O"); else strcpy(out, "O-O-O"); - return LegalityTest(board, flags, epfile, initialRights, - rf, ff, rt, ft, promoChar); + return LegalityTest(board, flags, rf, ff, rt, ft, promoChar); } /* End of code added by Tord */ /* Test for castling or ICS wild castling */ @@ -1486,8 +1480,7 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, this situation. So I am not going to worry about it; I'll just generate an ambiguous O-O in this case. */ - return LegalityTest(board, flags, epfile, initialRights, - rf, ff, rt, ft, promoChar); + return LegalityTest(board, flags, rf, ff, rt, ft, promoChar); } /* else fall through */ @@ -1500,15 +1493,13 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, cl.piece = piece; cl.kind = IllegalMove; cl.rank = cl.file = cl.either = 0; - GenLegal(board, flags, epfile, initialRights, - CoordsToAlgebraicCallback, (VOIDSTAR) &cl); + GenLegal(board, flags, CoordsToAlgebraicCallback, (VOIDSTAR) &cl); if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) { /* Generate pretty moves for moving into check, but still return IllegalMove. */ - GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights, - CoordsToAlgebraicCallback, (VOIDSTAR) &cl); + GenLegal(board, flags|F_IGNORE_CHECK, CoordsToAlgebraicCallback, (VOIDSTAR) &cl); if (cl.kind == IllegalMove) break; cl.kind = IllegalMove; } @@ -1735,7 +1726,7 @@ int PerpetualChase(int first, int last) if(appData.debugMode) fprintf(debugFP, "judge position %i\n", i); chaseStackPointer = 0; // clear stack that is going to hold possible chases // determine all captures possible after the move, and put them on chaseStack - GenLegal(boards[i+1], PosFlags(i), EP_NONE, initialRights, AttacksCallback, &cl); + GenLegal(boards[i+1], PosFlags(i), AttacksCallback, &cl); if(appData.debugMode) { int n; for(n=0; n= (int)BlackPawn && WhiteOnMove(currentMove); cl.count = 0; cl.rf = fromY; cl.ff = fromX; cl.rt = cl.ft = -1; - GenLegal(boards[currentMove], PosFlags(currentMove + swapColor), EP_NONE, - castlingRights[currentMove], ReadCallback, (VOIDSTAR) &cl); + GenLegal(boards[currentMove], PosFlags(currentMove + swapColor), ReadCallback, (VOIDSTAR) &cl); if(cl.count == 0) SayString("None", FALSE); boards[currentMove][fromY][fromX] = victim; // repair @@ -459,16 +457,14 @@ PossibleAttacked() victim = boards[currentMove][fromY][fromX]; // put dummy piece on target square, to activate Pawn captures boards[currentMove][fromY][fromX] = WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen; cl.count = 0; cl.rt = fromY; cl.ft = fromX; cl.rf = cl.ff = -1; - GenLegal(boards[currentMove], PosFlags(currentMove+1), EP_NONE, - castlingRights[currentMove], ReadCallback, (VOIDSTAR) &cl); + GenLegal(boards[currentMove], PosFlags(currentMove+1), ReadCallback, (VOIDSTAR) &cl); if(cl.count == 0) SayString("None", FALSE); SayString("You are defended by", FALSE); boards[currentMove][fromY][fromX] = WhiteOnMove(currentMove) ? BlackQueen : WhiteQueen; cl.count = 0; cl.rt = fromY; cl.ft = fromX; cl.rf = cl.ff = -1; - GenLegal(boards[currentMove], PosFlags(currentMove), EP_NONE, - castlingRights[currentMove], ReadCallback, (VOIDSTAR) &cl); + GenLegal(boards[currentMove], PosFlags(currentMove), ReadCallback, (VOIDSTAR) &cl); if(cl.count == 0) SayString("None", FALSE); boards[currentMove][fromY][fromX] = victim; // put back original occupant diff --git a/winboard/winboard.c b/winboard/winboard.c index 3870fc8..2bfe6f2 100644 --- a/winboard/winboard.c +++ b/winboard/winboard.c @@ -193,8 +193,8 @@ static HBRUSH lightSquareBrush, darkSquareBrush, blackSquareBrush, /* [HGM] for band between board and holdings */ explodeBrush, /* [HGM] atomic */ whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/; -static POINT gridEndpoints[(BOARD_SIZE + 1) * 4]; -static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2]; +static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2]; +static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2]; static HPEN gridPen = NULL; static HPEN highlightPen = NULL; static HPEN premovePen = NULL; @@ -216,7 +216,7 @@ static HBITMAP darkBackTexture = NULL; static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN; static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN; static int backTextureSquareSize = 0; -static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE]; +static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES]; #if __GNUC__ && !defined(_winmajor) #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */ @@ -2167,9 +2167,9 @@ InitAppData(LPSTR lpCmdLine) ParseArgs(StringGet, &lpCmdLine); /* [HGM] make sure board size is acceptable */ - if(appData.NrFiles > BOARD_SIZE || - appData.NrRanks > BOARD_SIZE ) - DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2); + if(appData.NrFiles > BOARD_FILES || + appData.NrRanks > BOARD_RANKS ) + DisplayFatalError("Recompile with BOARD_RANKS or BOARD_FILES, to support this size", 0, 2); /* [HGM] After parsing the options from the .ini file, and overruling them * with options from the command line, we now make an even higher priority @@ -4158,8 +4158,8 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc) if( liteBackTexture != NULL || darkBackTexture != NULL ) { static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */ if( backTextureSquareSize != squareSize - || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) { - backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT; + || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) { + backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT; backTextureSquareSize = squareSize; RebuildTextureSquareInfo(); } diff --git a/xboard.c b/xboard.c index a27a3be..cefa62c 100644 --- a/xboard.c +++ b/xboard.c @@ -467,8 +467,8 @@ Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget, commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu, menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell, ICSInputShell, fileNameShell, askQuestionShell; -XSegment gridSegments[(BOARD_SIZE + 1) * 2]; -XSegment jailGridSegments[(BOARD_SIZE + 3) * 2]; +XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2]; +XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6]; Font clockFontID, coordFontID, countFontID; XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct; XtAppContext appContext; @@ -2511,9 +2511,9 @@ main(argc, argv) } /* [HGM,HR] make sure board size is acceptable */ - if(appData.NrFiles > BOARD_SIZE || - appData.NrRanks > BOARD_SIZE ) - DisplayFatalError(_("Recompile with BOARD_SIZE > 12, to support this size"), 0, 2); + if(appData.NrFiles > BOARD_FILES || + appData.NrRanks > BOARD_RANKS ) + DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2); #if !HIGHDRAG /* This feature does not work; animation needs a rewrite */ @@ -5011,7 +5011,7 @@ static int check_castle_draw(newb, oldb, rrow, rcol) return 0; } -static int damage[BOARD_SIZE][BOARD_SIZE]; +static int damage[BOARD_RANKS][BOARD_FILES]; /* * event handler for redrawing the board