From: Arun Persaud Date: Sun, 7 Feb 2010 00:15:15 +0000 (-0800) Subject: Merge branch 'master' into gtk X-Git-Tag: gtk-20100206~14 X-Git-Url: http://winboard.nl/cgi-bin?p=xboard.git;a=commitdiff_plain;h=4042b38821940cd48e9f3d10b5208da7b6288dfd Merge branch 'master' into gtk Conflicts: Makefile.am backend.c configure.ac xboard.c xgamelist.c --- 4042b38821940cd48e9f3d10b5208da7b6288dfd diff --cc Makefile.am index 131a9fc,3abd176..6e5e713 --- a/Makefile.am +++ b/Makefile.am @@@ -40,13 -35,13 +40,17 @@@ EXTRA_DIST = pixmaps bitmaps svg sound DISTCLEANFILES = stamp-h - AM_CPPFLAGS=-DINFODIR='"$(infodir)"' @GTK_CFLAGS@ -AM_CPPFLAGS=-DINFODIR='"$(infodir)"' @X_CFLAGS@ -DSYSCONFDIR='"$(sysconfdir)"' ++ ++AM_CPPFLAGS=-DINFODIR='"$(infodir)"' @GTK_CFLAGS@ -DSYSCONFDIR='"$(sysconfdir)"' ++ info_TEXINFOS = xboard.texi xboard_TEXINFOS = copyright.texi man6_MANS = xboard.man - sysconf_DATA=xboard.conf ++ + dist_sysconf_DATA = xboard.conf + + xboard.man: xboard.texi copyright.texi gpl.texinfo version.texi $(srcdir)/texi2man $(srcdir)/xboard.texi > xboard.man || (rm -f xboard.man ; false) diff --cc backend.c index 6095cc6,afb509c..4d23241 --- a/backend.c +++ b/backend.c @@@ -1092,94 -1095,71 +1095,97 @@@ InitBackEnd2( void InitBackEnd3 P((void)) { - GameMode initialMode; - char buf[MSG_SIZ]; - int err; - - InitChessProgram(&first, startedFromSetupPosition); - - - if (appData.icsActive) { -#ifdef WIN32 - /* [DM] Make a console window if needed [HGM] merged ifs */ - ConsoleCreate(); -#endif - err = establish(); - if (err != 0) { - if (*appData.icsCommPort != NULLCHAR) { - sprintf(buf, _("Could not open comm port %s"), - appData.icsCommPort); - } else { - snprintf(buf, sizeof(buf), _("Could not connect to host %s, port %s"), - appData.icsHost, appData.icsPort); - } - DisplayFatalError(buf, err, 1); - return; + GameMode initialMode; + char buf[MSG_SIZ]; + int err; + + InitChessProgram(&first, startedFromSetupPosition); + + + if (appData.icsActive) + { + err = establish(); + if (err != 0) + { + if (*appData.icsCommPort != NULLCHAR) + { + sprintf(buf, _("Could not open comm port %s"), + appData.icsCommPort); + } + else + { + snprintf(buf, sizeof(buf), _("Could not connect to host %s, port %s"), + appData.icsHost, appData.icsPort); + } + DisplayFatalError(buf, err, 1); + return; } - SetICSMode(); - telnetISR = - AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR); - fromUserISR = - AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR); ++ + SetICSMode(); + telnetISR = + AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR); + fromUserISR = + AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR); + if(appData.keepAlive) // [HGM] alive: schedule sending of dummy 'date' command + ScheduleDelayedEvent(KeepAlive, appData.keepAlive*60*1000); - } else if (appData.noChessProgram) { - SetNCPMode(); - } else { - SetGNUMode(); } - - if (*appData.cmailGameName != NULLCHAR) { - SetCmailMode(); - OpenLoopback(&cmailPR); - cmailISR = - AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR); + else if (appData.noChessProgram) + { + SetNCPMode(); + } + else + { + SetGNUMode(); } - - ThawUI(); - DisplayMessage("", ""); - if (StrCaseCmp(appData.initialMode, "") == 0) { + + if (*appData.cmailGameName != NULLCHAR) + { + SetCmailMode(); + OpenLoopback(&cmailPR); + cmailISR = + AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR); + } + + ThawUI(); + DisplayMessage("", ""); + if (StrCaseCmp(appData.initialMode, "") == 0) + { initialMode = BeginningOfGame; - } else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) { + } + else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) + { initialMode = TwoMachinesPlay; - } else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) { - initialMode = AnalyzeFile; - } else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) { + } + else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) + { + initialMode = AnalyzeFile; + } + else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) + { initialMode = AnalyzeMode; - } else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) { + } + else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) + { initialMode = MachinePlaysWhite; - } else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) { + } + else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) + { initialMode = MachinePlaysBlack; - } else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) { + } + else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) + { initialMode = EditGame; - } else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) { + } + else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) + { initialMode = EditPosition; - } else if (StrCaseCmp(appData.initialMode, "Training") == 0) { + } + else if (StrCaseCmp(appData.initialMode, "Training") == 0) + { initialMode = Training; - } else { + } + else + { sprintf(buf, _("Unknown initialMode %s"), appData.initialMode); DisplayFatalError(buf, 0, 2); return; @@@ -5521,8 -5762,6 +5831,7 @@@ UserMoveTest(fromX, fromY, toX, toY, pr return WhiteDrop; /* Not needed to specify white or black yet */ } - userOfferedDraw = FALSE; + /* [HGM] always test for legality, to get promotion info */ moveType = LegalityTest(boards[currentMove], PosFlags(currentMove), fromY, fromX, toY, toX, promoChar); @@@ -5654,110 -5876,102 +5963,114 @@@ FinishMove(moveType, fromX, fromY, toX MakeMove(fromX, fromY, toX, toY, promoChar); /*updates forwardMostMove*/ - if (gameMode == BeginningOfGame) - if(Adjudicate(NULL)) return 1; // [HGM] adjudicate: take care of automtic game end + - if (gameMode == BeginningOfGame) { - if (appData.noChessProgram) { - gameMode = EditGame; - SetGameInfo(); - } else { - char buf[MSG_SIZ]; - gameMode = MachinePlaysBlack; - StartClocks(); - SetGameInfo(); - sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black); - DisplayTitle(buf); - if (first.sendName) { - sprintf(buf, "name %s\n", gameInfo.white); - SendToProgram(buf, &first); - } - StartClocks(); ++ if(Adjudicate(NULL)) return 1; // [HGM] adjudicate: take care of automtic game end ++ ++if (gameMode == BeginningOfGame) + { + if (appData.noChessProgram) + { + gameMode = EditGame; + SetGameInfo(); + } + else + { + char buf[MSG_SIZ]; + gameMode = MachinePlaysBlack; + StartClocks(); + SetGameInfo(); + sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black); + DisplayTitle(buf); + if (first.sendName) + { + sprintf(buf, "name %s\n", gameInfo.white); + SendToProgram(buf, &first); + } + StartClocks(); + } + ModeHighlight(); ++ } - ModeHighlight(); - } /* Relay move to ICS or chess engine */ - if (appData.icsActive) - { - if (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack || - gameMode == IcsExamining) - { - SendMoveToICS(moveType, fromX, fromY, toX, toY); - ics_user_moved = 1; - } ++ + if (appData.icsActive) { + if (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack || + gameMode == IcsExamining) { + if(userOfferedDraw && (signed char)boards[forwardMostMove][EP_STATUS] <= EP_DRAWS) { + SendToICS(ics_prefix); // [HGM] drawclaim: send caim and move on one line for FICS + SendToICS("draw "); + SendMoveToICS(moveType, fromX, fromY, toX, toY); + } + // also send plain move, in case ICS does not understand atomic claims + SendMoveToICS(moveType, fromX, fromY, toX, toY); + ics_user_moved = 1; + } + } else { + if (first.sendTime && (gameMode == BeginningOfGame || + gameMode == MachinePlaysWhite || + gameMode == MachinePlaysBlack)) { + SendTimeRemaining(&first, gameMode != MachinePlaysBlack); + } + if (gameMode != EditGame && gameMode != PlayFromGameFile) { + // [HGM] book: if program might be playing, let it use book + bookHit = SendMoveToBookUser(forwardMostMove-1, &first, FALSE); + first.maybeThinking = TRUE; + } else SendMoveToProgram(forwardMostMove-1, &first); + if (currentMove == cmailOldMove + 1) { + cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE; } - else - { - if (first.sendTime && (gameMode == BeginningOfGame || - gameMode == MachinePlaysWhite || - gameMode == MachinePlaysBlack)) - { - SendTimeRemaining(&first, gameMode != MachinePlaysBlack); - } - if (gameMode != EditGame && gameMode != PlayFromGameFile) - { - // [HGM] book: if program might be playing, let it use book - bookHit = SendMoveToBookUser(forwardMostMove-1, &first, FALSE); - first.maybeThinking = TRUE; - } - else - SendMoveToProgram(forwardMostMove-1, &first); - if (currentMove == cmailOldMove + 1) - { - cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE; - } - } + } ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ - switch (gameMode) { - case EditGame: - switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) { - case MT_NONE: - case MT_CHECK: + switch (gameMode) + { + case EditGame: + switch (MateTest(boards[currentMove], PosFlags(currentMove)) ) + { + case MT_NONE: + case MT_CHECK: + break; + case MT_CHECKMATE: + case MT_STAINMATE: + if (WhiteOnMove(currentMove)) { + GameEnds(BlackWins, "Black mates", GE_PLAYER); + } else { + GameEnds(WhiteWins, "White mates", GE_PLAYER); + } + break; + case MT_STALEMATE: + GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER); + break; + } break; - case MT_CHECKMATE: - case MT_STAINMATE: - if (WhiteOnMove(currentMove)) { - GameEnds(BlackWins, "Black mates", GE_PLAYER); - } else { - GameEnds(WhiteWins, "White mates", GE_PLAYER); - } + + case MachinePlaysBlack: + case MachinePlaysWhite: + /* disable certain menu options while machine is thinking */ + SetMachineThinkingEnables(); break; - case MT_STALEMATE: - GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER); + + default: break; } - - break; - - case MachinePlaysBlack: - case MachinePlaysWhite: - /* disable certain menu options while machine is thinking */ - SetMachineThinkingEnables(); - break; - - default: - break; - } - + userOfferedDraw = FALSE; // [HGM] drawclaim: after move made, and tested for claimable draw + - if(bookHit) { // [HGM] book: simulate book reply + if(bookHit) + { // [HGM] book: simulate book reply - static char bookMove[MSG_SIZ]; // a bit generous? + static char bookMove[MSG_SIZ]; // a bit generous? + - programStats.nodes = programStats.depth = programStats.time = + + programStats.nodes = programStats.depth = programStats.time = programStats.score = programStats.got_only_move = 0; - sprintf(programStats.movelist, "%s (xbook)", bookHit); + sprintf(programStats.movelist, "%s (xbook)", bookHit); + + strcpy(bookMove, "move "); + strcat(bookMove, bookHit); + HandleMachineMove(bookMove, &first); + } - strcpy(bookMove, "move "); - strcat(bookMove, bookHit); - HandleMachineMove(bookMove, &first); - } return 1; } @@@ -6027,6 -6249,69 +6348,69 @@@ void LeftClick(ClickType clickType, in } } + int RightClick(ClickType action, int x, int y, int *fromX, int *fromY) + { // front-end-free part taken out of PieceMenuPopup + int whichMenu; int xSqr, ySqr; + + if(seekGraphUp) { // [HGM] seekgraph + if(action == Press) SeekGraphClick(Press, x, y, 2); // 2 indicates right-click: no pop-down on miss + if(action == Release) SeekGraphClick(Release, x, y, 2); // and no challenge on hit + return -2; + } + + xSqr = EventToSquare(x, BOARD_WIDTH); + ySqr = EventToSquare(y, BOARD_HEIGHT); + if (action == Release) UnLoadPV(); // [HGM] pv + if (action != Press) return -2; // return code to be ignored + switch (gameMode) { + case IcsExamining: - if(xSqr < BOARD_LEFT || xSqr >= BOARD_RGHT) return -1; ++ if(xSqr < BOARD_LEFT || xSqr >= BOARD_RGHT) return -1; + case EditPosition: - if (xSqr == BOARD_LEFT-1 || xSqr == BOARD_RGHT) return -1; - if (xSqr < 0 || ySqr < 0) return -1; ++ if (xSqr == BOARD_LEFT-1 || xSqr == BOARD_RGHT) return -1; ++ if (xSqr < 0 || ySqr < 0) return -1; + whichMenu = 0; // edit-position menu + break; + case IcsObserving: + if(!appData.icsEngineAnalyze) return -1; + case IcsPlayingWhite: + case IcsPlayingBlack: + if(!appData.zippyPlay) goto noZip; + case AnalyzeMode: + case AnalyzeFile: + case MachinePlaysWhite: + case MachinePlaysBlack: + case TwoMachinesPlay: // [HGM] pv: use for showing PV + if (!appData.dropMenu) { + LoadPV(x, y); + return 2; // flag front-end to grab mouse events + } + if(gameMode == TwoMachinesPlay || gameMode == AnalyzeMode || + gameMode == AnalyzeFile || gameMode == IcsObserving) return -1; + case EditGame: + noZip: + if (xSqr < 0 || ySqr < 0) return -1; + if (!appData.dropMenu || appData.testLegality && + gameInfo.variant != VariantBughouse && + gameInfo.variant != VariantCrazyhouse) return -1; + whichMenu = 1; // drop menu + break; + default: + return -1; + } + + if (((*fromX = xSqr) < 0) || + ((*fromY = ySqr) < 0)) { + *fromX = *fromY = -1; + return -1; + } + if (flipView) + *fromX = BOARD_WIDTH - 1 - *fromX; + else + *fromY = BOARD_HEIGHT - 1 - *fromY; + + return whichMenu; + } + void SendProgramStatsToFrontend( ChessProgramState * cps, ChessProgramStats * cpstats ) { // char * hint = lastHint; @@@ -6053,6 -6338,360 +6437,361 @@@ SetProgramStats( &stats ); } + int + Adjudicate(ChessProgramState *cps) + { // [HGM] some adjudications useful with buggy engines + // [HGM] adjudicate: made into separate routine, which now can be called after every move + // In any case it determnes if the game is a claimable draw (filling in EP_STATUS). + // Actually ending the game is now based on the additional internal condition canAdjudicate. + // Only when the game is ended, and the opponent is a computer, this opponent gets the move relayed. + int k, count = 0; static int bare = 1; + ChessProgramState *engineOpponent = (gameMode == TwoMachinesPlay ? cps->other : (cps ? NULL : &first)); + Boolean canAdjudicate = !appData.icsActive; + + // most tests only when we understand the game, i.e. legality-checking on, and (for the time being) no piece drops + if(gameInfo.holdingsSize == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) { + if( appData.testLegality ) + { /* [HGM] Some more adjudications for obstinate engines */ + int NrWN=0, NrBN=0, NrWB=0, NrBB=0, NrWR=0, NrBR=0, + NrWQ=0, NrBQ=0, NrW=0, NrK=0, bishopsColor = 0, + NrPieces=0, NrPawns=0, PawnAdvance=0, i, j; + static int moveCount = 6; + ChessMove result; + char *reason = NULL; + ++ + /* Count what is on board. */ + for(i=0; i 1 ? WhiteWins : NrPieces - NrW > 1 ? BlackWins : GameIsDrawn, + "Xboard adjudication: Bare king", GE_XBOARD ); + return 1; + } + } + } else bare = 1; + + + // don't wait for engine to announce game end if we can judge ourselves + switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove)) ) { + case MT_CHECK: + if(gameInfo.variant == Variant3Check) { // [HGM] 3check: when in check, test if 3rd time + int i, checkCnt = 0; // (should really be done by making nr of checks part of game state) + for(i=forwardMostMove-2; i>=backwardMostMove; i-=2) { + if(MateTest(boards[i], PosFlags(i)) == MT_CHECK) + checkCnt++; + if(checkCnt >= 2) { + reason = "Xboard adjudication: 3rd check"; + boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; + break; + } + } + } + case MT_NONE: + default: + break; + case MT_STALEMATE: + case MT_STAINMATE: + reason = "Xboard adjudication: Stalemate"; + if((signed char)boards[forwardMostMove][EP_STATUS] != EP_CHECKMATE) { // [HGM] don't touch win through baring or K-capt + boards[forwardMostMove][EP_STATUS] = EP_STALEMATE; // default result for stalemate is draw + if(gameInfo.variant == VariantLosers || gameInfo.variant == VariantGiveaway) // [HGM] losers: + boards[forwardMostMove][EP_STATUS] = EP_WINS; // in these variants stalemated is always a win + else if(gameInfo.variant == VariantSuicide) // in suicide it depends + boards[forwardMostMove][EP_STATUS] = NrW == NrPieces-NrW ? EP_STALEMATE : + ((NrW < NrPieces-NrW) != WhiteOnMove(forwardMostMove) ? + EP_CHECKMATE : EP_WINS); + else if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi) + boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; // and in these variants being stalemated loses + } + break; + case MT_CHECKMATE: + reason = "Xboard adjudication: Checkmate"; + boards[forwardMostMove][EP_STATUS] = (gameInfo.variant == VariantLosers ? EP_WINS : EP_CHECKMATE); + break; + } + + switch(i = (signed char)boards[forwardMostMove][EP_STATUS]) { + case EP_STALEMATE: + result = GameIsDrawn; break; + case EP_CHECKMATE: + result = WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins; break; + case EP_WINS: + result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; break; + default: + result = (ChessMove) 0; + } + if(canAdjudicate && appData.checkMates && result) { // [HGM] mates: adjudicate finished games if requested + if(engineOpponent) + SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */ + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( result, reason, GE_XBOARD ); + return 1; + } + + /* Next absolutely insufficient mating material. */ + if( NrPieces == 2 || gameInfo.variant != VariantXiangqi && + gameInfo.variant != VariantShatranj && // [HGM] baring will remain possible + (NrPieces == 3 && NrWN+NrBN+NrWB+NrBB == 1 || + NrPieces == NrBB+NrWB+2 && bishopsColor != 3)) // [HGM] all Bishops (Ferz!) same color + { /* KBK, KNK, KK of KBKB with like Bishops */ + + /* always flag draws, for judging claims */ + boards[forwardMostMove][EP_STATUS] = EP_INSUF_DRAW; + + if(canAdjudicate && appData.materialDraws) { + /* but only adjudicate them if adjudication enabled */ + if(engineOpponent) { + SendToProgram("force\n", engineOpponent); // suppress reply + SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see last move */ + } + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( GameIsDrawn, "Xboard adjudication: Insufficient mating material", GE_XBOARD ); + return 1; + } + } + + /* Then some trivial draws (only adjudicate, cannot be claimed) */ + if(NrPieces == 4 && + ( NrWR == 1 && NrBR == 1 /* KRKR */ + || NrWQ==1 && NrBQ==1 /* KQKQ */ + || NrWN==2 || NrBN==2 /* KNNK */ + || NrWN+NrWB == 1 && NrBN+NrBB == 1 /* KBKN, KBKB, KNKN */ + ) ) { + if(canAdjudicate && --moveCount < 0 && appData.trivialDraws) + { /* if the first 3 moves do not show a tactical win, declare draw */ + if(engineOpponent) { + SendToProgram("force\n", engineOpponent); // suppress reply + SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */ + } + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( GameIsDrawn, "Xboard adjudication: Trivial draw", GE_XBOARD ); + return 1; + } + } else moveCount = 6; + } + } + + if (appData.debugMode) { int i; + fprintf(debugFP, "repeat test fmm=%d bmm=%d ep=%d, reps=%d\n", + forwardMostMove, backwardMostMove, boards[backwardMostMove][EP_STATUS], + appData.drawRepeats); + for( i=forwardMostMove; i>=backwardMostMove; i-- ) + fprintf(debugFP, "%d ep=%d\n", i, (signed char)boards[i][EP_STATUS]); + + } + + // Repetition draws and 50-move rule can be applied independently of legality testing + + /* Check for rep-draws */ + count = 0; + for(k = forwardMostMove-2; + k>=backwardMostMove && k>=forwardMostMove-100 && + (signed char)boards[k][EP_STATUS] < EP_UNKNOWN && + (signed char)boards[k+2][EP_STATUS] <= EP_NONE && (signed char)boards[k+1][EP_STATUS] <= EP_NONE; + k-=2) + { int rights=0; + if(CompareBoards(boards[k], boards[forwardMostMove])) { + /* compare castling rights */ + if( boards[forwardMostMove][CASTLING][2] != boards[k][CASTLING][2] && + (boards[k][CASTLING][0] != NoRights || boards[k][CASTLING][1] != NoRights) ) + rights++; /* King lost rights, while rook still had them */ + if( boards[forwardMostMove][CASTLING][2] != NoRights ) { /* king has rights */ + if( boards[forwardMostMove][CASTLING][0] != boards[k][CASTLING][0] || + boards[forwardMostMove][CASTLING][1] != boards[k][CASTLING][1] ) + rights++; /* but at least one rook lost them */ + } + if( boards[forwardMostMove][CASTLING][5] != boards[k][CASTLING][5] && + (boards[k][CASTLING][3] != NoRights || boards[k][CASTLING][4] != NoRights) ) + rights++; + if( boards[forwardMostMove][CASTLING][5] != NoRights ) { + if( boards[forwardMostMove][CASTLING][3] != boards[k][CASTLING][3] || + boards[forwardMostMove][CASTLING][4] != boards[k][CASTLING][4] ) + rights++; + } + if( canAdjudicate && rights == 0 && ++count > appData.drawRepeats-2 + && appData.drawRepeats > 1) { + /* adjudicate after user-specified nr of repeats */ + if(engineOpponent) { + SendToProgram("force\n", engineOpponent); // suppress reply + SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */ + } + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + if(gameInfo.variant == VariantXiangqi && appData.testLegality) { + // [HGM] xiangqi: check for forbidden perpetuals + int m, ourPerpetual = 1, hisPerpetual = 1; + for(m=forwardMostMove; m>k; m-=2) { + if(MateTest(boards[m], PosFlags(m)) != MT_CHECK) + ourPerpetual = 0; // the current mover did not always check + if(MateTest(boards[m-1], PosFlags(m-1)) != MT_CHECK) + hisPerpetual = 0; // the opponent did not always check + } + if(appData.debugMode) fprintf(debugFP, "XQ perpetual test, our=%d, his=%d\n", + ourPerpetual, hisPerpetual); + if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit + GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, + "Xboard adjudication: perpetual checking", GE_XBOARD ); + return 1; + } + if(hisPerpetual && !ourPerpetual) // he is checking us, but did not repeat yet + break; // (or we would have caught him before). Abort repetition-checking loop. + // Now check for perpetual chases + if(!ourPerpetual && !hisPerpetual) { // no perpetual check, test for chase + hisPerpetual = PerpetualChase(k, forwardMostMove); + ourPerpetual = PerpetualChase(k+1, forwardMostMove); + if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit + GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, + "Xboard adjudication: perpetual chasing", GE_XBOARD ); + return 1; + } + if(hisPerpetual && !ourPerpetual) // he is chasing us, but did not repeat yet + break; // Abort repetition-checking loop. + } + // if neither of us is checking or chasing all the time, or both are, it is draw + } + GameEnds( GameIsDrawn, "Xboard adjudication: repetition draw", GE_XBOARD ); + return 1; + } + if( rights == 0 && count > 1 ) /* occurred 2 or more times before */ + boards[forwardMostMove][EP_STATUS] = EP_REP_DRAW; + } + } + + /* Now we test for 50-move draws. Determine ply count */ + count = forwardMostMove; + /* look for last irreversble move */ + while( (signed char)boards[count][EP_STATUS] <= EP_NONE && count > backwardMostMove ) + count--; + /* if we hit starting position, add initial plies */ + if( count == backwardMostMove ) + count -= initialRulePlies; + count = forwardMostMove - count; + if( count >= 100) + boards[forwardMostMove][EP_STATUS] = EP_RULE_DRAW; + /* this is used to judge if draw claims are legal */ + if(canAdjudicate && appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) { + if(engineOpponent) { + SendToProgram("force\n", engineOpponent); // suppress reply + SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */ + } + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( GameIsDrawn, "Xboard adjudication: 50-move rule", GE_XBOARD ); + return 1; + } + + /* if draw offer is pending, treat it as a draw claim + * when draw condition present, to allow engines a way to + * claim draws before making their move to avoid a race + * condition occurring after their move + */ + if((gameMode == TwoMachinesPlay ? second.offeredDraw : userOfferedDraw) || first.offeredDraw ) { + char *p = NULL; + if((signed char)boards[forwardMostMove][EP_STATUS] == EP_RULE_DRAW) + p = "Draw claim: 50-move rule"; + if((signed char)boards[forwardMostMove][EP_STATUS] == EP_REP_DRAW) + p = "Draw claim: 3-fold repetition"; + if((signed char)boards[forwardMostMove][EP_STATUS] == EP_INSUF_DRAW) + p = "Draw claim: insufficient mating material"; + if( p != NULL && canAdjudicate) { + if(engineOpponent) { + SendToProgram("force\n", engineOpponent); // suppress reply + SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */ + } + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( GameIsDrawn, p, GE_XBOARD ); + return 1; + } + } + + if( canAdjudicate && appData.adjudicateDrawMoves > 0 && forwardMostMove > (2*appData.adjudicateDrawMoves) ) { + if(engineOpponent) { + SendToProgram("force\n", engineOpponent); // suppress reply + SendMoveToProgram(forwardMostMove-1, engineOpponent); /* make sure opponent gets to see move */ + } + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( GameIsDrawn, "Xboard adjudication: long game", GE_XBOARD ); + return 1; + } + return 0; + } + char *SendMoveToBookUser(int moveNr, ChessProgramState *cps, int initial) { // [HGM] book: this routine intercepts moves to simulate book replies char *bookHit = NULL; @@@ -6233,453 -6872,130 +6972,534 @@@ FakeBookMove: // [HGM] book: we jump he if (gameMode == TwoMachinesPlay) { GameEnds(machineWhite ? BlackWins : WhiteWins, buf1, GE_XBOARD); ++<<<<<<< HEAD + } + return; + } + + /* [HGM] Apparently legal, but so far only tested with EP_UNKOWN */ + /* So we have to redo legality test with true e.p. status here, */ + /* to make sure an illegal e.p. capture does not slip through, */ + /* to cause a forfeit on a justified illegal-move complaint */ + /* of the opponent. */ + if( gameMode==TwoMachinesPlay && appData.testLegality + && fromY != DROP_RANK /* [HGM] temporary; should still add legality test for drops */ + ) { + ChessMove moveType; + moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove), + fromY, fromX, toY, toX, promoChar); + if (appData.debugMode) { + int i; + for(i=0; i< nrCastlingRights; i++) fprintf(debugFP, "(%d,%d) ", + boards[forwardMostMove][CASTLING][i], castlingRank[i]); + fprintf(debugFP, "castling rights\n"); + } + if(moveType == IllegalMove) { + sprintf(buf1, "Xboard: Forfeit due to illegal move: %s (%c%c%c%c)%c", + machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0); + GameEnds(machineWhite ? BlackWins : WhiteWins, + buf1, GE_XBOARD); + return; + } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom) + /* [HGM] Kludge to handle engines that send FRC-style castling + when they shouldn't (like TSCP-Gothic) */ + switch(moveType) { + case WhiteASideCastleFR: + case BlackASideCastleFR: + toX+=2; + currentMoveString[2]++; + break; + case WhiteHSideCastleFR: + case BlackHSideCastleFR: + toX--; + currentMoveString[2]--; + break; + default: ; // nothing to do, but suppresses warning of pedantic compilers + } + } + hintRequested = FALSE; + lastHint[0] = NULLCHAR; + bookRequested = FALSE; + /* Program may be pondering now */ + cps->maybeThinking = TRUE; + if (cps->sendTime == 2) cps->sendTime = 1; + if (cps->offeredDraw) cps->offeredDraw--; + +#if ZIPPY + if ((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) && + first.initDone) { + SendMoveToICS(moveType, fromX, fromY, toX, toY); + ics_user_moved = 1; + if(appData.autoKibitz && !appData.icsEngineAnalyze ) { /* [HGM] kibitz: send most-recent PV info to ICS */ + char buf[3*MSG_SIZ]; + + sprintf(buf, "kibitz !!! %+.2f/%d (%.2f sec, %u nodes, %.0f knps) PV=%s\n", + programStats.score / 100., + programStats.depth, + programStats.time / 100., + (unsigned int)programStats.nodes, + (unsigned int)programStats.nodes / (10*abs(programStats.time) + 1.), + programStats.movelist); + SendToICS(buf); +if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.nodes, programStats.nodes); + } + } +#endif + /* currentMoveString is set as a side-effect of ParseOneMove */ + strcpy(machineMove, currentMoveString); + strcat(machineMove, "\n"); + strcpy(moveList[forwardMostMove], machineMove); + + /* [AS] Save move info and clear stats for next move */ + pvInfoList[ forwardMostMove ].score = programStats.score; + pvInfoList[ forwardMostMove ].depth = programStats.depth; + pvInfoList[ forwardMostMove ].time = programStats.time; // [HGM] PGNtime: take time from engine stats + ClearProgramStats(); + thinkOutput[0] = NULLCHAR; + hiddenThinkOutputState = 0; + + MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/ + + /* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */ + if( gameMode == TwoMachinesPlay && adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) { + int count = 0; + + while( count < adjudicateLossPlies ) { + int score = pvInfoList[ forwardMostMove - count - 1 ].score; + + if( count & 1 ) { + score = -score; /* Flip score for winning side */ + } + + if( score > adjudicateLossThreshold ) { + break; + } + + count++; + } + + if( count >= adjudicateLossPlies ) { + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + + GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, + "Xboard adjudication", + GE_XBOARD ); + + return; + } + } + + if( gameMode == TwoMachinesPlay ) { + // [HGM] some adjudications useful with buggy engines + int k, count = 0; static int bare = 1; + if(gameInfo.holdingsSize == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) { + + + if( appData.testLegality ) + { /* [HGM] Some more adjudications for obstinate engines */ + int NrWN=0, NrBN=0, NrWB=0, NrBB=0, NrWR=0, NrBR=0, + NrWQ=0, NrBQ=0, NrW=0, NrK=0, bishopsColor = 0, + NrPieces=0, NrPawns=0, PawnAdvance=0, i, j; + static int moveCount = 6; + ChessMove result; + char *reason = NULL; + + /* Count what is on board. */ + for(i=0; iother); // make sure opponent gets move + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins, + "Xboard adjudication: King destroyed", GE_XBOARD ); + return; + } + } + + /* Bare King in Shatranj (loses) or Losers (wins) */ + if( NrW == 1 || NrPieces - NrW == 1) { + if( gameInfo.variant == VariantLosers) { // [HGM] losers: bare King wins (stm must have it first) + boards[forwardMostMove][EP_STATUS] = EP_WINS; // mark as win, so it becomes claimable + if(appData.checkMates) { + SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets to see move + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, + "Xboard adjudication: Bare king", GE_XBOARD ); + return; + } + } else + if( gameInfo.variant == VariantShatranj && --bare < 0) + { /* bare King */ + boards[forwardMostMove][EP_STATUS] = EP_WINS; // make claimable as win for stm + if(appData.checkMates) { + /* but only adjudicate if adjudication enabled */ + SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets move + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( NrW > 1 ? WhiteWins : NrPieces - NrW > 1 ? BlackWins : GameIsDrawn, + "Xboard adjudication: Bare king", GE_XBOARD ); + return; + } + } + } else bare = 1; + + + // don't wait for engine to announce game end if we can judge ourselves + switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove)) ) { + case MT_CHECK: + if(gameInfo.variant == Variant3Check) { // [HGM] 3check: when in check, test if 3rd time + int i, checkCnt = 0; // (should really be done by making nr of checks part of game state) + for(i=forwardMostMove-2; i>=backwardMostMove; i-=2) { + if(MateTest(boards[i], PosFlags(i)) == MT_CHECK) + checkCnt++; + if(checkCnt >= 2) { + reason = "Xboard adjudication: 3rd check"; + boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; + break; + } + } + } + case MT_NONE: + default: + break; + case MT_STALEMATE: + case MT_STAINMATE: + reason = "Xboard adjudication: Stalemate"; + if((signed char)boards[forwardMostMove][EP_STATUS] != EP_CHECKMATE) { // [HGM] don't touch win through baring or K-capt + boards[forwardMostMove][EP_STATUS] = EP_STALEMATE; // default result for stalemate is draw + if(gameInfo.variant == VariantLosers || gameInfo.variant == VariantGiveaway) // [HGM] losers: + boards[forwardMostMove][EP_STATUS] = EP_WINS; // in these variants stalemated is always a win + else if(gameInfo.variant == VariantSuicide) // in suicide it depends + boards[forwardMostMove][EP_STATUS] = NrW == NrPieces-NrW ? EP_STALEMATE : + ((NrW < NrPieces-NrW) != WhiteOnMove(forwardMostMove) ? + EP_CHECKMATE : EP_WINS); + else if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi) + boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; // and in these variants being stalemated loses + } + break; + case MT_CHECKMATE: + reason = "Xboard adjudication: Checkmate"; + boards[forwardMostMove][EP_STATUS] = (gameInfo.variant == VariantLosers ? EP_WINS : EP_CHECKMATE); + break; ++======= ++>>>>>>> master } + return; + } ++<<<<<<< HEAD + switch(i = (signed char)boards[forwardMostMove][EP_STATUS]) { + case EP_STALEMATE: + result = GameIsDrawn; break; + case EP_CHECKMATE: + result = WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins; break; + case EP_WINS: + result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; break; + default: + result = (ChessMove) 0; + } + if(appData.checkMates && result) { // [HGM] mates: adjudicate finished games if requested + SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( result, reason, GE_XBOARD ); + return; + } + + /* Next absolutely insufficient mating material. */ + if( NrPieces == 2 || gameInfo.variant != VariantXiangqi && + gameInfo.variant != VariantShatranj && // [HGM] baring will remain possible + (NrPieces == 3 && NrWN+NrBN+NrWB+NrBB == 1 || + NrPieces == NrBB+NrWB+2 && bishopsColor != 3)) // [HGM] all Bishops (Ferz!) same color + { /* KBK, KNK, KK of KBKB with like Bishops */ ++======= + /* [HGM] Apparently legal, but so far only tested with EP_UNKOWN */ + /* So we have to redo legality test with true e.p. status here, */ + /* to make sure an illegal e.p. capture does not slip through, */ + /* to cause a forfeit on a justified illegal-move complaint */ + /* of the opponent. */ + if( gameMode==TwoMachinesPlay && appData.testLegality + && fromY != DROP_RANK /* [HGM] temporary; should still add legality test for drops */ + ) { + ChessMove moveType; + moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove), + fromY, fromX, toY, toX, promoChar); + if (appData.debugMode) { + int i; + for(i=0; i< nrCastlingRights; i++) fprintf(debugFP, "(%d,%d) ", + boards[forwardMostMove][CASTLING][i], castlingRank[i]); + fprintf(debugFP, "castling rights\n"); + } + if(moveType == IllegalMove) { + sprintf(buf1, "Xboard: Forfeit due to illegal move: %s (%c%c%c%c)%c", + machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0); + GameEnds(machineWhite ? BlackWins : WhiteWins, + buf1, GE_XBOARD); + return; + } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom) + /* [HGM] Kludge to handle engines that send FRC-style castling + when they shouldn't (like TSCP-Gothic) */ + switch(moveType) { + case WhiteASideCastleFR: + case BlackASideCastleFR: + toX+=2; + currentMoveString[2]++; + break; + case WhiteHSideCastleFR: + case BlackHSideCastleFR: + toX--; + currentMoveString[2]--; + break; + default: ; // nothing to do, but suppresses warning of pedantic compilers + } + } + hintRequested = FALSE; + lastHint[0] = NULLCHAR; + bookRequested = FALSE; + /* Program may be pondering now */ + cps->maybeThinking = TRUE; + if (cps->sendTime == 2) cps->sendTime = 1; + if (cps->offeredDraw) cps->offeredDraw--; ++>>>>>>> master - /* always flag draws, for judging claims */ - boards[forwardMostMove][EP_STATUS] = EP_INSUF_DRAW; + /* currentMoveString is set as a side-effect of ParseOneMove */ + strcpy(machineMove, currentMoveString); + strcat(machineMove, "\n"); + strcpy(moveList[forwardMostMove], machineMove); - if(appData.materialDraws) { - /* but only adjudicate them if adjudication enabled */ - SendToProgram("force\n", cps->other); // suppress reply - SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see last move */ - ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ - GameEnds( GameIsDrawn, "Xboard adjudication: Insufficient mating material", GE_XBOARD ); - return; - } - } + MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/ ++<<<<<<< HEAD + /* Then some trivial draws (only adjudicate, cannot be claimed) */ + if(NrPieces == 4 && + ( NrWR == 1 && NrBR == 1 /* KRKR */ + || NrWQ==1 && NrBQ==1 /* KQKQ */ + || NrWN==2 || NrBN==2 /* KNNK */ + || NrWN+NrWB == 1 && NrBN+NrBB == 1 /* KBKN, KBKB, KNKN */ + ) ) { + if(--moveCount < 0 && appData.trivialDraws) + { /* if the first 3 moves do not show a tactical win, declare draw */ + SendToProgram("force\n", cps->other); // suppress reply + SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( GameIsDrawn, "Xboard adjudication: Trivial draw", GE_XBOARD ); + return; + } + } else moveCount = 6; + } + } + + if (appData.debugMode) { int i; + fprintf(debugFP, "repeat test fmm=%d bmm=%d ep=%d, reps=%d\n", + forwardMostMove, backwardMostMove, boards[backwardMostMove][EP_STATUS], + appData.drawRepeats); + for( i=forwardMostMove; i>=backwardMostMove; i-- ) + fprintf(debugFP, "%d ep=%d\n", i, (signed char)boards[i][EP_STATUS]); + + } + + /* Check for rep-draws */ + count = 0; + for(k = forwardMostMove-2; + k>=backwardMostMove && k>=forwardMostMove-100 && + (signed char)boards[k][EP_STATUS] < EP_UNKNOWN && + (signed char)boards[k+2][EP_STATUS] <= EP_NONE && (signed char)boards[k+1][EP_STATUS] <= EP_NONE; + k-=2) + { int rights=0; + if(CompareBoards(boards[k], boards[forwardMostMove])) { + /* compare castling rights */ + if( boards[forwardMostMove][CASTLING][2] != boards[k][CASTLING][2] && + (boards[k][CASTLING][0] != NoRights || boards[k][CASTLING][1] != NoRights) ) + rights++; /* King lost rights, while rook still had them */ + if( boards[forwardMostMove][CASTLING][2] != NoRights ) { /* king has rights */ + if( boards[forwardMostMove][CASTLING][0] != boards[k][CASTLING][0] || + boards[forwardMostMove][CASTLING][1] != boards[k][CASTLING][1] ) + rights++; /* but at least one rook lost them */ + } + if( boards[forwardMostMove][CASTLING][5] != boards[k][CASTLING][5] && + (boards[k][CASTLING][3] != NoRights || boards[k][CASTLING][4] != NoRights) ) + rights++; + if( boards[forwardMostMove][CASTLING][5] != NoRights ) { + if( boards[forwardMostMove][CASTLING][3] != boards[k][CASTLING][3] || + boards[forwardMostMove][CASTLING][4] != boards[k][CASTLING][4] ) + rights++; + } + if( rights == 0 && ++count > appData.drawRepeats-2 + && appData.drawRepeats > 1) { + /* adjudicate after user-specified nr of repeats */ + SendToProgram("force\n", cps->other); // suppress reply + SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + if(gameInfo.variant == VariantXiangqi && appData.testLegality) { + // [HGM] xiangqi: check for forbidden perpetuals + int m, ourPerpetual = 1, hisPerpetual = 1; + for(m=forwardMostMove; m>k; m-=2) { + if(MateTest(boards[m], PosFlags(m)) != MT_CHECK) + ourPerpetual = 0; // the current mover did not always check + if(MateTest(boards[m-1], PosFlags(m-1)) != MT_CHECK) + hisPerpetual = 0; // the opponent did not always check + } + if(appData.debugMode) fprintf(debugFP, "XQ perpetual test, our=%d, his=%d\n", + ourPerpetual, hisPerpetual); + if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit + GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, + "Xboard adjudication: perpetual checking", GE_XBOARD ); + return; + } + if(hisPerpetual && !ourPerpetual) // he is checking us, but did not repeat yet + break; // (or we would have caught him before). Abort repetition-checking loop. + // Now check for perpetual chases + if(!ourPerpetual && !hisPerpetual) { // no perpetual check, test for chase + hisPerpetual = PerpetualChase(k, forwardMostMove); + ourPerpetual = PerpetualChase(k+1, forwardMostMove); + if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit + GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, + "Xboard adjudication: perpetual chasing", GE_XBOARD ); + return; + } + if(hisPerpetual && !ourPerpetual) // he is chasing us, but did not repeat yet + break; // Abort repetition-checking loop. + } + // if neither of us is checking or chasing all the time, or both are, it is draw + } + GameEnds( GameIsDrawn, "Xboard adjudication: repetition draw", GE_XBOARD ); + return; + } + if( rights == 0 && count > 1 ) /* occurred 2 or more times before */ + boards[forwardMostMove][EP_STATUS] = EP_REP_DRAW; + } + } + + /* Now we test for 50-move draws. Determine ply count */ + count = forwardMostMove; + /* look for last irreversble move */ + while( (signed char)boards[count][EP_STATUS] <= EP_NONE && count > backwardMostMove ) + count--; + /* if we hit starting position, add initial plies */ + if( count == backwardMostMove ) + count -= initialRulePlies; + count = forwardMostMove - count; + if( count >= 100) + boards[forwardMostMove][EP_STATUS] = EP_RULE_DRAW; + /* this is used to judge if draw claims are legal */ + if(appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) { + SendToProgram("force\n", cps->other); // suppress reply + SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + GameEnds( GameIsDrawn, "Xboard adjudication: 50-move rule", GE_XBOARD ); + return; ++======= + /* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */ + if( gameMode == TwoMachinesPlay && adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) { + int count = 0; + + while( count < adjudicateLossPlies ) { + int score = pvInfoList[ forwardMostMove - count - 1 ].score; + + if( count & 1 ) { + score = -score; /* Flip score for winning side */ ++>>>>>>> master } - /* if draw offer is pending, treat it as a draw claim - * when draw condition present, to allow engines a way to - * claim draws before making their move to avoid a race - * condition occurring after their move - */ - if( cps->other->offeredDraw || cps->offeredDraw ) { - char *p = NULL; - if((signed char)boards[forwardMostMove][EP_STATUS] == EP_RULE_DRAW) - p = "Draw claim: 50-move rule"; - if((signed char)boards[forwardMostMove][EP_STATUS] == EP_REP_DRAW) - p = "Draw claim: 3-fold repetition"; - if((signed char)boards[forwardMostMove][EP_STATUS] == EP_INSUF_DRAW) - p = "Draw claim: insufficient mating material"; - if( p != NULL ) { - SendToProgram("force\n", cps->other); // suppress reply - SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ - GameEnds( GameIsDrawn, p, GE_XBOARD ); - ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ - return; - } + if( score > adjudicateLossThreshold ) { + break; } + count++; + } - if( appData.adjudicateDrawMoves > 0 && forwardMostMove > (2*appData.adjudicateDrawMoves) ) { - SendToProgram("force\n", cps->other); // suppress reply - SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ - ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + if( count >= adjudicateLossPlies ) { + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ - GameEnds( GameIsDrawn, "Xboard adjudication: long game", GE_XBOARD ); + GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, + "Xboard adjudication", + GE_XBOARD ); - return; - } + return; + } } + if(Adjudicate(cps)) return; // [HGM] adjudicate: for all automatic game ends + + #if ZIPPY + if ((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) && + first.initDone) { + if(cps->offeredDraw && (signed char)boards[forwardMostMove][EP_STATUS] <= EP_DRAWS) { + SendToICS(ics_prefix); // [HGM] drawclaim: send caim and move on one line for FICS + SendToICS("draw "); + SendMoveToICS(moveType, fromX, fromY, toX, toY); + } + SendMoveToICS(moveType, fromX, fromY, toX, toY); + ics_user_moved = 1; + if(appData.autoKibitz && !appData.icsEngineAnalyze ) { /* [HGM] kibitz: send most-recent PV info to ICS */ + char buf[3*MSG_SIZ]; + + sprintf(buf, "kibitz !!! %+.2f/%d (%.2f sec, %u nodes, %.0f knps) PV=%s\n", + programStats.score / 100., + programStats.depth, + programStats.time / 100., + (unsigned int)programStats.nodes, + (unsigned int)programStats.nodes / (10*abs(programStats.time) + 1.), + programStats.movelist); + SendToICS(buf); + if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.nodes, programStats.nodes); + } + } + #endif + + /* [AS] Save move info and clear stats for next move */ + pvInfoList[ forwardMostMove-1 ].score = programStats.score; + pvInfoList[ forwardMostMove-1 ].depth = programStats.depth; + pvInfoList[ forwardMostMove-1 ].time = programStats.time; // [HGM] PGNtime: take time from engine stats + ClearProgramStats(); + thinkOutput[0] = NULLCHAR; + hiddenThinkOutputState = 0; + bookHit = NULL; if (gameMode == TwoMachinesPlay) { /* [HGM] relaying draw offers moved to after reception of move */ @@@ -11892,9 -12169,10 +12712,10 @@@ DrawEvent( your clock. Currently ICS doesn't let you do that; instead, you immediately punch your clock after making a move, but you can offer a draw at any time. */ - + SendToICS(ics_prefix); SendToICS("draw\n"); + userOfferedDraw = TRUE; // [HGM] drawclaim: also set flag in ICS play } else if (cmailMsgLoaded) { if (currentMove == cmailOldMove && commentList[cmailOldMove] != NULL && diff --cc configure.ac index e35bd66,d8c1554..a6d0664 --- a/configure.ac +++ b/configure.ac @@@ -28,7 -28,7 +28,8 @@@ dnl| to regenerate configure. Then sub dnl| the standard version of xboard. dnl| define second argument as VERSION.PATCHLEVEL. e.g. 4.4.0j -AC_INIT([xboard],[master-20100118],[bug-xboard@gnu.org]) +AC_INIT([xboard],[gtk-20100118],[bug-xboard@gnu.org]) ++ AM_INIT_AUTOMAKE AC_CONFIG_HEADERS([config.h]) diff --cc xboard.c index 343e0e6,6233629..4048069 --- a/xboard.c +++ b/xboard.c @@@ -1,4 -1,4 +1,4 @@@ --/* ++Xg/* * xboard.c -- X front end for XBoard * * Copyright 1991 by Digital Equipment Corporation, Maynard, @@@ -662,35 -666,36 +664,36 @@@ MenuItem optionsMenu[] = {N_("Engine #1 Settings ..."), FirstSettingsProc}, {N_("Engine #2 Settings ..."), SecondSettingsProc}, {N_("Time Control ..."), TimeControlProc}, + {N_("Game List ..."), GameListOptionsPopUp}, {"----", NothingProc}, - {N_("Always Queen"), AlwaysQueenProc}, - {N_("Animate Dragging"), AnimateDraggingProc}, - {N_("Animate Moving"), AnimateMovingProc}, - {N_("Auto Comment"), AutocommProc}, - {N_("Auto Flag"), AutoflagProc}, - {N_("Auto Flip View"), AutoflipProc}, - {N_("Auto Observe"), AutobsProc}, - {N_("Auto Raise Board"), AutoraiseProc}, - {N_("Auto Save"), AutosaveProc}, - {N_("Blindfold"), BlindfoldProc}, - {N_("Flash Moves"), FlashMovesProc}, - {N_("Get Move List"), GetMoveListProc}, -#if HIGHDRAG - {N_("Highlight Dragging"), HighlightDraggingProc}, -#endif - {N_("Highlight Last Move"), HighlightLastMoveProc}, - {N_("Move Sound"), MoveSoundProc}, - {N_("ICS Alarm"), IcsAlarmProc}, - {N_("Old Save Style"), OldSaveStyleProc}, - {N_("Periodic Updates"), PeriodicUpdatesProc}, - {N_("Ponder Next Move"), PonderNextMoveProc}, - {N_("Popup Exit Message"), PopupExitMessageProc}, - {N_("Popup Move Errors"), PopupMoveErrorsProc}, - {N_("Premove"), PremoveProc}, - {N_("Quiet Play"), QuietPlayProc}, - {N_("Show Coords"), ShowCoordsProc}, - {N_("Hide Thinking"), HideThinkingProc}, - {N_("Test Legality"), TestLegalityProc}, + // {N_("Always Queen"), AlwaysQueenProc}, + // {N_("Animate Dragging"), AnimateDraggingProc}, + // {N_("Animate Moving"), AnimateMovingProc}, + // {N_("Auto Comment"), AutocommProc}, + // {N_("Auto Flag"), AutoflagProc}, + // {N_("Auto Flip View"), AutoflipProc}, + // {N_("Auto Observe"), AutobsProc}, + // {N_("Auto Raise Board"), AutoraiseProc}, + // {N_("Auto Save"), AutosaveProc}, + // {N_("Blindfold"), BlindfoldProc}, + // {N_("Flash Moves"), FlashMovesProc}, + // {N_("Get Move List"), GetMoveListProc}, + //#if HIGHDRAG + // {N_("Highlight Dragging"), HighlightDraggingProc}, + //#endif + // {N_("Highlight Last Move"), HighlightLastMoveProc}, + // {N_("Move Sound"), MoveSoundProc}, + // {N_("ICS Alarm"), IcsAlarmProc}, + // {N_("Old Save Style"), OldSaveStyleProc}, + // {N_("Periodic Updates"), PeriodicUpdatesProc}, + // {N_("Ponder Next Move"), PonderNextMoveProc}, + // {N_("Popup Exit Message"), PopupExitMessageProc}, + // {N_("Popup Move Errors"), PopupMoveErrorsProc}, + // {N_("Premove"), PremoveProc}, + // {N_("Quiet Play"), QuietPlayProc}, + // {N_("Hide Thinking"), HideThinkingProc}, + // {N_("Test Legality"), TestLegalityProc}, + // {N_("Show Coords"), ShowCoordsProc}, {"----", NothingProc}, {N_("Save Settings Now"), SaveSettingsProc}, {N_("Save Settings on Exit"), SaveOnExitProc}, @@@ -781,14 -844,21 +784,23 @@@ XtActionsRec boardActions[] = { "AskQuestionProc", AskQuestionProc }, { "AskQuestionReplyAction", AskQuestionReplyAction }, { "PieceMenuPopup", PieceMenuPopup }, - { "WhiteClock", WhiteClock }, - { "BlackClock", BlackClock }, + // { "WhiteClock", WhiteClock }, + // { "BlackClock", BlackClock }, { "Iconify", Iconify }, - { "ResetProc", ResetProc }, - { "LoadGameProc", LoadGameProc }, - { "LoadNextGameProc", LoadNextGameProc }, - { "LoadPrevGameProc", LoadPrevGameProc }, { "LoadSelectedProc", LoadSelectedProc }, ++<<<<<<< HEAD + // { "LoadPositionProc", LoadPositionProc }, + // { "LoadNextPositionProc", LoadNextPositionProc }, + // { "LoadPrevPositionProc", LoadPrevPositionProc }, + // { "ReloadPositionProc", ReloadPositionProc }, ++======= + { "SetFilterProc", SetFilterProc }, + { "ReloadGameProc", ReloadGameProc }, + { "LoadPositionProc", LoadPositionProc }, + { "LoadNextPositionProc", LoadNextPositionProc }, + { "LoadPrevPositionProc", LoadPrevPositionProc }, + { "ReloadPositionProc", ReloadPositionProc }, ++>>>>>>> master { "CopyPositionProc", CopyPositionProc }, { "PastePositionProc", PastePositionProc }, { "CopyGameProc", CopyGameProc }, @@@ -878,11 -952,12 +890,12 @@@ { "TagsPopDown", (XtActionProc) TagsPopDown }, { "ErrorPopDown", (XtActionProc) ErrorPopDown }, { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown }, - { "FileNamePopDown", (XtActionProc) FileNamePopDown }, + // { "FileNamePopDown", (XtActionProc) FileNamePopDown }, { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown }, { "GameListPopDown", (XtActionProc) GameListPopDown }, + { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown }, { "PromotionPopDown", (XtActionProc) PromotionPopDown }, - { "HistoryPopDown", (XtActionProc) HistoryPopDown }, + // { "HistoryPopDown", (XtActionProc) HistoryPopDown }, { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown }, { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown }, { "ShufflePopDown", (XtActionProc) ShufflePopDown }, @@@ -1871,6 -2458,35 +1907,20 @@@ main(argc, argv if (appData.animate || appData.animateDragging) CreateAnimVars(); - XtAugmentTranslations(formWidget, - XtParseTranslationTable(globalTranslations)); - XtAugmentTranslations(boardWidget, - XtParseTranslationTable(boardTranslations)); - XtAugmentTranslations(whiteTimerWidget, - XtParseTranslationTable(whiteTranslations)); - XtAugmentTranslations(blackTimerWidget, - XtParseTranslationTable(blackTranslations)); - - /* Why is the following needed on some versions of X instead - * of a translation? */ - XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False, - (XtEventHandler) EventProc, NULL); - /* end why */ - + /* [AS] Restore layout */ + if( wpMoveHistory.visible ) { + HistoryPopUp(); + } + + if( wpEvalGraph.visible ) + { + EvalGraphPopUp(); + }; + + if( wpEngineOutput.visible ) { + EngineOutputPopUp(); + } + InitBackEnd2(); if (errorExitStatus == -1) { @@@ -2589,28 -3829,26 +2603,33 @@@ voi SetHighlights(fromX, fromY, toX, toY) int fromX, fromY, toX, toY; { - if (hi1X != fromX || hi1Y != fromY) { - if (hi1X >= 0 && hi1Y >= 0) { - drawHighlight(hi1X, hi1Y, lineGC); - } - } // [HGM] first erase both, then draw new! - if (hi2X != toX || hi2Y != toY) { - if (hi2X >= 0 && hi2Y >= 0) { - drawHighlight(hi2X, hi2Y, lineGC); - } - } - if (hi1X != fromX || hi1Y != fromY) { - if (fromX >= 0 && fromY >= 0) { - drawHighlight(fromX, fromY, highlineGC); - } - } - if (hi2X != toX || hi2Y != toY) { - if (toX >= 0 && toY >= 0) { - drawHighlight(toX, toY, highlineGC); - } - } + if (hi1X != fromX || hi1Y != fromY) + { + if (hi1X >= 0 && hi1Y >= 0) + { + drawHighlight(hi1X, hi1Y, LINE_TYPE_NORMAL); + } - if (fromX >= 0 && fromY >= 0) - { - drawHighlight(fromX, fromY, LINE_TYPE_HIGHLIGHT); - } + } + if (hi2X != toX || hi2Y != toY) + { + if (hi2X >= 0 && hi2Y >= 0) + { + drawHighlight(hi2X, hi2Y, LINE_TYPE_NORMAL); + } ++ } ++ if (hi1X != fromX || hi1Y != fromY) ++ { ++ if (fromX >= 0 && fromY >= 0) ++ { ++ drawHighlight(fromX, fromY, LINE_TYPE_HIGHLIGHT); ++ } ++ if (hi2X != toX || hi2Y != toY) ++ { + if (toX >= 0 && toY >= 0) + { + drawHighlight(toX, toY, LINE_TYPE_HIGHLIGHT); + } + } hi1X = fromX; hi1Y = fromY; hi2X = toX; @@@ -2760,158 -4119,125 +2779,171 @@@ void DrawSquare(row, column, piece, do_ square_color = SquareColor(row, column); - if ( // [HGM] holdings: blank out area between board and holdings - column == BOARD_LEFT-1 || column == BOARD_RGHT - || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize) - || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) { - BlankSquare(x, y, 2, EmptySquare, xBoardWindow); - - // [HGM] print piece counts next to holdings - string[1] = NULLCHAR; - if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) { - string[0] = '0' + piece; - XTextExtents(countFontStruct, string, 1, &direction, - &font_ascent, &font_descent, &overall); - if (appData.monoMode) { - XDrawImageString(xDisplay, xBoardWindow, countGC, - x + squareSize - overall.width - 2, - y + font_ascent + 1, string, 1); - } else { - XDrawString(xDisplay, xBoardWindow, countGC, - x + squareSize - overall.width - 2, - y + font_ascent + 1, string, 1); - } - } - if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) { - string[0] = '0' + piece; - XTextExtents(countFontStruct, string, 1, &direction, - &font_ascent, &font_descent, &overall); - if (appData.monoMode) { - XDrawImageString(xDisplay, xBoardWindow, countGC, - x + 2, y + font_ascent + 1, string, 1); - } else { - XDrawString(xDisplay, xBoardWindow, countGC, - x + 2, y + font_ascent + 1, string, 1); - } - } - } else { - if (piece == EmptySquare || appData.blindfold) { - BlankSquare(x, y, square_color, piece, xBoardWindow); - } else { - drawfunc = ChooseDrawFunc(); - if (do_flash && appData.flashCount > 0) { - for (i=0; i= gameInfo.holdingsSize) ) + { + BlankSquare(x, y, 2, EmptySquare, xBoardWindow); - string[1] = NULLCHAR; - if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0) - && column >= BOARD_LEFT && column < BOARD_RGHT) { - string[0] = 'a' + column - BOARD_LEFT; - XTextExtents(coordFontStruct, string, 1, &direction, - &font_ascent, &font_descent, &overall); - if (appData.monoMode) { - XDrawImageString(xDisplay, xBoardWindow, coordGC, - x + squareSize - overall.width - 2, - y + squareSize - font_descent - 1, string, 1); - } else { - XDrawString(xDisplay, xBoardWindow, coordGC, - x + squareSize - overall.width - 2, - y + squareSize - font_descent - 1, string, 1); - } - } - if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) { - string[0] = ONE + row; - XTextExtents(coordFontStruct, string, 1, &direction, - &font_ascent, &font_descent, &overall); - if (appData.monoMode) { - XDrawImageString(xDisplay, xBoardWindow, coordGC, - x + 2, y + font_ascent + 1, string, 1); - } else { - XDrawString(xDisplay, xBoardWindow, coordGC, - x + 2, y + font_ascent + 1, string, 1); - } - } - if(marker[row][column]) { - XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC, - x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360); - } -} + // [HGM] print piece counts next to holdings + string[1] = NULLCHAR; + if(piece > 1) + { + cairo_text_extents_t extents; + cairo_t *cr; + int xpos, ypos; + + /* get a cairo_t */ + cr = gdk_cairo_create (GDK_WINDOW(GUI_Board->window)); + + string[0] = '0' + piece; + + /* TODO this has to go into the font-selection */ + cairo_select_font_face (cr, "Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); ++ //TODO ++// switch (event->type) { ++// case Expose: ++// if (event->xexpose.count > 0) return; /* no clipping is done */ ++// XDrawPosition(widget, True, NULL); ++// break; ++// case MotionNotify: ++// if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break; ++// default: ++// return; ++// } ++//} ++/* end why */ + cairo_set_font_size (cr, 12.0); + cairo_text_extents (cr, string, &extents); -/* Why is this needed on some versions of X? */ -void EventProc(widget, unused, event) - Widget widget; - caddr_t unused; - XEvent *event; -{ - if (!XtIsRealized(widget)) - return; + if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) ) + { + xpos= x + squareSize - extents.width - 2; + ypos= y + extents.y_bearing + 1; + } + if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) + { + xpos= x + 2; + ypos = y + extents.y_bearing + 1; + } - switch (event->type) { - case Expose: - if (event->xexpose.count > 0) return; /* no clipping is done */ - XDrawPosition(widget, True, NULL); - break; - case MotionNotify: - if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break; - default: - return; - } -} -/* end why */ + /* TODO mono mode? */ + cairo_move_to (cr, xpos, ypos); + cairo_text_path (cr, string); + cairo_set_source_rgb (cr, 1.0, 1.0, 1); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_width (cr, 0.1); + cairo_stroke (cr); + + /* free memory */ + cairo_destroy (cr); + } + } + else + { + /* square on the board */ + if (piece == EmptySquare || appData.blindfold) + { + BlankSquare(x, y, square_color, piece, xBoardWindow); + } + else + { + if (do_flash && appData.flashCount > 0) + { + for (i=0; iwindow)); + + if (row == (flipView ? BOARD_HEIGHT-1 : 0) && + column >= BOARD_LEFT && column < BOARD_RGHT) + { + string[0] = 'a' + column - BOARD_LEFT; + cairo_text_extents (cr, string, &extents); + + xpos = x + squareSize - extents.width - 2; + ypos = y + squareSize - extents.height - extents.y_bearing - 1; + + if (appData.monoMode) + { /*TODO*/ + } + else + { + } + + cairo_move_to (cr, xpos, ypos); + cairo_text_path (cr, string); + cairo_set_source_rgb (cr, 0.0, 0.0, 0); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 1.0, 0); + cairo_set_line_width (cr, 0.1); + cairo_stroke (cr); + } + if ( column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) + { + + string[0] = ONE + row; + cairo_text_extents (cr, string, &extents); + + xpos = x + 2; + ypos = y + extents.height + 1; + + if (appData.monoMode) + { /*TODO*/ + } + else + { + } + + cairo_move_to (cr, xpos, ypos); + cairo_text_path (cr, string); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 0, 1.0); + cairo_set_line_width (cr, 0.1); + cairo_stroke (cr); + + } + /* free memory */ + cairo_destroy (cr); + } + + return; } + /* Returns 1 if there are "too many" differences between b1 and b2 (i.e. more than 1 move was made) */ static int too_many_diffs(b1, b2) @@@ -2984,46 -4340,48 +3046,48 @@@ static int damage[BOARD_RANKS][BOARD_FI /* * event handler for redrawing the board */ -void XDrawPosition(w, repaint, board) - Widget w; +void DrawPosition( repaint, board) /*Boolean*/int repaint; - Board board; + Board board; { - int i, j, do_flash; - static int lastFlipView = 0; - static int lastBoardValid = 0; - static Board lastBoard; - Arg args[16]; - int rrow, rcol; + int i, j, do_flash; + static int lastFlipView = 0; + static int lastBoardValid = 0; + static Board lastBoard; + int rrow, rcol; + if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up + - if (board == NULL) { - if (!lastBoardValid) return; - board = lastBoard; - } - if (!lastBoardValid || lastFlipView != flipView) { - XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None)); - XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"), - args, 1); - } - - /* - * It would be simpler to clear the window with XClearWindow() - * but this causes a very distracting flicker. - */ + if (board == NULL) { + if (!lastBoardValid) return; + board = lastBoard; + } + if (!lastBoardValid || lastFlipView != flipView) { + // XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None)); + // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"), + // args, 1); + } - if (!repaint && lastBoardValid && lastFlipView == flipView) { + /* + * It would be simpler to clear the window with XClearWindow() + * but this causes a very distracting flicker. + */ - /* If too much changes (begin observing new game, etc.), don't - do flashing */ - do_flash = too_many_diffs(board, lastBoard) ? 0 : 1; + if (!repaint && lastBoardValid && lastFlipView == flipView) + { + /* If too much changes (begin observing new game, etc.), don't + do flashing */ + do_flash = too_many_diffs(board, lastBoard) ? 0 : 1; - /* Special check for castling so we don't flash both the king - and the rook (just flash the king). */ - if (do_flash) { - if (check_castle_draw(board, lastBoard, &rrow, &rcol)) { - /* Draw rook with NO flashing. King will be drawn flashing later */ - DrawSquare(rrow, rcol, board[rrow][rcol], 0); - lastBoard[rrow][rcol] = board[rrow][rcol]; + /* Special check for castling so we don't flash both the king + and the rook (just flash the king). */ + if (do_flash) + { + if (check_castle_draw(board, lastBoard, &rrow, &rcol)) + { + /* Draw rook with NO flashing. King will be drawn flashing later */ + DrawSquare(rrow, rcol, board[rrow][rcol], 0); + lastBoard[rrow][rcol] = board[rrow][rcol]; } } diff --cc xgamelist.c index 51827b6,c23bf6f..70d1dc8 --- a/xgamelist.c +++ b/xgamelist.c @@@ -91,11 -90,11 +91,13 @@@ extern char *getenv() # define N_(s) s #endif +extern GtkWidget *GUI_GameList; +extern GtkListStore *LIST_GameList; + void SetFocus P((Widget w, XtPointer data, XEvent *event, Boolean *b)); + + extern Widget formWidget, shellWidget, boardWidget, menuBarWidget, gameListShell; -extern Display *xDisplay; + - extern Widget formWidget, boardWidget, menuBarWidget, gameListShell; extern int squareSize; extern Pixmap xMarkPixmap; extern char *layoutName; @@@ -125,9 -137,236 +140,45 @@@ GameListCreate(name, callback, client_d XtCallbackProc callback; XtPointer client_data; { - Arg args[16]; - Widget shell, form, viewport, listwidg, layout, label; - Widget b_load, b_loadprev, b_loadnext, b_close, b_filter; - Dimension fw_width; - int j; - GameListClosure *glc = (GameListClosure *) client_data; - - j = 0; - XtSetArg(args[j], XtNwidth, &fw_width); j++; - XtGetValues(formWidget, args, j); - - j = 0; - XtSetArg(args[j], XtNresizable, True); j++; - XtSetArg(args[j], XtNallowShellResize, True); j++; -#if TOPLEVEL - shell = gameListShell = - XtCreatePopupShell(name, topLevelShellWidgetClass, - shellWidget, args, j); -#else - shell = gameListShell = - XtCreatePopupShell(name, transientShellWidgetClass, - shellWidget, args, j); -#endif - layout = - XtCreateManagedWidget(layoutName, formWidgetClass, shell, - layoutArgs, XtNumber(layoutArgs)); - j = 0; - XtSetArg(args[j], XtNborderWidth, 0); j++; - form = - XtCreateManagedWidget("form", formWidgetClass, layout, args, j); - - j = 0; - XtSetArg(args[j], XtNtop, XtChainTop); j++; - XtSetArg(args[j], XtNbottom, XtChainBottom); j++; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; - XtSetArg(args[j], XtNright, XtChainRight); j++; - XtSetArg(args[j], XtNresizable, False); j++; - XtSetArg(args[j], XtNwidth, fw_width); j++; - XtSetArg(args[j], XtNallowVert, True); j++; - viewport = - XtCreateManagedWidget("viewport", viewportWidgetClass, form, args, j); - - j = 0; - XtSetArg(args[j], XtNlist, glc->strings); j++; - XtSetArg(args[j], XtNdefaultColumns, 1); j++; - XtSetArg(args[j], XtNforceColumns, True); j++; - XtSetArg(args[j], XtNverticalList, True); j++; - listwidg = - XtCreateManagedWidget("list", listWidgetClass, viewport, args, j); - XawListHighlight(listwidg, 0); - XtAugmentTranslations(listwidg, - XtParseTranslationTable(gameListTranslations)); - - j = 0; - XtSetArg(args[j], XtNfromVert, viewport); j++; - XtSetArg(args[j], XtNtop, XtChainBottom); j++; - XtSetArg(args[j], XtNbottom, XtChainBottom); j++; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; - XtSetArg(args[j], XtNright, XtChainLeft); j++; - b_load = - XtCreateManagedWidget(_("load"), commandWidgetClass, form, args, j); - XtAddCallback(b_load, XtNcallback, callback, client_data); - - j = 0; - XtSetArg(args[j], XtNfromVert, viewport); j++; - XtSetArg(args[j], XtNfromHoriz, b_load); j++; - XtSetArg(args[j], XtNtop, XtChainBottom); j++; - XtSetArg(args[j], XtNbottom, XtChainBottom); j++; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; - XtSetArg(args[j], XtNright, XtChainLeft); j++; - b_loadprev = - XtCreateManagedWidget(_("prev"), commandWidgetClass, form, args, j); - XtAddCallback(b_loadprev, XtNcallback, callback, client_data); - - j = 0; - XtSetArg(args[j], XtNfromVert, viewport); j++; - XtSetArg(args[j], XtNfromHoriz, b_loadprev); j++; - XtSetArg(args[j], XtNtop, XtChainBottom); j++; - XtSetArg(args[j], XtNbottom, XtChainBottom); j++; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; - XtSetArg(args[j], XtNright, XtChainLeft); j++; - b_loadnext = - XtCreateManagedWidget(_("next"), commandWidgetClass, form, args, j); - XtAddCallback(b_loadnext, XtNcallback, callback, client_data); - - j = 0; - XtSetArg(args[j], XtNfromVert, viewport); j++; - XtSetArg(args[j], XtNfromHoriz, b_loadnext); j++; - XtSetArg(args[j], XtNtop, XtChainBottom); j++; - XtSetArg(args[j], XtNbottom, XtChainBottom); j++; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; - XtSetArg(args[j], XtNright, XtChainLeft); j++; - b_close = - XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j); - XtAddCallback(b_close, XtNcallback, callback, client_data); - - j = 0; - XtSetArg(args[j], XtNfromVert, viewport); j++; - XtSetArg(args[j], XtNfromHoriz, b_close); j++; - XtSetArg(args[j], XtNtop, XtChainBottom); j++; - XtSetArg(args[j], XtNbottom, XtChainBottom); j++; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; - XtSetArg(args[j], XtNright, XtChainLeft); j++; - XtSetArg(args[j], XtNborderWidth, 0); j++; - label = - XtCreateManagedWidget(_("Filter:"), labelWidgetClass, form, args, j); - - j = 0; - XtSetArg(args[j], XtNfromVert, viewport); j++; - XtSetArg(args[j], XtNfromHoriz, label); j++; - XtSetArg(args[j], XtNtop, XtChainBottom); j++; - XtSetArg(args[j], XtNbottom, XtChainBottom); j++; - XtSetArg(args[j], XtNleft, XtChainLeft); j++; - XtSetArg(args[j], XtNright, XtChainRight); j++; - XtSetArg(args[j], XtNwidth, fw_width - 225 - squareSize); j++; - XtSetArg(args[j], XtNstring, filterString); j++; - XtSetArg(args[j], XtNdisplayCaret, False); j++; - XtSetArg(args[j], XtNresizable, True); j++; -// XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/ - /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */ - XtSetArg(args[j], XtNeditType, XawtextEdit); j++; - XtSetArg(args[j], XtNuseStringInPlace, False); j++; - filterText = - XtCreateManagedWidget(_("filtertext"), asciiTextWidgetClass, form, args, j); - XtAddEventHandler(filterText, ButtonPressMask, False, SetFocus, (XtPointer) shell); - XtOverrideTranslations(filterText, - XtParseTranslationTable(filterTranslations)); - - j = 0; - XtSetArg(args[j], XtNfromVert, viewport); j++; - XtSetArg(args[j], XtNfromHoriz, filterText); j++; - XtSetArg(args[j], XtNtop, XtChainBottom); j++; - XtSetArg(args[j], XtNbottom, XtChainBottom); j++; - XtSetArg(args[j], XtNleft, XtChainRight); j++; - XtSetArg(args[j], XtNright, XtChainRight); j++; - b_filter = - XtCreateManagedWidget(_("apply"), commandWidgetClass, form, args, j); - XtAddCallback(b_filter, XtNcallback, callback, client_data); - - - if(wpGameList.width > 0) { - glc->x = wpGameList.x; - glc->y = wpGameList.y; - glc->w = wpGameList.width; - glc->h = wpGameList.height; - } - - if (glc->x == -1) { - Position y1; - Dimension h1; - int xx, yy; - Window junk; - - j = 0; - XtSetArg(args[j], XtNheight, &h1); j++; - XtSetArg(args[j], XtNy, &y1); j++; - XtGetValues(boardWidget, args, j); - glc->w = fw_width * 3/4; - glc->h = squareSize * 3; - - XSync(xDisplay, False); -#ifdef NOTDEF - /* This code seems to tickle an X bug if it is executed too soon - after xboard starts up. The coordinates get transformed as if - the main window was positioned at (0, 0). - */ - XtTranslateCoords(shellWidget, (fw_width - glc->w) / 2, - y1 + (h1 - glc->h + appData.borderYoffset) / 2, - &glc->x, &glc->y); -#else /*!NOTDEF*/ - XTranslateCoordinates(xDisplay, XtWindow(shellWidget), - RootWindowOfScreen(XtScreen(shellWidget)), - (fw_width - glc->w) / 2, - y1 + (h1 - glc->h + appData.borderYoffset) / 2, - &xx, &yy, &junk); - glc->x = xx; - glc->y = yy; -#endif /*!NOTDEF*/ - if (glc->y < 0) glc->y = 0; /*avoid positioning top offscreen*/ - } - j = 0; - XtSetArg(args[j], XtNheight, glc->h); j++; - XtSetArg(args[j], XtNwidth, glc->w); j++; - XtSetArg(args[j], XtNx, glc->x - appData.borderXoffset); j++; - XtSetArg(args[j], XtNy, glc->y - appData.borderYoffset); j++; - XtSetValues(shell, args, j); - - XtRealizeWidget(shell); - CatchDeleteWindow(shell, "GameListPopDown"); - XtSetKeyboardFocus(shell, listwidg); - - return shell; + return; } + static int + GameListPrepare() + { // [HGM] filter: put in separate routine, to make callable from call-back + int nstrings; + ListGame *lg; + char **st, *line; + + nstrings = ((ListGame *) gameList.tailPred)->number; + glc->strings = (char **) malloc((nstrings + 1) * sizeof(char *)); + st = glc->strings; + lg = (ListGame *) gameList.head; + listLength = 0; + while (nstrings--) { + line = GameListLine(lg->number, &lg->gameInfo); + if(filterString[0] == NULLCHAR || SearchPattern( line, filterString ) ) { + *st++ = line; // [HGM] filter: make adding line conditional + listLength++; + } + lg = (ListGame *) lg->node.succ; + } + *st = NULL; + return listLength; + } + + static void + GameListReplace() + { // [HGM] filter: put in separate routine, to make callable from call-back + Arg args[16]; + int j; + Widget listwidg; + + listwidg = XtNameToWidget(glc->shell, "*form.viewport.list"); + XawListChange(listwidg, glc->strings, 0, 0, True); + XawListHighlight(listwidg, 0); + } + void GameListCallback(w, client_data, call_data) Widget w; @@@ -186,39 -433,49 +245,38 @@@ GameListPopUp(fp, filename FILE *fp; char *filename; { - Arg args[16]; - int j, nstrings; - Widget listwidg; - ListGame *lg; - char **st; - - if (glc == NULL) { - glc = (GameListClosure *) calloc(1, sizeof(GameListClosure)); - glc->x = glc->y = -1; - } - - if (glc->strings != NULL) { - st = glc->strings; - while (*st) { - free(*st++); - } - free(glc->strings); + GtkTreeIter iter; + int i=0,nstrings; + ListGame *lg; + + /* first clear everything, do we need this? */ + gtk_list_store_clear(LIST_GameList); + + /* fill list with information */ + lg = (ListGame *) gameList.head; + nstrings = ((ListGame *) gameList.tailPred)->number; + while (nstrings--) + { + gtk_list_store_append (LIST_GameList, &iter); + gtk_list_store_set (LIST_GameList, &iter, + 0, StrSave(filename), + 1, GameListLine(lg->number, &lg->gameInfo), + 2, fp, + -1); + lg = (ListGame *) lg->node.succ; } - - GameListPrepare(); // [HGM] filter: code put in separate routine - - glc->fp = fp; - - if (glc->filename != NULL) free(glc->filename); - glc->filename = StrSave(filename); + /* show widget */ + gtk_widget_show (GUI_GameList); +// XtPopup(glc->shell, XtGrabNone); +// glc->up = True; +// j = 0; +// XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++; +// XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Game List"), +// args, j); - if (glc->shell == NULL) { - glc->shell = GameListCreate(filename, GameListCallback, glc); - } else { - GameListReplace(); // [HGM] filter: code put in separate routine - j = 0; - XtSetArg(args[j], XtNiconName, (XtArgVal) filename); j++; - XtSetArg(args[j], XtNtitle, (XtArgVal) filename); j++; - XtSetValues(glc->shell, args, j); - } - - XtPopup(glc->shell, XtGrabNone); - glc->up = True; - j = 0; - XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++; - XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Game List"), - args, j); + return; } void @@@ -280,12 -554,52 +347,35 @@@ LoadSelectedProc(w, event, prms, nprms } void + SetFilterProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; + { + Arg args[16]; + String name; + Widget list; + int j = 0; + XtSetArg(args[j], XtNstring, &name); j++; + XtGetValues(filterText, args, j); + strcpy(filterString, name); + if(GameListPrepare()) GameListReplace(); // crashes on empty list... + list = XtNameToWidget(glc->shell, "*form.viewport.list"); + XawListHighlight(list, 0); + j = 0; + XtSetArg(args[j], XtNdisplayCaret, False); j++; + XtSetValues(filterText, args, j); + XtSetKeyboardFocus(glc->shell, list); + } + + void GameListPopDown() { - Arg args[16]; - int j; + /* hides the history window */ - if (glc == NULL) return; - j = 0; - XtSetArg(args[j], XtNx, &glc->x); j++; - XtSetArg(args[j], XtNy, &glc->y); j++; - XtSetArg(args[j], XtNheight, &glc->h); j++; - XtSetArg(args[j], XtNwidth, &glc->w); j++; - XtGetValues(glc->shell, args, j); - wpGameList.x = glc->x - 4; - wpGameList.y = glc->y - 23; - wpGameList.width = glc->w; - wpGameList.height = glc->h; - XtPopdown(glc->shell); - XtSetKeyboardFocus(shellWidget, formWidget); - glc->up = False; - j = 0; - XtSetArg(args[j], XtNleftBitmap, None); j++; - XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Game List"), - args, j); + gtk_widget_hide (GUI_GameList); + return; } void @@@ -301,7 -618,218 +394,220 @@@ GameListHighlight(index Boolean GameListIsUp() { - return glc && glc->up; + /* return status of history window */ + + return gtk_widget_get_visible (GUI_GameList); } + + //--------------------------------- Game-List options dialog ------------------------------------------ + + Widget gameListOptShell, listwidg; + + char *strings[20]; + int stringPtr; + + void GLT_ClearList() + { + strings[0] = NULL; + stringPtr = 0; + } + + void GLT_AddToList(char *name) + { + strings[stringPtr++] = name; + strings[stringPtr] = NULL; + } + + Boolean GLT_GetFromList(int index, char *name) + { + strcpy(name, strings[index]); + } + + void GLT_DeSelectList() + { + XawListChange(listwidg, strings, 0, 0, True); + XawListHighlight(listwidg, 0); + } + + void + GameListOptionsPopDown() + { + Arg args[16]; + int j; + + if (gameListOptShell == NULL) return; + XtPopdown(gameListOptShell); + XtDestroyWidget(gameListOptShell); + gameListOptShell = 0; + XtSetKeyboardFocus(shellWidget, formWidget); + } + + void + GameListOptionsCallback(w, client_data, call_data) + Widget w; + XtPointer client_data, call_data; + { + String name; + Arg args[16]; + int j; + Widget listwidg; + XawListReturnStruct *rs; + int index; + char *p; + + j = 0; + XtSetArg(args[j], XtNlabel, &name); j++; + XtGetValues(w, args, j); + + if (strcmp(name, _("OK")) == 0) { + GLT_ParseList(); + appData.gameListTags = strdup(lpUserGLT); + GameListOptionsPopDown(); + return; + } else + if (strcmp(name, _("cancel")) == 0) { + GameListOptionsPopDown(); + return; + } + listwidg = XtNameToWidget(gameListOptShell, "*form.list"); + rs = XawListShowCurrent(listwidg); + index = rs->list_index; + if (index < 0) { + DisplayError(_("No tag selected"), 0); + return; + } + p = strings[index]; + if (strcmp(name, _("down")) == 0) { + if(index >= strlen(GLT_ALL_TAGS)) return; + strings[index] = strings[index+1]; + strings[++index] = p; + } else + if (strcmp(name, _("up")) == 0) { + if(index == 0) return; + strings[index] = strings[index-1]; + strings[--index] = p; + } else + if (strcmp(name, _("factory")) == 0) { + strcpy(lpUserGLT, GLT_DEFAULT_TAGS); + GLT_TagsToList(lpUserGLT); + index = 0; + } + XawListHighlight(listwidg, index); + } + + Widget + GameListOptionsCreate() + { + Arg args[16]; + Widget shell, form, viewport, layout; + Widget b_load, b_loadprev, b_loadnext, b_close, b_cancel; + Dimension fw_width; + XtPointer client_data = NULL; + int j; + + j = 0; + XtSetArg(args[j], XtNwidth, &fw_width); j++; + XtGetValues(formWidget, args, j); + + j = 0; + XtSetArg(args[j], XtNresizable, True); j++; + XtSetArg(args[j], XtNallowShellResize, True); j++; + shell = gameListOptShell = + XtCreatePopupShell("Game-list options", transientShellWidgetClass, + shellWidget, args, j); + layout = + XtCreateManagedWidget(layoutName, formWidgetClass, shell, + layoutArgs, XtNumber(layoutArgs)); + j = 0; + XtSetArg(args[j], XtNborderWidth, 0); j++; + form = + XtCreateManagedWidget("form", formWidgetClass, layout, args, j); + + j = 0; + XtSetArg(args[j], XtNdefaultColumns, 1); j++; + XtSetArg(args[j], XtNforceColumns, True); j++; + XtSetArg(args[j], XtNverticalList, True); j++; + listwidg = viewport = + XtCreateManagedWidget("list", listWidgetClass, form, args, j); + XawListHighlight(listwidg, 0); + // XtAugmentTranslations(listwidg, + // XtParseTranslationTable(gameListOptTranslations)); + + j = 0; + XtSetArg(args[j], XtNfromVert, viewport); j++; + XtSetArg(args[j], XtNtop, XtChainBottom); j++; + XtSetArg(args[j], XtNbottom, XtChainBottom); j++; + XtSetArg(args[j], XtNleft, XtChainLeft); j++; + XtSetArg(args[j], XtNright, XtChainLeft); j++; + b_load = + XtCreateManagedWidget(_("factory"), commandWidgetClass, form, args, j); + XtAddCallback(b_load, XtNcallback, GameListOptionsCallback, client_data); + + j = 0; + XtSetArg(args[j], XtNfromVert, viewport); j++; + XtSetArg(args[j], XtNfromHoriz, b_load); j++; + XtSetArg(args[j], XtNtop, XtChainBottom); j++; + XtSetArg(args[j], XtNbottom, XtChainBottom); j++; + XtSetArg(args[j], XtNleft, XtChainLeft); j++; + XtSetArg(args[j], XtNright, XtChainLeft); j++; + b_loadprev = + XtCreateManagedWidget(_("up"), commandWidgetClass, form, args, j); + XtAddCallback(b_loadprev, XtNcallback, GameListOptionsCallback, client_data); + + j = 0; + XtSetArg(args[j], XtNfromVert, viewport); j++; + XtSetArg(args[j], XtNfromHoriz, b_loadprev); j++; + XtSetArg(args[j], XtNtop, XtChainBottom); j++; + XtSetArg(args[j], XtNbottom, XtChainBottom); j++; + XtSetArg(args[j], XtNleft, XtChainLeft); j++; + XtSetArg(args[j], XtNright, XtChainLeft); j++; + b_loadnext = + XtCreateManagedWidget(_("down"), commandWidgetClass, form, args, j); + XtAddCallback(b_loadnext, XtNcallback, GameListOptionsCallback, client_data); + + j = 0; + XtSetArg(args[j], XtNfromVert, viewport); j++; + XtSetArg(args[j], XtNfromHoriz, b_loadnext); j++; + XtSetArg(args[j], XtNtop, XtChainBottom); j++; + XtSetArg(args[j], XtNbottom, XtChainBottom); j++; + XtSetArg(args[j], XtNleft, XtChainLeft); j++; + XtSetArg(args[j], XtNright, XtChainLeft); j++; + b_cancel = + XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j); + XtAddCallback(b_cancel, XtNcallback, GameListOptionsCallback, client_data); + + j = 0; + XtSetArg(args[j], XtNfromVert, viewport); j++; + XtSetArg(args[j], XtNfromHoriz, b_cancel); j++; + XtSetArg(args[j], XtNtop, XtChainBottom); j++; + XtSetArg(args[j], XtNbottom, XtChainBottom); j++; + XtSetArg(args[j], XtNleft, XtChainLeft); j++; + XtSetArg(args[j], XtNright, XtChainLeft); j++; + b_close = + XtCreateManagedWidget(_("OK"), commandWidgetClass, form, args, j); + XtAddCallback(b_close, XtNcallback, GameListOptionsCallback, client_data); + + strcpy(lpUserGLT, appData.gameListTags); + GLT_TagsToList(lpUserGLT); + + XtRealizeWidget(shell); + CatchDeleteWindow(shell, "GameListOptionsPopDown"); + + return shell; + } + + void + GameListOptionsPopUp(Widget w, XEvent *event, String *prms, Cardinal *nprms) + { + Arg args[16]; + int j, nstrings; + Widget listwidg; + + if (gameListOptShell == NULL) { + gameListOptShell = GameListOptionsCreate(); + } + + XtPopup(gameListOptShell, XtGrabNone); + } + +