int promoDefaultAltered;
int keepInfo = 0; /* [HGM] to protect PGN tags in auto-step game analysis */
static int initPing = -1;
+static Boolean pieceDefs;
/* States for ics_getting_history */
#define H_FALSE 0
case VariantGrand:
flags &= ~F_ALL_CASTLE_OK;
break;
+ case VariantChu:
+ case VariantChuChess:
+ case VariantLion:
+ flags |= F_NULL_MOVE;
+ break;
default:
break;
}
static char resetOptions[] =
"-reuse -firstIsUCI false -firstHasOwnBookUCI true -firstTimeOdds 1 "
"-firstInitString \"" INIT_STRING "\" -firstComputerString \"" COMPUTER_STRING "\" "
- "-firstFeatures \"\" -firstLogo \"\" -firstAccumulateTC 1 "
+ "-firstFeatures \"\" -firstLogo \"\" -firstAccumulateTC 1 -fd \".\" "
"-firstOptions \"\" -firstNPS -1 -fn \"\" -firstScoreAbs false";
void
}
ParsePV(buf+startPV, FALSE, gameMode != AnalyzeMode);
*start = startPV; *end = index-1;
- extendGame = (gameMode == AnalyzeMode && appData.autoExtend);
+ extendGame = (gameMode == AnalyzeMode && appData.autoExtend && origIndex - startPV < 5);
return TRUE;
}
DrawPosition(FALSE, boards[currentMove]);
return;
} else if (toX >= 0 && toY >= 0) {
+ if(!appData.pieceMenu && toX == fromX && toY == fromY && boards[0][rf][ff] != EmptySquare) {
+ ChessSquare q, p = boards[0][rf][ff];
+ if(p >= BlackPawn) p = BLACK_TO_WHITE p;
+ if(CHUPROMOTED p < BlackPawn) p = q = CHUPROMOTED boards[0][rf][ff];
+ else p = CHUDEMOTED (q = boards[0][rf][ff]);
+ if(PieceToChar(q) == '+') gatingPiece = p;
+ }
boards[0][toY][toX] = boards[0][fromY][fromX];
if(fromX == BOARD_LEFT-2) { // handle 'moves' out of holdings
if(boards[0][fromY][0] != EmptySquare) {
return;
}
- if(toX < 0 || toY < 0) return;
+ if((toX < 0 || toY < 0) && (fromY != DROP_RANK || fromX != EmptySquare)) return;
pup = boards[currentMove][toY][toX];
/* [HGM] If move started in holdings, it means a drop. Convert to standard form */
moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),
fromY, fromX, toY, toX, promoChar);
- if(fromY == DROP_RANK && fromX == EmptySquare && (gameMode == AnalyzeMode || gameMode == EditGame)) moveType = NormalMove;
+ if(fromY == DROP_RANK && fromX == EmptySquare && (gameMode == AnalyzeMode || gameMode == EditGame || PosFlags(0) & F_NULL_MOVE)) moveType = NormalMove;
/* [HGM] but possibly ignore an IllegalMove result */
if (appData.testLegality) {
if(rf == fromY && ff == fromX && (killX < 0 && !(rt == rf && ft == ff) || abs(ft-killX) < 2 && abs(rt-killY) < 2))
(*m)[rt][ft] = 1 + (board[rt][ft] != EmptySquare
|| kind == WhiteCapturesEnPassant
- || kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0);
- else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3;
+ || kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0), legal[rt][ft] = 1;
+ else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3, legal[rt][ft] = 1;
}
static int hoverSavedValid;
} else {
int capt = 0;
if(!appData.markers || !appData.highlightDragging || appData.icsActive && gameInfo.variant < VariantShogi ||
- !appData.testLegality || gameMode == EditPosition) return;
+ !appData.testLegality && !pieceDefs || gameMode == EditPosition) return;
GenLegal(boards[currentMove], PosFlags(currentMove), Mark, (void*) marker, EmptySquare);
if(PosFlags(0) & F_MANDATORY_CAPTURE) {
for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) if(marker[y][x]>1) capt++;
char buf[MSG_SIZ]; // Inform engine of what user does
int r, f;
if(action[0] == 'l') // mark any target square of a lifted piece as legal to-square, clear markers
- for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) legal[r][f] = 1, marker[r][f] = 0;
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) legal[r][f] = !pieceDefs, marker[r][f] = 0;
if(!first.highlight || gameMode == EditPosition) return;
snprintf(buf, MSG_SIZ, "%s %c%d%s\n", action, x+AAA, y+ONE-'0', controlKey && action[0]=='p' ? "," : "");
SendToProgram(buf, &first);
clearFlag = 0;
- if(gameMode != EditPosition && !appData.testLegality && !legal[y][x] && (x != killX || y != killY) && !sweepSelecting) {
+ if(gameMode != EditPosition && !appData.testLegality && !legal[y][x] &&
+ fromX >= BOARD_LEFT && fromX < BOARD_RGHT && (x != killX || y != killY) && !sweepSelecting) {
if(dragging) DragPieceEnd(xPix, yPix), dragging = 0;
DisplayMessage(_("only marked squares are legal"),"");
DrawPosition(TRUE, NULL);
// probe EGBB
if(loaded == 2) return 13; // loading failed before
if(loaded == 0) {
- loaded = 2; // prepare for failure
char *p, *path = strstr(appData.egtFormats, "scorpio:"), buf[MSG_SIZ];
HMODULE lib;
PLOAD_EGBB loadBB;
+ loaded = 2; // prepare for failure
if(!path) return 13; // no egbb installed
strncpy(buf, path + 8, MSG_SIZ);
if(p = strchr(buf, ',')) *p = NULLCHAR; else p = buf + strlen(buf);
if( count & 1 ) {
score = -score; /* Flip score for winning side */
}
-printf("score=%d count=%d\n",score,count);
+
if( score > appData.adjudicateLossThreshold ) {
break;
}
startedFromSetupPosition = TRUE;
return;
}
+ if(sscanf(message, "piece %s %s", buf2, buf1) == 2) {
+ ChessSquare piece = WhitePawn;
+ char *p=buf2;
+ if(cps != &first || appData.testLegality) return;
+ if(*p == '+') piece = CHUPROMOTED WhitePawn, p++;
+ piece += CharToPiece(*p) - WhitePawn;
+ if(piece < EmptySquare) {
+ pieceDefs = TRUE;
+ ASSIGN(pieceDesc[piece], buf1);
+ if(isupper(*p) && p[1] == '&') { ASSIGN(pieceDesc[WHITE_TO_BLACK piece], buf1); }
+ }
+ return;
+ }
/* [HGM] Allow engine to set up a position. Don't ask me why one would
* want this, I was asked to put it in, and obliged.
*/
if (sscanf(message, "%d%c %d %d " u64Display " %[^\n]\n",
&plylev, &plyext, &curscore, &time, &nodes, buf1) >= 5) {
+ if(nodes>>32 == u64Const(0xFFFFFFFF)) // [HGM] negative node count read
+ nodes += u64Const(0x100000000);
+
if (plyext != ' ' && plyext != '\t') {
time *= 100;
}
fprintf(debugFP, "Reset(%d, %d) from gameMode %d\n",
redraw, init, gameMode);
}
+ pieceDefs = FALSE; // [HGM] gen: reset engine-defined piece moves
+ for(i=0; i<EmptySquare; i++) { FREE(pieceDesc[i]); pieceDesc[i] = NULL; }
CleanupTail(); // [HGM] vari: delete any stored variations
CommentPopDown(); // [HGM] make sure no comments to the previous game keep hanging on
pausing = pauseExamInvalid = FALSE;
SetHighlights(-1, -1, toX, toY);
}
} else {
+ int viaX = moveList[currentMove][5] - AAA;
+ int viaY = moveList[currentMove][6] - ONE;
fromX = moveList[currentMove][0] - AAA;
fromY = moveList[currentMove][1] - ONE;
HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove); /* [AS] */
+ if(moveList[currentMove][4] == ';') { // multi-leg
+ ChessSquare piece = boards[currentMove][viaY][viaX];
+ AnimateMove(boards[currentMove], fromX, fromY, viaX, viaY);
+ boards[currentMove][viaY][viaX] = boards[currentMove][fromY][fromX];
+ AnimateMove(boards[currentMove], fromX=viaX, fromY=viaY, toX, toY);
+ boards[currentMove][viaY][viaX] = piece;
+ } else
AnimateMove(boards[currentMove], fromX, fromY, toX, toY);
if (appData.highlightLastMove) {
int
QuickScan (Board board, Move *move)
{ // reconstruct game,and compare all positions in it
- int cnt=0, stretch=0, total = MakePieceList(board, counts);
+ int cnt=0, stretch=0, found = -1, total = MakePieceList(board, counts);
do {
int piece = move->piece;
int to = move->to, from = pieceList[piece];
+ if(found < 0) { // if already found just scan to game end for final piece count
+ if(QuickCompare(soughtBoard, minSought, maxSought) ||
+ appData.ignoreColors && QuickCompare(reverseBoard, minReverse, maxReverse) ||
+ flipSearch && (QuickCompare(flipBoard, minSought, maxSought) ||
+ appData.ignoreColors && QuickCompare(rotateBoard, minReverse, maxReverse))
+ ) {
+ static int lastCounts[EmptySquare+1];
+ int i;
+ if(stretch) for(i=0; i<EmptySquare; i++) if(lastCounts[i] != counts[i]) { stretch = 0; break; } // reset if material changes
+ if(stretch++ == 0) for(i=0; i<EmptySquare; i++) lastCounts[i] = counts[i]; // remember actual material
+ } else stretch = 0;
+ if(stretch && (appData.searchMode == 1 || stretch >= appData.stretch)) found = cnt + 1 - stretch;
+ if(found >= 0 && !appData.minPieces) return found;
+ }
if(piece <= Q_PROMO) { // special moves encoded by otherwise invalid piece numbers 1-4
- if(!piece) return -1;
+ if(!piece) return (appData.minPieces && (total < appData.minPieces || total > appData.maxPieces) ? -1 : found);
if(piece == Q_PROMO) { // promotion, encoded as (Q_PROMO, to) + (piece, promoType)
piece = (++move)->piece;
from = pieceList[piece];
}
}
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
+ if((total -= (quickBoard[to] != 0)) < soughtTotal && found < 0) return -1; // piece count dropped below what we search for
quickBoard[from] = 0;
aftercastle:
quickBoard[to] = piece;
pieceList[piece] = to;
cnt++; turn ^= 3;
- if(QuickCompare(soughtBoard, minSought, maxSought) ||
- appData.ignoreColors && QuickCompare(reverseBoard, minReverse, maxReverse) ||
- flipSearch && (QuickCompare(flipBoard, minSought, maxSought) ||
- appData.ignoreColors && QuickCompare(rotateBoard, minReverse, maxReverse))
- ) {
- static int lastCounts[EmptySquare+1];
- int i;
- if(stretch) for(i=0; i<EmptySquare; i++) if(lastCounts[i] != counts[i]) { stretch = 0; break; } // reset if material changes
- if(stretch++ == 0) for(i=0; i<EmptySquare; i++) lastCounts[i] = counts[i]; // remember actual material
- } else stretch = 0;
- if(stretch && (appData.searchMode == 1 || stretch >= appData.stretch)) return cnt + 1 - stretch;
move++;
} while(1);
}
}
}
-/* Save game in PGN style and close the file */
-int
-SaveGamePGN (FILE *f)
+/* Save game in PGN style */
+static void
+SaveGamePGN2 (FILE *f)
{
int i, offset, linelen, newblock;
// char *movetext;
} else {
fprintf(f, "%s\n\n", PGNResult(gameInfo.result));
}
+}
+/* Save game in PGN style and close the file */
+int
+SaveGamePGN (FILE *f)
+{
+ SaveGamePGN2(f);
fclose(f);
lastSavedGame = GameCheckSum(); // [HGM] save: remember ID of last saved game to prevent double saving
return TRUE;
if (gameMode == EditPosition || gameMode == IcsExamining) {
if(!appData.pieceMenu && blackPlaysFirst) EditPositionMenuEvent(ClearBoard, 0, 0);
SetBlackToPlayEvent();
- } else if ((gameMode == AnalyzeMode || gameMode == EditGame) && !blackFlag && WhiteOnMove(currentMove)) {
+ } else if ((gameMode == AnalyzeMode || gameMode == EditGame ||
+ gameMode == MachinePlaysBlack && PosFlags(0) & F_NULL_MOVE && !blackFlag && !shiftKey) && WhiteOnMove(currentMove)) {
UserMoveEvent((int)EmptySquare, DROP_RANK, 0, 0, 0); // [HGM] multi-move: if not out of time, enters null move
} else if (shiftKey) {
AdjustClock(which, -1);
if (gameMode == EditPosition || gameMode == IcsExamining) {
if(!appData.pieceMenu && !blackPlaysFirst) EditPositionMenuEvent(ClearBoard, 0, 0);
SetWhiteToPlayEvent();
- } else if ((gameMode == AnalyzeMode || gameMode == EditGame) && !whiteFlag && !WhiteOnMove(currentMove)) {
+ } else if ((gameMode == AnalyzeMode || gameMode == EditGame ||
+ gameMode == MachinePlaysWhite && PosFlags(0) & F_NULL_MOVE && !whiteFlag && !shiftKey) && !WhiteOnMove(currentMove)) {
UserMoveEvent((int)EmptySquare, DROP_RANK, 0, 0, 0); // [HGM] multi-move
} else if (shiftKey) {
AdjustClock(which, -1);
SetHighlights(-1, -1, toX, toY);
}
} else {
+ int viaX = moveList[target - 1][5] - AAA;
+ int viaY = moveList[target - 1][6] - ONE;
fromX = moveList[target - 1][0] - AAA;
fromY = moveList[target - 1][1] - ONE;
if (target == currentMove + 1) {
+ if(moveList[target - 1][4] == ';') { // multi-leg
+ ChessSquare piece = boards[currentMove][viaY][viaX];
+ AnimateMove(boards[currentMove], fromX, fromY, viaX, viaY);
+ boards[currentMove][viaY][viaX] = boards[currentMove][fromY][fromX];
+ AnimateMove(boards[currentMove], viaX, viaY, toX, toY);
+ boards[currentMove][viaY][viaX] = piece;
+ } else
AnimateMove(boards[currentMove], fromX, fromY, toX, toY);
}
if (appData.highlightLastMove) {
hintRequested = TRUE;
}
+int
+SaveSelected (FILE *g, int dummy, char *dummy2)
+{
+ ListGame * lg = (ListGame *) gameList.head;
+ int nItem, cnt=0;
+ FILE *f;
+
+ if( !(f = GameFile()) || ((ListGame *) gameList.tailPred)->number <= 0 ) {
+ DisplayError(_("Game list not loaded or empty"), 0);
+ return 0;
+ }
+
+ creatingBook = TRUE; // suppresses stuff during load game
+
+ /* Get list size */
+ for (nItem = 1; nItem <= ((ListGame *) gameList.tailPred)->number; nItem++){
+ if(lg->position >= 0) { // selected?
+ LoadGame(f, nItem, "", TRUE);
+ SaveGamePGN2(g); // leaves g open
+ cnt++; DoEvents();
+ }
+ lg = (ListGame *) lg->node.succ;
+ }
+
+ fclose(g);
+ creatingBook = FALSE;
+
+ return cnt;
+}
+
void
CreateBookEvent ()
{
/* Get list size */
for (nItem = 1; nItem <= ((ListGame *) gameList.tailPred)->number; nItem++){
- LoadGame(f, nItem, "", TRUE);
- AddGameToBook(TRUE);
+ if(lg->position >= 0) {
+ LoadGame(f, nItem, "", TRUE);
+ AddGameToBook(TRUE);
+ DoEvents();
+ }
lg = (ListGame *) lg->node.succ;
}
v = StringToVariant(s);
if(v == VariantNormal && strcmp(s, "normal") && !strstr(s, "_normal")) v = VariantUnknown; // garbage is recognized as normal
if(v == VariantUnknown) { // non-standard variant in list of engine-supported variants
+ if(!strcmp(s, "tenjiku") || !strcmp(s, "dai") || !strcmp(s, "dada") || // ignore Alien-Edition variants
+ !strcmp(s, "maka") || !strcmp(s, "tai") || !strcmp(s, "kyoku") ||
+ !strcmp(s, "checkers") || !strcmp(s, "go") || !strcmp(s, "reversi") ||
+ !strcmp(s, "dark") || !strcmp(s, "alien") || !strcmp(s, "multi") || !strcmp(s, "amazons") ) n++;
if(--n < 0) safeStrCpy(buf, s, MSG_SIZ);
}
if(p) *p++ = ',';