X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=ca839ca870c09a956e189a6b129dfc7bc95e450c;hb=97e95c084e4aacf02203d723937579e898d8e9ee;hp=d062185dc8e1410ee6d50f0368b9bd91571b4bd8;hpb=8746a61117e305a0cc3c2a113464a7a3d9c1230d;p=xboard.git diff --git a/backend.c b/backend.c index d062185..ca839ca 100644 --- a/backend.c +++ b/backend.c @@ -235,6 +235,8 @@ extern char installDir[MSG_SIZ]; extern int tinyLayout, smallLayout; ChessProgramStats programStats; +char lastPV[2][2*MSG_SIZ]; /* [HGM] pv: last PV in thinking output of each engine */ +int endPV = -1; static int exiting = 0; /* [HGM] moved to top */ static int setboardSpoiledMachineBlack = 0 /*, errorExitFlag = 0*/; int startedFromPositionFile = FALSE; Board filePosition; /* [HGM] loadPos */ @@ -247,6 +249,7 @@ int lastSavedGame; /* [HGM] save: ID of game */ char chatPartner[MAX_CHAT][MSG_SIZ]; /* [HGM] chat: list of chatting partners */ extern int chatCount; int chattingPartner; +char marker[BOARD_RANKS][BOARD_FILES]; /* [HGM] marks for target squares */ /* States for ics_getting_history */ #define H_FALSE 0 @@ -353,6 +356,7 @@ PosFlags(index) case VariantNoCastle: case VariantShatranj: case VariantCourier: + case VariantMakruk: flags &= ~F_ALL_CASTLE_OK; break; default: @@ -486,10 +490,10 @@ ChessSquare KnightmateArray[2][BOARD_FILES] = { }; ChessSquare fairyArray[2][BOARD_FILES] = { /* [HGM] Queen side differs from King side */ - { WhiteCannon, WhiteNightrider, WhiteAlfil, WhiteQueen, + { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteKing, WhiteBishop, WhiteKnight, WhiteRook }, - { BlackCannon, BlackNightrider, BlackAlfil, BlackQueen, - BlackKing, BlackBishop, BlackKnight, BlackRook } + { BlackLance, BlackAlfil, BlackMarshall, BlackAngel, + BlackKing, BlackMarshall, BlackAlfil, BlackLance } }; ChessSquare ShatranjArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatranj Q and P) */ @@ -499,6 +503,13 @@ ChessSquare ShatranjArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatr BlackFerz, BlackAlfil, BlackKnight, BlackRook } }; +ChessSquare makrukArray[2][BOARD_FILES] = { /* [HGM] (movGen knows about Shatranj Q and P) */ + { WhiteRook, WhiteKnight, WhiteMan, WhiteKing, + WhiteFerz, WhiteMan, WhiteKnight, WhiteRook }, + { BlackRook, BlackKnight, BlackMan, BlackFerz, + BlackKing, BlackMan, BlackKnight, BlackRook } +}; + #if (BOARD_FILES>=10) ChessSquare ShogiArray[2][BOARD_FILES] = { @@ -754,7 +765,7 @@ InitBackEnd1() /* [HGM] time odds: set factor for each machine */ first.timeOdds = appData.firstTimeOdds; second.timeOdds = appData.secondTimeOdds; - { int norm = 1; + { float norm = 1; if(appData.timeOddsMode) { norm = first.timeOdds; if(norm > second.timeOdds) norm = second.timeOdds; @@ -885,6 +896,7 @@ InitBackEnd1() case VariantAtomic: /* should work except for win condition */ case Variant3Check: /* should work except for win condition */ case VariantShatranj: /* should work except for all win conditions */ + case VariantMakruk: /* should work except for daw countdown */ case VariantBerolina: /* might work if TestLegality is off */ case VariantCapaRandom: /* should work */ case VariantJanus: /* should work */ @@ -2165,7 +2177,8 @@ read_from_ics(isr, closure, data, count, error) } buf[buf_len] = NULLCHAR; - next_out = leftover_len; +// next_out = leftover_len; // [HGM] should we set this to 0, and not print it in advance? + next_out = 0; leftover_start = 0; i = 0; @@ -2320,16 +2333,16 @@ read_from_ics(isr, closure, data, count, error) if(!suppressKibitz) // [HGM] kibitz AppendComment(forwardMostMove, StripHighlight(parse), TRUE); else { // [HGM kibitz: divert memorized engine kibitz to engine-output window - int nrDigit = 0, nrAlph = 0, i; + int nrDigit = 0, nrAlph = 0, j; if(parse_pos > MSG_SIZ - 30) // defuse unreasonably long input { parse_pos = MSG_SIZ-30; parse[parse_pos - 1] = '\n'; } parse[parse_pos] = NULLCHAR; // try to be smart: if it does not look like search info, it should go to // ICS interaction window after all, not to engine-output window. - for(i=0; i= '0' && parse[i] <= '9'); - nrAlph += (parse[i] >= 'a' && parse[i] <= 'z'); - nrAlph += (parse[i] >= 'A' && parse[i] <= 'Z'); + for(j=0; j= '0' && parse[j] <= '9'); + nrAlph += (parse[j] >= 'a' && parse[j] <= 'z'); + nrAlph += (parse[j] >= 'A' && parse[j] <= 'Z'); } if(nrAlph < 9*nrDigit) { // if more than 10% digit we assume search info int depth=0; float score; @@ -2339,6 +2352,7 @@ read_from_ics(isr, closure, data, count, error) pvInfoList[forwardMostMove-1].score = 100*score; } OutputKibitz(suppressKibitz, parse); + next_out = i+1; // [HGM] suppress printing in ICS window } else { char tmp[MSG_SIZ]; sprintf(tmp, _("your opponent kibitzes: %s"), parse); @@ -2347,7 +2361,7 @@ read_from_ics(isr, closure, data, count, error) } started = STARTED_NONE; } else { - /* Don't match patterns against characters in chatter */ + /* Don't match patterns against characters in comment */ i++; continue; } @@ -2447,9 +2461,11 @@ read_from_ics(isr, closure, data, count, error) } continue; } else - if(looking_at(buf, &i, "kibitzed to")) { // suppress the acknowledgements of our own autoKibitz - started = STARTED_CHATTER; - suppressKibitz = TRUE; + if(looking_at(buf, &i, "kibitzed to *\n") && atoi(star_match[0])) { + // suppress the acknowledgements of our own autoKibitz + SendToPlayer(star_match[0], strlen(star_match[0])); + looking_at(buf, &i, "*% "); // eat prompt + next_out = i; } } // [HGM] kibitz: end of patch @@ -2849,7 +2865,9 @@ read_from_ics(isr, closure, data, count, error) if (looking_at(buf, &i, "% ") || ((started == STARTED_MOVES || started == STARTED_MOVES_NOHIDE) && looking_at(buf, &i, "}*"))) { char *bookHit = NULL; // [HGM] book + if(suppressKibitz) next_out = i; savingComment = FALSE; + suppressKibitz = 0; switch (started) { case STARTED_MOVES: case STARTED_MOVES_NOHIDE: @@ -3146,6 +3164,7 @@ read_from_ics(isr, closure, data, count, error) strncmp(why, "Continuing ", 11) == 0) { gs_gamenum = gamenum; strcpy(gs_kind, strchr(why, ' ') + 1); + VariantSwitch(boards[currentMove], StringToVariant(gs_kind)); // [HGM] variantswitch: even before we get first board #if ZIPPY if (appData.zippyPlay) { ZippyGameStart(whitename, blackname); @@ -3275,6 +3294,7 @@ read_from_ics(isr, closure, data, count, error) while(looking_at(buf, &i, "\n")); // [HGM] skip empty lines if (looking_at(buf, &i, "*% ")) { savingComment = FALSE; + suppressKibitz = 0; } } next_out = i; @@ -3344,6 +3364,7 @@ read_from_ics(isr, closure, data, count, error) if (looking_at(buf, &i, "*% ")) { if(strchr(star_match[0], 7)) SendToPlayer("\007", 1); // Bell(); // FICS fuses bell for next board with prompt in zh captures savingComment = FALSE; + suppressKibitz = 0; } next_out = i; } @@ -3353,12 +3374,13 @@ read_from_ics(isr, closure, data, count, error) i++; /* skip unparsed character and loop back */ } - if (started != STARTED_MOVES && started != STARTED_BOARD && !suppressKibitz && // [HGM] kibitz suppress printing in ICS interaction window - started != STARTED_HOLDINGS && i > next_out) { - SendToPlayer(&buf[next_out], i - next_out); + if (started != STARTED_MOVES && started != STARTED_BOARD && !suppressKibitz && // [HGM] kibitz +// started != STARTED_HOLDINGS && i > next_out) { // [HGM] should we compare to leftover_start in stead of i? +// SendToPlayer(&buf[next_out], i - next_out); + started != STARTED_HOLDINGS && leftover_start > next_out) { + SendToPlayer(&buf[next_out], leftover_start - next_out); next_out = i; } - suppressKibitz = FALSE; // [HGM] kibitz: has done its duty in if-statement above leftover_len = buf_len - leftover_start; /* if buffer ends with something we couldn't parse, @@ -3692,16 +3714,16 @@ ParseBoard12(string) if(moveNum == 0 || gameInfo.variant != VariantFischeRandom) { int i, j; ChessSquare wKing = WhiteKing, bKing = BlackKing; - for(i=BOARD_LEFT, j= -1; i=BOARD_LEFT; i--) + for(i=BOARD_RGHT-1, j=NoRights; i>=BOARD_LEFT; i--) if(board[0][i] == WhiteRook) j = i; initialRights[1] = boards[moveNum][CASTLING][1] = (castle_wl == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j); - for(i=BOARD_LEFT, j= -1; i=BOARD_LEFT; i--) + for(i=BOARD_RGHT-1, j=NoRights; i>=BOARD_LEFT; i--) if(board[BOARD_HEIGHT-1][i] == BlackRook) j = i; initialRights[4] = boards[moveNum][CASTLING][4] = (castle_bl == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j); @@ -3711,6 +3733,11 @@ ParseBoard12(string) for(k=BOARD_LEFT; k framePtr) break; // no space, truncate + if(!valid) break; + endPV++; + CopyBoard(boards[endPV], boards[endPV-1]); + ApplyMove(fromX, fromY, toX, toY, promoChar, boards[endPV]); + moveList[endPV-1][0] = fromX + AAA; + moveList[endPV-1][1] = fromY + ONE; + moveList[endPV-1][2] = toX + AAA; + moveList[endPV-1][3] = toY + ONE; + parseList[endPV-1][0] = NULLCHAR; + } while(valid); + currentMove = endPV; + if(currentMove == forwardMostMove) ClearPremoveHighlights(); else + SetPremoveHighlights(moveList[currentMove-1][0]-AAA, moveList[currentMove-1][1]-ONE, + moveList[currentMove-1][2]-AAA, moveList[currentMove-1][3]-ONE); + DrawPosition(TRUE, boards[currentMove]); +} + +static int lastX, lastY; + +Boolean +LoadMultiPV(int x, int y, char *buf, int index, int *start, int *end) +{ + int startPV; + + if(index < 0 || index >= strlen(buf)) return FALSE; // sanity + lastX = x; lastY = y; + while(index > 0 && buf[index-1] != '\n') index--; // beginning of line + startPV = index; + while(buf[index] != '\n') if(buf[index++] == '\t') startPV = index; + index = startPV; + while(buf[index] && buf[index] != '\n') index++; + buf[index] = 0; + ParsePV(buf+startPV); + *start = startPV; *end = index-1; + return TRUE; +} + +Boolean +LoadPV(int x, int y) +{ // called on right mouse click to load PV + int which = gameMode == TwoMachinesPlay && (WhiteOnMove(forwardMostMove) == (second.twoMachinesColor[0] == 'w')); + lastX = x; lastY = y; + ParsePV(lastPV[which]); // load the PV of the thinking engine in the boards array. + return TRUE; +} + +void +UnLoadPV() +{ + if(endPV < 0) return; + endPV = -1; + currentMove = forwardMostMove; + ClearPremoveHighlights(); + DrawPosition(TRUE, boards[currentMove]); +} + +void +MovePV(int x, int y, int h) +{ // step through PV based on mouse coordinates (called on mouse move) + int margin = h>>3, step = 0; + + if(endPV < 0) return; + // we must somehow check if right button is still down (might be released off board!) + if(y < margin && (abs(x - lastX) > 6 || abs(y - lastY) > 6)) step = 1; else + if(y > h - margin && (abs(x - lastX) > 6 || abs(y - lastY) > 6)) step = -1; else + if( y > lastY + 6 ) step = -1; else if(y < lastY - 6) step = 1; + if(!step) return; + lastX = x; lastY = y; + if(currentMove + step > endPV || currentMove + step < forwardMostMove) step = 0; + currentMove += step; + if(currentMove == forwardMostMove) ClearPremoveHighlights(); else + SetPremoveHighlights(moveList[currentMove-1][0]-AAA, moveList[currentMove-1][1]-ONE, + moveList[currentMove-1][2]-AAA, moveList[currentMove-1][3]-ONE); + DrawPosition(FALSE, boards[currentMove]); +} + + // [HGM] shuffle: a general way to suffle opening setups, applicable to arbitrary variants. // All positions will have equal probability, but the current method will not provide a unique // numbering scheme for arrays that contain 3 or more pieces of the same kind. @@ -4666,6 +4796,12 @@ InitPosition(redraw) nrCastlingRights = 0; SetCharTable(pieceToChar, "PN.R.QB...Kpn.r.qb...k"); break; + case VariantMakruk: + pieces = makrukArray; + nrCastlingRights = 0; + startedFromSetupPosition = TRUE; + SetCharTable(pieceToChar, "PN.R.M....SKpn.r.m....sk"); + break; case VariantTwoKings: pieces = twoKingsArray; break; @@ -4725,7 +4861,7 @@ InitPosition(redraw) break; case VariantFairy: pieces = fairyArray; - SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk"); + SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVLSUKpnbrqfeacwmohijgdvlsuk"); break; case VariantGreat: pieces = GreatArray; @@ -4777,6 +4913,7 @@ InitPosition(redraw) pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */ if(pawnRow < 1) pawnRow = 1; + if(gameInfo.variant == VariantMakruk) pawnRow = 2; /* User pieceToChar list overrules defaults */ if(appData.pieceToCharTable != NULL) @@ -4962,6 +5099,8 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice) if(gameInfo.variant == VariantShogi) { promotionZoneSize = 3; highestPromotingPiece = (int)WhiteFerz; + } else if(gameInfo.variant == VariantMakruk) { + promotionZoneSize = 3; } // next weed out all moves that do not touch the promotion zone at all @@ -5005,7 +5144,7 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice) } // we either have a choice what to promote to, or (in Shogi) whether to promote - if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier) { + if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk) { *promoChoice = PieceToChar(BlackFerz); // no choice return FALSE; } @@ -5277,6 +5416,18 @@ UserMoveTest(fromX, fromY, toX, toY, promoChar, captureOwn) return AmbiguousMove; } else if (toX >= 0 && toY >= 0) { boards[0][toY][toX] = boards[0][fromY][fromX]; + if(fromX == BOARD_LEFT-2) { // handle 'moves' out of holdings + if(boards[0][fromY][0] != EmptySquare) { + if(boards[0][fromY][1]) boards[0][fromY][1]--; + if(boards[0][fromY][1] == 0) boards[0][fromY][0] = EmptySquare; + } + } else + if(fromX == BOARD_RGHT+1) { + if(boards[0][fromY][BOARD_WIDTH-1] != EmptySquare) { + if(boards[0][fromY][BOARD_WIDTH-2]) boards[0][fromY][BOARD_WIDTH-2]--; + if(boards[0][fromY][BOARD_WIDTH-2] == 0) boards[0][fromY][BOARD_WIDTH-1] = EmptySquare; + } + } else boards[0][fromY][fromX] = EmptySquare; return AmbiguousMove; } @@ -5529,6 +5680,43 @@ if(appData.debugMode) fprintf(debugFP, "moveType 4 = %d, promochar = %x\n", move FinishMove(moveType, fromX, fromY, toX, toY, promoChar); } +void +Mark(board, flags, kind, rf, ff, rt, ft, closure) + Board board; + int flags; + ChessMove kind; + int rf, ff, rt, ft; + VOIDSTAR closure; +{ + typedef char Markers[BOARD_RANKS][BOARD_FILES]; + Markers *m = (Markers *) closure; + if(rf == fromY && ff == fromX) + (*m)[rt][ft] = 1 + (board[rt][ft] != EmptySquare + || kind == WhiteCapturesEnPassant + || kind == BlackCapturesEnPassant); + else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3; +} + +void +MarkTargetSquares(int clear) +{ + int x, y; + if(!appData.markers || !appData.highlightDragging || + !appData.testLegality || gameMode == EditPosition) return; + if(clear) { + for(x=0; x1) capt++; + if(capt) + for(x=0; x= 0 && x < BOARD_LEFT || x >= BOARD_RGHT) { + ChessSquare piece = boards[currentMove][fromY][fromX]; + if(gameMode == EditPosition && piece != EmptySquare && + fromX >= BOARD_LEFT && fromX < BOARD_RGHT) { + int n; + + if(x == BOARD_LEFT-2 && piece >= BlackPawn) { + n = PieceToNumber(piece - (int)BlackPawn); + if(n > gameInfo.holdingsSize) { n = 0; piece = BlackPawn; } + boards[currentMove][BOARD_HEIGHT-1 - n][0] = piece; + boards[currentMove][BOARD_HEIGHT-1 - n][1]++; + } else + if(x == BOARD_RGHT+1 && piece < BlackPawn) { + n = PieceToNumber(piece); + if(n > gameInfo.holdingsSize) { n = 0; piece = WhitePawn; } + boards[currentMove][n][BOARD_WIDTH-1] = piece; + boards[currentMove][n][BOARD_WIDTH-2]++; + } + boards[currentMove][fromY][fromX] = EmptySquare; + } ClearHighlights(); fromX = fromY = -1; - DrawPosition(TRUE, NULL); + DrawPosition(TRUE, boards[currentMove]); return; } @@ -5735,6 +5945,8 @@ void SendProgramStatsToFrontend( ChessProgramState * cps, ChessProgramStats * cp stats.an_move_count = cpstats->nr_moves; } + if(stats.pv && stats.pv[0]) strcpy(lastPV[stats.which], stats.pv); // [HGM] pv: remember last PV of each + SetProgramStats( &stats ); } @@ -5796,6 +6008,8 @@ HandleMachineMove(message, cps) int machineWhite; char *bookHit; + cps->userError = 0; + FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book hit /* * Kludge to ignore BEL characters @@ -6468,6 +6682,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. return; } if (!strncmp(message, "tellusererror ", 14)) { + cps->userError = 1; DisplayError(message + 14, 0); return; } @@ -7351,6 +7566,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) Board board; { ChessSquare captured = board[toY][toX], piece, king; int p, oldEP = EP_NONE, berolina = 0; + int promoRank = gameInfo.variant == VariantMakruk ? 3 : 1; /* [HGM] compute & store e.p. status and castling rights for new position */ /* we can always do that 'in place', now pointers to these rights are passed to ApplyMove */ @@ -7397,7 +7613,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) } /* [HGM] In Shatranj and Courier all promotions are to Ferz */ - if((gameInfo.variant==VariantShatranj || gameInfo.variant==VariantCourier) + if((gameInfo.variant==VariantShatranj || gameInfo.variant==VariantCourier || gameInfo.variant == VariantMakruk) && promoChar != 0) promoChar = PieceToChar(WhiteFerz); if (fromX == toX && fromY == toY) return; @@ -7448,7 +7664,7 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) board[toY][toX+1] = board[fromY][BOARD_LEFT]; board[fromY][BOARD_LEFT] = EmptySquare; } else if (board[fromY][fromX] == WhitePawn - && toY == BOARD_HEIGHT-1 + && toY >= BOARD_HEIGHT-promoRank && gameInfo.variant != VariantXiangqi ) { /* white pawn promotion */ @@ -7512,13 +7728,13 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board) board[fromY][0] = EmptySquare; board[toY][2] = BlackRook; } else if (board[fromY][fromX] == BlackPawn - && toY == 0 + && toY < promoRank && gameInfo.variant != VariantXiangqi ) { /* black pawn promotion */ - board[0][toX] = CharToPiece(ToLower(promoChar)); - if (board[0][toX] == EmptySquare) { - board[0][toX] = BlackQueen; + board[toY][toX] = CharToPiece(ToLower(promoChar)); + if (board[toY][toX] == EmptySquare) { + board[toY][toX] = BlackQueen; } if(gameInfo.variant==VariantBughouse || gameInfo.variant==VariantCrazyhouse) /* [HGM] use shadow piece */ @@ -7705,6 +7921,7 @@ MakeMove(fromX, fromY, toX, toY, promoChar) 0, 1); return; } + UnLoadPV(); // [HGM] pv: if we are looking at a PV, abort this if (commentList[forwardMostMove+1] != NULL) { free(commentList[forwardMostMove+1]); commentList[forwardMostMove+1] = NULL; @@ -11301,9 +11518,20 @@ EditPositionMenuEvent(selection, x, y) case EmptySquare: if (gameMode == IcsExamining) { + if (x < BOARD_LEFT || x >= BOARD_RGHT) break; // [HGM] holdings sprintf(buf, "%sx@%c%c\n", ics_prefix, AAA + x, ONE + y); SendToICS(buf); } else { + if(x < BOARD_LEFT || x >= BOARD_RGHT) { + if(x == BOARD_LEFT-2) { + if(y < BOARD_HEIGHT-1-gameInfo.holdingsSize) break; + boards[0][y][1] = 0; + } else + if(x == BOARD_RGHT+1) { + if(y >= gameInfo.holdingsSize) break; + boards[0][y][BOARD_WIDTH-2] = 0; + } else break; + } boards[0][y][x] = EmptySquare; DrawPosition(FALSE, boards[0]); } @@ -11329,7 +11557,8 @@ EditPositionMenuEvent(selection, x, y) case BlackQueen: if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi || - gameInfo.variant == VariantCourier ) + gameInfo.variant == VariantCourier || + gameInfo.variant == VariantMakruk ) selection = (ChessSquare)((int)selection - (int)WhiteQueen + (int)WhiteFerz); goto defaultlabel; @@ -11342,12 +11571,28 @@ EditPositionMenuEvent(selection, x, y) default: defaultlabel: if (gameMode == IcsExamining) { + if (x < BOARD_LEFT || x >= BOARD_RGHT) break; // [HGM] holdings sprintf(buf, "%s%c@%c%c\n", ics_prefix, PieceToChar(selection), AAA + x, ONE + y); SendToICS(buf); } else { + if(x < BOARD_LEFT || x >= BOARD_RGHT) { + int n; + if(x == BOARD_LEFT-2 && selection >= BlackPawn) { + n = PieceToNumber(selection - BlackPawn); + if(n > gameInfo.holdingsSize) { n = 0; selection = BlackPawn; } + boards[0][BOARD_HEIGHT-1-n][0] = selection; + boards[0][BOARD_HEIGHT-1-n][1]++; + } else + if(x == BOARD_RGHT+1 && selection < BlackPawn) { + n = PieceToNumber(selection); + if(n > gameInfo.holdingsSize) { n = 0; selection = WhitePawn; } + boards[0][n][BOARD_WIDTH-1] = selection; + boards[0][n][BOARD_WIDTH-2]++; + } + } else boards[0][y][x] = selection; - DrawPosition(FALSE, boards[0]); + DrawPosition(TRUE, boards[0]); } break; } @@ -12422,7 +12667,7 @@ SendToProgram(message, cps) } gameInfo.resultDetails = StrSave(buf); } - DisplayFatalError(buf, error, 1); + if(!cps->userError || !appData.popupExitMessage) DisplayFatalError(buf, error, 1); else errorExitStatus = 1; } } @@ -12454,7 +12699,7 @@ ReceiveFromProgram(isr, closure, message, count, error) gameInfo.resultDetails = StrSave(buf); } RemoveInputSource(cps->isr); - DisplayFatalError(buf, 0, 1); + if(!cps->userError || !appData.popupExitMessage) DisplayFatalError(buf, 0, 1); else errorExitStatus = 1; } else { sprintf(buf, _("Error reading from %s chess program (%s)"), @@ -12467,7 +12712,7 @@ ReceiveFromProgram(isr, closure, message, count, error) cps->pr = NoProc; } - DisplayFatalError(buf, error, 1); + if(!cps->userError || !appData.popupExitMessage) DisplayFatalError(buf, error, 1); else errorExitStatus = 1; } return; } @@ -12612,7 +12857,7 @@ SendTimeRemaining(cps, machineWhite) /* [HGM] translate opponent's time by time-odds factor */ otime = (otime * cps->other->timeOdds) / cps->timeOdds; if (appData.debugMode) { - fprintf(debugFP, "time odds: %d %d \n", cps->timeOdds, cps->other->timeOdds); + fprintf(debugFP, "time odds: %f %f \n", cps->timeOdds, cps->other->timeOdds); } if (time <= 0) time = 1; @@ -13304,12 +13549,12 @@ DecrementClocks() if(whiteNPS >= 0) lastTickLength = 0; timeRemaining = whiteTimeRemaining -= lastTickLength; DisplayWhiteClock(whiteTimeRemaining - fudge, - WhiteOnMove(currentMove)); + WhiteOnMove(currentMove < forwardMostMove ? currentMove : forwardMostMove)); } else { if(blackNPS >= 0) lastTickLength = 0; timeRemaining = blackTimeRemaining -= lastTickLength; DisplayBlackClock(blackTimeRemaining - fudge, - !WhiteOnMove(currentMove)); + !WhiteOnMove(currentMove < forwardMostMove ? currentMove : forwardMostMove)); } if (CheckFlags()) return; @@ -13739,7 +13984,7 @@ PositionToFEN(move, overrideCastling) } if(gameInfo.variant != VariantShogi && gameInfo.variant != VariantXiangqi && - gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier ) { + gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier && gameInfo.variant != VariantMakruk ) { /* En passant target square */ if (move > backwardMostMove) { fromX = moveList[move - 1][0] - AAA; @@ -13914,10 +14159,12 @@ ParseFEN(board, blackPlaysFirst, fen) } /* assume possible unless obviously impossible */ if(initialRights[0]!=NoRights && board[castlingRank[0]][initialRights[0]] != WhiteRook) board[CASTLING][0] = NoRights; if(initialRights[1]!=NoRights && board[castlingRank[1]][initialRights[1]] != WhiteRook) board[CASTLING][1] = NoRights; - if(initialRights[2]!=NoRights && board[castlingRank[2]][initialRights[2]] != WhiteKing) board[CASTLING][2] = NoRights; + if(initialRights[2]!=NoRights && board[castlingRank[2]][initialRights[2]] != WhiteUnicorn + && board[castlingRank[2]][initialRights[2]] != WhiteKing) board[CASTLING][2] = NoRights; if(initialRights[3]!=NoRights && board[castlingRank[3]][initialRights[3]] != BlackRook) board[CASTLING][3] = NoRights; if(initialRights[4]!=NoRights && board[castlingRank[4]][initialRights[4]] != BlackRook) board[CASTLING][4] = NoRights; - if(initialRights[5]!=NoRights && board[castlingRank[5]][initialRights[5]] != BlackKing) board[CASTLING][5] = NoRights; + if(initialRights[5]!=NoRights && board[castlingRank[5]][initialRights[5]] != BlackUnicorn + && board[castlingRank[5]][initialRights[5]] != BlackKing) board[CASTLING][5] = NoRights; FENrulePlies = 0; while(*p==' ') p++; @@ -13932,12 +14179,18 @@ ParseFEN(board, blackPlaysFirst, fen) (gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) && ( *p >= 'a' && *p < 'a' + gameInfo.boardWidth) || ( *p >= 'A' && *p < 'A' + gameInfo.boardWidth) ) { - char c = *p++; int whiteKingFile=-1, blackKingFile=-1; + char c = *p++; int whiteKingFile=NoRights, blackKingFile=NoRights; for(i=BOARD_LEFT; i> 1; // for these variant scanning fails + if(whiteKingFile == NoRights || board[0][whiteKingFile] != WhiteUnicorn + && board[0][whiteKingFile] != WhiteKing) whiteKingFile = NoRights; + if(blackKingFile == NoRights || board[BOARD_HEIGHT-1][blackKingFile] != BlackUnicorn + && board[BOARD_HEIGHT-1][blackKingFile] != BlackKing) blackKingFile = NoRights; switch(c) { case'K': for(i=BOARD_RGHT-1; board[0][i]!=WhiteRook && i>whiteKingFile; i--); @@ -13945,7 +14198,7 @@ ParseFEN(board, blackPlaysFirst, fen) board[CASTLING][2] = whiteKingFile; break; case'Q': - for(i=BOARD_LEFT; board[0][i]!=WhiteRook && i