X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=c34724e5ef514395e048a34f528aa1e505129a98;hb=797e76a7d465fb38fafa878fe62abb768213ba1d;hp=0e36ec2b3452c8272ce08e964a5b2e20099c455b;hpb=cc5c5550e44afbcc5a1952a574c211b80f63ebbd;p=xboard.git diff --git a/backend.c b/backend.c index 0e36ec2..c34724e 100644 --- a/backend.c +++ b/backend.c @@ -351,6 +351,8 @@ PosFlags(index) flags &= ~F_ALL_CASTLE_OK; case VariantGiveaway: // [HGM] moved this case label one down: seems Giveaway does have castling on ICC! flags |= F_IGNORE_CHECK; + case VariantLosers: + flags |= F_MANDATORY_CAPTURE; //[HGM] losers: sets flag so TestLegality rejects non-capts if capts exist break; case VariantAtomic: flags |= F_IGNORE_CHECK | F_ATOMIC_CAPTURE; @@ -617,6 +619,7 @@ InitBackEnd1() ShowThinkingEvent(); // [HGM] thinking: make sure post/nopost state is set according to options GetTimeMark(&programStartTime); + srand(programStartTime.ms); // [HGM] book: makes sure random is unpredictabe to msec level ClearProgramStats(); programStats.ok_to_send = 1; @@ -746,6 +749,8 @@ InitBackEnd1() first.useFEN960 = FALSE; second.useFEN960 = FALSE; first.useOOCastle = TRUE; second.useOOCastle = TRUE; /* End of new features added by Tord. */ + first.fenOverride = appData.fenOverride1; + second.fenOverride = appData.fenOverride2; /* [HGM] time odds: set factor for each machine */ first.timeOdds = appData.firstTimeOdds; @@ -4253,106 +4258,7 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar) } } -#if 0 -/* [AS] FRC game initialization */ -static int FindEmptySquare( Board board, int n ) -{ - int i = 0; - - while( 1 ) { - while( board[0][i] != EmptySquare ) i++; - if( n == 0 ) - break; - n--; - i++; - } - - return i; -} - -static void ShuffleFRC( Board board ) -{ - int i; - - srand( time(0) ); - - for( i=0; i<8; i++ ) { - board[0][i] = EmptySquare; - } - - board[0][(rand() % 4)*2 ] = WhiteBishop; /* On dark square */ - board[0][(rand() % 4)*2+1] = WhiteBishop; /* On lite square */ - board[0][FindEmptySquare(board, rand() % 6)] = WhiteQueen; - board[0][FindEmptySquare(board, rand() % 5)] = WhiteKnight; - board[0][FindEmptySquare(board, rand() % 4)] = WhiteKnight; - board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook; - initialRights[1] = initialRights[4] = - castlingRights[0][1] = castlingRights[0][4] = i; - board[0][ i=FindEmptySquare(board, 0) ] = WhiteKing; - initialRights[2] = initialRights[5] = - castlingRights[0][2] = castlingRights[0][5] = i; - board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook; - initialRights[0] = initialRights[3] = - castlingRights[0][0] = castlingRights[0][3] = i; - - for( i=BOARD_LEFT; i> 8 ^ random() << 8; if(seed<0) seed = -seed; @@ -4508,8 +4413,6 @@ void SetUpShuffle(Board board, int number) if(number >= 0) appData.defaultFrcPosition %= nrOfShuffles; // normalize } -#endif - int SetCharTable( char *table, const char * map ) /* [HGM] moved here from winboard.c because of its general usefulness */ /* Basically a safe strcpy that uses the last character as King */ @@ -4627,11 +4530,6 @@ InitPosition(redraw) break; case VariantTwoKings: pieces = twoKingsArray; - nrCastlingRights = 8; /* add rights for second King */ - castlingRights[0][6] = initialRights[2] = 5; - castlingRights[0][7] = initialRights[5] = 5; - castlingRank[6] = 0; - castlingRank[7] = BOARD_HEIGHT-1; break; case VariantCapaRandom: shuffleOpenings = TRUE; @@ -4797,8 +4695,8 @@ InitPosition(redraw) if(gameInfo.variant == VariantSuper) Prelude(initialPosition); if(gameInfo.variant == VariantGreat) { // promotion commoners - initialPosition[PieceToNumber(WhiteMan)][BOARD_RGHT-1] = WhiteMan; - initialPosition[PieceToNumber(WhiteMan)][BOARD_RGHT-2] = 9; + initialPosition[PieceToNumber(WhiteMan)][BOARD_WIDTH-1] = WhiteMan; + initialPosition[PieceToNumber(WhiteMan)][BOARD_WIDTH-2] = 9; initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][0] = BlackMan; initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][1] = 9; } @@ -4857,7 +4755,7 @@ SendBoard(cps, moveNum) char message[MSG_SIZ]; if (cps->useSetboard) { - char* fen = PositionToFEN(moveNum, cps->useFEN960); + char* fen = PositionToFEN(moveNum, cps->fenOverride); sprintf(message, "setboard %s\n", fen); SendToProgram(message, cps); free(fen); @@ -5815,8 +5713,13 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if(appData.checkMates) { SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */ ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ - GameEnds( GameIsDrawn, "Xboard adjudication: Stalemate", - GE_XBOARD ); + if(gameInfo.variant == VariantLosers || gameInfo.variant == VariantSuicide + || gameInfo.variant == VariantGiveaway) // [HGM] losers: + GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, // stalemated side wins! + "Xboard adjudication: Stalemate", GE_XBOARD ); + else + GameEnds( GameIsDrawn, "Xboard adjudication: Stalemate", GE_XBOARD ); + return; } break; case MT_CHECKMATE: @@ -5824,9 +5727,10 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h 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) ? BlackWins : WhiteWins, - "Xboard adjudication: Checkmate", - GE_XBOARD ); + GameEnds( WhiteOnMove(forwardMostMove) != (gameInfo.variant == VariantLosers) // [HGM] losers: + ? BlackWins : WhiteWins, // reverse the result ( A!=1 is !A for a boolean) + "Xboard adjudication: Checkmate", GE_XBOARD ); + return; } break; } @@ -5834,7 +5738,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h 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, bishopsColor = 0, + NrWQ=0, NrBQ=0, NrW=0, NrK=0, bishopsColor = 0, NrPieces=0, NrPawns=0, PawnAdvance=0, i, j; static int moveCount = 6; @@ -5845,6 +5749,9 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h switch((int) p) { /* count B,N,R and other of each side */ + case WhiteKing: + case BlackKing: + NrK++; break; // [HGM] atomic: count Kings case WhiteKnight: NrWN++; break; case WhiteBishop: @@ -5881,6 +5788,45 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h } } + if(gameInfo.variant == VariantAtomic && NrK < 2) { + // [HGM] atomic: stm must have lost his King on previous move, as destroying own K is illegal + epStatus[forwardMostMove] = EP_CHECKMATE; // make claimable as if stm is checkmated + if(appData.checkMates) { + SendMoveToProgram(forwardMostMove-1, cps->other); // 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) + epStatus[forwardMostMove] = EP_STALEMATE; // kludge to make position claimable as win + 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 */ + epStatus[forwardMostMove] = EP_CHECKMATE; // 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; + + if( NrPieces == 2 || gameInfo.variant != VariantXiangqi && gameInfo.variant != VariantShatranj && // [HGM] baring will remain possible (NrPieces == 3 && NrWN+NrBN+NrWB+NrBB == 1 || @@ -5900,20 +5846,6 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h } } - /* Shatranj baring rule */ - if( gameInfo.variant == VariantShatranj && (NrW == 1 || NrPieces - NrW == 1) ) - { /* bare King */ - - if(--bare < 0 && appData.checkMates) { - /* but only adjudicate them if adjudication enabled */ - SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see 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; - /* Then some trivial draws (only adjudicate, cannot be claimed) */ if(NrPieces == 4 && ( NrWR == 1 && NrBR == 1 /* KRKR */ @@ -7799,20 +7731,35 @@ GameEnds(result, resultDetails, whosays) if(gameMode == TwoMachinesPlay && appData.testClaims) { if(appData.testLegality && whosays >= GE_ENGINE1 ) { char claimer; + ChessMove trueResult = (ChessMove) -1; claimer = whosays == GE_ENGINE1 ? /* color of claimer */ first.twoMachinesColor[0] : second.twoMachinesColor[0] ; - if( (gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) && - (result == WhiteWins && claimer == 'w' || - result == BlackWins && claimer == 'b' ) ) { - if (appData.debugMode) { - fprintf(debugFP, "result=%d sp=%d move=%d\n", - result, epStatus[forwardMostMove], forwardMostMove); + + // [HGM] losers: because the logic is becoming a bit hairy, determine true result first + if(epStatus[forwardMostMove] == EP_CHECKMATE) { + /* [HGM] verify: engine mate claims accepted if they were flagged */ + trueResult = WhiteOnMove(forwardMostMove) != (gameInfo.variant == VariantLosers) + ? BlackWins : WhiteWins; // [HGM] losers: reverse the result in VariantLosers! + } else + if(epStatus[forwardMostMove] == EP_STALEMATE) { + trueResult = GameIsDrawn; // default; in variants where stalemate loses, Status is CHECKMATE + if(gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuicide || + gameInfo.variant == VariantLosers) // [HGM] losers: in giveaway variants stalemate wins + trueResult = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; } - /* [HGM] verify: engine mate claims accepted if they were flagged */ - if(epStatus[forwardMostMove] != EP_CHECKMATE && - result != (WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins)) { + + // now verify win claims, but not in drop games, as we don't understand those yet + if( (gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper + || gameInfo.variant == VariantGreat) && + (result == WhiteWins && claimer == 'w' || + result == BlackWins && claimer == 'b' ) ) { // case to verify: engine claims own win + if (appData.debugMode) { + fprintf(debugFP, "result=%d sp=%d move=%d\n", + result, epStatus[forwardMostMove], forwardMostMove); + } + if(result != trueResult) { sprintf(buf, "False win claim: '%s'", resultDetails); result = claimer == 'w' ? BlackWins : WhiteWins; resultDetails = buf; @@ -7832,7 +7779,9 @@ GameEnds(result, resultDetails, whosays) } /* [HGM] bare: don't allow bare King to win */ if((gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) - && result != GameIsDrawn) + && gameInfo.variant != VariantLosers && gameInfo.variant != VariantGiveaway + && gameInfo.variant != VariantSuicide // [HGM] losers: except in losers, of course... + && result != GameIsDrawn) { int i, j, k=0, color = (result==WhiteWins ? (int)WhitePawn : (int)BlackPawn); for(j=BOARD_LEFT; j 0 || startedFromSetupPosition) { - char *fen = PositionToFEN(backwardMostMove, 1); + char *fen = PositionToFEN(backwardMostMove, NULL); fprintf(f, "[FEN \"%s\"]\n[SetUp \"1\"]\n", fen); fprintf(f, "\n{--------------\n"); PrintPosition(f, backwardMostMove); @@ -9810,7 +9759,7 @@ SavePosition(f, dummy, dummy2) PrintPosition(f, currentMove); fprintf(f, "--------------]\n"); } else { - fen = PositionToFEN(currentMove, 1); + fen = PositionToFEN(currentMove, NULL); fprintf(f, "%s\n", fen); free(fen); } @@ -12401,8 +12350,9 @@ ParseOption(Option *opt, ChessProgramState *cps) } else return FALSE; *p = 0; // terminate option name // now look if the command-line options define a setting for this engine option. - p = strstr(cps->optionSettings, opt->name); - if(p == cps->optionSettings || p[-1] == ',') { + if(cps->optionSettings && cps->optionSettings[0]) + p = strstr(cps->optionSettings, opt->name); else p = NULL; + if(p && (p == cps->optionSettings || p[-1] == ',')) { sprintf(buf, "option %s", p); if(p = strstr(buf, ",")) *p = 0; strcat(buf, "\n"); @@ -13345,9 +13295,9 @@ PGNDate() char * -PositionToFEN(move, useFEN960) +PositionToFEN(move, overrideCastling) int move; - int useFEN960; + char *overrideCastling; { int i, j, fromX, fromY, toX, toY; int whiteToPlay; @@ -13422,6 +13372,9 @@ PositionToFEN(move, useFEN960) *p++ = whiteToPlay ? 'w' : 'b'; *p++ = ' '; + if(q = overrideCastling) { // [HGM] FRC: override castling & e.p fields for non-compliant engines + while(*p++ = *q++); if(q != overrideCastling+1) p[-1] = ' '; + } else { if(nrCastlingRights) { q = p; if(gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) { @@ -13479,6 +13432,7 @@ PositionToFEN(move, useFEN960) } *p++ = ' '; } + } /* [HGM] find reversible plies */ { int i = 0, j=move;