#else\r
\r
#define DoSleep( n )\r
+typedef int BOOL;\r
\r
#endif\r
\r
static int exiting = 0; /* [HGM] moved to top */\r
static int setboardSpoiledMachineBlack = 0, errorExitFlag = 0;\r
extern int startedFromPositionFile;\r
-int startedFromPositionFile = FALSE; Board filePosition; /* [HGM] loadPos */\r
-char endingGame = 0; /* [HGM] crash: flag to prevent recursion of GameEnds() */\r
+int startedFromPositionFile = FALSE; Board filePosition; /* [HGM] loadPos */\r
+char endingGame = 0; /* [HGM] crash: flag to prevent recursion of GameEnds() */\r
+int whiteNPS, blackNPS; /* [HGM] nps: for easily making clocks aware of NPS */\r
+VariantClass currentlyInitializedVariant; /* [HGM] variantswitch */\r
\r
/* States for ics_getting_history */\r
#define H_FALSE 0\r
case VariantKriegspiel:\r
flags |= F_KRIEGSPIEL_CAPTURE;\r
break;\r
-/* case VariantCapaRandom: */\r
+ case VariantCapaRandom: \r
case VariantFischeRandom:\r
flags |= F_FRC_TYPE_CASTLING; /* [HGM] enable this through flag */\r
case VariantNoCastle:\r
+ case VariantShatranj:\r
+ case VariantCourier:\r
flags &= ~F_ALL_CASTLE_OK;\r
break;\r
default:\r
char FENepStatus;\r
FILE *serverMoves = NULL; // next two for broadcasting (/serverMoves option)\r
int loadFlag = 0; \r
+int shuffleOpenings;\r
\r
ChessSquare FIDEArray[2][BOARD_SIZE] = {\r
{ WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen,\r
BlackKing, BlackBishop, BlackMarshall, BlackKnight, BlackRook }\r
};\r
\r
+ChessSquare JanusArray[2][BOARD_SIZE] = {\r
+ { WhiteRook, WhiteAngel, WhiteKnight, WhiteBishop, WhiteKing, \r
+ WhiteQueen, WhiteBishop, WhiteKnight, WhiteAngel, WhiteRook },\r
+ { BlackRook, BlackAngel, BlackKnight, BlackBishop, BlackKing, \r
+ BlackQueen, BlackBishop, BlackKnight, BlackAngel, BlackRook }\r
+};\r
+\r
#ifdef GOTHIC\r
ChessSquare GothicArray[2][BOARD_SIZE] = {\r
{ WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteMarshall, \r
first.useSigterm = second.useSigterm = TRUE;\r
first.reuse = appData.reuseFirst;\r
second.reuse = appData.reuseSecond;\r
+ first.nps = appData.firstNPS; // [HGM] nps: copy nodes per second\r
+ second.nps = appData.secondNPS;\r
first.useSetboard = second.useSetboard = FALSE;\r
first.useSAN = second.useSAN = FALSE;\r
first.usePing = second.usePing = FALSE;\r
\r
/* [HGM] debug */\r
first.debug = second.debug = FALSE;\r
+ first.supportsNPS = second.supportsNPS = UNKNOWN;\r
\r
first.scoreIsAbsolute = appData.firstScoreIsAbsolute; /* [AS] */\r
second.scoreIsAbsolute = appData.secondScoreIsAbsolute; /* [AS] */\r
case VariantNormal: /* definitely works! */\r
case VariantWildCastle: /* pieces not automatically shuffled */\r
case VariantNoCastle: /* pieces not automatically shuffled */\r
- case VariantFischeRandom: /* Fabien: pieces not automatically shuffled */\r
+ case VariantFischeRandom: /* [HGM] works and shuffles pieces */\r
case VariantLosers: /* should work except for win condition,\r
and doesn't know captures are mandatory */\r
case VariantSuicide: /* should work except for win condition,\r
case VariantTwoKings: /* should work */\r
case VariantAtomic: /* should work except for win condition */\r
case Variant3Check: /* should work except for win condition */\r
- case VariantShatranj: /* might work if TestLegality is off */\r
+ case VariantShatranj: /* should work except for all win conditions */\r
+ case VariantBerolina: /* might work if TestLegality is off */\r
+ case VariantCapaRandom: /* should work */\r
break;\r
}\r
}\r
char buf[MSG_SIZ];\r
int err;\r
\r
- if (appData.debugMode) {\r
- fprintf(debugFP, "From InitBackend3\n");\r
- }\r
InitChessProgram(&first, startedFromSetupPosition);\r
\r
if (appData.icsActive) {\r
case 45:\r
v = VariantFalcon;\r
break;\r
-\r
+ case 46:\r
+ v = VariantCapaRandom;\r
+ break;\r
+ case 47:\r
+ v = VariantBerolina;\r
+ break;\r
+ case 48:\r
+ v = VariantJanus;\r
+ break;\r
case -1:\r
/* Found "wild" or "w" in the string but no number;\r
must assume it's normal chess. */\r
\r
}\r
\r
-char startBoard[MSG_SIZ]; /* [HGM] variantswitch */\r
\r
void\r
VariantSwitch(Board board, VariantClass newVariant)\r
{\r
- int newHoldingsWidth, newWidth = 8, newHeight = 8, i, j, oldCurrentMove = currentMove;\r
+ int newHoldingsWidth, newWidth = 8, newHeight = 8, i, j;\r
+ int oldCurrentMove = currentMove, oldForwardMostMove = forwardMostMove, oldBackwardMostMove = backwardMostMove;\r
Board tempBoard; int saveCastling[BOARD_SIZE], saveEP;\r
\r
startedFromPositionFile = FALSE;\r
VariantName(gameInfo.variant), VariantName(newVariant));\r
setbuf(debugFP, NULL);\r
}\r
+ shuffleOpenings = 0; /* [HGM] shuffle */\r
gameInfo.holdingsSize = 5; /* [HGM] prepare holdings */\r
- switch(newVariant) {\r
+ switch(newVariant) {\r
case VariantShogi:\r
newWidth = 9; newHeight = 9;\r
gameInfo.holdingsSize = 7;\r
saveEP = epStatus[0];\r
#endif\r
InitPosition(FALSE); /* this sets up board[0], but also other stuff */\r
- forwardMostMove = backwardMostMove =\r
- currentMove = oldCurrentMove; /* InitPos reset this, but we need still to redraw it */\r
#if 0\r
epStatus[0] = saveEP;\r
for(i=0; i<BOARD_SIZE; i++) castlingRights[0][i] = saveCastling[i];\r
CopyBoard(tempBoard, board); /* restore position received from ICS */\r
#endif\r
} else { gameInfo.variant = newVariant; InitPosition(FALSE); }\r
+\r
+ forwardMostMove = oldForwardMostMove;\r
+ backwardMostMove = oldBackwardMostMove;\r
+ currentMove = oldCurrentMove; /* InitPos reset these, but we need still to redraw the position */\r
}\r
\r
static int loggedOn = FALSE;\r
/* Send "new" early, in case this command takes\r
a long time to finish, so that we'll be ready\r
for the next challenge. */\r
+ gameInfo.variant = VariantNormal; // [HGM] variantswitch: suppress sending of 'variant'\r
Reset(TRUE, TRUE);\r
}\r
#endif /*ZIPPY*/\r
if(startedFromSetupPosition)\r
initialRulePlies = irrev_count; /* [HGM] 50-move counter offset */\r
}\r
- /* [HGM] variantswitch: remember the last initial position parsed, */\r
- /* because it might have been parsed in the wrong variant, so that */\r
- /* we can re-parse it once we know the proper variant (which might */\r
- /* have different piece assignments for the same letters). */\r
- if(moveNum == 0) strcpy(startBoard, string);\r
\r
/* [HGM] Set castling rights. Take the outermost Rooks,\r
to make it also work for FRC opening positions. Note that board12\r
sprintf(str, "Couldn't parse move \"%s\" from ICS", move_str);\r
DisplayError(str, 0);\r
} else {\r
+ if(gameInfo.variant == currentlyInitializedVariant) // [HGM] refrain sending moves engine can't understand!\r
SendMoveToProgram(moveNum - 1, &first);\r
}\r
}\r
if (gameInfo.variant != VariantBughouse &&\r
gameInfo.variant != VariantCrazyhouse) {\r
if (tinyLayout || smallLayout) {\r
- sprintf(str, "%s(%d) %s(%d) {%d %d}", \r
+ if(gameInfo.variant == VariantNormal)\r
+ sprintf(str, "%s(%d) %s(%d) {%d %d}", \r
gameInfo.white, white_stren, gameInfo.black, black_stren,\r
basetime, increment);\r
+ else\r
+ sprintf(str, "%s(%d) %s(%d) {%d %d w%d}", \r
+ gameInfo.white, white_stren, gameInfo.black, black_stren,\r
+ basetime, increment, (int) gameInfo.variant);\r
} else {\r
- sprintf(str, "%s (%d) vs. %s (%d) {%d %d}", \r
+ if(gameInfo.variant == VariantNormal)\r
+ sprintf(str, "%s (%d) vs. %s (%d) {%d %d}", \r
gameInfo.white, white_stren, gameInfo.black, black_stren,\r
basetime, increment);\r
+ else\r
+ sprintf(str, "%s (%d) vs. %s (%d) {%d %d %s}", \r
+ gameInfo.white, white_stren, gameInfo.black, black_stren,\r
+ basetime, increment, VariantName(gameInfo.variant));\r
}\r
DisplayTitle(str);\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "Display title '%s, gameInfo.variant = %d'\n", str, gameInfo.variant);\r
+ }\r
}\r
\r
\r
/* Added by Tord: Send castle moves in "O-O" in FRC games if required by\r
* the engine. It would be nice to have a better way to identify castle \r
* moves here. */\r
- if(gameInfo.variant == VariantFischeRandom && cps->useOOCastle) {\r
+ if((gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom)\r
+ && cps->useOOCastle) {\r
if (appData.debugMode) {\r
fprintf(debugFP, "Tord's FRC castling code\n");\r
}\r
case BlackDrop:\r
*fromX = *moveType == WhiteDrop ?\r
(int) CharToPiece(ToUpper(currentMoveString[0])) :\r
- (int) CharToPiece(ToLower(currentMoveString[0]));\r
+ (int) CharToPiece(ToLower(currentMoveString[0]));\r
*fromY = DROP_RANK;\r
*toX = currentMoveString[2] - AAA;\r
*toY = currentMoveString[3] - ONE;\r
return i;\r
}\r
\r
+#if 0\r
static void ShuffleFRC( Board board )\r
{\r
int 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
+// 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
+#define LITE 2\r
+#define ANY 3\r
+\r
+int squaresLeft[4];\r
+int piecesLeft[(int)BlackPawn];\r
+long long int seed, nrOfShuffles;\r
+\r
+int put(Board board, int pieceType, int rank, int n, int shade)\r
+// put the piece on the (n-1)-th empty squares of the given shade\r
+{\r
+ int i;\r
+\r
+ for(i=BOARD_LEFT; i<BOARD_RGHT; i++) {\r
+ if( ((i-BOARD_LEFT)&1)+1 & shade && board[rank][i] == EmptySquare && n-- == 0) {\r
+ board[rank][i] = (ChessSquare) pieceType;\r
+ squaresLeft[(i-BOARD_LEFT&1) + 1]--;\r
+ squaresLeft[ANY]--;\r
+ piecesLeft[pieceType]--; \r
+ return i;\r
+ }\r
+ }\r
+ return -1;\r
+}\r
+\r
+\r
+void AddOnePiece(Board board, int pieceType, int rank, int shade)\r
+// calculate where the next piece goes, (any empty square), and put it there\r
+{\r
+ int i;\r
+\r
+ i = seed % squaresLeft[shade];\r
+ nrOfShuffles *= squaresLeft[shade];\r
+ seed /= squaresLeft[shade];\r
+ put(board, pieceType, rank, i, shade);\r
+}\r
+\r
+void AddTwoPieces(Board board, int pieceType, int rank)\r
+// calculate where the next 2 identical pieces go, (any empty square), and put it there\r
+{\r
+ int i, n=squaresLeft[ANY], j=n-1, k;\r
+\r
+ k = n*(n-1)/2; // nr of possibilities, not counting permutations\r
+ i = seed % k; // pick one\r
+ nrOfShuffles *= k;\r
+ seed /= k;\r
+ while(i >= j) i -= j--;\r
+ j = n - 1 - j; i += j;\r
+ put(board, pieceType, rank, j, ANY);\r
+ put(board, pieceType, rank, i, ANY);\r
+}\r
+\r
+void SetUpShuffle(Board board, int number)\r
+{\r
+ int i, p, first=1;\r
+\r
+ seed = number, nrOfShuffles = 1;\r
+ if(number < 0) { \r
+ srand(time(0)); \r
+ for(i=0; i<50; i++) seed += rand();\r
+ seed = rand() ^ rand()<<16; \r
+ }\r
+\r
+ squaresLeft[DARK] = (BOARD_RGHT - BOARD_LEFT + 1)/2;\r
+ squaresLeft[ANY] = BOARD_RGHT - BOARD_LEFT;\r
+ squaresLeft[LITE] = squaresLeft[ANY] - squaresLeft[DARK];\r
+\r
+ for(p = 0; p<=(int)WhiteKing; p++) piecesLeft[p] = 0;\r
+\r
+ for(i=BOARD_LEFT; i<BOARD_RGHT; i++) { // count pieces and clear board\r
+ p = (int) board[0][i];\r
+ if(p < (int) BlackPawn) piecesLeft[p] ++;\r
+ board[0][i] = EmptySquare;\r
+ }\r
+\r
+ if(PosFlags(0) & F_ALL_CASTLE_OK) {\r
+ // shuffles restricted to allow normal castling put KRR first\r
+ if(piecesLeft[(int)WhiteKing]) // King goes rightish of middle\r
+ put(board, WhiteKing, 0, (gameInfo.boardWidth+1)/2, ANY);\r
+ else if(piecesLeft[(int)WhiteUnicorn]) // in Knightmate Unicorn castles\r
+ put(board, WhiteUnicorn, 0, (gameInfo.boardWidth+1)/2, ANY);\r
+ if(piecesLeft[(int)WhiteRook]) // First supply a Rook for K-side castling\r
+ put(board, WhiteRook, 0, gameInfo.boardWidth-2, ANY);\r
+ if(piecesLeft[(int)WhiteRook]) // Then supply a Rook for Q-side castling\r
+ put(board, WhiteRook, 0, 0, ANY);\r
+ // in variants with super-numerary Kings and Rooks, we leave these for the shuffle\r
+ }\r
+\r
+ if((BOARD_RGHT-BOARD_LEFT & 1) == 0)\r
+ // only for even boards make effort to put pairs of colorbound pieces on opposite colors\r
+ for(p = (int) WhiteKing; p > (int) WhitePawn; p--) {\r
+ if(p != (int) WhiteBishop && p != (int) WhiteFerz && p != (int) WhiteAlfil) continue;\r
+ while(piecesLeft[p] >= 2) {\r
+ AddOnePiece(board, p, 0, LITE);\r
+ AddOnePiece(board, p, 0, DARK);\r
+ }\r
+ // Odd color-bound pieces are shuffled with the rest (to not run out of paired squares)\r
+ }\r
+\r
+ for(p = (int) WhiteKing - 2; p > (int) WhitePawn; p--) {\r
+ // Remaining pieces (non-colorbound, or odd color bound) can be put anywhere\r
+ // but we leave King and Rooks for last, to possibly obey FRC restriction\r
+ if(p == (int)WhiteRook) continue;\r
+ while(piecesLeft[p] >= 2) AddTwoPieces(board, p, 0); // add in pairs, for not counting permutations\r
+ if(piecesLeft[p]) AddOnePiece(board, p, 0, ANY); // add the odd piece\r
+ }\r
+\r
+ // now everything is placed, except perhaps King (Unicorn) and Rooks\r
+\r
+ if(PosFlags(0) & F_FRC_TYPE_CASTLING) {\r
+ // Last King gets castling rights\r
+ while(piecesLeft[(int)WhiteUnicorn]) {\r
+ i = put(board, WhiteUnicorn, 0, piecesLeft[(int)WhiteRook]/2, ANY);\r
+ initialRights[2] = initialRights[5] = castlingRights[0][2] = castlingRights[0][5] = i;\r
+ }\r
+\r
+ while(piecesLeft[(int)WhiteKing]) {\r
+ i = put(board, WhiteKing, 0, piecesLeft[(int)WhiteRook]/2, ANY);\r
+ initialRights[2] = initialRights[5] = castlingRights[0][2] = castlingRights[0][5] = i;\r
+ }\r
+\r
+\r
+ } else {\r
+ while(piecesLeft[(int)WhiteKing]) AddOnePiece(board, WhiteKing, 0, ANY);\r
+ while(piecesLeft[(int)WhiteUnicorn]) AddOnePiece(board, WhiteUnicorn, 0, ANY);\r
+ }\r
+\r
+ // Only Rooks can be left; simply place them all\r
+ while(piecesLeft[(int)WhiteRook]) {\r
+ i = put(board, WhiteRook, 0, 0, ANY);\r
+ if(PosFlags(0) & F_FRC_TYPE_CASTLING) { // first and last Rook get FRC castling rights\r
+ if(first) {\r
+ first=0;\r
+ initialRights[1] = initialRights[4] = castlingRights[0][1] = castlingRights[0][4] = i;\r
+ }\r
+ initialRights[0] = initialRights[3] = castlingRights[0][0] = castlingRights[0][3] = i;\r
+ }\r
+ }\r
+ for(i=BOARD_LEFT; i<BOARD_RGHT; i++) { // copy black from white\r
+ board[BOARD_HEIGHT-1][i] = (int) board[0][i] < BlackPawn ? WHITE_TO_BLACK board[0][i] : EmptySquare;\r
+ }\r
+\r
+ if(number >= 0) appData.defaultFrcPosition %= nrOfShuffles; // normalize\r
+}\r
+\r
+#endif\r
\r
BOOL SetCharTable( char *table, const char * map )\r
/* [HGM] moved here from winboard.c because of its general usefulness */\r
oldv = gameInfo.variant;\r
\r
currentMove = forwardMostMove = backwardMostMove = 0;\r
+ if(appData.icsActive) shuffleOpenings = FALSE; // [HGM] shuffle: in ICS mode, only shuffle on ICS request\r
\r
/* [AS] Initialize pv info list [HGM] and game status */\r
{\r
SetCharTable(pieceToChar, "PNBRQ...........Kpnbrq...........k"); \r
\r
switch (gameInfo.variant) {\r
+ case VariantFischeRandom:\r
+ shuffleOpenings = TRUE;\r
default:\r
pieces = FIDEArray;\r
break;\r
castlingRank[6] = 0;\r
castlingRank[7] = BOARD_HEIGHT-1;\r
break;\r
+ case VariantCapaRandom:\r
+ shuffleOpenings = TRUE;\r
case VariantCapablanca:\r
pieces = CapablancaArray;\r
gameInfo.boardWidth = 10;\r
gameInfo.boardWidth = 10;\r
SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack"); \r
break;\r
+ case VariantJanus:\r
+ pieces = JanusArray;\r
+ gameInfo.boardWidth = 10;\r
+ SetCharTable(pieceToChar, "PNBRQ..JKpnbrq..jk"); \r
+ nrCastlingRights = 6;\r
+ castlingRights[0][0] = initialRights[0] = BOARD_RGHT-1;\r
+ castlingRights[0][1] = initialRights[1] = BOARD_LEFT;\r
+ castlingRights[0][2] = initialRights[2] = BOARD_WIDTH-1>>1;\r
+ castlingRights[0][3] = initialRights[3] = BOARD_RGHT-1;\r
+ castlingRights[0][4] = initialRights[4] = BOARD_LEFT;\r
+ castlingRights[0][5] = initialRights[5] = BOARD_WIDTH-1>>1;\r
+ break;\r
case VariantFalcon:\r
pieces = FalconArray;\r
gameInfo.boardWidth = 10;\r
case VariantWildCastle:\r
pieces = FIDEArray;\r
/* !!?shuffle with kings guaranteed to be on d or e file */\r
+ shuffleOpenings = 1;\r
break;\r
case VariantNoCastle:\r
pieces = FIDEArray;\r
nrCastlingRights = 0;\r
for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1;\r
/* !!?unconstrained back-rank shuffle */\r
+ shuffleOpenings = 1;\r
break;\r
}\r
\r
castlingRights[0][5] = initialRights[5] = BOARD_WIDTH>>1;\r
}\r
\r
+#if 0\r
if(gameInfo.variant == VariantFischeRandom) {\r
if( appData.defaultFrcPosition < 0 ) {\r
ShuffleFRC( initialPosition );\r
SetupFRC( initialPosition, appData.defaultFrcPosition );\r
}\r
startedFromSetupPosition = TRUE;\r
- } else if(startedFromPositionFile) {\r
+ } else \r
+#else\r
+ if (appData.debugMode) {\r
+ fprintf(debugFP, "shuffleOpenings = %d\n", shuffleOpenings);\r
+ }\r
+ if(shuffleOpenings) {\r
+ SetUpShuffle(initialPosition, appData.defaultFrcPosition);\r
+ startedFromSetupPosition = TRUE;\r
+ }\r
+#endif\r
+ if(startedFromPositionFile) {\r
/* [HGM] loadPos: use PositionFile for every new game */\r
CopyBoard(initialPosition, filePosition);\r
for(i=0; i<nrCastlingRights; i++)\r
SendToProgram("edit\n", cps);\r
SendToProgram("#\n", cps);\r
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
- bp = &boards[moveNum][i][0];\r
+ bp = &boards[moveNum][i][BOARD_LEFT];\r
for (j = BOARD_LEFT; j < BOARD_RGHT; j++, bp++) {\r
if ((int) *bp < (int) BlackPawn) {\r
sprintf(message, "%c%c%c\n", PieceToChar(*bp), \r
\r
SendToProgram("c\n", cps);\r
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
- bp = &boards[moveNum][i][0];\r
+ bp = &boards[moveNum][i][BOARD_LEFT];\r
for (j = BOARD_LEFT; j < BOARD_RGHT; j++, bp++) {\r
if (((int) *bp != (int) EmptySquare)\r
&& ((int) *bp >= (int) BlackPawn)) {\r
int x;\r
int y;\r
{\r
- if (x < BOARD_LEFT || x >= BOARD_RGHT || y < 0 || y >= BOARD_HEIGHT)\r
+ if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT)\r
return -1;\r
else\r
return boards[currentMove][y][x];\r
WhitePawn <= pup && pup < BlackPawn ||\r
BlackPawn <= pdown && pdown < EmptySquare &&\r
BlackPawn <= pup && pup < EmptySquare \r
- ) && !(gameInfo.variant == VariantFischeRandom &&\r
+ ) && !((gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) &&\r
(pup == WhiteRook && pdown == WhiteKing && fromY == 0 && toY == 0||\r
pup == BlackRook && pdown == BlackKing && fromY == BOARD_HEIGHT-1 && toY == BOARD_HEIGHT-1 ) \r
) )\r
sprintf(buf, "name %s\n", gameInfo.white);\r
SendToProgram(buf, &first);\r
}\r
+ StartClocks();\r
}\r
ModeHighlight();\r
}\r
machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);\r
GameEnds(machineWhite ? BlackWins : WhiteWins,\r
buf1, GE_XBOARD);\r
- } else if(gameInfo.variant != VariantFischeRandom)\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
switch(moveType) {\r
first.initDone) {\r
SendMoveToICS(moveType, fromX, fromY, toX, toY);\r
ics_user_moved = 1;\r
+ if(appData.autoKibitz) { /* [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
+ programStats.score / 100.,\r
+ programStats.time / 100.,\r
+ (double) programStats.nodes,\r
+ programStats.nodes / (10*abs(programStats.time) + 1.),\r
+ programStats.movelist);\r
+ SendToICS(buf);\r
+ }\r
}\r
#endif\r
/* currentMoveString is set as a side-effect of ParseOneMove */\r
}\r
}\r
\r
+ /* Shatranj baring rule */\r
+ if( gameInfo.variant == VariantShatranj && (NrW == 1 || NrPieces - NrW == 1) )\r
+ { /* bare King */\r
+\r
+ if(--bare < 0 && appData.checkMates) {\r
+ /* but only adjudicate them if adjudication enabled */\r
+ ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
+ GameEnds( NrW > 1 ? WhiteWins : NrPiece - NrW > 1 ? BlackWins : GameIsDrawn, \r
+ "Xboard adjudication: Bare king", GE_XBOARD );\r
+ return;\r
+ }\r
+ } else bare = 1;\r
+\r
/* Then some trivial draws (only adjudicate, cannot be claimed) */\r
if(NrPieces == 4 && \r
( NrWR == 1 && NrBR == 1 /* KRKR */\r
ParseFeatures(message+8, cps);\r
}\r
if (sscanf(message, "pong %d", &cps->lastPong) == 1) {\r
- return;\r
+ return;\r
}\r
/*\r
* If the move is illegal, cancel it and redraw the board.\r
programStats.score = curscore;\r
programStats.got_only_move = 0;\r
\r
+ if(cps->nps >= 0) { /* [HGM] nps: use engine nodes or time to decrement clock */\r
+ int ticklen;\r
+\r
+ if(cps->nps == 0) ticklen = 10*time; // use engine reported time\r
+ else ticklen = (1000. * nodes) / cps->nps; // convert node count to time\r
+ if(WhiteOnMove(forwardMostMove)) \r
+ whiteTimeRemaining = timeRemaining[0][forwardMostMove] - ticklen;\r
+ else blackTimeRemaining = timeRemaining[1][forwardMostMove] - ticklen;\r
+ }\r
+\r
/* Buffer overflow protection */\r
if (buf1[0] != NULLCHAR) {\r
if (strlen(buf1) >= sizeof(programStats.movelist)\r
int promoChar;\r
Board board;\r
{\r
- ChessSquare captured = board[toY][toX], piece, king; int p;\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
{ int i, j;\r
\r
+ if(gameInfo.variant == VariantBerolina) berolina = EP_BEROLIN_A;\r
+ oldEP = epStatus[p-1];\r
epStatus[p] = EP_NONE;\r
\r
if( board[toY][toX] != EmptySquare ) \r
\r
if( board[fromY][fromX] == WhitePawn ) {\r
epStatus[p] = EP_PAWN_MOVE; \r
- if( toY-fromY==2 &&\r
- (toX>BOARD_LEFT && board[toY][toX-1] == BlackPawn ||\r
- toX<BOARD_RGHT-1 && board[toY][toX+1] == BlackPawn ) )\r
- epStatus[p] = toX;\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
+ if(toX<BOARD_RGHT-1 && board[toY][toX+1] == BlackPawn &&\r
+ gameInfo.variant != VariantBerolina || toX > fromX) \r
+ epStatus[p] = toX;\r
} else \r
if( board[fromY][fromX] == BlackPawn ) {\r
epStatus[p] = EP_PAWN_MOVE; \r
- if( toY-fromY== -2 &&\r
- (toX>BOARD_LEFT && board[toY][toX-1] == WhitePawn ||\r
- toX<BOARD_RGHT-1 && board[toY][toX+1] == WhitePawn ) )\r
- epStatus[p] = toX;\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
+ if(toX<BOARD_RGHT-1 && board[toY][toX+1] == WhitePawn &&\r
+ gameInfo.variant != VariantBerolina || toX > fromX) \r
+ epStatus[p] = toX;\r
}\r
\r
for(i=0; i<nrCastlingRights; i++) {\r
} else if ((fromY == BOARD_HEIGHT-4)\r
&& (toX != fromX)\r
&& gameInfo.variant != VariantXiangqi\r
+ && gameInfo.variant != VariantBerolina\r
&& (board[fromY][fromX] == WhitePawn)\r
&& (board[toY][toX] == EmptySquare)) {\r
board[fromY][fromX] = EmptySquare;\r
board[toY][toX] = WhitePawn;\r
captured = board[toY - 1][toX];\r
board[toY - 1][toX] = EmptySquare;\r
+ } else if ((fromY == BOARD_HEIGHT-4)\r
+ && (toX == fromX)\r
+ && gameInfo.variant == VariantBerolina\r
+ && (board[fromY][fromX] == WhitePawn)\r
+ && (board[toY][toX] == EmptySquare)) {\r
+ board[fromY][fromX] = EmptySquare;\r
+ board[toY][toX] = WhitePawn;\r
+ if(oldEP & EP_BEROLIN_A) {\r
+ captured = board[fromY][fromX-1];\r
+ board[fromY][fromX-1] = EmptySquare;\r
+ }else{ captured = board[fromY][fromX+1];\r
+ board[fromY][fromX+1] = EmptySquare;\r
+ }\r
} else if (board[fromY][fromX] == king\r
&& fromX != BOARD_LEFT && fromX != BOARD_RGHT-1 // [HGM] cylinder */\r
&& toY == fromY && toX > fromX+1) {\r
} else if ((fromY == 3)\r
&& (toX != fromX)\r
&& gameInfo.variant != VariantXiangqi\r
+ && gameInfo.variant != VariantBerolina\r
&& (board[fromY][fromX] == BlackPawn)\r
&& (board[toY][toX] == EmptySquare)) {\r
board[fromY][fromX] = EmptySquare;\r
board[toY][toX] = BlackPawn;\r
captured = board[toY + 1][toX];\r
board[toY + 1][toX] = EmptySquare;\r
+ } else if ((fromY == 3)\r
+ && (toX == fromX)\r
+ && gameInfo.variant == VariantBerolina\r
+ && (board[fromY][fromX] == BlackPawn)\r
+ && (board[toY][toX] == EmptySquare)) {\r
+ board[fromY][fromX] = EmptySquare;\r
+ board[toY][toX] = BlackPawn;\r
+ if(oldEP & EP_BEROLIN_A) {\r
+ captured = board[fromY][fromX-1];\r
+ board[fromY][fromX-1] = EmptySquare;\r
+ }else{ captured = board[fromY][fromX+1];\r
+ board[fromY][fromX+1] = EmptySquare;\r
+ }\r
} else {\r
board[toY][toX] = board[fromY][fromX];\r
board[fromY][fromX] = EmptySquare;\r
if (gameInfo.variant != VariantNormal &&\r
gameInfo.variant != VariantLoadable\r
/* [HGM] also send variant if board size non-standard */\r
- || gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8\r
+ || gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0\r
) {\r
char *v = VariantName(gameInfo.variant);\r
if (cps->protocolVersion != 1 && StrStr(cps->variants, v) == NULL) {\r
overruled = gameInfo.boardWidth != 9 || gameInfo.boardHeight != 9 || gameInfo.holdingsSize != 7;\r
if( gameInfo.variant == VariantBughouse || gameInfo.variant == VariantCrazyhouse )\r
overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 5;\r
- if( gameInfo.variant == VariantCapablanca || gameInfo.variant == VariantGothic || gameInfo.variant == VariantFalcon )\r
+ if( gameInfo.variant == VariantCapablanca || gameInfo.variant == VariantCapaRandom || \r
+ gameInfo.variant == VariantGothic || gameInfo.variant == VariantFalcon )\r
overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;\r
if( gameInfo.variant == VariantCourier )\r
overruled = gameInfo.boardWidth != 12 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;\r
} else sprintf(b, "%s", VariantName(gameInfo.variant));\r
sprintf(buf, "variant %s\n", b);\r
SendToProgram(buf, cps);\r
- /* [HGM] send opening position in FRC to first engine */\r
- if(setup /* cps == &first && gameInfo.variant == VariantFischeRandom */) {\r
+ }\r
+ currentlyInitializedVariant = gameInfo.variant;\r
+\r
+ /* [HGM] send opening position in FRC to first engine */\r
+ if(setup) {\r
SendToProgram("force\n", cps);\r
SendBoard(cps, 0);\r
/* engine is now in force mode! Set flag to wake it up after first move. */\r
setboardSpoiledMachineBlack = 1;\r
- }\r
}\r
+\r
if (cps->sendICS) {\r
sprintf(buf, "ics %s\n", appData.icsActive ? appData.icsHost : "-");\r
SendToProgram(buf, cps);\r
fprintf(debugFP, "Feeding %smoves %d through %d to %s chess program\n",\r
startedFromSetupPosition ? "position and " : "",\r
backwardMostMove, upto, cps->which);\r
+ if(currentlyInitializedVariant != gameInfo.variant) { char buf[MSG_SIZ];\r
+ // [HGM] variantswitch: make engine aware of new variant\r
+ if(cps->protocolVersion > 1 && StrStr(cps->variants, VariantName(gameInfo.variant)) == NULL)\r
+ return; // [HGM] refrain from feeding moves altogether if variant is unsupported!\r
+ sprintf(buf, "variant %s\n", VariantName(gameInfo.variant));\r
+ SendToProgram(buf, cps);\r
+ currentlyInitializedVariant = gameInfo.variant;\r
+ }\r
SendToProgram("force\n", cps);\r
if (startedFromSetupPosition) {\r
SendBoard(cps, backwardMostMove);\r
if (appData.noChessProgram || first.pr != NoProc) return;\r
\r
StartChessProgram(&first);\r
- if (appData.debugMode) {\r
- fprintf(debugFP, "From ResurrectChessProgram\n");\r
- }\r
InitChessProgram(&first, FALSE);\r
FeedMovesToProgram(&first, currentMove);\r
\r
ExitAnalyzeMode();\r
gameMode = BeginningOfGame;\r
ModeHighlight();\r
+ if(appData.icsActive) gameInfo.variant = VariantNormal;\r
InitPosition(redraw);\r
for (i = 0; i < MAX_MOVES; i++) {\r
if (commentList[i] != NULL) {\r
StartChessProgram(&first);\r
}\r
if (init) {\r
- if (appData.debugMode) {\r
- fprintf(debugFP, "From Reset\n");\r
+ InitChessProgram(&first, startedFromSetupPosition);\r
}\r
-InitChessProgram(&first, startedFromSetupPosition);}\r
DisplayTitle("");\r
DisplayMessage("", "");\r
HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1);\r
initialRulePlies = FENrulePlies;\r
epStatus[0] = FENepStatus;\r
for( i=0; i< nrCastlingRights; i++ )\r
- castlingRights[0][i] = FENcastlingRights[i];\r
+ initialRights[i] = castlingRights[0][i] = FENcastlingRights[i];\r
}\r
if (blackPlaysFirst) {\r
currentMove = forwardMostMove = backwardMostMove = 1;\r
if (first.pr == NoProc) {\r
StartChessProgram(&first);\r
}\r
- if (appData.debugMode) {\r
- fprintf(debugFP, "From LoadGame\n");\r
- }\r
InitChessProgram(&first, FALSE);\r
SendToProgram("force\n", &first);\r
if (startedFromSetupPosition) {\r
strcpy(lastLoadPositionTitle, title);\r
if (first.pr == NoProc) {\r
StartChessProgram(&first);\r
- if (appData.debugMode) {\r
- fprintf(debugFP, "From LoadPosition\n");\r
- }\r
InitChessProgram(&first, FALSE);\r
} \r
pn = positionNumber;\r
/* [HGM] add time */\r
char buf[MSG_SIZ]; int seconds = 0;\r
\r
+#if 0\r
if(i >= backwardMostMove) {\r
/* take the time that changed */\r
seconds = timeRemaining[0][i] - timeRemaining[0][i+1];\r
seconds = timeRemaining[1][i] - timeRemaining[1][i+1];\r
}\r
seconds /= 1000;\r
- seconds = pvInfoList[i].time/100;\r
+#endif\r
+ seconds = pvInfoList[i].time/100; // [HGM] PVtime: use engine time\r
if (appData.debugMode) {\r
fprintf(debugFP, "times = %d %d %d %d, seconds=%d\n",\r
timeRemaining[0][i+1], timeRemaining[0][i],\r
return;\r
}\r
DisplayMessage("", "");\r
- if (appData.debugMode) {\r
- fprintf(debugFP, "From TwoMachines\n");\r
- }\r
InitChessProgram(&second, FALSE);\r
SendToProgram("force\n", &second);\r
if (startedFromSetupPosition) {\r
EditPositionDone()\r
{\r
startedFromSetupPosition = TRUE;\r
- if (appData.debugMode) {\r
- fprintf(debugFP, "From EditPosition\n");\r
- }\r
InitChessProgram(&first, FALSE);\r
SendToProgram("force\n", &first);\r
if (blackPlaysFirst) {\r
*end_str = NULLCHAR;\r
\r
if (appData.debugMode) {\r
- TimeMark now;\r
- GetTimeMark(&now);\r
- fprintf(debugFP, "%ld <%-6s: %s\n", \r
- SubtractTimeMarks(&now, &programStartTime),\r
- cps->which, message);\r
+ TimeMark now; int print = 1;\r
+ char *quote = ""; char c; int i;\r
+\r
+ if(appData.engineComments != 1) { /* [HGM] debug: decide if protocol-violating output is written */\r
+ char start = message[0];\r
+ if(start >='A' && start <= 'Z') start += 'a' - 'A'; // be tolerant to capitalizing\r
+ if(sscanf(message, "%d%c%d%d%d", &i, &c, &i, &i, &i) != 5 && \r
+ sscanf(message, "move %c", &c)!=1 && sscanf(message, "offer%c", &c)!=1 &&\r
+ sscanf(message, "resign%c", &c)!=1 && sscanf(message, "feature %c", &c)!=1 &&\r
+ sscanf(message, "error %c", &c)!=1 && sscanf(message, "illegal %c", &c)!=1 &&\r
+ sscanf(message, "tell%c", &c)!=1 && sscanf(message, "0-1 %c", &c)!=1 &&\r
+ sscanf(message, "askuser%c", &c)!=1 && sscanf(message, "1-0 %c", &c)!=1 && \r
+ sscanf(message, "1/2-1/2 %c", &c)!=1 && start != '#')\r
+ { quote = "# "; print = (appData.engineComments == 2); }\r
+ message[0] = start; // restore original message\r
+ }\r
+ if(print) {\r
+ GetTimeMark(&now);\r
+ fprintf(debugFP, "%ld <%-6s: %s%s\n", \r
+ SubtractTimeMarks(&now, &programStartTime), cps->which, \r
+ quote,\r
+ message);\r
+ }\r
}\r
HandleMachineMove(message, cps);\r
}\r
}\r
SendToProgram(buf, cps);\r
}\r
+\r
+ if(cps->nps > 0) { /* [HGM] nps */\r
+ if(cps->supportsNPS == FALSE) cps->nps = -1; // don't use if engine explicitly says not supported!\r
+ else {\r
+ sprintf(buf, "nps %d\n", cps->nps);\r
+ SendToProgram(buf, cps);\r
+ }\r
+ }\r
}\r
\r
ChessProgramState *WhitePlayer()\r
if (BoolFeature(&p, "name", &cps->sendName, cps)) continue;\r
if (BoolFeature(&p, "pause", &val, cps)) continue; /* unused at present */\r
if (BoolFeature(&p, "debug", &cps->debug, cps)) continue;\r
+ if (BoolFeature(&p, "nps", &cps->supportsNPS, cps)) continue;\r
if (IntFeature(&p, "level", &cps->maxNrOfSessions, cps)) continue;\r
if (IntFeature(&p, "done", &val, cps)) {\r
FeatureDone(cps, val);\r
if (fudge < 0 || fudge > FUDGE) fudge = 0;\r
\r
if (WhiteOnMove(forwardMostMove)) {\r
+ if(whiteNPS >= 0) lastTickLength = 0;\r
timeRemaining = whiteTimeRemaining -= lastTickLength;\r
DisplayWhiteClock(whiteTimeRemaining - fudge,\r
WhiteOnMove(currentMove));\r
} else {\r
+ if(blackNPS >= 0) lastTickLength = 0;\r
timeRemaining = blackTimeRemaining -= lastTickLength;\r
DisplayBlackClock(blackTimeRemaining - fudge,\r
!WhiteOnMove(currentMove));\r
if (StopClockTimer() && appData.clockMode) {\r
lastTickLength = SubtractTimeMarks(&now, &tickStartTM);\r
if (WhiteOnMove(forwardMostMove)) {\r
+ if(blackNPS >= 0) lastTickLength = 0;\r
blackTimeRemaining -= lastTickLength;\r
/* [HGM] PGNtime: save time for PGN file if engine did not give it */\r
if(pvInfoList[forwardMostMove-1].time == -1)\r
pvInfoList[forwardMostMove-1].time = \r
(timeRemaining[1][forwardMostMove-1] - blackTimeRemaining)/10;\r
} else {\r
- whiteTimeRemaining -= lastTickLength;\r
+ if(whiteNPS >= 0) lastTickLength = 0;\r
+ whiteTimeRemaining -= lastTickLength;\r
/* [HGM] PGNtime: save time for PGN file if engine did not give it */\r
if(pvInfoList[forwardMostMove-1].time == -1)\r
pvInfoList[forwardMostMove-1].time = \r
\r
lastTickLength = SubtractTimeMarks(&now, &tickStartTM);\r
if (WhiteOnMove(forwardMostMove)) {\r
+ if(whiteNPS >= 0) lastTickLength = 0;\r
whiteTimeRemaining -= lastTickLength;\r
DisplayWhiteClock(whiteTimeRemaining, WhiteOnMove(currentMove));\r
} else {\r
+ if(blackNPS >= 0) lastTickLength = 0;\r
blackTimeRemaining -= lastTickLength;\r
DisplayBlackClock(blackTimeRemaining, !WhiteOnMove(currentMove));\r
}\r
GetTimeMark(&tickStartTM);\r
intendedTickLength = NextTickLength(WhiteOnMove(forwardMostMove) ?\r
whiteTimeRemaining : blackTimeRemaining);\r
+\r
+ /* [HGM] nps: figure out nps factors, by determining which engine plays white and/or black once and for all */\r
+ whiteNPS = blackNPS = -1; \r
+ if(gameMode == MachinePlaysWhite || gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'w'\r
+ || appData.zippyPlay && gameMode == IcsPlayingBlack) // first (perhaps only) engine has white\r
+ whiteNPS = first.nps;\r
+ if(gameMode == MachinePlaysBlack || gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'b'\r
+ || appData.zippyPlay && gameMode == IcsPlayingWhite) // first (perhaps only) engine has black\r
+ blackNPS = first.nps;\r
+ if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'b') // second only used in Two-Machines mode\r
+ whiteNPS = second.nps;\r
+ if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'w')\r
+ blackNPS = second.nps;\r
+ if(appData.debugMode) fprintf(debugFP, "nps: w=%d, b=%d\n", whiteNPS, blackNPS);\r
+\r
StartClockTimer(intendedTickLength);\r
}\r
\r
\r
if(nrCastlingRights) {\r
q = p;\r
- if(gameInfo.variant == VariantFischeRandom) {\r
+ if(gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) {\r
/* [HGM] write directly from rights */\r
if(castlingRights[move][2] >= 0 &&\r
castlingRights[move][0] >= 0 )\r
FENepStatus = EP_UNKNOWN;\r
for(i=0; i<nrCastlingRights; i++ ) {\r
FENcastlingRights[i] =\r
- gameInfo.variant == VariantFischeRandom ? -1 : initialRights[i];\r
+ gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom ? -1 : initialRights[i];\r
} /* assume possible unless obviously impossible */\r
if(initialRights[0]>=0 && board[castlingRank[0]][initialRights[0]] != WhiteRook) FENcastlingRights[0] = -1;\r
if(initialRights[1]>=0 && board[castlingRank[1]][initialRights[1]] != WhiteRook) FENcastlingRights[1] = -1;\r
}\r
}\r
while(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-' ||\r
- gameInfo.variant == VariantFischeRandom &&\r
+ (gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) &&\r
( *p >= 'a' && *p < 'a' + gameInfo.boardWidth) ||\r
( *p >= 'A' && *p < 'A' + gameInfo.boardWidth) ) {\r
char c = *p++; int whiteKingFile=-1, blackKingFile=-1;\r