X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=07df9ce10b050c624ee1d933b6e6013841dabc00;hb=42747fc80391054f0b2c4794645a1db73984b842;hp=eed8bff3bad356e92d318fef1afda6356f51f2c4;hpb=c95ef32a700132a134f335f857ca6f1b6f3c169f;p=xboard.git diff --git a/backend.c b/backend.c index eed8bff..07df9ce 100644 --- a/backend.c +++ b/backend.c @@ -449,6 +449,7 @@ int adjudicateLossPlies = 6; char white_holding[64], black_holding[64]; TimeMark lastNodeCountTime; long lastNodeCount=0; +int shiftKey; // [HGM] set by mouse handler int have_sent_ICS_logon = 0; int sending_ICS_login = 0; @@ -1027,6 +1028,13 @@ int NextSessionFromString( char ** str, int *moves, long * tc, long *inc, int *i if(**str == '!') type = *(*str)++; // Bronstein TC if(result = NextIntegerFromString( str, &temp2)) return -1; *inc = temp2 * 1000; + if(**str == '.') { // read fraction of increment + char *start = ++(*str); + if(result = NextIntegerFromString( str, &temp2)) return -1; + temp2 *= 1000; + while(start++ < *str) temp2 /= 10; + *inc += temp2; + } } else *inc = 0; *moves = 0; *tc = temp * 1000; *incType = type; return 0; @@ -1069,14 +1077,13 @@ int GetTimeQuota(int movenr, int lastUsed, char *tcString) int ParseTimeControl(tc, ti, mps) char *tc; - int ti; + float ti; int mps; { long tc1; long tc2; char buf[MSG_SIZ], buf2[MSG_SIZ], *mytc = tc; int min, sec=0; - int len; if(ti >= 0 && !strchr(tc, '+') && !strchr(tc, '/') ) mps = 0; if(!strchr(tc, '+') && !strchr(tc, '/') && sscanf(tc, "%d:%d", &min, &sec) >= 1) @@ -1084,17 +1091,17 @@ ParseTimeControl(tc, ti, mps) if(ti > 0) { if(mps) - snprintf(buf, MSG_SIZ, ":%d/%s+%d", mps, mytc, ti); - else - snprintf(buf, MSG_SIZ, ":%s+%d", mytc, ti); + snprintf(buf, MSG_SIZ, ":%d/%s+%g", mps, mytc, ti); + else + snprintf(buf, MSG_SIZ, ":%s+%g", mytc, ti); } else { if(mps) snprintf(buf, MSG_SIZ, ":%d/%s", mps, mytc); - else + else snprintf(buf, MSG_SIZ, ":%s", mytc); } fullTimeControlString = StrSave(buf); // this should now be in PGN format - + if( NextTimeControlFromString( &tc, &tc1 ) != 0 ) { return FALSE; } @@ -3112,17 +3119,25 @@ read_from_ics(isr, closure, data, count, error) if (!have_sent_ICS_logon && looking_at(buf, &i, "login:")) { ICSInitScript(); have_sent_ICS_logon = 1; - sending_ICS_password = 0; // in case we come back to login - sending_ICS_login = 1; + /* if we don't send the login/password via icsLogon, use special readline + code for it */ + if (strlen(appData.icsLogon)==0) + { + sending_ICS_password = 0; // in case we come back to login + sending_ICS_login = 1; + }; continue; } /* need to shadow the password */ if (!sending_ICS_password && looking_at(buf, &i, "password:")) { - sending_ICS_password = 1; + /* if we don't send the login/password via icsLogon, use special readline + code for it */ + if (strlen(appData.icsLogon)==0) + sending_ICS_password = 1; continue; } - - if (ics_getting_history != H_GETTING_MOVES /*smpos kludge*/ && + + if (ics_getting_history != H_GETTING_MOVES /*smpos kludge*/ && (looking_at(buf, &i, "\n<12> ") || looking_at(buf, &i, "<12> "))) { loggedOn = TRUE; @@ -3993,7 +4008,7 @@ ParseBoard12(string) } if (gameInfo.boardHeight != ranks || gameInfo.boardWidth != files || - weird && (int)gameInfo.variant <= (int)VariantShogi) { + weird && (int)gameInfo.variant < (int)VariantShogi) { /* [HGM] We seem to have switched variant unexpectedly * Try to guess new variant from board size */ @@ -4322,6 +4337,8 @@ ParseBoard12(string) // So we parse the long-algebraic move string in stead of the SAN move int valid; char buf[MSG_SIZ], *prom; + if(gameInfo.variant == VariantShogi && !strchr(move_str, '=') && !strchr(move_str, '@')) + strcat(move_str, "="); // if ICS does not say 'promote' on non-drop, we defer. // str looks something like "Q/a1-a2"; kill the slash if(str[1] == '/') snprintf(buf, MSG_SIZ,"%c%s", str[0], str+2); @@ -4360,8 +4377,24 @@ 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] = '^'; safeStrCpy(moveList[moveNum - 1], currentMoveString, sizeof(moveList[moveNum - 1])/sizeof(moveList[moveNum - 1][0])); strcat(moveList[moveNum - 1], "\n"); + + if(gameInfo.holdingsWidth && !appData.disguise) // inherit info that ICS does not give from previous board + for(k=0; k= BlackPawn && old < BlackCannon) + boards[moveNum][k][j] = PROMOTED old; // choose correct type of Gold in promotion + else boards[moveNum][k][j] = old; // preserve type of Gold + } else if((old == WhitePawn || old == BlackPawn) && new != EmptySquare) // Pawn promotions (but not e.p.capture!) + boards[moveNum][k][j] = PROMOTED new; // use non-primordial representation of chosen piece + } } else { /* Move from ICS was illegal!? Punt. */ if (appData.debugMode) { @@ -4651,7 +4684,7 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY, promoChar) break; case WhiteNonPromotion: case BlackNonPromotion: - sprintf(user_move, "%c%c%c%c=\n", AAA + fromX, ONE + fromY, AAA + toX, ONE + toY); + sprintf(user_move, "%c%c%c%c==\n", AAA + fromX, ONE + fromY, AAA + toX, ONE + toY); break; case WhitePromotion: case BlackPromotion: @@ -4670,14 +4703,16 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY, promoChar) break; case WhiteDrop: case BlackDrop: + drop: snprintf(user_move, MSG_SIZ, "%c@%c%c\n", - ToUpper(PieceToChar((ChessSquare) fromX)), - AAA + toX, ONE + toY); + ToUpper(PieceToChar((ChessSquare) fromX)), + AAA + toX, ONE + toY); break; + case IllegalMove: /* could be a variant we don't quite understand */ + if(fromY == DROP_RANK) goto drop; // We need 'IllegalDrop' move type? case NormalMove: case WhiteCapturesEnPassant: case BlackCapturesEnPassant: - case IllegalMove: /* could be a variant we don't quite understand */ snprintf(user_move, MSG_SIZ,"%c%c%c%c\n", AAA + fromX, ONE + fromY, AAA + toX, ONE + toY); break; @@ -4849,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) { @@ -5686,6 +5718,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 @@ -5698,7 +5735,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; } @@ -5840,6 +5877,8 @@ OnlyMove(int *x, int *y, Boolean captures) { case IcsPlayingBlack: if(WhiteOnMove(currentMove)) return FALSE; break; + case EditGame: + break; default: return FALSE; } @@ -6033,15 +6072,15 @@ UserMoveEvent(fromX, fromY, toX, toY, promoChar) pup = boards[currentMove][toY][toX]; /* [HGM] If move started in holdings, it means a drop. Convert to standard form */ - if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) { + if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) { if( pup != EmptySquare ) return; moveType = WhiteOnMove(currentMove) ? WhiteDrop : BlackDrop; - if(appData.debugMode) fprintf(debugFP, "Drop move %d, curr=%d, x=%d,y=%d, p=%d\n", + if(appData.debugMode) fprintf(debugFP, "Drop move %d, curr=%d, x=%d,y=%d, p=%d\n", moveType, currentMove, fromX, fromY, boards[currentMove][fromY][fromX]); // holdings might not be sent yet in ICS play; we have to figure out which piece belongs here if(fromX == 0) fromY = BOARD_HEIGHT-1 - fromY; // black holdings upside-down fromX = fromX ? WhitePawn : BlackPawn; // first piece type in selected holdings - while(PieceToChar(fromX) == '.' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++; + while(PieceToChar(fromX) == '.' || PieceToNumber(fromX) != fromY && fromX != (int) EmptySquare) fromX++; fromY = DROP_RANK; } @@ -6126,7 +6165,8 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar) the previous line in Analysis Mode */ if ((gameMode == AnalyzeMode || gameMode == EditGame) && currentMove < forwardMostMove) { - PushTail(currentMove, forwardMostMove); // [HGM] vari: save tail of game + if(appData.variations && shiftKey) PushTail(currentMove, forwardMostMove); // [HGM] vari: save tail of game + else forwardMostMove = currentMove; } /* If we need the chess program but it's dead, restart it */ @@ -6276,6 +6316,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; @@ -6486,9 +6540,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; @@ -8320,10 +8378,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; @@ -8586,11 +8640,11 @@ 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) { + if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) + && promoChar != NULLCHAR && gameInfo.holdingsSize) { // [HGM] superchess: take promotion piece out of holdings int k = PieceToNumber(CharToPiece(ToUpper(promoChar))); if((int)piece < (int)BlackPawn) { // determine stm from piece color @@ -13270,7 +13324,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"); @@ -13539,10 +13593,10 @@ SendTimeControl(cps, mps, tc, inc, sd, st) /* Note old gnuchess bug -- minutes:seconds used to not work. Fixed in later versions, but still avoid :seconds when seconds is 0. */ - snprintf(buf, MSG_SIZ, "level %d %ld %d\n", mps, tc/60000, inc/1000); + snprintf(buf, MSG_SIZ, "level %d %ld %g\n", mps, tc/60000, inc/1000.); } else { - snprintf(buf, MSG_SIZ, "level %d %ld:%02d %d\n", mps, tc/60000, - seconds, inc/1000); + snprintf(buf, MSG_SIZ, "level %d %ld:%02d %g\n", mps, tc/60000, + seconds, inc/1000.); } } SendToProgram(buf, cps); @@ -14298,7 +14352,7 @@ DecrementClocks() if (WhiteOnMove(forwardMostMove)) { if(whiteNPS >= 0) lastTickLength = 0; timeRemaining = whiteTimeRemaining -= lastTickLength; - if(timeRemaining < 0) { + if(timeRemaining < 0 && !appData.icsActive) { GetTimeQuota((forwardMostMove-whiteStartMove-1)/2, 0, whiteTC); // sets suddenDeath & nextSession; if(suddenDeath) { // [HGM] if we run out of a non-last incremental session, go to the next whiteStartMove = forwardMostMove; whiteTC = nextSession; @@ -14310,7 +14364,7 @@ DecrementClocks() } else { if(blackNPS >= 0) lastTickLength = 0; timeRemaining = blackTimeRemaining -= lastTickLength; - if(timeRemaining < 0) { // [HGM] if we run out of a non-last incremental session, go to the next + if(timeRemaining < 0 && !appData.icsActive) { // [HGM] if we run out of a non-last incremental session, go to the next GetTimeQuota((forwardMostMove-blackStartMove-1)/2, 0, blackTC); if(suddenDeath) { blackStartMove = forwardMostMove;