From: H.G. Muller Date: Mon, 21 Oct 2013 17:54:22 +0000 (+0200) Subject: Allow piece promotion by pieceToChar in all variants X-Git-Url: http://winboard.nl/cgi-bin?p=xboard.git;a=commitdiff_plain;h=81a640a52b1e72cc1d26d9d85a6644ffb933b06c Allow piece promotion by pieceToChar in all variants If the pieceToCharTable specifies a piece has a promoted version, by defining the latter as '+', this will now trigger the promotion procedure when such a piece moves to touch the zone. Legality testing will consider such moves legal. The promotion character will be a '+', in SAN generated as an '=+' suffix (to not confuse with check), while deferral will have no suffix. Pieces without specified promoted version do not promote, unless they are Pawns. These then offer choice between all pieces, as usual. --- diff --git a/backend.c b/backend.c index a9abaa8..14967d6 100644 --- a/backend.c +++ b/backend.c @@ -5313,13 +5313,15 @@ void Sweep (int step) { ChessSquare king = WhiteKing, pawn = WhitePawn, last = promoSweep; + static int toggleFlag; if(gameInfo.variant == VariantKnightmate) king = WhiteUnicorn; if(gameInfo.variant == VariantSuicide || gameInfo.variant == VariantGiveaway) king = EmptySquare; if(promoSweep >= BlackPawn) king = WHITE_TO_BLACK king, pawn = WHITE_TO_BLACK pawn; if(gameInfo.variant == VariantSpartan && pawn == BlackPawn) pawn = BlackLance, king = EmptySquare; if(fromY != BOARD_HEIGHT-2 && fromY != 1) pawn = EmptySquare; + if(!step) toggleFlag = Partner(&last); // piece has shogi-promotion do { - if(step && !Partner(&promoSweep)) promoSweep -= step; + if(step && !(toggleFlag && Partner(&promoSweep))) promoSweep -= step; if(promoSweep == EmptySquare) promoSweep = BlackPawn; // wrap else if((int)promoSweep == -1) promoSweep = WhiteKing; else if(promoSweep == BlackPawn && step < 0) promoSweep = WhitePawn; @@ -6457,7 +6459,7 @@ HasPromotionChoice (int fromX, int fromY, int toX, int toY, char *promoChoice, i /* [HGM] rewritten IsPromotion to only flag promotions that offer a choice */ /* [HGM] add Shogi promotions */ int promotionZoneSize=1, highestPromotingPiece = (int)WhitePawn; - ChessSquare piece; + ChessSquare piece, partner; ChessMove moveType; Boolean premove; @@ -6542,8 +6544,9 @@ HasPromotionChoice (int fromX, int fromY, int toX, int toY, char *promoChoice, i } // give caller the default choice even if we will not make it *promoChoice = ToLower(PieceToChar(defaultPromoChoice)); - if(IS_SHOGI(gameInfo.variant)) *promoChoice = (defaultPromoChoice == piece ? '=' : '+'); - if(gameInfo.variant == VariantChuChess) *promoChoice = (piece == WhitePawn || piece == BlackPawn ? 'q' : '+'); + partner = piece; // pieces can promote if the pieceToCharTable says so + if(IS_SHOGI(gameInfo.variant)) *promoChoice = (defaultPromoChoice == piece && sweepSelect ? '=' : '+'); // obsolete? + else if(Partner(&partner)) *promoChoice = (defaultPromoChoice == piece && sweepSelect ? NULLCHAR : '+'); if( sweepSelect && gameInfo.variant != VariantGreat && gameInfo.variant != VariantGrand && gameInfo.variant != VariantSuper) return FALSE; @@ -7209,14 +7212,15 @@ ChessSquare gatingPiece = EmptySquare; // exported to front-end, for dragging int CanPromote (ChessSquare piece, int y) { + int zone = (gameInfo.variant == VariantChuChess ? 3 : 1); if(gameMode == EditPosition) return FALSE; // no promotions when editing position // some variants have fixed promotion piece, no promotion at all, or another selection mechanism if(IS_SHOGI(gameInfo.variant) || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat || gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN) return FALSE; - return (piece == BlackPawn && y == 1 || - piece == WhitePawn && y == BOARD_HEIGHT-2 || + return (piece == BlackPawn && y <= zone || + piece == WhitePawn && y >= BOARD_HEIGHT-1-zone || piece == BlackLance && y == 1 || piece == WhiteLance && y == BOARD_HEIGHT-2 ); } @@ -7506,6 +7510,7 @@ LeftClick (ClickType clickType, int xPix, int yPix) if(appData.sweepSelect) { ChessSquare piece = boards[currentMove][fromY][fromX]; promoSweep = defaultPromoChoice; + if(gameInfo.variant == VariantChuChess && piece != WhitePawn && piece != BlackPawn) promoSweep = piece; else if(PieceToChar(CHUPROMOTED piece) == '+') promoSweep = CHUPROMOTED piece; selectFlag = 0; lastX = xPix; lastY = yPix; Sweep(0); // Pawn that is going to promote: preview promotion piece @@ -7522,7 +7527,7 @@ LeftClick (ClickType clickType, int xPix, int yPix) ClearHighlights(); } } else if(sweepSelecting) { // this must be the up-click corresponding to the down-click that started the sweep - sweepSelecting = 0; + sweepSelecting = 0; appData.animate = FALSE; // do not animate, a selected piece already on to-square if (appData.animate || appData.highlightLastMove) { SetHighlights(fromX, fromY, toX, toY); } else { @@ -7604,7 +7609,7 @@ LeftClick (ClickType clickType, int xPix, int yPix) DisplayMessage("Click in holdings to choose piece", ""); return; } - PromotionPopUp(); + PromotionPopUp(promoChoice); } else { int oldMove = currentMove; UserMoveEvent(fromX, fromY, toX, toY, promoChoice); diff --git a/dialogs.c b/dialogs.c index d1777df..1bc08a7 100644 --- a/dialogs.c +++ b/dialogs.c @@ -1600,6 +1600,7 @@ PromoPick (int n) ClearHighlights(); return; } + if(promoChar == '=' && !IS_SHOGI(gameInfo.variant)) promoChar = NULLCHAR; UserMoveEvent(fromX, fromY, toX, toY, promoChar); if (!appData.highlightLastMove || gotPremove) ClearHighlights(); @@ -1616,11 +1617,11 @@ SetPromo (char *name, int nr, char promoChar) } void -PromotionPopUp () +PromotionPopUp (char choice) { // choice depends on variant: prepare dialog acordingly count = 8; - SetPromo(_("Cancel"), --count, 0); // Beware: GenericPopUp cannot handle user buttons named "cancel" (lowe case)! - if(!IS_SHOGI(gameInfo.variant)) { + SetPromo(_("Cancel"), --count, -1); // Beware: GenericPopUp cannot handle user buttons named "cancel" (lowe case)! + if(choice != '+') { if (!appData.testLegality || gameInfo.variant == VariantSuicide || gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) || gameInfo.variant == VariantGiveaway) { diff --git a/frontend.h b/frontend.h index e4b8684..d16fde6 100644 --- a/frontend.h +++ b/frontend.h @@ -129,7 +129,7 @@ DelayedEventCallback GetDelayedEvent P((void)); void CancelDelayedEvent P((void)); // [HGM] mouse: next six used by mouse handler, which was moved to backend extern int fromX, fromY, toX, toY; -void PromotionPopUp P((void)); +void PromotionPopUp P((char choice)); void DragPieceBegin P((int x, int y, Boolean instantly)); void DragPieceEnd P((int x, int y)); void DragPieceMove P((int x, int y)); diff --git a/moves.c b/moves.c index bf5ee28..fba01a7 100644 --- a/moves.c +++ b/moves.c @@ -1984,7 +1984,8 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p /* [HGM] in Shogi non-pawns can promote */ *outp++ = promoChar; // Don't bother to correct move type, return value is never used! } - else if (gameInfo.variant != VariantSuper && promoChar && + else if (gameInfo.variant == VariantChuChess && promoChar || + gameInfo.variant != VariantSuper && promoChar && (piece == WhiteLance || piece == BlackLance) ) { // Lance sometimes represents Pawn *outp++ = '='; *outp++ = ToUpper(promoChar); diff --git a/parser.c b/parser.c index bd1a38a..08dc513 100644 --- a/parser.c +++ b/parser.c @@ -155,7 +155,7 @@ PromoSuffix (char **p) if(**p == '=' || (gameInfo.variant == VariantSChess) && **p == '/') (*p)++; // optional = (or / for Seirawan gating) if(**p == '(' && (*p)[2] == ')' && isalpha( (*p)[1] )) { (*p) += 3; return ToLower((*p)[-2]); } if(isalpha(**p) && **p != 'x') return ToLower(*(*p)++); // reserve 'x' for multi-leg captures? - if(*p != start) return '='; // must be the optional = + if(*p != start) return **p == '+' ? *(*p)++ : '='; // must be the optional = (or =+) return NULLCHAR; // no suffix detected } @@ -285,12 +285,15 @@ NextUnit (char **p) toY = cl.rtIn = (currentMoveString[3] = Number(p) + '0') - ONE; } if(type[0] != NOTHING && type[1] != NOTHING && type[3] != NOTHING) { // fully specified. + ChessSquare realPiece = boards[yyboardindex][fromY][fromX]; // Note that Disambiguate does not work for illegal moves, but flags them as impossible if(piece) { // check if correct piece indicated - ChessSquare realPiece = boards[yyboardindex][fromY][fromX]; if(PieceToChar(realPiece) == '~') realPiece = (ChessSquare) (DEMOTED realPiece); if(!(appData.icsActive && PieceToChar(realPiece) == '+') && // trust ICS if it moves promoted pieces piece && realPiece != cl.pieceIn) return ImpossibleMove; + } else if(!separator && **p == '+') { // could be a protocol move, where bare '+' suffix means shogi-style promotion + if(realPiece < (wom ? WhiteCannon : BlackCannon) && PieceToChar(PROMOTED realPiece) == '+') // seems to be that + currentMoveString[4] = cl.promoCharIn = *(*p)++; // append promochar after all } result = LegalityTest(boards[yyboardindex], PosFlags(yyboardindex), fromY, fromX, toY, toX, cl.promoCharIn); if (currentMoveString[4] == NULLCHAR) { // suppy missing mandatory promotion character diff --git a/winboard/winboard.c b/winboard/winboard.c index 1539f42..bf98cc0 100644 --- a/winboard/winboard.c +++ b/winboard/winboard.c @@ -4445,6 +4445,8 @@ ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam); } +static int promoStyle; + /* Process messages for Promotion dialog box */ LRESULT CALLBACK Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) @@ -4475,13 +4477,9 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) PieceToChar(BlackMarshall) != '~') ) ? SW_SHOW : SW_HIDE); /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */ - ShowWindow(GetDlgItem(hDlg, PB_Rook), - gameInfo.variant != VariantShogi ? - SW_SHOW : SW_HIDE); - ShowWindow(GetDlgItem(hDlg, PB_Bishop), - gameInfo.variant != VariantShogi ? - SW_SHOW : SW_HIDE); - if(gameInfo.variant == VariantShogi) { + ShowWindow(GetDlgItem(hDlg, PB_Rook), !style ? SW_SHOW : SW_HIDE); + ShowWindow(GetDlgItem(hDlg, PB_Bishop), !style ? SW_SHOW : SW_HIDE); + if(style) { SetDlgItemText(hDlg, PB_Queen, "YES"); SetDlgItemText(hDlg, PB_Knight, "NO"); SetWindowText(hDlg, "Promote?"); @@ -4502,7 +4500,7 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing); break; case PB_Queen: - promoChar = gameInfo.variant == VariantShogi ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen)); + promoChar = style ? '+' : ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen)); break; case PB_Rook: promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteRook : BlackRook)); @@ -4519,7 +4517,8 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) promoChar = ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteAngel : BlackAngel)); break; case PB_Knight: - promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight); + promoChar = gameInfo.variant == VariantShogi ? '=' : style ? NULLCHAR : + ToLower(PieceToChar(WhiteOnMove(currentMove) ? WhiteKnight : BlackKnight)); break; default: return FALSE; @@ -4550,8 +4549,9 @@ PromotionPopup(HWND hwnd) } void -PromotionPopUp() +PromotionPopUp(char choice) { + promoStyle = (choice == '+'); DrawPosition(TRUE, NULL); PromotionPopup(hwndMain); } @@ -6847,6 +6847,7 @@ GothicPopUp(char *title, VariantClass variant) static char *history[HISTORY_SIZE]; int histIn = 0, histP = 0; + VOID SaveInHistory(char *cmd) {