X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=749bac904daa7ebb112d08a903aa89f3572ff329;hb=211b194243de81ed013566a30ef754018586c4e1;hp=39467aeae6f8fc4ff54ea1497e36755ca6a25300;hpb=665a404fb62e2092170f221e27c9ba9423850bfe;p=xboard.git diff --git a/backend.c b/backend.c index 39467ae..749bac9 100644 --- a/backend.c +++ b/backend.c @@ -295,6 +295,7 @@ ChessSquare promoSweep = EmptySquare, defaultPromoChoice; int promoDefaultAltered; int keepInfo = 0; /* [HGM] to protect PGN tags in auto-step game analysis */ static int initPing = -1; +static Boolean pieceDefs; /* States for ics_getting_history */ #define H_FALSE 0 @@ -413,6 +414,11 @@ PosFlags (index) case VariantGrand: flags &= ~F_ALL_CASTLE_OK; break; + case VariantChu: + case VariantChuChess: + case VariantLion: + flags |= F_NULL_MOVE; + break; default: break; } @@ -847,6 +853,7 @@ InitEngine (ChessProgramState *cps, int n) cps->analyzing = FALSE; cps->initDone = FALSE; cps->reload = FALSE; + cps->pseudo = appData.pseudo[n]; /* New features added by Tord: */ cps->useFEN960 = FALSE; @@ -948,7 +955,7 @@ extern Boolean isUCI, hasBook, storeVariant, v1, addToList, useNick; static char resetOptions[] = "-reuse -firstIsUCI false -firstHasOwnBookUCI true -firstTimeOdds 1 " "-firstInitString \"" INIT_STRING "\" -firstComputerString \"" COMPUTER_STRING "\" " - "-firstFeatures \"\" -firstLogo \"\" -firstAccumulateTC 1 " + "-firstFeatures \"\" -firstLogo \"\" -firstAccumulateTC 1 -fd \".\" " "-firstOptions \"\" -firstNPS -1 -fn \"\" -firstScoreAbs false"; void @@ -5674,7 +5681,7 @@ LoadMultiPV (int x, int y, char *buf, int index, int *start, int *end, int pane) } ParsePV(buf+startPV, FALSE, gameMode != AnalyzeMode); *start = startPV; *end = index-1; - extendGame = (gameMode == AnalyzeMode && appData.autoExtend); + extendGame = (gameMode == AnalyzeMode && appData.autoExtend && origIndex - startPV < 5); return TRUE; } @@ -6021,9 +6028,10 @@ InitPosition (int redraw) gameInfo.boardHeight = 8; gameInfo.holdingsSize = 0; nrCastlingRights = -1; /* [HGM] Kludge to indicate default should be used */ - for(i=0; i= 0 && toY >= 0) { + if(!appData.pieceMenu && toX == fromX && toY == fromY && boards[0][rf][ff] != EmptySquare) { + ChessSquare q, p = boards[0][rf][ff]; + if(p >= BlackPawn) p = BLACK_TO_WHITE p; + if(CHUPROMOTED p < BlackPawn) p = q = CHUPROMOTED boards[0][rf][ff]; + else p = CHUDEMOTED (q = boards[0][rf][ff]); + if(PieceToChar(q) == '+') gatingPiece = p; + } boards[0][toY][toX] = boards[0][fromY][fromX]; if(fromX == BOARD_LEFT-2) { // handle 'moves' out of holdings if(boards[0][fromY][0] != EmptySquare) { @@ -6959,7 +6974,7 @@ UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar) return; } - if(toX < 0 || toY < 0) return; + if((toX < 0 || toY < 0) && (fromY != DROP_RANK || fromX != EmptySquare)) return; pup = boards[currentMove][toY][toX]; /* [HGM] If move started in holdings, it means a drop. Convert to standard form */ @@ -6979,7 +6994,7 @@ UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar) moveType = LegalityTest(boards[currentMove], PosFlags(currentMove), fromY, fromX, toY, toX, promoChar); - if(fromY == DROP_RANK && fromX == EmptySquare && (gameMode == AnalyzeMode || gameMode == EditGame)) moveType = NormalMove; + if(fromY == DROP_RANK && fromX == EmptySquare && (gameMode == AnalyzeMode || gameMode == EditGame || PosFlags(0) & F_NULL_MOVE)) moveType = NormalMove; /* [HGM] but possibly ignore an IllegalMove result */ if (appData.testLegality) { @@ -7247,8 +7262,8 @@ Mark (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VO if(rf == fromY && ff == fromX && (killX < 0 && !(rt == rf && ft == ff) || abs(ft-killX) < 2 && abs(rt-killY) < 2)) (*m)[rt][ft] = 1 + (board[rt][ft] != EmptySquare || kind == WhiteCapturesEnPassant - || kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0); - else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3; + || kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0), legal[rt][ft] = 1; + else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3, legal[rt][ft] = 1; } static int hoverSavedValid; @@ -7264,7 +7279,7 @@ MarkTargetSquares (int clear) } else { int capt = 0; if(!appData.markers || !appData.highlightDragging || appData.icsActive && gameInfo.variant < VariantShogi || - !appData.testLegality || gameMode == EditPosition) return; + !appData.testLegality && !pieceDefs || gameMode == EditPosition) return; GenLegal(boards[currentMove], PosFlags(currentMove), Mark, (void*) marker, EmptySquare); if(PosFlags(0) & F_MANDATORY_CAPTURE) { for(x=0; x1) capt++; @@ -7340,7 +7355,8 @@ void ReportClick(char *action, int x, int y) char buf[MSG_SIZ]; // Inform engine of what user does int r, f; if(action[0] == 'l') // mark any target square of a lifted piece as legal to-square, clear markers - for(r=0; r= BOARD_LEFT && fromX < BOARD_RGHT && (x != killX || y != killY) && !sweepSelecting) { if(dragging) DragPieceEnd(xPix, yPix), dragging = 0; DisplayMessage(_("only marked squares are legal"),""); DrawPosition(TRUE, NULL); @@ -8358,10 +8375,10 @@ BitbaseProbe () // probe EGBB if(loaded == 2) return 13; // loading failed before if(loaded == 0) { - loaded = 2; // prepare for failure char *p, *path = strstr(appData.egtFormats, "scorpio:"), buf[MSG_SIZ]; HMODULE lib; PLOAD_EGBB loadBB; + loaded = 2; // prepare for failure if(!path) return 13; // no egbb installed strncpy(buf, path + 8, MSG_SIZ); if(p = strchr(buf, ',')) *p = NULLCHAR; else p = buf + strlen(buf); @@ -8714,7 +8731,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if( count & 1 ) { score = -score; /* Flip score for winning side */ } -printf("score=%d count=%d\n",score,count); + if( score > appData.adjudicateLossThreshold ) { break; } @@ -8873,6 +8890,19 @@ printf("score=%d count=%d\n",score,count); startedFromSetupPosition = TRUE; return; } + if(sscanf(message, "piece %s %s", buf2, buf1) == 2) { + ChessSquare piece = WhitePawn; + char *p=buf2; + if(cps != &first || appData.testLegality) return; + if(*p == '+') piece = CHUPROMOTED WhitePawn, p++; + piece += CharToPiece(*p) - WhitePawn; + if(piece < EmptySquare) { + pieceDefs = TRUE; + ASSIGN(pieceDesc[piece], buf1); + if(isupper(*p) && p[1] == '&') { ASSIGN(pieceDesc[WHITE_TO_BLACK piece], buf1); } + } + 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. */ @@ -9136,6 +9166,10 @@ printf("score=%d count=%d\n",score,count); Don't use it. */ cps->sendTime = 0; } + if (cps->pseudo) { // [HGM] pseudo-engine, granted unusual powers + if (sscanf(message, "wtime %ld\n", &whiteTimeRemaining) == 1 || // adjust clock times + sscanf(message, "btime %ld\n", &blackTimeRemaining) == 1 ) return; + } /* * If chess program startup fails, exit with an error message. @@ -9404,6 +9438,9 @@ printf("score=%d count=%d\n",score,count); if (sscanf(message, "%d%c %d %d " u64Display " %[^\n]\n", &plylev, &plyext, &curscore, &time, &nodes, buf1) >= 5) { + if(nodes>>32 == u64Const(0xFFFFFFFF)) // [HGM] negative node count read + nodes += u64Const(0x100000000); + if (plyext != ' ' && plyext != '\t') { time *= 100; } @@ -9847,6 +9884,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) if(gameInfo.variant == VariantBerolina) berolina = EP_BEROLIN_A; oldEP = (signed char)board[EP_STATUS]; board[EP_STATUS] = EP_NONE; + board[EP_FILE] = board[EP_RANK] = 100; if (fromY == DROP_RANK) { /* must be first */ @@ -9881,6 +9919,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers board[EP_STATUS] = EP_PAWN_MOVE; if( toY-fromY==2) { + board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = (fromY + toY)/2; if(toX>BOARD_LEFT && board[toY][toX-1] == BlackPawn && gameInfo.variant != VariantBerolina || toX < fromX) board[EP_STATUS] = toX | berolina; @@ -9893,6 +9932,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers board[EP_STATUS] = EP_PAWN_MOVE; if( toY-fromY== -2) { + board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = (fromY + toY)/2; if(toX>BOARD_LEFT && board[toY][toX-1] == WhitePawn && gameInfo.variant != VariantBerolina || toX < fromX) board[EP_STATUS] = toX | berolina; @@ -9902,6 +9942,11 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) } } + if(fromY == 0) board[TOUCHED_W] |= 1<piece; int to = move->to, from = pieceList[piece]; + if(found < 0) { // if already found just scan to game end for final piece count + if(QuickCompare(soughtBoard, minSought, maxSought) || + appData.ignoreColors && QuickCompare(reverseBoard, minReverse, maxReverse) || + flipSearch && (QuickCompare(flipBoard, minSought, maxSought) || + appData.ignoreColors && QuickCompare(rotateBoard, minReverse, maxReverse)) + ) { + static int lastCounts[EmptySquare+1]; + int i; + if(stretch) for(i=0; i= appData.stretch)) found = cnt + 1 - stretch; + if(found >= 0 && !appData.minPieces) return found; + } if(piece <= Q_PROMO) { // special moves encoded by otherwise invalid piece numbers 1-4 - if(!piece) return -1; + if(!piece) return (appData.minPieces && (total < appData.minPieces || total > appData.maxPieces) ? -1 : found); if(piece == Q_PROMO) { // promotion, encoded as (Q_PROMO, to) + (piece, promoType) piece = (++move)->piece; from = pieceList[piece]; @@ -12376,23 +12447,12 @@ QuickScan (Board board, Move *move) } } if(appData.searchMode > 2) counts[pieceType[quickBoard[to]]]--; // account capture - if((total -= (quickBoard[to] != 0)) < soughtTotal) return -1; // piece count dropped below what we search for + if((total -= (quickBoard[to] != 0)) < soughtTotal && found < 0) return -1; // piece count dropped below what we search for quickBoard[from] = 0; aftercastle: quickBoard[to] = piece; pieceList[piece] = to; cnt++; turn ^= 3; - if(QuickCompare(soughtBoard, minSought, maxSought) || - appData.ignoreColors && QuickCompare(reverseBoard, minReverse, maxReverse) || - flipSearch && (QuickCompare(flipBoard, minSought, maxSought) || - appData.ignoreColors && QuickCompare(rotateBoard, minReverse, maxReverse)) - ) { - static int lastCounts[EmptySquare+1]; - int i; - if(stretch) for(i=0; i= appData.stretch)) return cnt + 1 - stretch; move++; } while(1); } @@ -13345,9 +13405,9 @@ GetOutOfBookInfo (char * buf) } } -/* Save game in PGN style and close the file */ -int -SaveGamePGN (FILE *f) +/* Save game in PGN style */ +static void +SaveGamePGN2 (FILE *f) { int i, offset, linelen, newblock; // char *movetext; @@ -13507,7 +13567,13 @@ SaveGamePGN (FILE *f) } else { fprintf(f, "%s\n\n", PGNResult(gameInfo.result)); } +} +/* Save game in PGN style and close the file */ +int +SaveGamePGN (FILE *f) +{ + SaveGamePGN2(f); fclose(f); lastSavedGame = GameCheckSum(); // [HGM] save: remember ID of last saved game to prevent double saving return TRUE; @@ -15007,14 +15073,14 @@ EditPositionMenuEvent (ChessSquare selection, int x, int y) boards[0][y][x] = p; } } - menuBoard[1][x] = menuBoard[BOARD_HEIGHT-2][x] = p; } if(gameMode != IcsExamining) { // [HGM] editpos: cycle trough boards - for(x = BOARD_LEFT; x < BOARD_RGHT; x++) { // create 'menu board' by removing duplicates - ChessSquare p = menuBoard[0][x]; - for(y = x + 1; y < BOARD_RGHT; y++) if(menuBoard[0][y] == p) menuBoard[0][y] = EmptySquare; - p = menuBoard[BOARD_HEIGHT-1][x]; - for(y = x + 1; y < BOARD_RGHT; y++) if(menuBoard[BOARD_HEIGHT-1][y] == p) menuBoard[BOARD_HEIGHT-1][y] = EmptySquare; + int r; + for(r = 0; r < BOARD_HEIGHT; r++) { + for(x = BOARD_LEFT; x < BOARD_RGHT; x++) { // create 'menu board' by removing duplicates + ChessSquare p = menuBoard[r][x]; + for(y = x + 1; y < BOARD_RGHT; y++) if(menuBoard[r][y] == p) menuBoard[r][y] = EmptySquare; + } } DisplayMessage("Clicking clock again restores position", ""); if(gameInfo.variant != lastVariant) lastVariant = gameInfo.variant, CopyBoard(erasedBoard, boards[0]); @@ -15276,7 +15342,8 @@ ClockClick (int which) if (gameMode == EditPosition || gameMode == IcsExamining) { if(!appData.pieceMenu && blackPlaysFirst) EditPositionMenuEvent(ClearBoard, 0, 0); SetBlackToPlayEvent(); - } else if ((gameMode == AnalyzeMode || gameMode == EditGame) && !blackFlag && WhiteOnMove(currentMove)) { + } else if ((gameMode == AnalyzeMode || gameMode == EditGame || + gameMode == MachinePlaysBlack && PosFlags(0) & F_NULL_MOVE && !blackFlag && !shiftKey) && WhiteOnMove(currentMove)) { UserMoveEvent((int)EmptySquare, DROP_RANK, 0, 0, 0); // [HGM] multi-move: if not out of time, enters null move } else if (shiftKey) { AdjustClock(which, -1); @@ -15288,7 +15355,8 @@ ClockClick (int which) if (gameMode == EditPosition || gameMode == IcsExamining) { if(!appData.pieceMenu && !blackPlaysFirst) EditPositionMenuEvent(ClearBoard, 0, 0); SetWhiteToPlayEvent(); - } else if ((gameMode == AnalyzeMode || gameMode == EditGame) && !whiteFlag && !WhiteOnMove(currentMove)) { + } else if ((gameMode == AnalyzeMode || gameMode == EditGame || + gameMode == MachinePlaysWhite && PosFlags(0) & F_NULL_MOVE && !whiteFlag && !shiftKey) && !WhiteOnMove(currentMove)) { UserMoveEvent((int)EmptySquare, DROP_RANK, 0, 0, 0); // [HGM] multi-move } else if (shiftKey) { AdjustClock(which, -1); @@ -15452,9 +15520,18 @@ ForwardInner (int target) SetHighlights(-1, -1, toX, toY); } } else { + int viaX = moveList[target - 1][5] - AAA; + int viaY = moveList[target - 1][6] - ONE; fromX = moveList[target - 1][0] - AAA; fromY = moveList[target - 1][1] - ONE; if (target == currentMove + 1) { + if(moveList[target - 1][4] == ';') { // multi-leg + ChessSquare piece = boards[currentMove][viaY][viaX]; + AnimateMove(boards[currentMove], fromX, fromY, viaX, viaY); + boards[currentMove][viaY][viaX] = boards[currentMove][fromY][fromX]; + AnimateMove(boards[currentMove], viaX, viaY, toX, toY); + boards[currentMove][viaY][viaX] = piece; + } else AnimateMove(boards[currentMove], fromX, fromY, toX, toY); } if (appData.highlightLastMove) { @@ -15800,6 +15877,36 @@ HintEvent () hintRequested = TRUE; } +int +SaveSelected (FILE *g, int dummy, char *dummy2) +{ + ListGame * lg = (ListGame *) gameList.head; + int nItem, cnt=0; + FILE *f; + + if( !(f = GameFile()) || ((ListGame *) gameList.tailPred)->number <= 0 ) { + DisplayError(_("Game list not loaded or empty"), 0); + return 0; + } + + creatingBook = TRUE; // suppresses stuff during load game + + /* Get list size */ + for (nItem = 1; nItem <= ((ListGame *) gameList.tailPred)->number; nItem++){ + if(lg->position >= 0) { // selected? + LoadGame(f, nItem, "", TRUE); + SaveGamePGN2(g); // leaves g open + cnt++; DoEvents(); + } + lg = (ListGame *) lg->node.succ; + } + + fclose(g); + creatingBook = FALSE; + + return cnt; +} + void CreateBookEvent () { @@ -15825,8 +15932,11 @@ CreateBookEvent () /* Get list size */ for (nItem = 1; nItem <= ((ListGame *) gameList.tailPred)->number; nItem++){ - LoadGame(f, nItem, "", TRUE); - AddGameToBook(TRUE); + if(lg->position >= 0) { + LoadGame(f, nItem, "", TRUE); + AddGameToBook(TRUE); + DoEvents(); + } lg = (ListGame *) lg->node.succ; } @@ -16525,6 +16635,10 @@ EngineDefinedVariant (ChessProgramState *cps, int n) v = StringToVariant(s); if(v == VariantNormal && strcmp(s, "normal") && !strstr(s, "_normal")) v = VariantUnknown; // garbage is recognized as normal if(v == VariantUnknown) { // non-standard variant in list of engine-supported variants + if(!strcmp(s, "tenjiku") || !strcmp(s, "dai") || !strcmp(s, "dada") || // ignore Alien-Edition variants + !strcmp(s, "maka") || !strcmp(s, "tai") || !strcmp(s, "kyoku") || + !strcmp(s, "checkers") || !strcmp(s, "go") || !strcmp(s, "reversi") || + !strcmp(s, "dark") || !strcmp(s, "alien") || !strcmp(s, "multi") || !strcmp(s, "amazons") ) n++; if(--n < 0) safeStrCpy(buf, s, MSG_SIZ); } if(p) *p++ = ','; @@ -17633,12 +17747,12 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts) if(PieceToChar(piece) == '+') { /* [HGM] write promoted pieces as '+' (Shogi) */ *p++ = '+'; - piece = (ChessSquare)(DEMOTED piece); + piece = (ChessSquare)(CHUDEMOTED piece); } *p++ = (piece == DarkSquare ? '*' : PieceToChar(piece)); if(p[-1] == '~') { /* [HGM] flag promoted pieces as '~' (Crazyhouse) */ - p[-1] = PieceToChar((ChessSquare)(DEMOTED piece)); + p[-1] = PieceToChar((ChessSquare)(CHUDEMOTED piece)); *p++ = '~'; } }