X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=2c7933ede4fbfddd7ed3e127ecbd5345e46b845b;hb=00f49d137feed871220bb1ed4193f86704d20dbf;hp=1c4bddcde20b36628ed565ce5cc850c32a707194;hpb=50b75711089c434a89fcb126a5db86e7eb8246a3;p=xboard.git diff --git a/backend.c b/backend.c index 1c4bddc..2c7933e 100644 --- a/backend.c +++ b/backend.c @@ -295,6 +295,7 @@ ChessSquare promoSweep = EmptySquare, defaultPromoChoice; int promoDefaultAltered; int keepInfo = 0; /* [HGM] to protect PGN tags in auto-step game analysis */ static int initPing = -1; +int border; /* [HGM] width of board rim, needed to size seek graph */ /* States for ics_getting_history */ #define H_FALSE 0 @@ -847,7 +848,7 @@ InitEngine (ChessProgramState *cps, int n) if(cps->tidy == NULL) cps->tidy = (char*) malloc(MSG_SIZ); TidyProgramName(cps->program, cps->host, cps->tidy); cps->matchWins = 0; - ASSIGN(cps->variants, appData.variant); + ASSIGN(cps->variants, appData.noChessProgram ? "" : appData.variant); cps->analysisSupport = 2; /* detect */ cps->analyzing = FALSE; cps->initDone = FALSE; @@ -954,7 +955,7 @@ extern Boolean isUCI, hasBook, storeVariant, v1, addToList, useNick; static char resetOptions[] = "-reuse -firstIsUCI false -firstHasOwnBookUCI true -firstTimeOdds 1 " "-firstInitString \"" INIT_STRING "\" -firstComputerString \"" COMPUTER_STRING "\" " - "-firstFeatures \"\" -firstLogo \"\" -firstAccumulateTC 1 " + "-firstFeatures \"\" -firstLogo \"\" -firstAccumulateTC 1 -fd \".\" " "-firstOptions \"\" -firstNPS -1 -fn \"\" -firstScoreAbs false"; void @@ -1200,6 +1201,11 @@ InitBackEnd1 () DisplayFatalError(buf, 0, 2); return; + case VariantNormal: /* definitely works! */ + if(strcmp(appData.variant, "normal") && !appData.noChessProgram) { // [HGM] hope this is an engine-defined variant + safeStrCpy(engineVariant, appData.variant, MSG_SIZ); + return; + } case VariantXiangqi: /* [HGM] repetition rules not implemented */ case VariantFairy: /* [HGM] TestLegality definitely off! */ case VariantGothic: /* [HGM] should work */ @@ -1212,7 +1218,6 @@ InitBackEnd1 () case VariantFalcon: /* [HGM] untested */ case VariantCrazyhouse: /* holdings not shown, ([HGM] fixed that!) offboard interposition not understood */ - case VariantNormal: /* definitely works! */ case VariantWildCastle: /* pieces not automatically shuffled */ case VariantNoCastle: /* pieces not automatically shuffled */ case VariantFischeRandom: /* [HGM] works and shuffles pieces */ @@ -2103,14 +2108,14 @@ StringToVariant (char *e) int wnum = -1; VariantClass v = VariantNormal; int i, found = FALSE; - char buf[MSG_SIZ]; + char buf[MSG_SIZ], c; int len; if (!e) return v; /* [HGM] skip over optional board-size prefixes */ - if( sscanf(e, "%dx%d_", &i, &i) == 2 || - sscanf(e, "%dx%d+%d_", &i, &i, &i) == 3 ) { + if( sscanf(e, "%dx%d_%c", &i, &i, &c) == 3 || + sscanf(e, "%dx%d+%d_%c", &i, &i, &i, &c) == 4 ) { while( *e++ != '_'); } @@ -2120,7 +2125,7 @@ StringToVariant (char *e) } else for (i=0; i= VariantShogi && isalpha(p[strlen(variantNames[i])])) continue; + if(p && i >= VariantShogi && (p != e || isalpha(p[strlen(variantNames[i])]))) continue; v = (VariantClass) i; found = TRUE; break; @@ -2716,8 +2721,8 @@ DrawSeekGraph () { int i; if(!seekGraphUp) return FALSE; - h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap; - w = BOARD_WIDTH * (squareSize + lineGap) + lineGap; + h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap + 2*border; + w = BOARD_WIDTH * (squareSize + lineGap) + lineGap + 2*border; DrawSeekBackground(0, 0, w, h); DrawSeekAxis(hMargin, h-1-vMargin, w-5, h-1-vMargin); @@ -5323,6 +5328,7 @@ UploadGameEvent () } int killX = -1, killY = -1; // [HGM] lion: used for passing e.p. capture square to MakeMove +int legNr = 1; void CoordsToComputerAlgebraic (int rf, int ff, int rt, int ft, char promoChar, char move[7]) @@ -5680,7 +5686,7 @@ LoadMultiPV (int x, int y, char *buf, int index, int *start, int *end, int pane) } ParsePV(buf+startPV, FALSE, gameMode != AnalyzeMode); *start = startPV; *end = index-1; - extendGame = (gameMode == AnalyzeMode && appData.autoExtend); + extendGame = (gameMode == AnalyzeMode && appData.autoExtend && origIndex - startPV < 5); return TRUE; } @@ -6027,9 +6033,10 @@ InitPosition (int redraw) gameInfo.boardHeight = 8; gameInfo.holdingsSize = 0; nrCastlingRights = -1; /* [HGM] Kludge to indicate default should be used */ - for(i=0; i= BlackPawn ? BLACK_TO_WHITE piece : piece; promotionZoneSize = BOARD_HEIGHT/3; highestPromotingPiece = (p >= WhiteLion || PieceToChar(piece + 22) == '.') ? WhitePawn : WhiteLion; - } else if(gameInfo.variant == VariantShogi || gameInfo.variant == VariantChuChess) { + } else if(gameInfo.variant == VariantShogi) { promotionZoneSize = BOARD_HEIGHT/3; highestPromotingPiece = (int)WhiteAlfil; } else if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess) { @@ -6984,7 +6991,7 @@ UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar) // holdings might not be sent yet in ICS play; we have to figure out which piece belongs here if(fromX == 0) fromY = BOARD_HEIGHT-1 - fromY; // black holdings upside-down fromX = fromX ? WhitePawn : BlackPawn; // first piece type in selected holdings - while(PieceToChar(fromX) == '.' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++; + while(PieceToChar(fromX) == '.' || PieceToChar(fromX) == '+' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++; fromY = DROP_RANK; } @@ -7257,11 +7264,11 @@ Mark (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VO { typedef char Markers[BOARD_RANKS][BOARD_FILES]; Markers *m = (Markers *) closure; - if(rf == fromY && ff == fromX && (killX < 0 && !(rt == rf && ft == ff) || abs(ft-killX) < 2 && abs(rt-killY) < 2)) + if(rf == fromY && ff == fromX && (killX < 0 ? !(rt == rf && ft == ff) && legNr & 1 : rt == killY && ft == killX || legNr & 2)) (*m)[rt][ft] = 1 + (board[rt][ft] != EmptySquare || kind == WhiteCapturesEnPassant - || kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0); - else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3; + || kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0), legal[rt][ft] = 1; + else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3, legal[rt][ft] = 1; } static int hoverSavedValid; @@ -7277,7 +7284,7 @@ MarkTargetSquares (int clear) } else { int capt = 0; if(!appData.markers || !appData.highlightDragging || appData.icsActive && gameInfo.variant < VariantShogi || - !appData.testLegality || gameMode == EditPosition) return; + !appData.testLegality && !pieceDefs || gameMode == EditPosition) return; GenLegal(boards[currentMove], PosFlags(currentMove), Mark, (void*) marker, EmptySquare); if(PosFlags(0) & F_MANDATORY_CAPTURE) { for(x=0; x1) capt++; @@ -7353,7 +7360,8 @@ void ReportClick(char *action, int x, int y) char buf[MSG_SIZ]; // Inform engine of what user does int r, f; if(action[0] == 'l') // mark any target square of a lifted piece as legal to-square, clear markers - for(r=0; r= BOARD_LEFT && fromX < BOARD_RGHT && (x != killX || y != killY) && !sweepSelecting) { if(dragging) DragPieceEnd(xPix, yPix), dragging = 0; DisplayMessage(_("only marked squares are legal"),""); DrawPosition(TRUE, NULL); @@ -8727,7 +8736,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if( count & 1 ) { score = -score; /* Flip score for winning side */ } -printf("score=%d count=%d\n",score,count); + if( score > appData.adjudicateLossThreshold ) { break; } @@ -8869,7 +8878,6 @@ printf("score=%d count=%d\n",score,count); s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf); ASSIGN(appData.pieceToCharTable, buf); } - if(startedFromSetupPosition) return; dummy = sscanf(message+s, "%dx%d+%d_%s", &w, &h, &hand, varName); if(dummy >= 3) { while(message[s] && message[s++] != ' '); @@ -8879,13 +8887,36 @@ printf("score=%d count=%d\n",score,count); if(dummy == 4) gameInfo.variant = StringToVariant(varName); // parent variant InitPosition(1); // calls InitDrawingSizes to let new parameters take effect if(*buf) SetCharTable(pieceToChar, buf); // do again, for it was spoiled by InitPosition + startedFromSetupPosition = FALSE; } } + if(startedFromSetupPosition) return; ParseFEN(boards[0], &dummy, message+s, FALSE); DrawPosition(TRUE, boards[0]); + CopyBoard(initialPosition, boards[0]); startedFromSetupPosition = TRUE; return; } + if(sscanf(message, "piece %s %s", buf2, buf1) == 2) { + ChessSquare piece = WhitePawn; + char *p=buf2; + if(*p == '+') piece = CHUPROMOTED WhitePawn, p++; + piece += CharToPiece(*p) - WhitePawn; + if(cps != &first || appData.testLegality && *engineVariant == NULLCHAR + /* always accept definition of */ && piece != WhiteFalcon && piece != BlackFalcon + /* wild-card pieces. */ && piece != WhiteCobra && piece != BlackCobra + /* For variants we don't have */ && gameInfo.variant != VariantBerolina + /* correct rules for, we cannot */ && gameInfo.variant != VariantCylinder + /* enforce legality on our own! */ && gameInfo.variant != VariantUnknown + && gameInfo.variant != VariantGreat + && gameInfo.variant != VariantFairy ) return; + if(piece < EmptySquare) { + pieceDefs = TRUE; + ASSIGN(pieceDesc[piece], buf1); + if(isupper(*p) && p[1] == '&') { ASSIGN(pieceDesc[WHITE_TO_BLACK piece], buf1); } + } + return; + } /* [HGM] Allow engine to set up a position. Don't ask me why one would * want this, I was asked to put it in, and obliged. */ @@ -9858,7 +9889,7 @@ ParseGameHistory (char *game) void ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) { - ChessSquare captured = board[toY][toX], piece, king; int p, oldEP = EP_NONE, berolina = 0; + ChessSquare captured = board[toY][toX], piece, king; int p, rookX, oldEP = EP_NONE, berolina = 0; int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess ? 3 : 1; /* [HGM] compute & store e.p. status and castling rights for new position */ @@ -9867,6 +9898,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) if(gameInfo.variant == VariantBerolina) berolina = EP_BEROLIN_A; oldEP = (signed char)board[EP_STATUS]; board[EP_STATUS] = EP_NONE; + board[EP_FILE] = board[EP_RANK] = 100; if (fromY == DROP_RANK) { /* must be first */ @@ -9900,7 +9932,8 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) if( board[fromY][fromX] == WhitePawn ) { if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers board[EP_STATUS] = EP_PAWN_MOVE; - if( toY-fromY==2) { + if( toY-fromY>=2) { + board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = toY - 1 | 128*(toY - fromY > 2); if(toX>BOARD_LEFT && board[toY][toX-1] == BlackPawn && gameInfo.variant != VariantBerolina || toX < fromX) board[EP_STATUS] = toX | berolina; @@ -9912,7 +9945,8 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) if( board[fromY][fromX] == BlackPawn ) { if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers board[EP_STATUS] = EP_PAWN_MOVE; - if( toY-fromY== -2) { + if( toY-fromY<= -2) { + board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = toY + 1 | 128*(fromY - toY > 2); if(toX>BOARD_LEFT && board[toY][toX-1] == WhitePawn && gameInfo.variant != VariantBerolina || toX < fromX) board[EP_STATUS] = toX | berolina; @@ -9922,6 +9956,11 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) } } + if(fromY == 0) board[TOUCHED_W] |= 1< fromX) != (piece == WhiteRook)) { @@ -9955,6 +9995,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) } } else if (board[fromY][fromX] == BlackKing && board[toY][toX] == BlackRook || board[fromY][fromX] == BlackRook && board[toY][toX] == BlackKing) { + board[EP_STATUS] = EP_NONE; board[fromY][fromX] = EmptySquare; board[toY][toX] = EmptySquare; if((toX > fromX) != (piece == BlackRook)) { @@ -9969,15 +10010,17 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) && toY == fromY && toX > fromX+1) { board[fromY][fromX] = EmptySquare; board[toY][toX] = king; - board[toY][toX-1] = board[fromY][BOARD_RGHT-1]; - board[fromY][BOARD_RGHT-1] = EmptySquare; + for(rookX=BOARD_RGHT-1; board[toY][rookX] == DarkSquare && rookX > toX + 1; rookX--); + board[toY][toX-1] = board[fromY][rookX]; + board[fromY][rookX] = EmptySquare; } else if (board[fromY][fromX] == king && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1 // [HGM] cylinder */ && toY == fromY && toX < fromX-1) { board[fromY][fromX] = EmptySquare; board[toY][toX] = king; - board[toY][toX+1] = board[fromY][BOARD_LEFT]; - board[fromY][BOARD_LEFT] = EmptySquare; + for(rookX=BOARD_LEFT; board[toY][rookX] == DarkSquare && rookX < toX - 1; rookX++); + board[toY][toX+1] = board[fromY][rookX]; + board[fromY][rookX] = EmptySquare; } else if ((board[fromY][fromX] == WhitePawn && gameInfo.variant != VariantXiangqi || board[fromY][fromX] == WhiteLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu) && toY >= BOARD_HEIGHT-promoRank && promoChar // defaulting to Q is done elsewhere @@ -9988,7 +10031,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]); board[fromY][fromX] = EmptySquare; } else if ((fromY >= BOARD_HEIGHT>>1) - && (oldEP == toX || oldEP == EP_UNKNOWN || appData.testLegality) + && (oldEP == toX || oldEP == EP_UNKNOWN || appData.testLegality || abs(toX - fromX) > 4) && (toX != fromX) && gameInfo.variant != VariantXiangqi && gameInfo.variant != VariantBerolina @@ -9996,8 +10039,10 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) && (board[toY][toX] == EmptySquare)) { board[fromY][fromX] = EmptySquare; board[toY][toX] = WhitePawn; - captured = board[toY - 1][toX]; - board[toY - 1][toX] = EmptySquare; + if(toY == board[EP_RANK] - 128 + 1) + captured = board[toY - 2][toX], board[toY - 2][toX] = EmptySquare; + else + captured = board[toY - 1][toX], board[toY - 1][toX] = EmptySquare; } else if ((fromY == BOARD_HEIGHT-4) && (toX == fromX) && gameInfo.variant == VariantBerolina @@ -10016,15 +10061,17 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) && toY == fromY && toX > fromX+1) { board[fromY][fromX] = EmptySquare; board[toY][toX] = king; - board[toY][toX-1] = board[fromY][BOARD_RGHT-1]; - board[fromY][BOARD_RGHT-1] = EmptySquare; + for(rookX=BOARD_RGHT-1; board[toY][rookX] == DarkSquare && rookX > toX + 1; rookX--); + board[toY][toX-1] = board[fromY][rookX]; + board[fromY][rookX] = EmptySquare; } else if (board[fromY][fromX] == king && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1 // [HGM] cylinder */ && toY == fromY && toX < fromX-1) { board[fromY][fromX] = EmptySquare; board[toY][toX] = king; - board[toY][toX+1] = board[fromY][BOARD_LEFT]; - board[fromY][BOARD_LEFT] = EmptySquare; + for(rookX=BOARD_LEFT; board[toY][rookX] == DarkSquare && rookX < toX - 1; rookX++); + board[toY][toX+1] = board[fromY][rookX]; + board[fromY][rookX] = EmptySquare; } else if (fromY == 7 && fromX == 3 && board[fromY][fromX] == BlackKing && toY == 7 && toX == 5) { @@ -10049,7 +10096,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]); board[fromY][fromX] = EmptySquare; } else if ((fromY < BOARD_HEIGHT>>1) - && (oldEP == toX || oldEP == EP_UNKNOWN || appData.testLegality) + && (oldEP == toX || oldEP == EP_UNKNOWN || appData.testLegality || abs(toX - fromX) > 4) && (toX != fromX) && gameInfo.variant != VariantXiangqi && gameInfo.variant != VariantBerolina @@ -10057,8 +10104,10 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) && (board[toY][toX] == EmptySquare)) { board[fromY][fromX] = EmptySquare; board[toY][toX] = BlackPawn; - captured = board[toY + 1][toX]; - board[toY + 1][toX] = EmptySquare; + if(toY == board[EP_RANK] - 128 - 1) + captured = board[toY + 2][toX], board[toY + 2][toX] = EmptySquare; + else + captured = board[toY + 1][toX], board[toY + 1][toX] = EmptySquare; } else if ((fromY == 3) && (toX == fromX) && gameInfo.variant == VariantBerolina @@ -10118,8 +10167,8 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) p = (int) captured; if (p >= (int) BlackPawn) { p -= (int)BlackPawn; - if(gameInfo.variant == VariantShogi && DEMOTED p >= 0) { - /* in Shogi restore piece to its original first */ + if(DEMOTED p >= 0 && PieceToChar(p) == '+') { + /* Restore shogi-promoted piece to its original first */ captured = (ChessSquare) (DEMOTED captured); p = DEMOTED p; } @@ -10129,7 +10178,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) board[p][BOARD_WIDTH-1] = BLACK_TO_WHITE captured; } else { p -= (int)WhitePawn; - if(gameInfo.variant == VariantShogi && DEMOTED p >= 0) { + if(DEMOTED p >= 0 && PieceToChar(p) == '+') { captured = (ChessSquare) (DEMOTED captured); p = DEMOTED p; } @@ -10457,7 +10506,19 @@ InitChessProgram (ChessProgramState *cps, int setup) b = SupportedVariant(cps->variants, gameInfo.variant, gameInfo.boardWidth, gameInfo.boardHeight, gameInfo.holdingsSize, cps->protocolVersion, cps->tidy); if (b == NULL) { - DisplayFatalError(variantError, 0, 1); + VariantClass v; + char c, *q = cps->variants, *p = strchr(q, ','); + if(p) *p = NULLCHAR; + v = StringToVariant(q); + DisplayError(variantError, 0); + if(v != VariantUnknown && cps == &first) { + int w, h, s; + if(sscanf(q, "%dx%d+%d_%c", &w, &h, &s, &c) == 4) // get size overrides the engine needs with it (if any) + appData.NrFiles = w, appData.NrRanks = h, appData.holdingsSize = s, q = strchr(q, '_') + 1; + ASSIGN(appData.variant, q); + Reset(TRUE, FALSE); + } + if(p) *p = ','; return; } @@ -11607,6 +11668,8 @@ Reset (int redraw, int init) fprintf(debugFP, "Reset(%d, %d) from gameMode %d\n", redraw, init, gameMode); } + pieceDefs = FALSE; // [HGM] gen: reset engine-defined piece moves + for(i=0; i=BOARD_LEFT; i--) + if(boards[move][VIRGIN][i] & VIRGIN_W) *p++ = i + AAA + 'A' - 'a'; + } else { /* [HGM] write directly from rights */ if(boards[move][CASTLING][2] != NoRights && boards[move][CASTLING][0] != NoRights ) @@ -17775,12 +17859,18 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts) if(boards[move][CASTLING][2] != NoRights && boards[move][CASTLING][1] != NoRights ) *p++ = boards[move][CASTLING][1] + AAA + 'A' - 'a'; + } + if(handB) { + for(i=BOARD_RGHT-1; i>=BOARD_LEFT; i--) + if(boards[move][VIRGIN][i] & VIRGIN_B) *p++ = i + AAA; + } else { 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 */ @@ -17790,9 +17880,8 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts) boards[move][CASTLING][2] != NoRights ) k = 1, *p++ = 'K'; q = (boards[move][CASTLING][1] == BOARD_LEFT && boards[move][CASTLING][2] != NoRights ); - if(gameInfo.variant == VariantSChess) { // for S-Chess, indicate all vrgin backrank pieces - for(i=j=0; i=BOARD_LEFT+q && j; i--) + if(handW) { // for S-Chess with pieces in hand, list virgin pieces between K and Q + for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q; i--) if((boards[move][0][i] != WhiteKing || k+q == 0) && boards[move][VIRGIN][i] & VIRGIN_W) *p++ = i + AAA + 'A' - 'a'; } @@ -17802,9 +17891,8 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts) boards[move][CASTLING][5] != NoRights ) k = 1, *p++ = 'k'; q = (boards[move][CASTLING][4] == BOARD_LEFT && boards[move][CASTLING][5] != NoRights ); - if(gameInfo.variant == VariantSChess) { - for(i=j=0; i=BOARD_LEFT+q && j; i--) + if(handB) { + for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q; i--) if((boards[move][BOARD_HEIGHT-1][i] != BlackKing || k+q == 0) && boards[move][VIRGIN][i] & VIRGIN_B) *p++ = i + AAA; }