X-Git-Url: http://winboard.nl/cgi-bin?p=xboard.git;a=blobdiff_plain;f=moves.c;h=a53ca599486d494e29b6ae5de7d1dacf0e32189d;hp=0b6b9b44c87376841c67cbaa6702b2f376f636f0;hb=37266870c73e9be76c84d0f097ebee25ad17ebdf;hpb=9efb2d38d555f7ca5d0666246f789979d9d4115e diff --git a/moves.c b/moves.c index 0b6b9b4..a53ca59 100644 --- a/moves.c +++ b/moves.c @@ -5,7 +5,8 @@ * Massachusetts. * * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free + * Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -126,7 +127,7 @@ 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,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 @@ -256,10 +257,11 @@ LoadPieceDesc (char *s) 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] || promoted)) { + if(piece < BlackPawn && (pieceToChar[WHITE_TO_BLACK piece] == pieceToChar[piece] + 32 || promoted)) { ASSIGN(pieceDesc[WHITE_TO_BLACK piece], p); } pieceDefs = TRUE; + if(q) *q = ';'; } return ok; } @@ -309,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; @@ -406,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; } @@ -452,20 +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); - if(occup & mode & 3 && (killX < 0 || killX == x && killY == y)) { // destructive first leg + 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; - MovesFromString(board, flags, f, r, x, y, dir, cont, &OK, &cnt); // count possible continuations - if(cnt) { // and if there are - if(killX < 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, rg, cont, &OK, &cnt); // count possible continuations + legNr >>= 1; + 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; } } @@ -609,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; @@ -747,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)) @@ -924,11 +934,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); @@ -938,6 +951,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); @@ -1169,6 +1183,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; @@ -1254,14 +1274,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); @@ -1277,24 +1297,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; @@ -1311,7 +1333,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; @@ -1320,7 +1342,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; @@ -1329,7 +1351,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); @@ -1338,7 +1360,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); @@ -1398,7 +1420,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); @@ -1654,11 +1676,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 } @@ -1676,7 +1698,7 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant { CheckTestClosure cl; ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing; - ChessSquare captured = EmptySquare, ep=0, trampled=0; + ChessSquare captured = EmptySquare, ep=0, trampled=0, trampled2 = 0; int saveKill = killX; /* Suppress warnings on uninitialized variables */ @@ -1701,7 +1723,10 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant board[rf][ft] = EmptySquare; } else { captured = board[rt][ft]; - if(killX >= 0) { trampled = board[killY][killX]; board[killY][killX] = EmptySquare; killX = -1; } + if(killX >= 0) { + trampled = board[killY][killX]; board[killY][killX] = EmptySquare; killX = -1; saveKill += (kill2X << 16) + (1 << 30); + if(kill2X >= 0) { trampled2 = board[kill2Y][kill2X]; board[kill2Y][kill2X] = EmptySquare; kill2X = -1; } + } } if(rf == DROP_RANK) board[rt][ft] = ff; else { // [HGM] drop board[rt][ft] = board[rf][ff]; @@ -1750,7 +1775,10 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant board[rf][ft] = captured; board[rt][ft] = EmptySquare; } else { - if(saveKill >= 0) board[killY][killX = saveKill] = trampled; + if(saveKill >= 0) { + if(saveKill & 1<<30) board[kill2Y][kill2X = saveKill >> 16 & 0xFFF] = trampled2; + board[killY][killX = saveKill & 0xFFF] = trampled; + } board[rt][ft] = captured; } board[EP_STATUS] = ep; @@ -2031,7 +2059,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]) == '~' @@ -2042,7 +2070,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; @@ -2115,7 +2143,7 @@ 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; pieceDefs = FALSE; spare.count = 0; // See if the (erroneous) built-in rules would resolve that GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) &spare, closure->pieceIn);