X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=moves.c;h=867a94061a9c5938caf23f815bcd61096bb8ca5d;hb=ebd7f78161504e46896f7d96bb41e29714b2fd53;hp=e0ad2e1dbfafe35ecccb1a92e8f2328670e6588a;hpb=0278ebc80411a20fd23303156285e55ce8d2b0a5;p=xboard.git diff --git a/moves.c b/moves.c index e0ad2e1..867a940 100644 --- a/moves.c +++ b/moves.c @@ -72,7 +72,6 @@ int BlackPiece P((ChessSquare)); int SameColor P((ChessSquare, ChessSquare)); int PosFlags(int index); -extern signed char initialRights[BOARD_FILES]; /* [HGM] all rights enabled, set in InitPosition */ int quickFlag; char *pieceDesc[EmptySquare]; char *defaultDesc[EmptySquare] = { @@ -122,12 +121,13 @@ unsigned char pieceToChar[EmptySquare+1] = { 'o', 'h', 'i', 'j', 'g', 'd', 'v', 'l', 's', 'u', 'k', 'x' }; unsigned char pieceNickName[EmptySquare]; +int promoPartner[EmptySquare]; char PieceToChar (ChessSquare p) { int c; - if((int)p < 0 || (int)p >= (int)EmptySquare) return('x'); /* [HGM] for safety */ + if((int)p < 0 || (int)p >= (int)EmptySquare) return('?'); /* [HGM] for safety */ c = pieceToChar[(int) p]; if(c & 128) c = c & 63 | 64; return c; @@ -205,7 +205,7 @@ CollectPieceDescriptors () // dump all engine defined pieces, and pieces with non-standard names, // but suppress black pieces that are the same as their white counterpart ChessSquare p; - static char buf[MSG_SIZ]; + static char buf[MSG_SIZ], s[2]; char *m, c, d, *pieceName = defaultName; int len; *buf = NULLCHAR; @@ -215,22 +215,56 @@ CollectPieceDescriptors () if(gameInfo.variant == VariantXiangqi) pieceName = xqName; for(p=WhitePawn; p= BlackPawn && pieceToChar[BLACK_TO_WHITE p] == toupper(c) - && (c != '+' || pieceToChar[DEMOTED BLACK_TO_WHITE p] == d)) { // black member of normal pair + m = pieceDesc[p]; d = (c == '+' ? pieceToChar[DEMOTED(p)] : c); + if(p >= BlackPawn && pieceToChar[BLACK_TO_WHITE p] == (c & ~32) + && (c != '+' || pieceToChar[DEMOTED(BLACK_TO_WHITE p)] == d)) {// black member of normal pair char *wm = pieceDesc[BLACK_TO_WHITE p]; if(!m && !wm || m && wm && !strcmp(wm, m)) continue; // moves as a white piece } else // white or unpaired black - if((p < BlackPawn || CharToPiece(toupper(d)) != EmptySquare) && // white or lone black + if((p < BlackPawn || CharToPiece(d & ~32) != EmptySquare) && // white or lone black !pieceDesc[p] /*&& pieceName[p] == c*/) continue; // orthodox piece known by its usual name // TODO: listing pieces because of unusual name can only be done if we have accurate Betza of all defaults if(!m) m = defaultDesc[p]; + if(!m) continue; len = strlen(buf); - snprintf(buf+len, MSG_SIZ-len, "%s%s%c:%s", len ? ";" : "", c == '+' ? "+" : "", d, m); + *s = (d > 128 ? SUFFIXES[d-128>>6] : 0); d = 64 + (d & 63); + snprintf(buf+len, MSG_SIZ-len, "%s%s%c%s:%s", len ? ";" : "", c == '+' ? "+" : "", d, s, m); } return buf; } +int +LoadPieceDesc (char *s) +{ + ChessSquare piece; + static char suf[] = SUFFIXES; + char *r, *p, *q = s; + int ok = TRUE, promoted, c; + while(q && *s) { + p = s; + q = strchr(s, ';'); + if(q) *q = 0, s = q+1; + if(*p == '+') promoted = 1, p++; else promoted = 0; + c = *p++; + if(!c) { ok = FALSE; continue; } // bad syntax + if(*p && (r = strchr(suf, *p))) c += 64*(r - suf + 1), p++; + if(*p++ != ':') { ok = FALSE; continue; } // bad syntax + if(!strcmp(p, "(null)")) continue; // handle bug in writing of XBoard 4.8.0 + piece = CharToPiece(c); + if(piece >= EmptySquare) { ok = FALSE; continue; } // non-existent piece + if(promoted) { + piece = promoPartner[piece]; + if(pieceToChar[piece] != '+') { ok = FALSE; continue; } // promoted form does not exist + } + ASSIGN(pieceDesc[piece], p); + if(piece < BlackPawn && (pieceToChar[WHITE_TO_BLACK piece] == pieceToChar[piece] + 32 || promoted)) { + ASSIGN(pieceDesc[WHITE_TO_BLACK piece], p); + } + pieceDefs = TRUE; + } + return ok; +} + // [HGM] gen: configurable move generation from Betza notation sent by engine. // Some notes about two-leg moves: GenPseudoLegal() works in two modes, depending on whether a 'kill- // square has been set: without one is generates all moves, and a global int legNr flags in bits 0 and 1 @@ -286,9 +320,9 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle if(pc == WhitePawn || pc == WhiteLance) promo = WhitePromotion, promoRank = BOARD_HEIGHT-1; else if(pc == BlackPawn || pc == BlackLance) promo = BlackPromotion, promoRank = 0; while(*p) { // more moves to go - int expo = 1, dx, dy, x, y, mode, dirSet, ds2=0, retry=0, initial=0, jump=1, skip = 0, all = 0; + int expo = -1, dx, dy, x, y, mode, dirSet, ds2=0, retry=0, initial=0, jump=1, skip = 0, all = 0; char *cont = NULL; - if(*p == 'i') initial = 1, desc = ++p; + while(*p == 'i') initial++, desc = ++p; while(islower(*p)) p++; // skip prefixes if(!isupper(*p)) return; // syntax error: no atom dx = xStep[*p-'A'] - '0';// step vector of atom @@ -373,12 +407,14 @@ 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] || r == 0 && board[TOUCHED_W] & 1< 1 && dx == 0 && dy == 0) { // castling indicated by O + number + if(expo > 0 && dx == 0 && dy == 0) { // castling indicated by O + number mode |= 1024; dy = 1; } + if(expo < 0) expo = 1; // use 1 for default if(!cont) { if(!(mode & 15)) mode |= his + 4; // no mode spec, use default = mc } else { @@ -409,8 +445,8 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle if(y < 0 || y >= BOARD_HEIGHT) break; // vertically off-board: always done if(x < BOARD_LEFT) { if(mode & 128) x += BOARD_RGHT - BOARD_LEFT, loop++; else break; } if(x >= BOARD_RGHT) { if(mode & 128) x -= BOARD_RGHT - BOARD_LEFT, loop++; else break; } - if(board[y][x] == DarkSquare) break; // black squares are supposed to be off board if(j) { j--; continue; } // skip irrespective of occupation + if(board[y][x] == DarkSquare) break; // black squares are supposed to be off board if(!jump && board[y - vy + vy/2][x - vx + vx/2] != EmptySquare) break; // blocked if(jump > 1 && board[y - vy + vy/2][x - vx + vx/2] == EmptySquare) break; // no hop if(x == f && y == r && !loop) occup = 4; else // start square counts as empty (if not around cylinder!) @@ -449,7 +485,7 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle if(occup == 4) continue; // skip empty squares if((x == BOARD_LEFT + skip || x > BOARD_LEFT + skip && vx < 0 && board[y][x-1-skip] == DarkSquare) && board[y][x] == initialPosition[y][x]) { // reached initial corner piece - if(pc != WhiteKing && pc != BlackKing) { // non-royal castling (to be entered as two-leg move via 'Rook') + if(pc != WhiteKing && pc != BlackKing || expo == 1) { // non-royal castling (to be entered as two-leg move via 'Rook') if(killX < 0) cb(board, flags, FirstLeg, r, f, y, x, cl); if(killX < f) legNr <<= 1, cb(board, flags, NormalMove, r, f, y, f - expo, cl), legNr >>= 1; } else @@ -457,7 +493,7 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle } if((x == BOARD_RGHT-1-skip || x < BOARD_RGHT-1-skip && vx > 0 && board[y][x+1+skip] == DarkSquare) && board[y][x] == initialPosition[y][x]) { - if(pc != WhiteKing && pc != BlackKing) { + if(pc != WhiteKing && pc != BlackKing || expo == 1) { if(killX < 0) cb(board, flags, FirstLeg, r, f, y, x, cl); if(killX > f) legNr <<= 1, cb(board, flags, NormalMove, r, f, y, f + expo, cl), legNr >>= 1; } else @@ -709,7 +745,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, if ((flags & F_WHITE_ON_MOVE) != (board[rf][ff] < BlackPawn)) continue; // [HGM] speed: wrong color m = 0; piece = board[rf][ff]; if(PieceToChar(piece) == '~') - piece = (ChessSquare) ( DEMOTED piece ); + 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); @@ -885,14 +921,14 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, /* Gold General (and all its promoted versions) . First do the */ /* diagonal forward steps, then proceed as normal Wazir */ - case SHOGI (PROMOTED WhitePawn): + case SHOGI (PROMO WhitePawn): if(gameInfo.variant == VariantShogi) goto WhiteGold; - case SHOGI (PROMOTED BlackPawn): + case SHOGI (PROMO BlackPawn): if(gameInfo.variant == VariantShogi) goto BlackGold; SlideVertical(board, flags, rf, ff, callback, closure); break; - case SHOGI (PROMOTED WhiteKnight): + case SHOGI (PROMO WhiteKnight): if(gameInfo.variant == VariantShogi) goto WhiteGold; case SHOGI BlackDrunk: case SHOGI BlackAlfil: @@ -901,7 +937,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, StepBackward(board, flags, rf, ff, callback, closure); break; - case SHOGI (PROMOTED BlackKnight): + case SHOGI (PROMO BlackKnight): if(gameInfo.variant == VariantShogi) goto BlackGold; case SHOGI WhiteDrunk: case SHOGI WhiteAlfil: @@ -911,15 +947,15 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, break; - case SHOGI WhiteStag: - case SHOGI BlackStag: + case SHOGI WhiteGnu: + case SHOGI BlackGnu: if(gameInfo.variant == VariantShogi) goto BlackGold; SlideVertical(board, flags, rf, ff, callback, closure); Ferz(board, flags, rf, ff, callback, closure); StepSideways(board, flags, rf, ff, callback, closure); break; - case SHOGI (PROMOTED WhiteQueen): + case SHOGI (PROMO WhiteQueen): case SHOGI WhiteTokin: case SHOGI WhiteWazir: WhiteGold: @@ -927,7 +963,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, Wazir(board, flags, rf, ff, callback, closure); break; - case SHOGI (PROMOTED BlackQueen): + case SHOGI (PROMO BlackQueen): case SHOGI BlackTokin: case SHOGI BlackWazir: BlackGold: @@ -1238,9 +1274,9 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, StepVertical(board, flags, rf, ff, callback, closure); break; - case SHOGI (PROMOTED WhiteFerz): + case SHOGI (PROMO WhiteFerz): if(gameInfo.variant == VariantShogi) goto WhiteGold; - case SHOGI (PROMOTED BlackFerz): + case SHOGI (PROMO BlackFerz): if(gameInfo.variant == VariantShogi) goto BlackGold; case SHOGI WhitePSword: case SHOGI BlackPSword: @@ -1276,7 +1312,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, SlideVertical(board, flags, rf, ff, callback, closure); break; - case SHOGI WhiteHorned: + case SHOGI WhiteCat: Sting(board, flags, rf, ff, 1, 0, callback, closure); callback(board, flags, NormalMove, rf, ff, rf, ff, closure); if(killX >= 0) break; @@ -1285,7 +1321,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, SlideBackward(board, flags, rf, ff, callback, closure); break; - case SHOGI BlackHorned: + case SHOGI BlackCat: Sting(board, flags, rf, ff, -1, 0, callback, closure); callback(board, flags, NormalMove, rf, ff, rf, ff, closure); if(killX >= 0) break; @@ -1294,7 +1330,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, SlideForward(board, flags, rf, ff, callback, closure); break; - case SHOGI WhiteEagle: + case SHOGI WhiteDagger: 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); @@ -1303,7 +1339,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, SlideDiagBackward(board, flags, rf, ff, callback, closure); break; - case SHOGI BlackEagle: + case SHOGI BlackDagger: 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); @@ -1674,10 +1710,11 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant } ep = board[EP_STATUS]; if( captured == WhiteLion || captured == BlackLion ) { // [HGM] lion: Chu Lion-capture rules - ChessSquare victim = killX < 0 ? EmptySquare : trampled; + ChessSquare victim = saveKill < 0 ? EmptySquare : trampled; if( (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion) && // capturer is Lion (ff - ft > 1 || ft - ff > 1 || rf - rt > 1 || rt - rf > 1) && // captures from a distance - (victim == EmptySquare || victim == WhitePawn || victim == BlackPawn) ) // no or worthless 'bridge' + (victim == EmptySquare || victim == WhitePawn || victim == BlackPawn // no or worthless 'bridge' + || victim == WhiteCobra || victim == BlackCobra) ) // (Pawn or Go Between) board[EP_STATUS] = EP_ROYAL_LION; // on distant Lion x Lion victim must not be pseudo-legally protected } } @@ -1790,7 +1827,7 @@ LegalityTest (Board board, int flags, int rf, int ff, int rt, int ft, int promoC if(quickFlag) flags = flags & ~1 | quickFlag & 1; // [HGM] speed: in quick mode quickFlag specifies side-to-move. if(rf == DROP_RANK) return LegalDrop(board, flags, ff, rt, ft); piece = filterPiece = board[rf][ff]; - if(PieceToChar(piece) == '~') filterPiece = DEMOTED piece; + if(PieceToChar(piece) == '~') filterPiece = DEMOTED(piece); /* [HGM] Cobra and Falcon are wildcard pieces; consider all their moves legal */ /* (perhaps we should disallow moves that obviously leave us in check?) */ @@ -1830,7 +1867,7 @@ LegalityTest (Board board, int flags, int rf, int ff, int rt, int ft, int promoC if(cl.kind != NormalMove || promoChar == NULLCHAR || promoChar == '=') return cl.kind; if(promoChar != '+') return CharToPiece(promoChar) == EmptySquare ? ImpossibleMove : IllegalMove; - if(PieceToChar(CHUPROMOTED board[rf][ff]) != '+') { + if(PieceToChar(CHUPROMOTED(board[rf][ff])) != '+') { if(PieceToChar(CHUPROMOTED (board[rf][ff] < BlackPawn ? WhitePawn : BlackPawn)) != '.') return ImpossibleMove; } @@ -1877,7 +1914,7 @@ if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promo // should test if in zone, really if(gameInfo.variant == VariantChuChess && (piece == WhiteKnight || piece == BlackKnight) && HasLion(board, flags)) return IllegalMove; - if(PieceToChar(PROMOTED piece) == '+') return flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion; + if(PieceToChar(PROMOTED(piece)) == '+') return flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion; } else if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi if (cl.kind == WhitePromotion || cl.kind == BlackPromotion) { @@ -1999,7 +2036,7 @@ DisambiguateCallback (Board board, int flags, ChessMove kind, int rf, int ff, in if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff] || PieceToChar(board[rf][ff]) == '~' - && cl->pieceIn == (ChessSquare)(DEMOTED board[rf][ff]) + && cl->pieceIn == (ChessSquare)(DEMOTED(board[rf][ff])) ) && (cl->rfIn == -1 || cl->rfIn == rf) && (cl->ffIn == -1 || cl->ffIn == ff) && @@ -2155,7 +2192,7 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure) else if(c == 'l' && gameInfo.variant == VariantChuChess && HasLion(board, flags)) closure->kind = IllegalMove; } else if (c == '+') { // '+' outside shogi, check if pieceToCharTable enabled it ChessSquare p = closure->piece; - if(p > WhiteMan && p < BlackPawn || p > BlackMan || PieceToChar(PROMOTED p) != '+') + if(p > WhiteMan && p < BlackPawn || p > BlackMan || PieceToChar(PROMOTED(p)) != '+') closure->kind = ImpossibleMove; // used on non-promotable piece else if(gameInfo.variant == VariantChuChess && HasLion(board, flags)) closure->kind = IllegalMove; } else if (c != NULLCHAR) closure->kind = IllegalMove; @@ -2200,7 +2237,7 @@ CoordsToAlgebraicCallback (Board board, int flags, ChessMove kind, int rf, int f if ((rt == cl->rt && ft == cl->ft || rt == rf && ft == ff) && // [HGM] null move matches any toSquare (board[rf][ff] == cl->piece || PieceToChar(board[rf][ff]) == '~' && - (ChessSquare) (DEMOTED board[rf][ff]) == cl->piece) + (ChessSquare) (DEMOTED(board[rf][ff])) == cl->piece) ) { if (rf == cl->rf) { if (ff == cl->ff) { @@ -2244,7 +2281,7 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p if (promoChar == 'x') promoChar = NULLCHAR; piece = board[rf][ff]; - if(PieceToChar(piece)=='~') piece = (ChessSquare)(DEMOTED piece); + if(PieceToChar(piece)=='~') piece = (ChessSquare)(DEMOTED(piece)); switch (piece) { case WhitePawn: @@ -2336,13 +2373,13 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p cl.kind = IllegalMove; cl.rank = cl.file = cl.either = 0; c = PieceToChar(piece) ; - GenLegal(board, flags, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED piece)); // [HGM] speed + GenLegal(board, flags, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED(piece))); // [HGM] speed 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, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED piece)); + GenLegal(board, flags|F_IGNORE_CHECK, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED(piece))); if (cl.kind == IllegalMove) break; cl.kind = IllegalMove; } @@ -2354,7 +2391,7 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p */ if( c == '~' || c == '+') { /* [HGM] print nonexistent piece as its demoted version */ - piece = (ChessSquare) (DEMOTED piece - 11*(gameInfo.variant == VariantChu)); + piece = (ChessSquare) (CHUDEMOTED(piece)); } if(c=='+') *outp++ = c; *outp++ = ToUpper(PieceToChar(piece)); @@ -2412,7 +2449,10 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p int r, f; for(r=0; r