extern int chatCount;
int chattingPartner;
char marker[BOARD_RANKS][BOARD_FILES]; /* [HGM] marks for target squares */
+char legal[BOARD_RANKS][BOARD_FILES]; /* [HGM] legal target squares */
char lastMsg[MSG_SIZ];
ChessSquare pieceSweep = EmptySquare;
ChessSquare promoSweep = EmptySquare, defaultPromoChoice;
cps->scoreIsAbsolute = appData.scoreIsAbsolute[n]; /* [AS] */
cps->isUCI = appData.isUCI[n]; /* [AS] */
cps->hasOwnBookUCI = appData.hasOwnBookUCI[n]; /* [AS] */
+ cps->highlight = 0;
if (appData.protocolVersion[n] > PROTOVER
|| appData.protocolVersion[n] < 1)
SendToICS(ics_prefix);
SendToICS(buf);
if(startedFromSetupPosition || backwardMostMove != 0) {
- fen = PositionToFEN(backwardMostMove, NULL);
+ fen = PositionToFEN(backwardMostMove, NULL, 1);
if(ics_type == ICS_ICC) { // on ICC we can simply send a complete FEN to set everything
snprintf(buf, MSG_SIZ,"loadfen %s\n", fen);
SendToICS(buf);
}
-static int lastX, lastY, selectFlag, dragging;
+static int lastX, lastY, lastLeftX, lastLeftY, selectFlag, dragging;
+static ClickType lastClickType;
void
Sweep (int step)
case VariantMakruk:
pieces = makrukArray;
nrCastlingRights = 0;
- startedFromSetupPosition = TRUE;
SetCharTable(pieceToChar, "PN.R.M....SKpn.r.m....sk");
break;
case VariantASEAN:
pieces = aseanArray;
nrCastlingRights = 0;
- startedFromSetupPosition = TRUE;
SetCharTable(pieceToChar, "PN.R.Q....BKpn.r.q....bk");
break;
case VariantTwoKings:
char message[MSG_SIZ];
if (cps->useSetboard) {
- char* fen = PositionToFEN(moveNum, cps->fenOverride);
+ char* fen = PositionToFEN(moveNum, cps->fenOverride, 1);
snprintf(message, MSG_SIZ,"setboard %s\n", fen);
SendToProgram(message, cps);
free(fen);
}
void
+MarkByFEN(char *fen)
+{
+ int r, f;
+ if(!appData.markers || !appData.highlightDragging) return;
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) legal[r][f] = 0;
+ r=BOARD_HEIGHT-1; f=BOARD_LEFT;
+ while(*fen) {
+ int s = 0;
+ marker[r][f] = 0;
+ if(*fen == 'M') legal[r][f] = 2; else // request promotion choice
+ if(*fen >= 'A' && *fen <= 'Z') legal[r][f] = 1; else
+ if(*fen >= 'a' && *fen <= 'z') *fen += 'A' - 'a';
+ if(*fen == '/' && f > BOARD_LEFT) f = BOARD_LEFT, r--; else
+ if(*fen == 'T') marker[r][f++] = 0; else
+ if(*fen == 'Y') marker[r][f++] = 1; else
+ if(*fen == 'G') marker[r][f++] = 3; else
+ if(*fen == 'B') marker[r][f++] = 4; else
+ if(*fen == 'C') marker[r][f++] = 5; else
+ if(*fen == 'M') marker[r][f++] = 6; else
+ if(*fen == 'W') marker[r][f++] = 7; else
+ if(*fen == 'D') marker[r][f++] = 8; else
+ if(*fen == 'R') marker[r][f++] = 2; else {
+ while(*fen <= '9' && *fen >= '0') s = 10*s + *fen++ - '0';
+ f += s; fen -= s>0;
+ }
+ while(f >= BOARD_RGHT) f -= BOARD_RGHT - BOARD_LEFT, r--;
+ if(r < 0) break;
+ fen++;
+ }
+ DrawPosition(TRUE, NULL);
+}
+
+void
Mark (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)
{
typedef char Markers[BOARD_RANKS][BOARD_FILES];
void
MarkTargetSquares (int clear)
{
- int x, y;
- if(clear) // no reason to ever suppress clearing
- for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) marker[y][x] = 0;
- if(!appData.markers || !appData.highlightDragging || appData.icsActive && gameInfo.variant < VariantShogi ||
- !appData.testLegality || gameMode == EditPosition) return;
- if(!clear) {
+ int x, y, sum=0;
+ if(clear) { // no reason to ever suppress clearing
+ for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) sum += marker[y][x], marker[y][x] = 0;
+ if(!sum) return; // nothing was cleared,no redraw needed
+ } else {
int capt = 0;
+ if(!appData.markers || !appData.highlightDragging || appData.icsActive && gameInfo.variant < VariantShogi ||
+ !appData.testLegality || 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++;
}
void
+HoverEvent (int hiX, int hiY, int x, int y)
+{
+ static char baseMarker[BOARD_RANKS][BOARD_FILES], baseLegal[BOARD_RANKS][BOARD_FILES];
+ int r, f;
+ if(!first.highlight) return;
+ if(hiX == -1 && hiY == -1 && x == fromX && y == fromY) // record markings
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++)
+ baseMarker[r][f] = marker[r][f], baseLegal[r][f] = legal[r][f];
+ else if(hiX != x || hiY != y) {
+ // [HGM] lift: entered new to-square; redraw arrow, and inform engine
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++)
+ marker[r][f] = baseMarker[r][f], legal[r][f] = baseLegal[r][f];
+ if((marker[y][x] == 2 || marker[y][x] == 6) && legal[y][x]) {
+ char buf[MSG_SIZ];
+ snprintf(buf, MSG_SIZ, "hover %c%d\n", x + AAA, y + ONE - '0');
+ SendToProgram(buf, &first);
+ }
+ SetHighlights(fromX, fromY, x, y);
+ }
+}
+
+void ReportClick(char *action, int x, int y)
+{
+ 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;
+ 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);
+}
+
+void
LeftClick (ClickType clickType, int xPix, int yPix)
{
int x, y;
prevClickTime = lastClickTime; GetTimeMark(&lastClickTime);
if (clickType == Press) ErrorPopDown();
+ lastClickType = clickType, lastLeftX = xPix, lastLeftY = yPix; // [HGM] alien: remember state
x = EventToSquare(xPix, BOARD_WIDTH);
y = EventToSquare(yPix, BOARD_HEIGHT);
/* First square */
if (OKToStartUserMove(fromX, fromY)) {
second = 0;
+ ReportClick("lift", x, y);
MarkTargetSquares(0);
if(gameMode == EditPosition && controlKey) gatingPiece = boards[currentMove][fromY][fromX];
DragPieceBegin(xPix, yPix, FALSE); dragging = 1;
}
promoDefaultAltered = FALSE;
MarkTargetSquares(1);
- if(!second || appData.oneClick && !OnlyMove(&x, &y, TRUE)) {
+ if(!(second && appData.oneClick && OnlyMove(&x, &y, TRUE))) {
if (appData.highlightDragging) {
SetHighlights(x, y, -1, -1);
} else {
else gatingPiece = doubleClick ? fromP : EmptySquare;
fromX = x;
fromY = y; dragging = 1;
+ ReportClick("lift", x, y);
MarkTargetSquares(0);
DragPieceBegin(xPix, yPix, FALSE);
if(appData.sweepSelect && CanPromote(piece = boards[currentMove][y][x], y)) {
second = sweepSelecting = 0;
fromX = fromY = -1;
gatingPiece = EmptySquare;
+ MarkTargetSquares(1);
ClearHighlights();
gotPremove = 0;
ClearPremoveHighlights();
clearFlag = 0;
+ if(gameMode != EditPosition && !appData.testLegality && !legal[y][x]) {
+ if(dragging) DragPieceEnd(xPix, yPix), dragging = 0;
+ DisplayMessage(_("only marked squares are legal"),"");
+ DrawPosition(TRUE, NULL);
+ return; // ignore to-click
+ }
+
/* we now have a different from- and (possibly off-board) to-square */
/* Completed move */
if(!sweepSelecting) {
if(x >= BOARD_LEFT && x < BOARD_RGHT) clearFlag = 1; // and defer click-click move of empty-square to up-click
return;
}
- if(HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, FALSE)) {
+ if(legal[y][x] == 2 || HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, FALSE)) {
if(appData.sweepSelect) {
ChessSquare piece = boards[currentMove][fromY][fromX];
promoSweep = defaultPromoChoice;
// off-board moves should not be highlighted
if(x < 0 || y < 0) ClearHighlights();
+ else ReportClick("put", x, y);
if(gatingPiece != EmptySquare && gameInfo.variant == VariantSChess) promoChoice = ToLower(PieceToChar(gatingPiece));
SendToProgram("force\n", cps);
cps->bookSuspend = TRUE; // flag indicating it has to be restarted
}
+ if(bookHit) setboardSpoiledMachineBlack = FALSE; // suppress 'go' in SendMoveToProgram
if(!initial) SendMoveToProgram(moveNr, cps); // with hit on initial position there is no move
// now arrange restart after book miss
if(bookHit) {
MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/
+ /* Test suites abort the 'game' after one move */
+ if(*appData.finger) {
+ static FILE *f;
+ char *fen = PositionToFEN(backwardMostMove, NULL, 0); // no counts in EPD
+ if(!f) f = fopen(appData.finger, "w");
+ if(f) fprintf(f, "%s bm %s;\n", fen, parseList[backwardMostMove]), fflush(f);
+ else { DisplayFatalError("Bad output file", errno, 0); return; }
+ free(fen);
+ GameEnds(GameUnfinished, NULL, GE_XBOARD);
+ }
+
/* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */
if( gameMode == TwoMachinesPlay && adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) {
int count = 0;
if (sscanf(message, "pong %d", &cps->lastPong) == 1) {
return;
}
+ if(!strncmp(message, "highlight ", 10)) {
+ if(appData.testLegality && appData.markers) return;
+ MarkByFEN(message+10); // [HGM] alien: allow engine to mark board squares
+ return;
+ }
+ if(!strncmp(message, "click ", 6)) {
+ char f, c=0; int x, y; // [HGM] alien: allow engine to finish user moves (i.e. engine-driven one-click moving)
+ if(appData.testLegality || !appData.oneClick) return;
+ sscanf(message+6, "%c%d%c", &f, &y, &c);
+ x = f - 'a' + BOARD_LEFT, y -= ONE - '0';
+ if(flipView) x = BOARD_WIDTH-1 - x; else y = BOARD_HEIGHT-1 - y;
+ x = x*squareSize + (x+1)*lineGap + squareSize/2;
+ y = y*squareSize + (y+1)*lineGap + squareSize/2;
+ f = first.highlight; first.highlight = 0; // kludge to suppress lift/put in response to own clicks
+ if(lastClickType == Press) // if button still down, fake release on same square, to be ready for next click
+ LeftClick(Release, lastLeftX, lastLeftY);
+ controlKey = (c == ',');
+ LeftClick(Press, x, y);
+ LeftClick(Release, x, y);
+ first.highlight = f;
+ return;
+ }
/*
* If the move is illegal, cancel it and redraw the board.
* Also deal with other error cases. Matching is rather loose
PlayIcsUnfinishedSound();
}
}
+ if(appData.quitNext) { ExitEvent(0); return; }
} else if (gameMode == EditGame ||
gameMode == PlayFromGameFile ||
gameMode == AnalyzeMode ||
if(appData.numberTag && matchMode) fprintf(f, "[Number \"%d\"]\n", nextGame+1); // [HGM] number tag
if (backwardMostMove > 0 || startedFromSetupPosition) {
- char *fen = PositionToFEN(backwardMostMove, NULL);
+ char *fen = PositionToFEN(backwardMostMove, NULL, 1);
fprintf(f, "[FEN \"%s\"]\n[SetUp \"1\"]\n", fen);
fprintf(f, "\n{--------------\n");
PrintPosition(f, backwardMostMove);
PrintPosition(f, currentMove);
fprintf(f, "--------------]\n");
} else {
- fen = PositionToFEN(currentMove, NULL);
+ fen = PositionToFEN(currentMove, NULL, 1);
fprintf(f, "%s\n", fen);
free(fen);
}
CreateBookEvent ()
{
ListGame * lg = (ListGame *) gameList.head;
- FILE *f;
+ FILE *f, *g;
int nItem;
static int secondTime = FALSE;
return;
}
- if(!secondTime && (f = fopen(appData.polyglotBook, "r"))) {
- fclose(f);
+ if(!secondTime && (g = fopen(appData.polyglotBook, "r"))) {
+ fclose(g);
secondTime++;
DisplayNote(_("Book file exists! Try again for overwrite."));
return;
/* End of additions by Tord */
/* [HGM] added features: */
+ if (BoolFeature(&p, "highlight", &cps->highlight, cps)) continue;
if (BoolFeature(&p, "debug", &cps->debug, cps)) continue;
if (BoolFeature(&p, "nps", &cps->supportsNPS, cps)) continue;
if (IntFeature(&p, "level", &cps->maxNrOfSessions, cps)) continue;
char *
-PositionToFEN (int move, char *overrideCastling)
+PositionToFEN (int move, char *overrideCastling, int moveCounts)
{
int i, j, fromX, fromY, toX, toY;
int whiteToPlay;
}
}
- /* [HGM] find reversible plies */
+ if(moveCounts)
{ int i = 0, j=move;
+ /* [HGM] find reversible plies */
if (appData.debugMode) { int k;
fprintf(debugFP, "write FEN 50-move: %d %d %d\n", initialRulePlies, forwardMostMove, backwardMostMove);
for(k=backwardMostMove; k<=forwardMostMove; k++)
if( j == backwardMostMove ) i += initialRulePlies;
sprintf(p, "%d ", i);
p += i>=100 ? 4 : i >= 10 ? 3 : 2;
- }
- /* Fullmove number */
- sprintf(p, "%d", (move / 2) + 1);
+
+ /* Fullmove number */
+ sprintf(p, "%d", (move / 2) + 1);
+ } else *--p = NULLCHAR;
return StrSave(buf);
}