X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=moves.c;h=a6b066b5fbdbe4bdeb488e74ff53c8a02e68a6a0;hb=v4.9.x;hp=d0fc45e9562584424420e24228063577006077e1;hpb=af3d528cf16eae800ff7f0b8b62f77ced7493412;p=xboard.git diff --git a/moves.c b/moves.c index d0fc45e..a6b066b 100644 --- a/moves.c +++ b/moves.c @@ -170,7 +170,7 @@ CopyBoard (Board to, Board from) { int i, j; - for (i = 0; i < BOARD_HEIGHT; i++) + for (i = 0; i < handSize; i++) for (j = 0; j < BOARD_WIDTH; j++) to[i][j] = from[i][j]; for (j = 0; j < BOARD_FILES; j++) // [HGM] gamestate: copy castling rights and ep status @@ -206,8 +206,8 @@ CollectPieceDescriptors () // but suppress black pieces that are the same as their white counterpart ChessSquare p; static char buf[MSG_SIZ], s[2]; - char *m, c, d, *pieceName = defaultName; - int len; + char *m, *pieceName = defaultName; + int len, c, d; *buf = NULLCHAR; if(!pieceDefs) return ""; if(gameInfo.variant == VariantChu) return ""; // for now don't do this for Chu Shogi @@ -261,6 +261,7 @@ LoadPieceDesc (char *s) ASSIGN(pieceDesc[WHITE_TO_BLACK piece], p); } pieceDefs = TRUE; + if(q) *q = ';'; } return ok; } @@ -310,7 +311,7 @@ OK (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOID } void -MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle, char *desc, MoveCallback cb, VOIDSTAR cl) +MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle, int range, char *desc, MoveCallback cb, VOIDSTAR cl) { char buf[80], *p = desc, *atom = NULL; int mine, his, dir, bit, occup, i, ep, promoRank = -1; @@ -407,10 +408,13 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle if(isdigit(*++p)) expo = atoi(p++); // read exponent if(expo > 9) p++; // allow double-digit desc = p; // this is start of next move - if(initial == 2) { if(board[r][f] != initialPosition[r-2*his+3][f]) continue; } else - if(initial && (board[r][f] != initialPosition[r][f] || + if(initial == 2) { if(board[r][f] != initialPosition[r-2*his+3][f]) continue; initial = 0; } else + if(initial && !range) { + if( (board[r][f] != initialPosition[r][f] || r == 0 && board[TOUCHED_W] & 1< 0 && dx == 0 && dy == 0) { // castling indicated by O + number mode |= 1024; dy = 1; } @@ -453,23 +457,25 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle if(board[y][x] < BlackPawn) occup = 0x101; else if(board[y][x] < EmptySquare) occup = 0x102; else occup = 4; + if(initial && expo - i + 1 != range) { if(occup == 4) continue; else break; } if(cont) { // non-final leg if(mode&16 && his&occup) occup &= 3;// suppress hopping foe in t-mode if(occup & mode) { // valid intermediate square, do continuation char origAtom = *atom; + int rg = (expo != 1 ? expo - i + 1 : range); // pass length of last *slider* leg if(!(bit & all)) *atom = rotate[*atom - 'A']; // orth-diag interconversion to make direction valid if(occup & mode & 0x104) // no side effects, merge legs to one move - MovesFromString(board, flags, f, r, x, y, dir, cont, cb, cl); + MovesFromString(board, flags, f, r, x, y, dir, rg, cont, cb, cl); if(occup & mode & 3 && (killX < 0 || kill2X < 0 && (legNr > 1 || killX == x && killY == y) || (legNr == 1 ? kill2X == x && kill2Y == y : killX == x && killY == y))) { // destructive first leg int cnt = 0; legNr <<= 1; - MovesFromString(board, flags, f, r, x, y, dir, cont, &OK, &cnt); // count possible continuations + MovesFromString(board, flags, f, r, x, y, dir, rg, cont, &OK, &cnt); // count possible continuations legNr >>= 1; - if(cnt) { // and if there are + if(cnt) { // and if there are if(legNr & 1 ? killX < 0 : kill2X < 0) cb(board, flags, FirstLeg, r, f, y, x, cl); // then generate their first leg legNr <<= 1; - MovesFromString(board, flags, f, r, x, y, dir, cont, cb, cl); + MovesFromString(board, flags, f, r, x, y, dir, rg, cont, cb, cl); legNr >>= 1; } } @@ -613,12 +619,12 @@ Bishop (Board board, int flags, int rf, int ff, MoveCallback callback, VOIDSTAR void Sting (Board board, int flags, int rf, int ff, int dy, int dx, MoveCallback callback, VOIDSTAR closure) -{ // Lion-like move of Horned Falcon and Souring Eagle +{ // Lion-like move of Horned Falcon and Soaring Eagle int ft = ff + dx, rt = rf + dy; if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) return; legNr += 2; if (!SameColor(board[rf][ff], board[rt][ft])) - callback(board, flags, board[rt][ft] != EmptySquare ? FirstLeg : NormalMove, rf, ff, rt, ft, closure); + callback(board, flags, killX < 0 && board[rt][ft] != EmptySquare ? FirstLeg : NormalMove, rf, ff, rt, ft, closure); legNr -= 2; ft += dx; rt += dy; if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) return; @@ -751,7 +757,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, piece = (ChessSquare) ( DEMOTED(piece) ); if(filter != EmptySquare && piece != filter) continue; if(pieceDefs && pieceDesc[piece]) { // [HGM] gen: use engine-defined moves - MovesFromString(board, flags, ff, rf, -1, -1, 0, pieceDesc[piece], callback, closure); + MovesFromString(board, flags, ff, rf, -1, -1, 0, 0, pieceDesc[piece], callback, closure); continue; } if(IS_SHOGI(gameInfo.variant)) @@ -803,9 +809,10 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, rf, ff, rf + 1, ff + s, closure); } if (rf >= BOARD_HEIGHT+1>>1) {// [HGM] grand: 4th & 5th rank on 10-board + int victimFile = (board[LAST_TO] & 0x40 ? ff + s : board[LAST_TO] & 255); if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && - (epfile == ff + s || epfile == EP_UNKNOWN) && rf < BOARD_HEIGHT-3 && - board[rf][ff + s] == BlackPawn && + (board[EP_FILE] == ff + s || epfile == EP_UNKNOWN) && rf < BOARD_HEIGHT-3 && + (board[rf][victimFile] == BlackPawn || board[rf][victimFile] == BlackLance) && board[rf+1][ff + s] == EmptySquare) { callback(board, flags, WhiteCapturesEnPassant, rf, ff, rf+1, ff + s, closure); @@ -853,9 +860,10 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, rf, ff, rf - 1, ff + s, closure); } if (rf < BOARD_HEIGHT>>1) { + int victimFile = (board[LAST_TO] & 0x40 ? ff + s : board[LAST_TO] & 255); if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && - (epfile == ff + s || epfile == EP_UNKNOWN) && rf > 2 && - board[rf][ff + s] == WhitePawn && + (board[EP_FILE] == ff + s || epfile == EP_UNKNOWN) && rf > 2 && + (board[rf][victimFile] == WhitePawn || board[rf][victimFile] == WhiteLance) && board[rf-1][ff + s] == EmptySquare) { callback(board, flags, BlackCapturesEnPassant, rf, ff, rf-1, ff + s, closure); @@ -928,11 +936,14 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, if(gameInfo.variant == VariantShogi) goto WhiteGold; case SHOGI (PROMO BlackPawn): if(gameInfo.variant == VariantShogi) goto BlackGold; + case SHOGI WhiteAxe: + case SHOGI BlackAxe: SlideVertical(board, flags, rf, ff, callback, closure); break; case SHOGI (PROMO WhiteKnight): if(gameInfo.variant == VariantShogi) goto WhiteGold; + case SHOGI WhiteClaw: case SHOGI BlackDrunk: case SHOGI BlackAlfil: Ferz(board, flags, rf, ff, callback, closure); @@ -942,6 +953,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, case SHOGI (PROMO BlackKnight): if(gameInfo.variant == VariantShogi) goto BlackGold; + case SHOGI BlackClaw: case SHOGI WhiteDrunk: case SHOGI WhiteAlfil: Ferz(board, flags, rf, ff, callback, closure); @@ -976,6 +988,14 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, case WhiteWazir: case BlackWazir: + if(gameInfo.variant == VariantXiangqi) { + int palace = (piece == WhiteWazir ? 1 : BOARD_HEIGHT-2); // Palace center + if(ff <= BOARD_WIDTH/2 && !SameColor(board[rf][ff+1], piece)) callback(board, flags, NormalMove, rf, ff, rf, ff+1, closure); + if(ff >= BOARD_WIDTH/2 && !SameColor(board[rf][ff-1], piece)) callback(board, flags, NormalMove, rf, ff, rf, ff-1, closure); + if(rf >= palace && !SameColor(board[rf-1][ff], piece)) callback(board, flags, NormalMove, rf, ff, rf-1, ff, closure); + if(rf <= palace && !SameColor(board[rf+1][ff], piece)) callback(board, flags, NormalMove, rf, ff, rf+1, ff, closure); + break; + } Wazir(board, flags, rf, ff, callback, closure); break; @@ -1095,19 +1115,16 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, /* Make Dragon-King Dababba & Rook-like outside Shogi, for better disambiguation in variant Fairy */ case WhiteDragon: case BlackDragon: - if(gameInfo.variant == VariantChuChess) goto DragonKing; + if(gameInfo.variant == VariantChuChess || gameInfo.variant == VariantSpartan) goto DragonKing; for (d = 0; d <= 1; d++) // Dababba moves that Rook cannot do for (s = -2; s <= 2; s += 4) { rt = rf + s * d; ft = ff + s * (1 - d); if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue; - if (board[rf+rt>>1][ff+ft>>1] == EmptySquare && gameInfo.variant != VariantSpartan) continue; + if (board[rf+rt>>1][ff+ft>>1] == EmptySquare) continue; if (SameColor(board[rf][ff], board[rt][ft])) continue; callback(board, flags, NormalMove, rf, ff, rt, ft, closure); } - if(gameInfo.variant == VariantSpartan) // in Spartan Chess restrict range to modern Dababba - Wazir(board, flags, rf, ff, callback, closure); - else Rook(board, flags, rf, ff, callback, closure); break; @@ -1132,6 +1149,19 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, Knight(board, flags, rf, ff, callback, closure); break; + case WhiteTower: + case BlackTower: + for (d = 0; d <= 1; d++) // Dababba moves + for (s = -2; s <= 2; s += 4) { + rt = rf + s * d; + ft = ff + s * (1 - d); + if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue; + if (SameColor(board[rf][ff], board[rt][ft])) continue; + callback(board, flags, NormalMove, rf, ff, rt, ft, closure); + } + Wazir(board, flags, rf, ff, callback, closure); + break; + /* Shogi Rooks are ordinary Rooks */ case SHOGI WhiteRook: case SHOGI BlackRook: @@ -1173,6 +1203,12 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, case WhiteFerz: case BlackFerz: + if(gameInfo.variant == VariantXiangqi && ff != BOARD_WIDTH>>1) { + int rt = (piece == BlackFerz ? BOARD_HEIGHT-2 : 1); + int ft = BOARD_WIDTH>>1; + if(!SameColor(board[rf][ff], board[rt][ft])) + callback(board, flags, NormalMove, rf, ff, rt, ft, closure); + } else /* [HGM] support Shatranj pieces */ Ferz(board, flags, rf, ff, callback, closure); break; @@ -1258,14 +1294,14 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue; if (!(ff == ft && rf == rt) && SameColor(board[rf][ff], board[rt][ft])) continue; i = (killX >= 0 && (rt-killY)*(rt-killY) + (killX-ft)*(killX-ft) < 3); legNr += 2*i; - callback(board, flags, (rt-rf)*(rt-rf) + (ff-ft)*(ff-ft) < 3 && board[rt][ft] != EmptySquare ? FirstLeg : NormalMove, + callback(board, flags, (rt-rf)*(rt-rf) + (ff-ft)*(ff-ft) < 3 && board[rt][ft] != EmptySquare && !i ? FirstLeg : NormalMove, rf, ff, rt, ft, closure); legNr -= 2*i; } break; - case SHOGI WhiteFalcon: - case SHOGI BlackFalcon: + case SHOGI WhiteDagger: + case SHOGI BlackDagger: case SHOGI WhitePDagger: case SHOGI BlackPDagger: SlideSideways(board, flags, rf, ff, callback, closure); @@ -1281,24 +1317,26 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, if(gameInfo.variant == VariantShogi) goto WhiteGold; case SHOGI (PROMO BlackFerz): if(gameInfo.variant == VariantShogi) goto BlackGold; + case SHOGI WhiteSword: + case SHOGI BlackSword: case SHOGI WhitePSword: case SHOGI BlackPSword: SlideVertical(board, flags, rf, ff, callback, closure); StepSideways(board, flags, rf, ff, callback, closure); break; - case SHOGI WhiteUnicorn: - case SHOGI BlackUnicorn: + case SHOGI WhiteCat: + case SHOGI BlackCat: Ferz(board, flags, rf, ff, callback, closure); StepVertical(board, flags, rf, ff, callback, closure); break; - case SHOGI WhiteMan: + case SHOGI WhiteCopper: StepDiagForward(board, flags, rf, ff, callback, closure); StepVertical(board, flags, rf, ff, callback, closure); break; - case SHOGI BlackMan: + case SHOGI BlackCopper: StepDiagBackward(board, flags, rf, ff, callback, closure); StepVertical(board, flags, rf, ff, callback, closure); break; @@ -1315,7 +1353,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, SlideVertical(board, flags, rf, ff, callback, closure); break; - case SHOGI WhiteCat: + case SHOGI WhiteUnicorn: Sting(board, flags, rf, ff, 1, 0, callback, closure); callback(board, flags, NormalMove, rf, ff, rf, ff, closure); if(killX >= 0) break; @@ -1324,7 +1362,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, SlideBackward(board, flags, rf, ff, callback, closure); break; - case SHOGI BlackCat: + case SHOGI BlackUnicorn: Sting(board, flags, rf, ff, -1, 0, callback, closure); callback(board, flags, NormalMove, rf, ff, rf, ff, closure); if(killX >= 0) break; @@ -1333,7 +1371,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, SlideForward(board, flags, rf, ff, callback, closure); break; - case SHOGI WhiteDagger: + case SHOGI WhiteFalcon: Sting(board, flags, rf, ff, 1, 1, callback, closure); Sting(board, flags, rf, ff, 1, -1, callback, closure); callback(board, flags, NormalMove, rf, ff, rf, ff, closure); @@ -1342,7 +1380,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, SlideDiagBackward(board, flags, rf, ff, callback, closure); break; - case SHOGI BlackDagger: + case SHOGI BlackFalcon: Sting(board, flags, rf, ff, -1, 1, callback, closure); Sting(board, flags, rf, ff, -1, -1, callback, closure); callback(board, flags, NormalMove, rf, ff, rf, ff, closure); @@ -1402,7 +1440,7 @@ GenLegalCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt if(rFilter >= 0 && rFilter != rt || fFilter >= 0 && fFilter != ft) return; // [HGM] speed: ignore moves with wrong to-square - if (board[EP_STATUS] == EP_IRON_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)) return; //[HGM] lion + if ((int)board[EP_STATUS] == EP_IRON_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)) return; //[HGM] lion if (!(flags & F_IGNORE_CHECK) ) { int check, promo = (gameInfo.variant == VariantSpartan && kind == BlackPromotion); @@ -1658,11 +1696,11 @@ CheckTestCallback (Board board, int flags, ChessMove kind, int rf, int ff, int r register CheckTestClosure *cl = (CheckTestClosure *) closure; if (rt == cl->rking && ft == cl->fking) { - if(xqCheckers[EP_STATUS] >= 2 && xqCheckers[rf][ff]) return; // checker is piece with suspended checking power + if((int)xqCheckers[EP_STATUS] >= 2 && xqCheckers[rf][ff]) return; // checker is piece with suspended checking power cl->check++; xqCheckers[rf][ff] = xqCheckers[EP_STATUS] & 1; // remember who is checking (if status == 1) } - if( board[EP_STATUS] == EP_ROYAL_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion) + if( (int)board[EP_STATUS] == EP_ROYAL_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion) && (gameInfo.variant != VariantLion || board[rf][ff] != WhiteKing && board[rf][ff] != BlackKing) ) cl->check++; // [HGM] lion: forbidden counterstrike against Lion equated to putting yourself in check } @@ -1699,6 +1737,8 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant } } + if(PieceToChar(king) == '.') return 0; // never in check if the royal piece does not participate + if (rt >= 0) { if (enPassant) { captured = board[rf][ft]; @@ -1728,10 +1768,10 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant /* For compatibility with ICS wild 9, we scan the board in the order a1, a2, a3, ... b1, b2, ..., h8 to find the first king, and we test only whether that one is in check. */ + cl.check = 0; for (cl.fking = BOARD_LEFT+0; cl.fking < BOARD_RGHT; cl.fking++) for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) { if (board[cl.rking][cl.fking] == king) { - cl.check = 0; if(gameInfo.variant == VariantXiangqi) { /* [HGM] In Xiangqi opposing Kings means check as well */ int i, dir; @@ -1766,7 +1806,7 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant board[EP_STATUS] = ep; } - return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king + return cl.fking < BOARD_RGHT ? cl.check : (gameInfo.variant == VariantAtomic)*1000; // [HGM] atomic: return 1000 if we have no king } int @@ -1786,7 +1826,7 @@ LegalDrop (Board board, int flags, ChessSquare piece, int rt, int ft) if(appData.debugMode) fprintf(debugFP, "LegalDrop: %d @ %d,%d)\n", piece, ft, rt); if(board[rt][ft] != EmptySquare) return ImpossibleMove; // must drop to empty square n = PieceToNumber(piece); - if((gameInfo.holdingsWidth == 0 || (flags & F_WHITE_ON_MOVE ? board[n][BOARD_WIDTH-1] : board[BOARD_HEIGHT-1-n][0]) != piece) + if((gameInfo.holdingsWidth == 0 || (flags & F_WHITE_ON_MOVE ? board[n][BOARD_WIDTH-1] : board[handSize-1-n][0]) != piece) && gameInfo.variant != VariantBughouse) // in bughouse we don't check for availability, because ICS doesn't always tell us return ImpossibleMove; // piece not available if(gameInfo.variant == VariantShogi) { // in Shogi lots of drops are forbidden! @@ -2041,7 +2081,7 @@ DisambiguateCallback (Board board, int flags, ChessMove kind, int rf, int ff, in // [HGM] wild: for wild-card pieces rt and rf are dummies if(piece == WhiteFalcon || piece == BlackFalcon || piece == WhiteCobra || piece == BlackCobra) - wildCard = TRUE; + wildCard = !pieceDefs; // no wildcards when engine defined pieces if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff] || PieceToChar(board[rf][ff]) == '~' @@ -2052,7 +2092,7 @@ DisambiguateCallback (Board board, int flags, ChessMove kind, int rf, int ff, in (cl->rtIn == -1 || cl->rtIn == rt || wildCard) && (cl->ftIn == -1 || cl->ftIn == ft || wildCard)) { - if(cl->count && rf == cl->rf && ff == cl->ff) return; // duplicate move + if(cl->count && rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft) return; // duplicate move if(cl->count == 1 && kifu & 0x7E && cl->rfIn == -1 && cl->ffIn == -1) { // traditional Shogi disambiguation required int this = 1, other = 1; @@ -2125,8 +2165,13 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure) return; } } - } else if(pieceDefs && closure->count > 1) { // [HGM] gen: move is ambiguous under engine-defined rules + } else if(pieceDefs && closure->count > 1 && closure->rtIn >=0) { // [HGM] gen: move is ambiguous under engine-defined rules (and not one-click) DisambiguateClosure spare = *closure; + if(gameInfo.variant == VariantXiangqi && closure->pieceIn == EmptySquare && closure->ffIn < 0) { + closure->ffIn = closure->ftIn; //closure->pieceIn = (flags & 1 ? BlackPawn : WhitePawn); // forward Pawn push has priority + Disambiguate(board, flags, closure); + return; + } pieceDefs = FALSE; spare.count = 0; // See if the (erroneous) built-in rules would resolve that GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) &spare, closure->pieceIn); if(spare.count == 1) *closure = spare; // It does, so use those in stead (game from file saved before gen patch?) @@ -2356,9 +2401,9 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p ((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) || (ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) { if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2) - snprintf(out, MOVE_LEN, "O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar)); + snprintf(out, MOVE_LEN, "O-O%c%c%c", promoChar ? '/' : 0, ToUpper(promoChar), ff + AAA); else - snprintf(out, MOVE_LEN, "O-O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar)); + snprintf(out, MOVE_LEN, "O-O-O%c%c%c", promoChar ? '/' : 0, ToUpper(promoChar), ff + AAA); /* This notation is always unambiguous, unless there are kings on both the d and e files, with "wild castling" @@ -2433,8 +2478,15 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p *outp++ = ToUpper(promoChar); } else if (gameInfo.variant == VariantSChess && promoChar) { // and in S-Chess we have gating + ChessSquare victim = board[rt][ft]; + if(piece == WhiteRook && victim == WhiteKing || + piece == BlackRook && victim == BlackKing) { + strncpy(out, "O-O-O", MOVE_LEN); + outp = out + 3 + 2*(ft > ff); + } *outp++ = '/'; *outp++ = ToUpper(promoChar); + if(out[0] == 'O') *outp++ = ff + AAA; } *outp = NULLCHAR; return cl.kind;