int LoadGameFromFile P((char *filename, int n, char *title, int useList));
int LoadPositionFromFile P((char *filename, int n, char *title));
int SavePositionToFile P((char *filename));
-void ApplyMove P((int fromX, int fromY, int toX, int toY, int promoChar,
- Board board));
void MakeMove P((int fromX, int fromY, int toX, int toY, int promoChar));
void ShowMove P((int fromX, int fromY, int toX, int toY));
int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
void ResetClocks P((void));
char *PGNDate P((void));
void SetGameInfo P((void));
-Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
int RegisterMove P((void));
void MakeRegisteredMove P((void));
void TruncateGame P((void));
hisPerpetual = PerpetualChase(k, forwardMostMove);
ourPerpetual = PerpetualChase(k+1, forwardMostMove);
if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit
+ static char resdet[MSG_SIZ];
result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins;
- details = "Xboard adjudication: perpetual chasing";
+ details = resdet;
+ snprintf(resdet, MSG_SIZ, "Xboard adjudication: perpetual chasing of %c%c", ourPerpetual>>8, ourPerpetual&255);
} else
if(hisPerpetual && !ourPerpetual) // he is chasing us, but did not repeat yet
break; // Abort repetition-checking loop.
ChessSquare pieceType[256] = { EmptySquare };
Board soughtBoard, reverseBoard, flipBoard, rotateBoard;
int counts[EmptySquare], minSought[EmptySquare], minReverse[EmptySquare], maxSought[EmptySquare], maxReverse[EmptySquare];
+int soughtTotal, turn;
Boolean epOK, flipSearch;
typedef struct {
unsigned char piece, to;
} Move;
-#define DATABASESIZE 10000000 /* good for 100k games */
-Move moveDatabase[DATABASESIZE];
-int movePtr;
+#define DSIZE (250000)
-void MakePieceList(Board board, int *counts)
+Move initialSpace[DSIZE+1000]; // gamble on that game will not be more than 500 moves
+Move *moveDatabase = initialSpace;
+unsigned int movePtr, dataSize = DSIZE;
+
+int MakePieceList(Board board, int *counts)
{
- int r, f, n=Q_PROMO;
+ int r, f, n=Q_PROMO, total=0;
for(r=0;r<EmptySquare;r++) counts[r] = 0; // piece-type counts
for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
int sq = f + (r<<4);
counts[board[r][f]]++;
if(board[r][f] == WhiteKing) pieceList[1] = n; else
if(board[r][f] == BlackKing) pieceList[2] = n; // remember which are Kings, for castling
+ total++;
}
}
epOK = gameInfo.variant != VariantXiangqi && gameInfo.variant != VariantBerolina;
+ return total;
}
void PackMove(int fromX, int fromY, int toX, int toY, ChessSquare promoPiece)
int PackGame(Board board)
{
+ Move *newSpace = NULL;
moveDatabase[movePtr].piece = 0; // terminate previous game
- if(movePtr > DATABASESIZE - 500) return 0; // gamble on that game will not be more than 250 moves
+ if(movePtr > dataSize) {
+ if(appData.debugMode) fprintf(debugFP, "move-cache overflow, enlarge to %d MB\n", dataSize/128);
+ dataSize *= 8; // increase size by factor 8 (512KB -> 4MB -> 32MB -> 256MB -> 2GB)
+ if(dataSize) newSpace = (Move*) calloc(8*dataSize + 1000, sizeof(Move));
+ if(newSpace) {
+ int i;
+ Move *p = moveDatabase, *q = newSpace;
+ for(i=0; i<movePtr; i++) *q++ = *p++; // copy to newly allocated space
+ if(dataSize > 8*DSIZE) free(moveDatabase); // and free old space (if it was allocated)
+ moveDatabase = newSpace;
+ } else { // calloc failed, we must be out of memory. Too bad...
+ dataSize = 0; // prevent calloc events for all subsequent games
+ return 0; // and signal this one isn't cached
+ }
+ }
movePtr++;
MakePieceList(board, counts);
return movePtr;
switch(appData.searchMode)
{
case 1: // exact position match
+ if(!(turn & board[EP_STATUS-1])) return FALSE; // wrong side to move
for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
if(board[r][f] != pieceType[quickBoard[(r<<4)+f]]) return FALSE;
}
int QuickScan(Board board, Move *move)
{ // reconstruct game,and compare all positions in it
- int cnt=0, stretch=0;
- MakePieceList(board, counts);
+ int cnt=0, stretch=0, total = MakePieceList(board, counts);
do {
int piece = move->piece;
int to = move->to, from = pieceList[piece];
counts[move->to]++;
} else if(piece == Q_EP) { // e.p. capture, encoded as (Q_EP, ep-sqr) + (piece, to)
counts[pieceType[quickBoard[to]]]--;
- quickBoard[to] = 0;
+ quickBoard[to] = 0; total--;
move++;
continue;
} else if(piece <= Q_BCASTL) { // castling, encoded as (Q_XCASTL, king-to) + (rook, rook-to)
}
}
if(appData.searchMode > 2) counts[pieceType[quickBoard[to]]]--; // account capture
+ if((total -= (quickBoard[to] != 0)) < soughtTotal) return -1; // piece count dropped below what we search for
quickBoard[from] = 0;
quickBoard[to] = piece;
pieceList[piece] = to;
- cnt++;
+ cnt++; turn ^= 3;
if(QuickCompare(soughtBoard, minSought, maxSought) ||
appData.ignoreColors && QuickCompare(reverseBoard, minReverse, maxReverse) ||
flipSearch && (QuickCompare(flipBoard, minSought, maxSought) ||
} while(1);
}
-InitSearch()
+void InitSearch()
{
int r, f;
flipSearch = FALSE;
CopyBoard(soughtBoard, boards[currentMove]);
- MakePieceList(soughtBoard, maxSought);
+ soughtTotal = MakePieceList(soughtBoard, maxSought);
+ soughtBoard[EP_STATUS-1] = (currentMove & 1) + 1;
+ if(currentMove == 0 && gameMode == EditPosition) soughtBoard[EP_STATUS-1] = blackPlaysFirst + 1; // (!)
CopyBoard(reverseBoard, boards[currentMove]);
for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
int piece = boards[currentMove][BOARD_HEIGHT-1-r][f];
if(piece < BlackPawn) piece += BlackPawn; else if(piece < EmptySquare) piece -= BlackPawn; // color-flip
reverseBoard[r][f] = piece;
}
+ reverseBoard[EP_STATUS-1] = soughtBoard[EP_STATUS-1] ^ 3;
for(r=0; r<6; r++) reverseBoard[CASTLING][r] = boards[currentMove][CASTLING][(r+3)%6];
if(appData.findMirror && appData.searchMode <= 3 && (!nrCastlingRights
|| (boards[currentMove][CASTLING][2] == NoRights ||
MakePieceList(soughtBoard, minSought);
for(r=0; r<BlackPawn; r++) minReverse[r] = minSought[r+BlackPawn], minReverse[r+BlackPawn] = minSought[r];
}
+ if(gameInfo.variant == VariantCrazyhouse || gameInfo.variant == VariantShogi || gameInfo.variant == VariantBughouse)
+ soughtTotal = 0; // in drop games nr of pieces does not fall monotonously
}
GameInfo dummyInfo;
if(lg->gameInfo.fen) ParseFEN(boards[scratch], &btm, lg->gameInfo.fen);
else CopyBoard(boards[scratch], initialPosition); // default start position
if(lg->moves) {
+ turn = btm + 1;
if((next = QuickScan( boards[scratch], &moveDatabase[lg->moves] )) < 0) return -1; // quick scan rules out it is there
if(appData.searchMode >= 4) return next; // for material searches, trust QuickScan.
}