int LoadPositionFromFile P((char *filename, int n, char *title));\r
int SavePositionToFile P((char *filename));\r
void ApplyMove P((int fromX, int fromY, int toX, int toY, int promoChar,\r
- Board board));\r
+ Board board, char *castle, char *ep));\r
void MakeMove P((int fromX, int fromY, int toX, int toY, int promoChar));\r
void ShowMove P((int fromX, int fromY, int toX, int toY));\r
int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
ShowThinkingEvent(); // [HGM] thinking: make sure post/nopost state is set according to options\r
\r
GetTimeMark(&programStartTime);\r
+ srand(programStartTime.ms); // [HGM] book: makes sure random is unpredictabe to msec level\r
\r
ClearProgramStats();\r
programStats.ok_to_send = 1;\r
first.useFEN960 = FALSE; second.useFEN960 = FALSE;\r
first.useOOCastle = TRUE; second.useOOCastle = TRUE;\r
/* End of new features added by Tord. */\r
+ first.fenOverride = appData.fenOverride1;\r
+ second.fenOverride = appData.fenOverride2;\r
\r
/* [HGM] time odds: set factor for each machine */\r
first.timeOdds = appData.firstTimeOdds;\r
nrAlph += (parse[i] >= 'A' && parse[i] <= 'Z');\r
}\r
if(nrAlph < 9*nrDigit) { // if more than 10% digit we assume search info\r
+ int depth=0; float score;\r
+ if(sscanf(parse, "!!! %f/%d", &score, &depth) == 2 && depth>0) {\r
+ // [HGM] kibitz: save kibitzed opponent info for PGN and eval graph\r
+ pvInfoList[forwardMostMove-1].depth = depth;\r
+ pvInfoList[forwardMostMove-1].score = 100*score;\r
+ }\r
OutputKibitz(suppressKibitz, parse);\r
} else {\r
char tmp[MSG_SIZ];\r
else strcpy(buf, str); // might be castling\r
if((prom = strstr(move_str, "=")) && !strstr(buf, "=")) \r
strcat(buf, prom); // long move lacks promo specification!\r
- if(!appData.testLegality) {\r
+ if(!appData.testLegality && move_str[1] != '@') { // drops never ambiguous (parser chokes on long form!)\r
if(appData.debugMode) \r
fprintf(debugFP, "replaced ICS move '%s' by '%s'\n", move_str, buf);\r
strcpy(move_str, buf);\r
strcat(parseList[moveNum - 1], "+");\r
break;\r
case MT_CHECKMATE:\r
+ case MT_STAINMATE: // [HGM] xq: for notation stalemate that wins counts as checkmate\r
strcat(parseList[moveNum - 1], "#");\r
break;\r
}\r
}\r
}\r
\r
-#if 0\r
-/* [AS] FRC game initialization */\r
-static int FindEmptySquare( Board board, int n )\r
-{\r
- int i = 0;\r
-\r
- while( 1 ) {\r
- while( board[0][i] != EmptySquare ) i++;\r
- if( n == 0 )\r
- break;\r
- n--;\r
- i++;\r
- }\r
-\r
- return i;\r
-}\r
-\r
-static void ShuffleFRC( Board board )\r
-{\r
- int i;\r
-\r
- srand( time(0) );\r
- \r
- for( i=0; i<8; i++ ) {\r
- board[0][i] = EmptySquare;\r
- }\r
-\r
- board[0][(rand() % 4)*2 ] = WhiteBishop; /* On dark square */\r
- board[0][(rand() % 4)*2+1] = WhiteBishop; /* On lite square */\r
- board[0][FindEmptySquare(board, rand() % 6)] = WhiteQueen;\r
- board[0][FindEmptySquare(board, rand() % 5)] = WhiteKnight;\r
- board[0][FindEmptySquare(board, rand() % 4)] = WhiteKnight;\r
- board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook;\r
- initialRights[1] = initialRights[4] =\r
- castlingRights[0][1] = castlingRights[0][4] = i;\r
- board[0][ i=FindEmptySquare(board, 0) ] = WhiteKing;\r
- initialRights[2] = initialRights[5] =\r
- castlingRights[0][2] = castlingRights[0][5] = i;\r
- board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook;\r
- initialRights[0] = initialRights[3] =\r
- castlingRights[0][0] = castlingRights[0][3] = i;\r
-\r
- for( i=BOARD_LEFT; i<BOARD_RGHT; i++ ) {\r
- board[BOARD_HEIGHT-1][i] = board[0][i] + BlackPawn - WhitePawn;\r
- }\r
-}\r
-\r
-static unsigned char FRC_KnightTable[10] = {\r
- 0x00, 0x01, 0x02, 0x03, 0x11, 0x12, 0x13, 0x22, 0x23, 0x33\r
-};\r
-\r
-static void SetupFRC( Board board, int pos_index )\r
-{\r
- int i;\r
- unsigned char knights;\r
-\r
- /* Bring the position index into a safe range (just in case...) */\r
- if( pos_index < 0 ) pos_index = 0;\r
-\r
- pos_index %= 960;\r
-\r
- /* Clear the board */\r
- for( i=0; i<8; i++ ) {\r
- board[0][i] = EmptySquare;\r
- }\r
-\r
- /* Place bishops and queen */\r
- board[0][ (pos_index % 4)*2 + 1 ] = WhiteBishop; /* On lite square */\r
- pos_index /= 4;\r
- \r
- board[0][ (pos_index % 4)*2 ] = WhiteBishop; /* On dark square */\r
- pos_index /= 4;\r
-\r
- board[0][ FindEmptySquare(board, pos_index % 6) ] = WhiteQueen;\r
- pos_index /= 6;\r
-\r
- /* Place knigths */\r
- knights = FRC_KnightTable[ pos_index ];\r
-\r
- board[0][ FindEmptySquare(board, knights / 16) ] = WhiteKnight;\r
- board[0][ FindEmptySquare(board, knights % 16) ] = WhiteKnight;\r
-\r
- /* Place rooks and king */\r
- board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook;\r
- initialRights[1] = initialRights[4] =\r
- castlingRights[0][1] = castlingRights[0][4] = i;\r
- board[0][ i=FindEmptySquare(board, 0) ] = WhiteKing;\r
- initialRights[2] = initialRights[5] =\r
- castlingRights[0][2] = castlingRights[0][5] = i;\r
- board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook;\r
- initialRights[0] = initialRights[3] =\r
- castlingRights[0][0] = castlingRights[0][3] = i;\r
-\r
- /* Mirror piece placement for black */\r
- for( i=BOARD_LEFT; i<BOARD_RGHT; i++ ) {\r
- board[BOARD_HEIGHT-1][i] = board[0][i] + BlackPawn - WhitePawn;\r
- }\r
-}\r
-#else\r
-// [HGM] shuffle: a more general way to suffle opening setups, applicable to arbitrry variants.\r
+// [HGM] shuffle: a general way to suffle opening setups, applicable to arbitrary variants.\r
// All positions will have equal probability, but the current method will not provide a unique\r
// numbering scheme for arrays that contain 3 or more pieces of the same kind.\r
#define DARK 1\r
\r
int squaresLeft[4];\r
int piecesLeft[(int)BlackPawn];\r
-u64 seed, nrOfShuffles;\r
+int seed, nrOfShuffles;\r
\r
void GetPositionNumber()\r
{ // sets global variable seed\r
\r
seed = appData.defaultFrcPosition;\r
if(seed < 0) { // randomize based on time for negative FRC position numbers\r
- srandom(time(0)); \r
for(i=0; i<50; i++) seed += random();\r
seed = random() ^ random() >> 8 ^ random() << 8;\r
if(seed<0) seed = -seed;\r
if(number >= 0) appData.defaultFrcPosition %= nrOfShuffles; // normalize\r
}\r
\r
-#endif\r
-\r
int SetCharTable( char *table, const char * map )\r
/* [HGM] moved here from winboard.c because of its general usefulness */\r
/* Basically a safe strcpy that uses the last character as King */\r
char message[MSG_SIZ];\r
\r
if (cps->useSetboard) {\r
- char* fen = PositionToFEN(moveNum, cps->useFEN960);\r
+ char* fen = PositionToFEN(moveNum, cps->fenOverride);\r
sprintf(message, "setboard %s\n", fen);\r
SendToProgram(message, cps);\r
free(fen);\r
* If they don't match, display an error message.\r
*/\r
int saveAnimate;\r
- Board testBoard;\r
+ Board testBoard; char testRights[BOARD_SIZE]; char testStatus;\r
CopyBoard(testBoard, boards[currentMove]);\r
- ApplyMove(fromX, fromY, toX, toY, promoChar, testBoard);\r
+ ApplyMove(fromX, fromY, toX, toY, promoChar, testBoard, testRights, &testStatus);\r
\r
if (CompareBoards(testBoard, boards[currentMove+1])) {\r
ForwardInner(currentMove+1);\r
\r
MakeMove(fromX, fromY, toX, toY, promoChar); /*updates forwardMostMove*/\r
\r
- if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) \r
- && promoChar != NULLCHAR && gameInfo.holdingsSize) { \r
- // [HGM] superchess: take promotion piece out of holdings\r
- int k = PieceToNumber(CharToPiece(ToUpper(promoChar)));\r
- if(WhiteOnMove(forwardMostMove-1)) {\r
- if(!--boards[forwardMostMove][k][BOARD_WIDTH-2])\r
- boards[forwardMostMove][k][BOARD_WIDTH-1] = EmptySquare;\r
- } else {\r
- if(!--boards[forwardMostMove][BOARD_HEIGHT-1-k][1])\r
- boards[forwardMostMove][BOARD_HEIGHT-1-k][0] = EmptySquare;\r
- }\r
- }\r
-\r
if (gameMode == BeginningOfGame) {\r
if (appData.noChessProgram) {\r
gameMode = EditGame;\r
case MT_CHECK:\r
break;\r
case MT_CHECKMATE:\r
+ case MT_STAINMATE:\r
if (WhiteOnMove(currentMove)) {\r
GameEnds(BlackWins, "Black mates", GE_PLAYER);\r
} else {\r
machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);\r
GameEnds(machineWhite ? BlackWins : WhiteWins,\r
buf1, GE_XBOARD);\r
+ return;\r
} else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom)\r
/* [HGM] Kludge to handle engines that send FRC-style castling\r
when they shouldn't (like TSCP-Gothic) */\r
if(appData.autoKibitz && !appData.icsEngineAnalyze ) { /* [HGM] kibitz: send most-recent PV info to ICS */\r
char buf[3*MSG_SIZ];\r
\r
- sprintf(buf, "kibitz %d/%+.2f (%.2f sec, %.0f nodes, %1.0f knps) PV = %s\n",\r
- programStats.depth,\r
+ sprintf(buf, "kibitz !!! %+.2f/%d (%.2f sec, %.0f nodes, %1.0f knps) PV=%s\n",\r
programStats.score / 100.,\r
+ programStats.depth,\r
programStats.time / 100.,\r
u64ToDouble(programStats.nodes),\r
u64ToDouble(programStats.nodes) / (10*abs(programStats.time) + 1.),\r
int k, count = 0, epFile = epStatus[forwardMostMove]; static int bare = 1;\r
if(gameInfo.holdingsSize == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {\r
\r
- if(appData.testLegality)\r
- // don't wait for engine to announce game end if we can judge ourselves\r
- switch (MateTest(boards[forwardMostMove],\r
- PosFlags(forwardMostMove), epFile,\r
- castlingRights[forwardMostMove]) ) {\r
- case MT_NONE:\r
- case MT_CHECK:\r
- default:\r
- break;\r
- case MT_STALEMATE:\r
- epStatus[forwardMostMove] = EP_STALEMATE;\r
- if(appData.checkMates) {\r
- SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
- ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
- if(gameInfo.variant == VariantLosers || gameInfo.variant == VariantSuicide\r
- || gameInfo.variant == VariantGiveaway) // [HGM] losers:\r
- GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, // stalemated side wins!\r
- "Xboard adjudication: Stalemate", GE_XBOARD );\r
- else\r
- GameEnds( GameIsDrawn, "Xboard adjudication: Stalemate", GE_XBOARD );\r
- return;\r
- }\r
- break;\r
- case MT_CHECKMATE:\r
- epStatus[forwardMostMove] = EP_CHECKMATE;\r
- if(appData.checkMates) {\r
- SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
- ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
- GameEnds( WhiteOnMove(forwardMostMove) != (gameInfo.variant == VariantLosers) // [HGM] losers:\r
- ? BlackWins : WhiteWins, // reverse the result ( A!=1 is !A for a boolean)\r
- "Xboard adjudication: Checkmate", GE_XBOARD );\r
- return;\r
- }\r
- break;\r
- }\r
\r
if( appData.testLegality )\r
{ /* [HGM] Some more adjudications for obstinate engines */\r
NrWQ=0, NrBQ=0, NrW=0, NrK=0, bishopsColor = 0,\r
NrPieces=0, NrPawns=0, PawnAdvance=0, i, j;\r
static int moveCount = 6;\r
+ ChessMove result;\r
+ char *reason = NULL;\r
\r
- /* First absolutely insufficient mating material. Count what is on board. */\r
+ /* Count what is on board. */\r
for(i=0; i<BOARD_HEIGHT; i++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++)\r
{ ChessSquare p = boards[forwardMostMove][i][j];\r
int m=i;\r
}\r
}\r
\r
+ /* Some material-based adjudications that have to be made before stalemate test */\r
if(gameInfo.variant == VariantAtomic && NrK < 2) {\r
// [HGM] atomic: stm must have lost his King on previous move, as destroying own K is illegal\r
epStatus[forwardMostMove] = EP_CHECKMATE; // make claimable as if stm is checkmated\r
/* Bare King in Shatranj (loses) or Losers (wins) */\r
if( NrW == 1 || NrPieces - NrW == 1) {\r
if( gameInfo.variant == VariantLosers) { // [HGM] losers: bare King wins (stm must have it first)\r
- epStatus[forwardMostMove] = EP_STALEMATE; // kludge to make position claimable as win\r
+ epStatus[forwardMostMove] = EP_WINS; // mark as win, so it becomes claimable\r
if(appData.checkMates) {\r
- SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
+ SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets to see move\r
ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, \r
"Xboard adjudication: Bare king", GE_XBOARD );\r
} else\r
if( gameInfo.variant == VariantShatranj && --bare < 0)\r
{ /* bare King */\r
- epStatus[forwardMostMove] = EP_CHECKMATE; // make claimable as win for stm\r
+ epStatus[forwardMostMove] = EP_WINS; // make claimable as win for stm\r
if(appData.checkMates) {\r
/* but only adjudicate if adjudication enabled */\r
SendMoveToProgram(forwardMostMove-1, cps->other); // make sure opponent gets move\r
} else bare = 1;\r
\r
\r
+ // don't wait for engine to announce game end if we can judge ourselves\r
+ switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove), epFile,\r
+ castlingRights[forwardMostMove]) ) {\r
+ case MT_NONE:\r
+ case MT_CHECK:\r
+ default:\r
+ break;\r
+ case MT_STALEMATE:\r
+ case MT_STAINMATE:\r
+ reason = "Xboard adjudication: Stalemate";\r
+ if(epStatus[forwardMostMove] != EP_CHECKMATE) { // [HGM] don't touch win through baring or K-capt\r
+ epStatus[forwardMostMove] = EP_STALEMATE; // default result for stalemate is draw\r
+ if(gameInfo.variant == VariantLosers || gameInfo.variant == VariantGiveaway) // [HGM] losers:\r
+ epStatus[forwardMostMove] = EP_WINS; // in these variants stalemated is always a win\r
+ else if(gameInfo.variant == VariantSuicide) // in suicide it depends\r
+ epStatus[forwardMostMove] = NrW == NrPieces-NrW ? EP_STALEMATE :\r
+ ((NrW < NrPieces-NrW) != WhiteOnMove(forwardMostMove) ?\r
+ EP_CHECKMATE : EP_WINS);\r
+ else if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi)\r
+ epStatus[forwardMostMove] = EP_CHECKMATE; // and in these variants being stalemated loses\r
+ }\r
+ break;\r
+ case MT_CHECKMATE:\r
+ reason = "Xboard adjudication: Checkmate";\r
+ epStatus[forwardMostMove] = (gameInfo.variant == VariantLosers ? EP_WINS : EP_CHECKMATE);\r
+ break;\r
+ }\r
+\r
+ switch(i = epStatus[forwardMostMove]) {\r
+ case EP_STALEMATE:\r
+ result = GameIsDrawn; break;\r
+ case EP_CHECKMATE:\r
+ result = WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins; break;\r
+ case EP_WINS:\r
+ result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins; break;\r
+ default:\r
+ result = (ChessMove) 0;\r
+ }\r
+ if(appData.checkMates && result) { // [HGM] mates: adjudicate finished games if requested\r
+ SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
+ ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
+ GameEnds( result, reason, GE_XBOARD );\r
+ return;\r
+ }\r
+\r
+ /* Next absolutely insufficient mating material. */\r
if( NrPieces == 2 || gameInfo.variant != VariantXiangqi && \r
gameInfo.variant != VariantShatranj && // [HGM] baring will remain possible\r
(NrPieces == 3 && NrWN+NrBN+NrWB+NrBB == 1 ||\r
if(!ourPerpetual && !hisPerpetual) { // no perpetual check, test for chase\r
hisPerpetual = PerpetualChase(k, forwardMostMove);\r
ourPerpetual = PerpetualChase(k+1, forwardMostMove);\r
- if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit\r
+ if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit\r
GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, \r
"Xboard adjudication: perpetual chasing", GE_XBOARD );\r
return;\r
EP_UNKNOWN, fromY, fromX, toY, toX, promoChar,\r
parseList[boardIndex]);\r
CopyBoard(boards[boardIndex + 1], boards[boardIndex]);\r
+ {int i; for(i=0; i<BOARD_SIZE; i++) castlingRights[boardIndex+1][i] = castlingRights[boardIndex][i];}\r
/* currentMoveString is set as a side-effect of yylex */\r
strcpy(moveList[boardIndex], currentMoveString);\r
strcat(moveList[boardIndex], "\n");\r
boardIndex++;\r
- ApplyMove(fromX, fromY, toX, toY, promoChar, boards[boardIndex]);\r
+ ApplyMove(fromX, fromY, toX, toY, promoChar, boards[boardIndex], \r
+ castlingRights[boardIndex], &epStatus[boardIndex]);\r
switch (MateTest(boards[boardIndex], PosFlags(boardIndex),\r
EP_UNKNOWN, castlingRights[boardIndex]) ) {\r
case MT_NONE:\r
strcat(parseList[boardIndex - 1], "+");\r
break;\r
case MT_CHECKMATE:\r
+ case MT_STAINMATE:\r
strcat(parseList[boardIndex - 1], "#");\r
break;\r
}\r
\r
/* Apply a move to the given board */\r
void\r
-ApplyMove(fromX, fromY, toX, toY, promoChar, board)\r
+ApplyMove(fromX, fromY, toX, toY, promoChar, board, castling, ep)\r
int fromX, fromY, toX, toY;\r
int promoChar;\r
Board board;\r
+ char *castling;\r
+ char *ep;\r
{\r
ChessSquare captured = board[toY][toX], piece, king; int p, oldEP = EP_NONE, berolina = 0;\r
\r
/* [HGM] compute & store e.p. status and castling rights for new position */\r
- /* if we are updating a board for which those exist (i.e. in boards[]) */\r
- if((p = ((int)board - (int)boards[0])/((int)boards[1]-(int)boards[0])) < MAX_MOVES && p > 0)\r
+ /* we can always do that 'in place', now pointers to these rights are passed to ApplyMove */\r
{ int i;\r
\r
if(gameInfo.variant == VariantBerolina) berolina = EP_BEROLIN_A;\r
- oldEP = epStatus[p-1];\r
- epStatus[p] = EP_NONE;\r
+ oldEP = *ep;\r
+ *ep = EP_NONE;\r
\r
if( board[toY][toX] != EmptySquare ) \r
- epStatus[p] = EP_CAPTURE; \r
+ *ep = EP_CAPTURE; \r
\r
if( board[fromY][fromX] == WhitePawn ) {\r
if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers\r
- epStatus[p] = EP_PAWN_MOVE;\r
+ *ep = EP_PAWN_MOVE;\r
if( toY-fromY==2) {\r
if(toX>BOARD_LEFT && board[toY][toX-1] == BlackPawn &&\r
gameInfo.variant != VariantBerolina || toX < fromX)\r
- epStatus[p] = toX | berolina;\r
+ *ep = toX | berolina;\r
if(toX<BOARD_RGHT-1 && board[toY][toX+1] == BlackPawn &&\r
gameInfo.variant != VariantBerolina || toX > fromX) \r
- epStatus[p] = toX;\r
+ *ep = toX;\r
}\r
} else \r
if( board[fromY][fromX] == BlackPawn ) {\r
if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers\r
- epStatus[p] = EP_PAWN_MOVE; \r
+ *ep = EP_PAWN_MOVE; \r
if( toY-fromY== -2) {\r
if(toX>BOARD_LEFT && board[toY][toX-1] == WhitePawn &&\r
gameInfo.variant != VariantBerolina || toX < fromX)\r
- epStatus[p] = toX | berolina;\r
+ *ep = toX | berolina;\r
if(toX<BOARD_RGHT-1 && board[toY][toX+1] == WhitePawn &&\r
gameInfo.variant != VariantBerolina || toX > fromX) \r
- epStatus[p] = toX;\r
+ *ep = toX;\r
}\r
}\r
\r
for(i=0; i<nrCastlingRights; i++) {\r
- castlingRights[p][i] = castlingRights[p-1][i];\r
- if(castlingRights[p][i] == fromX && castlingRank[i] == fromY ||\r
- castlingRights[p][i] == toX && castlingRank[i] == toY \r
- ) castlingRights[p][i] = -1; // revoke for moved or captured piece\r
+ if(castling[i] == fromX && castlingRank[i] == fromY ||\r
+ castling[i] == toX && castlingRank[i] == toY \r
+ ) castling[i] = -1; // revoke for moved or captured piece\r
}\r
\r
}\r
board[toY][toX] = (ChessSquare) (PROMOTED piece);\r
}\r
\r
+ if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) \r
+ && promoChar != NULLCHAR && gameInfo.holdingsSize) { \r
+ // [HGM] superchess: take promotion piece out of holdings\r
+ int k = PieceToNumber(CharToPiece(ToUpper(promoChar)));\r
+ if((int)piece < (int)BlackPawn) { // determine stm from piece color\r
+ if(!--board[k][BOARD_WIDTH-2])\r
+ board[k][BOARD_WIDTH-1] = EmptySquare;\r
+ } else {\r
+ if(!--board[BOARD_HEIGHT-1-k][1])\r
+ board[BOARD_HEIGHT-1-k][0] = EmptySquare;\r
+ }\r
+ }\r
+\r
}\r
\r
/* Updates forwardMostMove */\r
commentList[forwardMostMove+1] = NULL;\r
}\r
CopyBoard(boards[forwardMostMove+1], boards[forwardMostMove]);\r
- ApplyMove(fromX, fromY, toX, toY, promoChar, boards[forwardMostMove+1]);\r
+ {int i; for(i=0; i<BOARD_SIZE; i++) castlingRights[forwardMostMove+1][i] = castlingRights[forwardMostMove][i];}\r
+ ApplyMove(fromX, fromY, toX, toY, promoChar, boards[forwardMostMove+1], \r
+ castlingRights[forwardMostMove+1], &epStatus[forwardMostMove+1]);\r
forwardMostMove++; // [HGM] bare: moved to after ApplyMove, to make sure clock interrupt finds complete board\r
gameInfo.result = GameUnfinished;\r
if (gameInfo.resultDetails != NULL) {\r
strcat(parseList[forwardMostMove - 1], "+");\r
break;\r
case MT_CHECKMATE:\r
+ case MT_STAINMATE:\r
strcat(parseList[forwardMostMove - 1], "#");\r
break;\r
}\r
// [HGM] losers: because the logic is becoming a bit hairy, determine true result first\r
if(epStatus[forwardMostMove] == EP_CHECKMATE) {\r
/* [HGM] verify: engine mate claims accepted if they were flagged */\r
- trueResult = WhiteOnMove(forwardMostMove) != (gameInfo.variant == VariantLosers)\r
- ? BlackWins : WhiteWins; // [HGM] losers: reverse the result in VariantLosers!\r
+ trueResult = WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins;\r
} else\r
- if(epStatus[forwardMostMove] == EP_STALEMATE) {\r
+ if(epStatus[forwardMostMove] == EP_WINS) { // added code for games where being mated is a win\r
+ /* [HGM] verify: engine mate claims accepted if they were flagged */\r
+ trueResult = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins;\r
+ } else\r
+ if(epStatus[forwardMostMove] == EP_STALEMATE) { // only used to indicate draws now\r
trueResult = GameIsDrawn; // default; in variants where stalemate loses, Status is CHECKMATE\r
- if(gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuicide || \r
- gameInfo.variant == VariantLosers) // [HGM] losers: in giveaway variants stalemate wins\r
- trueResult = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins;\r
}\r
\r
// now verify win claims, but not in drop games, as we don't understand those yet\r
case MT_CHECK:\r
break;\r
case MT_CHECKMATE:\r
+ case MT_STAINMATE:\r
if (WhiteOnMove(currentMove)) {\r
GameEnds(BlackWins, "Black mates", GE_FILE);\r
} else {\r
case MT_CHECK:\r
break;\r
case MT_CHECKMATE:\r
+ case MT_STAINMATE:\r
if (WhiteOnMove(currentMove)) {\r
GameEnds(BlackWins, "Black mates", GE_FILE);\r
} else {\r
break;\r
\r
case MT_CHECKMATE:\r
+ case MT_STAINMATE:\r
if (WhiteOnMove(currentMove)) {\r
GameEnds(BlackWins, "Black mates", GE_PLAYER);\r
} else {\r
PrintPGNTags(f, &gameInfo);\r
\r
if (backwardMostMove > 0 || startedFromSetupPosition) {\r
- char *fen = PositionToFEN(backwardMostMove, 1);\r
+ char *fen = PositionToFEN(backwardMostMove, NULL);\r
fprintf(f, "[FEN \"%s\"]\n[SetUp \"1\"]\n", fen);\r
fprintf(f, "\n{--------------\n");\r
PrintPosition(f, backwardMostMove);\r
linelen += numlen;\r
\r
/* Get move */\r
- movelen = strlen(parseList[i]); /* [HGM] pgn: line-break point before move */\r
+ strcpy(move_buffer, parseList[i]); // [HGM] pgn: print move via buffer, so it can be edited\r
+ movelen = strlen(move_buffer); /* [HGM] pgn: line-break point before move */\r
+ if( i >= 0 && appData.saveExtendedInfoInPGN && pvInfoList[i].depth > 0 ) {\r
+ int p = movelen - 1;\r
+ if(move_buffer[p] == ' ') p--;\r
+ if(move_buffer[p] == ')') { // [HGM] pgn: strip off ICS time if we have extended info\r
+ while(p && move_buffer[--p] != '(');\r
+ if(p && move_buffer[p-1] == ' ') move_buffer[movelen=p-1] = 0;\r
+ }\r
+ }\r
\r
/* Print move */\r
blank = linelen > 0 && movelen > 0;\r
fprintf(f, " ");\r
linelen++;\r
}\r
- fprintf(f, parseList[i]);\r
+ fprintf(f, move_buffer);\r
linelen += movelen;\r
\r
/* [AS] Add PV info if present */\r
/* [HGM] add time */\r
char buf[MSG_SIZ]; int seconds = 0;\r
\r
-#if 0\r
+#if 1\r
if(i >= backwardMostMove) {\r
if(WhiteOnMove(i))\r
seconds = timeRemaining[0][i] - timeRemaining[0][i+1]\r
- + GetTimeQuota(i/2) / WhitePlayer()->timeOdds;\r
+ + GetTimeQuota(i/2) / (1000*WhitePlayer()->timeOdds);\r
else\r
seconds = timeRemaining[1][i] - timeRemaining[1][i+1]\r
- + GetTimeQuota(i/2) / WhitePlayer()->other->timeOdds;\r
+ + GetTimeQuota(i/2) / (1000*WhitePlayer()->other->timeOdds);\r
}\r
seconds = (seconds+50)/100; // deci-seconds, rounded to nearest\r
#else\r
PrintPosition(f, currentMove);\r
fprintf(f, "--------------]\n");\r
} else {\r
- fen = PositionToFEN(currentMove, 1);\r
+ fen = PositionToFEN(currentMove, NULL);\r
fprintf(f, "%s\n", fen);\r
free(fen);\r
}\r
WhiteOnMove(moveNumber) ? " " : ".. ",\r
parseList[moveNumber]);\r
}\r
+ // [HGM] PV info: display PV info together with (or as) comment\r
+ if(moveNumber >= 0 && (depth = pvInfoList[moveNumber].depth) > 0) {\r
+ if(text == NULL) text = ""; \r
+ score = pvInfoList[moveNumber].score;\r
+ sprintf(buf, "%s%.2f/%d %d\n%s", score>0 ? "+" : "", score/100.,\r
+ depth, (pvInfoList[moveNumber].time+50)/100, text);\r
+ text = buf;\r
+ }\r
} else title[0] = 0;\r
\r
- // [HGM] PV info: display PV info together with (or as) comment\r
- if(moveNumber >= 0 && (depth = pvInfoList[moveNumber].depth) > 0) {\r
- if(text == NULL) text = ""; \r
- score = pvInfoList[moveNumber].score;\r
- sprintf(buf, "%s%.2f/%d %d\n%s", score>0 ? "+" : "", score/100.,\r
- depth, (pvInfoList[moveNumber].time+50)/100, text);\r
- CommentPopUp(title, buf);\r
- } else\r
if (text != NULL)\r
CommentPopUp(title, text);\r
}\r
\r
\r
char *\r
-PositionToFEN(move, useFEN960)\r
+PositionToFEN(move, overrideCastling)\r
int move;\r
- int useFEN960;\r
+ char *overrideCastling;\r
{\r
int i, j, fromX, fromY, toX, toY;\r
int whiteToPlay;\r
*p++ = whiteToPlay ? 'w' : 'b';\r
*p++ = ' ';\r
\r
+ if(q = overrideCastling) { // [HGM] FRC: override castling & e.p fields for non-compliant engines\r
+ while(*p++ = *q++); if(q != overrideCastling+1) p[-1] = ' ';\r
+ } else {\r
if(nrCastlingRights) {\r
q = p;\r
if(gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) {\r
}\r
*p++ = ' ';\r
}\r
+ }\r
\r
/* [HGM] find reversible plies */\r
{ int i = 0, j=move;\r