X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=1de9cb765e7b282f6bfe61cdda06f338581287c3;hb=37c976246d65ccb8ed013af03dac284b4a431cff;hp=ea13ca81e96c01156feeb68ebc1f5a87479c5ec8;hpb=1f84be6944ee48b72a33cf064661fa1a2129b885;p=xboard.git diff --git a/backend.c b/backend.c index ea13ca8..1de9cb7 100644 --- a/backend.c +++ b/backend.c @@ -4377,7 +4377,7 @@ ParseBoard12(string) strcat(parseList[moveNum - 1], " "); strcat(parseList[moveNum - 1], elapsed_time); /* currentMoveString is set as a side-effect of ParseOneMove */ - if(gameInfo.variant == VariantShogi && currentMoveString[4]) currentMoveString[4] = '+'; + if(gameInfo.variant == VariantShogi && currentMoveString[4]) currentMoveString[4] = '^'; safeStrCpy(moveList[moveNum - 1], currentMoveString, sizeof(moveList[moveNum - 1])/sizeof(moveList[moveNum - 1][0])); strcat(moveList[moveNum - 1], "\n"); @@ -4884,9 +4884,6 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar) int *fromX, *fromY, *toX, *toY; char *promoChar; { - if (appData.debugMode) { - fprintf(debugFP, "move to parse: %s\n", move); - } *moveType = yylexstr(moveNum, move, yy_textstr, sizeof yy_textstr); switch (*moveType) { @@ -5598,7 +5595,8 @@ SendBoard(cps, moveNum) /* Kludge to set black to move, avoiding the troublesome and now * deprecated "black" command. */ - if (!WhiteOnMove(moveNum)) SendToProgram("a2a3\n", cps); + if (!WhiteOnMove(moveNum)) // [HGM] but better a deprecated command than an illegal move... + SendToProgram(boards[0][1][BOARD_LEFT] == WhitePawn ? "a2a3\n" : "black\n", cps); SendToProgram("edit\n", cps); SendToProgram("#\n", cps); @@ -5721,6 +5719,11 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice) *promoChoice = PieceToChar(BlackFerz); // no choice return FALSE; } + // no sense asking what we must promote to if it is going to explode... + if(gameInfo.variant == VariantAtomic && boards[currentMove][toY][toX] != EmptySquare) { + *promoChoice = PieceToChar(BlackQueen); // Queen as good as any + return FALSE; + } if(autoQueen) { // predetermined if(gameInfo.variant == VariantSuicide || gameInfo.variant == VariantLosers) *promoChoice = PieceToChar(BlackKing); // in Suicide Q is the last thing we want @@ -5733,7 +5736,7 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice) gameMode == IcsPlayingBlack && WhiteOnMove(currentMove); if(appData.testLegality && !premove) { moveType = LegalityTest(boards[currentMove], PosFlags(currentMove), - fromY, fromX, toY, toX, NULLCHAR); + fromY, fromX, toY, toX, gameInfo.variant == VariantShogi ? '+' : NULLCHAR); if(moveType != WhitePromotion && moveType != BlackPromotion) return FALSE; } @@ -5875,6 +5878,8 @@ OnlyMove(int *x, int *y, Boolean captures) { case IcsPlayingBlack: if(WhiteOnMove(currentMove)) return FALSE; break; + case EditGame: + break; default: return FALSE; } @@ -6312,6 +6317,20 @@ MarkTargetSquares(int clear) DrawPosition(TRUE, NULL); } +int +Explode(Board board, int fromX, int fromY, int toX, int toY) +{ + if(gameInfo.variant == VariantAtomic && + (board[toY][toX] != EmptySquare || // capture? + toX != fromX && (board[fromY][fromX] == WhitePawn || // e.p. ? + board[fromY][fromX] == BlackPawn ) + )) { + AnimateAtomicCapture(board, fromX, fromY, toX, toY); + return TRUE; + } + return FALSE; +} + void LeftClick(ClickType clickType, int xPix, int yPix) { int x, y; @@ -6522,9 +6541,13 @@ void LeftClick(ClickType clickType, int xPix, int yPix) } PromotionPopUp(); } else { + int oldMove = currentMove; UserMoveEvent(fromX, fromY, toX, toY, promoChoice); if (!appData.highlightLastMove || gotPremove) ClearHighlights(); if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY); + if(saveAnimate && !appData.animate && currentMove != oldMove && // drag-move was performed + Explode(boards[currentMove-1], fromX, fromY, toX, toY)) + DrawPosition(TRUE, boards[currentMove]); fromX = fromY = -1; } appData.animate = saveAnimate; @@ -7434,6 +7457,15 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. return; // [HGM] This return was missing, causing option features to be recognized as non-compliant commands! } + if (!appData.testLegality && !strncmp(message, "setup ", 6)) { // [HGM] allow first engine to define opening position + int dummy, s=6; char buf[MSG_SIZ]; + if(appData.icsActive || forwardMostMove != 0 || cps != &first || startedFromSetupPosition) return; + if(sscanf(message, "setup (%s", buf) == 1) s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf); + ParseFEN(boards[0], &dummy, message+s); + DrawPosition(TRUE, boards[0]); + startedFromSetupPosition = TRUE; + return; + } /* [HGM] Allow engine to set up a position. Don't ask me why one would * want this, I was asked to put it in, and obliged. */ @@ -8190,7 +8222,7 @@ ParseGameHistory(game) yynewstr(game); for (;;) { yyboardindex = boardIndex; - moveType = (ChessMove) yylex(); + moveType = (ChessMove) Myylex(); switch (moveType) { case IllegalMove: /* maybe suicide chess, etc. */ if (appData.debugMode) { @@ -8356,10 +8388,6 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) if( board[toY][toX] != EmptySquare ) board[EP_STATUS] = EP_CAPTURE; - /* [HGM] In Shatranj and Courier all promotions are to Ferz */ - if((gameInfo.variant==VariantShatranj || gameInfo.variant==VariantCourier || gameInfo.variant == VariantMakruk) - && promoChar != 0) promoChar = PieceToChar(WhiteFerz); - if (fromY == DROP_RANK) { /* must be first */ piece = board[toY][toX] = (ChessSquare) fromX; @@ -8622,8 +8650,8 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) if(promoChar == '+') { /* [HGM] Shogi-style promotions, to piece implied by original (Might overwrite orinary Pawn promotion) */ board[toY][toX] = (ChessSquare) (PROMOTED piece); - } else if(!appData.testLegality) { // without legality testing, unconditionally believe promoChar - board[toY][toX] = CharToPiece(promoChar); + } else if(!appData.testLegality && promoChar != NULLCHAR && promoChar != '=') { // without legality testing, unconditionally believe promoChar + board[toY][toX] = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar)); } if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) && promoChar != NULLCHAR && gameInfo.holdingsSize) { @@ -9643,7 +9671,7 @@ LoadGameOneMove(readAhead) } else { if (gameFileFP == NULL) return FALSE; - moveType = (ChessMove) yylex(); + moveType = (ChessMove) Myylex(); } done = FALSE; @@ -10138,7 +10166,7 @@ LoadGame(f, gameNumber, title, useList) cm = lastLoadGameStart = EndOfFile; while (gn > 0) { yyboardindex = forwardMostMove; - cm = (ChessMove) yylex(); + cm = (ChessMove) Myylex(); switch (cm) { case EndOfFile: if (cmailMsgLoaded) { @@ -10191,7 +10219,7 @@ LoadGame(f, gameNumber, title, useList) if (gn > 0) { do { yyboardindex = forwardMostMove; - cm = (ChessMove) yylex(); + cm = (ChessMove) Myylex(); } while (cm == PGNTag || cm == Comment); } break; @@ -10230,7 +10258,7 @@ LoadGame(f, gameNumber, title, useList) /* Skip any header junk before position diagram and/or move 1 */ for (;;) { yyboardindex = forwardMostMove; - cm = (ChessMove) yylex(); + cm = (ChessMove) Myylex(); if (cm == EndOfFile || cm == GNUChessGame || cm == XBoardGame) { @@ -10303,7 +10331,7 @@ LoadGame(f, gameNumber, title, useList) } yyboardindex = forwardMostMove; - cm = (ChessMove) yylex(); + cm = (ChessMove) Myylex(); /* Handle comments interspersed among the tags */ while (cm == Comment) { @@ -10313,7 +10341,7 @@ LoadGame(f, gameNumber, title, useList) p = yy_text; AppendComment(currentMove, p, FALSE); yyboardindex = forwardMostMove; - cm = (ChessMove) yylex(); + cm = (ChessMove) Myylex(); } } @@ -10390,7 +10418,7 @@ LoadGame(f, gameNumber, title, useList) } } yyboardindex = forwardMostMove; - cm = (ChessMove) yylex(); + cm = (ChessMove) Myylex(); } if (first.pr == NoProc) { @@ -10416,7 +10444,7 @@ LoadGame(f, gameNumber, title, useList) p = yy_text; AppendComment(currentMove, p, FALSE); yyboardindex = forwardMostMove; - cm = (ChessMove) yylex(); + cm = (ChessMove) Myylex(); } if ((cm == EndOfFile && lastLoadGameStart != EndOfFile ) || @@ -11825,6 +11853,37 @@ DisplayTwoMachinesTitle() } void +SettingsMenuIfReady() +{ + if (second.lastPing != second.lastPong) { + DisplayMessage("", _("Waiting for second chess program")); + ScheduleDelayedEvent(SettingsMenuIfReady, 10); // [HGM] fast: lowered from 1000 + return; + } + ThawUI(); + DisplayMessage("", ""); + SettingsPopUp(&second); +} + +int +WaitForSecond(DelayedEventCallback retry) +{ + if (second.pr == NULL) { + StartChessProgram(&second); + if (second.protocolVersion == 1) { + retry(); + } else { + /* kludge: allow timeout for initial "feature" command */ + FreezeUI(); + DisplayMessage("", _("Starting second chess program")); + ScheduleDelayedEvent(retry, FEATURE_TIMEOUT); + } + return 1; + } + return 0; +} + +void TwoMachinesEvent P((void)) { int i; @@ -11866,21 +11925,14 @@ TwoMachinesEvent P((void)) TruncateGame(); // [HGM] vari: MachineWhite and MachineBlack do this... ResurrectChessProgram(); /* in case first program isn't running */ - if (second.pr == NULL) { - StartChessProgram(&second); - if (second.protocolVersion == 1) { - TwoMachinesEventIfReady(); - } else { - /* kludge: allow timeout for initial "feature" command */ - FreezeUI(); - DisplayMessage("", _("Starting second chess program")); - ScheduleDelayedEvent(TwoMachinesEventIfReady, FEATURE_TIMEOUT); - } - return; - } + if(WaitForSecond(TwoMachinesEventIfReady)) return; DisplayMessage("", ""); InitChessProgram(&second, FALSE); SendToProgram("force\n", &second); + if(first.lastPing != first.lastPong) { // [HGM] wait till we are sure first engine has set up position + ScheduleDelayedEvent(TwoMachinesEvent, 10); + return; + } if (startedFromSetupPosition) { SendBoard(&second, backwardMostMove); if (appData.debugMode) { @@ -13306,7 +13358,7 @@ if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces); } else { commentList[index] = (char *) malloc(len + 6); // perhaps wastes 4... if(addBraces) - safeStrCpy(commentList[index], "{\n", sizeof(commentList[index])/sizeof(commentList[index][0])); + safeStrCpy(commentList[index], "{\n", 3); else commentList[index][0] = NULLCHAR; strcat(commentList[index], text); strcat(commentList[index], "\n"); @@ -13785,6 +13837,20 @@ ParseOption(Option *opt, ChessProgramState *cps) if(p && (p == cps->optionSettings || p[-1] == ',')) { snprintf(buf, MSG_SIZ, "option %s", p); if(p = strstr(buf, ",")) *p = 0; + if(q = strchr(buf, '=')) switch(opt->type) { + case ComboBox: + for(n=0; nmax; n++) + if(!strcmp(((char**)opt->textValue)[n], q+1)) opt->value = n; + break; + case TextBox: + safeStrCpy(opt->textValue, q+1, MSG_SIZ - (opt->textValue - opt->name)); + break; + case Spin: + case CheckBox: + opt->value = atoi(q+1); + default: + break; + } strcat(buf, "\n"); SendToProgram(buf, cps); } @@ -13798,6 +13864,7 @@ FeatureDone(cps, val) { DelayedEventCallback cb = GetDelayedEvent(); if ((cb == InitBackEnd3 && cps == &first) || + (cb == SettingsMenuIfReady && cps == &second) || (cb == TwoMachinesEventIfReady && cps == &second)) { CancelDelayedEvent(); ScheduleDelayedEvent(cb, val ? 1 : 3600000);