X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=moves.c;h=6ccbb1c082d295a68447ada3bb6a942d8ee051ca;hb=9141872e84a1ce7db0c62539d23c6a3f105dd8f8;hp=a0f7b7e24251245c99542cb948be08c33981700f;hpb=d098a3196db8758737f6a79992b460306045d499;p=xboard.git diff --git a/moves.c b/moves.c index a0f7b7e..6ccbb1c 100644 --- a/moves.c +++ b/moves.c @@ -418,9 +418,28 @@ void GenPseudoLegal(board, flags, callback, closure) && !SameColor(board[rf][ff], board[rt][ft])) callback(board, flags, NormalMove, rf, ff, rt, ft, closure); + if(gameInfo.variant != VariantFairy && gameInfo.variant != VariantGreat) continue; + rt = rf + rs; // in unknown variant we assume Modern Elephant, which can also do one step + ft = ff + fs; + if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) + && !SameColor(board[rf][ff], board[rt][ft])) + callback(board, flags, NormalMove, + rf, ff, rt, ft, closure); } break; + /* Make Dragon-Horse also do Dababba moves outside Shogi, for better disambiguation in variant Fairy */ + case WhiteCardinal: + case BlackCardinal: + 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 (SameColor(board[rf][ff], board[rt][ft])) continue; + callback(board, flags, NormalMove, rf, ff, rt, ft, closure); + } + /* Shogi Dragon Horse has to continue with Wazir after Bishop */ case SHOGI WhiteCardinal: case SHOGI BlackCardinal: @@ -477,6 +496,19 @@ void GenPseudoLegal(board, flags, callback, closure) } break; + /* Make Dragon-King Dababba & Rook-like outside Shogi, for better disambiguation in variant Fairy */ + case WhiteDragon: + case BlackDragon: + 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 || 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); + } + goto doRook; + /* Shogi Dragon King has to continue as Ferz after Rook moves */ case SHOGI WhiteDragon: case SHOGI BlackDragon: @@ -492,6 +524,7 @@ void GenPseudoLegal(board, flags, callback, closure) case SHOGI BlackRook: case WhiteRook: case BlackRook: + doRook: for (d = 0; d <= 1; d++) for (s = -1; s <= 1; s += 2) for (i = 1;; i++) { @@ -601,12 +634,60 @@ void GenPseudoLegal(board, flags, callback, closure) } } break; + + Amazon: + /* First do Bishop,then continue like Chancellor */ + for (rs = -1; rs <= 1; rs += 2) + for (fs = -1; fs <= 1; fs += 2) + for (i = 1;; i++) { + rt = rf + (i * rs); + ft = ff + (i * fs); + if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break; + if (SameColor(board[rf][ff], board[rt][ft])) break; + callback(board, flags, NormalMove, + rf, ff, rt, ft, closure); + if (board[rt][ft] != EmptySquare) break; + } + m++; + goto doRook; + + // Use Lance as Berolina / Spartan Pawn. + case WhiteLance: + if(gameInfo.variant == VariantSuper) goto Amazon; + if (rf < BOARD_HEIGHT-1 && BlackPiece(board[rf + 1][ff])) + callback(board, flags, + rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove, + rf, ff, rf + 1, ff, closure); + for (s = -1; s <= 1; s += 2) { + if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && board[rf + 1][ff + s] == EmptySquare) + callback(board, flags, + rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove, + rf, ff, rf + 1, ff + s, closure); + if (rf == 1 && ff + 2*s >= BOARD_LEFT && ff + 2*s < BOARD_RGHT && board[3][ff + 2*s] == EmptySquare ) + callback(board, flags, NormalMove, rf, ff, 3, ff + 2*s, closure); + } + break; + + case BlackLance: + if(gameInfo.variant == VariantSuper) goto Amazon; + if (rf > 0 && WhitePiece(board[rf - 1][ff])) + callback(board, flags, + rf <= promoRank ? BlackPromotion : NormalMove, + rf, ff, rf - 1, ff, closure); + for (s = -1; s <= 1; s += 2) { + if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && board[rf - 1][ff + s] == EmptySquare) + callback(board, flags, + rf <= promoRank ? BlackPromotion : NormalMove, + rf, ff, rf - 1, ff + s, closure); + if (rf == BOARD_HEIGHT-2 && ff + 2*s >= BOARD_LEFT && ff + 2*s < BOARD_RGHT && board[rf-2][ff + 2*s] == EmptySquare ) + callback(board, flags, NormalMove, rf, ff, rf-2, ff + 2*s, closure); + } + break; + case WhiteFalcon: // [HGM] wild: for wildcards, self-capture symbolizes move to anywhere case BlackFalcon: case WhiteCobra: case BlackCobra: - case WhiteLance: - case BlackLance: callback(board, flags, NormalMove, rf, ff, rf, ff, closure); break; @@ -676,7 +757,7 @@ int GenLegal(board, flags, callback, closure) VOIDSTAR closure; { GenLegalClosure cl; - int ff, ft, k, left, right; + int ff, ft, k, left, right, swap; int ignoreCheck = (flags & F_IGNORE_CHECK) != 0; ChessSquare wKing = WhiteKing, bKing = BlackKing, *castlingRights = board[CASTLING]; @@ -773,10 +854,11 @@ int GenLegal(board, flags, callback, closure) } } - if(flags & F_FRC_TYPE_CASTLING) { + if((swap = gameInfo.variant == VariantSChess) || flags & F_FRC_TYPE_CASTLING) { /* generate all potential FRC castling moves (KxR), ignoring flags */ /* [HGM] test if the Rooks we find have castling rights */ + /* In S-Chess we generate RxK for allowed castlings, for gating at Rook square */ if ((flags & F_WHITE_ON_MOVE) != 0) { @@ -795,7 +877,7 @@ int GenLegal(board, flags, callback, closure) for(k=left; k= BlackPawn) ) - promoChar = '^'; // allowed ICS notations + promoChar = '+'; // allowed ICS notations if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promoChar : '-'); - if(promoChar != NULLCHAR && promoChar != '^' && promoChar != '=') + if(promoChar != NULLCHAR && promoChar != '+' && promoChar != '=') return CharToPiece(promoChar) == EmptySquare ? ImpossibleMove : IllegalMove; else if(flags & F_WHITE_ON_MOVE) { if( (int) piece < (int) WhiteWazir && @@ -1048,23 +1140,24 @@ if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promo piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */ cl.kind = promoChar == '=' ? IllegalMove : WhitePromotion; else /* promotion optional, default is defer */ - cl.kind = promoChar == '^' ? WhitePromotion : WhiteNonPromotion; - } else cl.kind = promoChar == '^' ? IllegalMove : NormalMove; + cl.kind = promoChar == '+' ? WhitePromotion : WhiteNonPromotion; + } else cl.kind = promoChar == '+' ? IllegalMove : NormalMove; } else { if( (int) piece < (int) BlackWazir && (rf < BOARD_HEIGHT/3 || rt < BOARD_HEIGHT/3) ) { if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 || piece == BlackKnight && rt < 2 ) /* promotion obligatory */ cl.kind = promoChar == '=' ? IllegalMove : BlackPromotion; else /* promotion optional, default is defer */ - cl.kind = promoChar == '^' ? BlackPromotion : BlackNonPromotion; - } else cl.kind = promoChar == '^' ? IllegalMove : NormalMove; + cl.kind = promoChar == '+' ? BlackPromotion : BlackNonPromotion; + } else cl.kind = promoChar == '+' ? IllegalMove : NormalMove; } } } else if (promoChar != NULLCHAR) { if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi if (cl.kind == WhitePromotion || cl.kind == BlackPromotion) { - if(CharToPiece(promoChar) == EmptySquare) cl.kind = ImpossibleMove; // non-existing piece + if(CharToPiece(flags & F_WHITE_ON_MOVE ? ToUpper(promoChar) : ToLower(promoChar)) == EmptySquare) + cl.kind = ImpossibleMove; // non-existing piece } else { cl.kind = IllegalMove; } @@ -1166,8 +1259,7 @@ void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure) // [HGM] wild: for wild-card pieces rt and rf are dummies if(piece == WhiteFalcon || piece == BlackFalcon || - piece == WhiteCobra || piece == BlackCobra || - piece == WhiteLance || piece == BlackLance) + piece == WhiteCobra || piece == BlackCobra) wildCard = TRUE; if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff] @@ -1189,7 +1281,7 @@ void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure) cl->ft = wildCard ? cl->ftIn : ft; cl->kind = kind; } - cl->captures += (board[cl->rt][cl->ft] != EmptySquare); // [HGM] oneclick: count captures + cl->captures += (board[rt][ft] != EmptySquare); // [HGM] oneclick: count captures } } @@ -1227,15 +1319,24 @@ void Disambiguate(board, flags, closure) } if (c == 'x') c = NULLCHAR; // get rid of any 'x' (which should never happen?) + if(gameInfo.variant == VariantSChess && c && c != '=' && closure->piece != WhitePawn && closure->piece != BlackPawn) { + if(closure->piece < BlackPawn) { // white + if(closure->rf != 0) closure->kind = IllegalMove; // must be on back rank + if(board[PieceToNumber(CharToPiece(ToUpper(c)))][BOARD_WIDTH-2] == 0) closure->kind = ImpossibleMove;// must be in stock + } else { + if(closure->rf != BOARD_HEIGHT-1) closure->kind = IllegalMove; + if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(c)))][1] == 0) closure->kind = ImpossibleMove; + } + } else if(gameInfo.variant == VariantShogi) { - /* [HGM] Shogi promotions. On input, '=' means defer, '^' promote. Afterwards, c is set to '+' for promotions, NULL other */ + /* [HGM] Shogi promotions. On input, '=' means defer, '+' promote. Afterwards, c is set to '+' for promotions, NULL other */ if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) { ChessSquare piece = closure->piece; if (c == 'd' && (piece == WhiteRook || piece == BlackRook) || c == 'h' && (piece == WhiteBishop || piece == BlackBishop) || c == 'g' && (piece <= WhiteFerz || piece <= BlackFerz && piece >= BlackPawn) ) - c = '^'; // allowed ICS notations - if(c != NULLCHAR && c != '^' && c != '=') closure->kind = IllegalMove; // otherwise specifying a piece is illegal + c = '+'; // allowed ICS notations + if(c != NULLCHAR && c != '+' && c != '=') closure->kind = IllegalMove; // otherwise specifying a piece is illegal else if(flags & F_WHITE_ON_MOVE) { if( (int) piece < (int) WhiteWazir && (closure->rf >= BOARD_HEIGHT-(BOARD_HEIGHT/3) || closure->rt >= BOARD_HEIGHT-(BOARD_HEIGHT/3)) ) { @@ -1243,19 +1344,19 @@ void Disambiguate(board, flags, closure) piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */ closure->kind = c == '=' ? IllegalMove : WhitePromotion; else /* promotion optional, default is defer */ - closure->kind = c == '^' ? WhitePromotion : WhiteNonPromotion; - } else closure->kind = c == '^' ? IllegalMove : NormalMove; + closure->kind = c == '+' ? WhitePromotion : WhiteNonPromotion; + } else closure->kind = c == '+' ? IllegalMove : NormalMove; } else { if( (int) piece < (int) BlackWazir && (closure->rf < BOARD_HEIGHT/3 || closure->rt < BOARD_HEIGHT/3) ) { if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 || piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */ closure->kind = c == '=' ? IllegalMove : BlackPromotion; else /* promotion optional, default is defer */ - closure->kind = c == '^' ? BlackPromotion : BlackNonPromotion; - } else closure->kind = c == '^' ? IllegalMove : NormalMove; + closure->kind = c == '+' ? BlackPromotion : BlackNonPromotion; + } else closure->kind = c == '+' ? IllegalMove : NormalMove; } } - if(closure->kind == WhitePromotion || closure->kind == BlackPromotion) c = '^'; else + if(closure->kind == WhitePromotion || closure->kind == BlackPromotion) c = '+'; else if(closure->kind == WhiteNonPromotion || closure->kind == BlackNonPromotion) c = '='; } else if (closure->kind == WhitePromotion || closure->kind == BlackPromotion) { @@ -1270,7 +1371,7 @@ void Disambiguate(board, flags, closure) } else if (c != NULLCHAR) closure->kind = IllegalMove; closure->promoChar = ToLower(c); // this can be NULLCHAR! Note we keep original promoChar even if illegal. - if(c != '^' && c != '=' && c != NULLCHAR && CharToPiece(c) == EmptySquare) + if(c != '+' && c != '=' && c != NULLCHAR && CharToPiece(flags & F_WHITE_ON_MOVE ? ToUpper(c) : ToLower(c)) == EmptySquare) closure->kind = ImpossibleMove; // but we cannot handle non-existing piece types! if (closure->count > 1) { closure->kind = AmbiguousMove; @@ -1315,7 +1416,7 @@ void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure) register CoordsToAlgebraicClosure *cl = (CoordsToAlgebraicClosure *) closure; - if (rt == cl->rt && ft == cl->ft && + 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) @@ -1434,9 +1535,9 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out) ((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) - safeStrCpy(out, "O-O", MOVE_LEN); + snprintf(out, MOVE_LEN, "O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar)); else - safeStrCpy(out, "O-O-O", MOVE_LEN); + snprintf(out, MOVE_LEN, "O-O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar)); /* This notation is always unambiguous, unless there are kings on both the d and e files, with "wild castling" @@ -1501,19 +1602,15 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out) else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; } if (gameInfo.variant == VariantShogi) { /* [HGM] in Shogi non-pawns can promote */ - if(promoChar == '^') promoChar = '+'; *outp++ = promoChar; // Don't bother to correct move type, return value is never used! } + else if (gameInfo.variant == VariantSChess && promoChar) { // and in S-Chess we have gating + *outp++ = '/'; + *outp++ = ToUpper(promoChar); + } *outp = NULLCHAR; return cl.kind; - - /* [HGM] Always long notation for fairies we don't know */ - case WhiteFalcon: - case BlackFalcon: - case WhiteLance: - case BlackLance: - case WhiteGrasshopper: - case BlackGrasshopper: + case EmptySquare: /* Moving a nonexistent piece */ break; @@ -1528,13 +1625,19 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out) a piece of the same color. */ outp = out; + c = 0; if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) { + int r, f; + for(r=0; r