* Massachusetts.
*
* Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free
+ * Software Foundation, Inc.
*
* Enhancements Copyright 2005 Alessandro Scotti
*
void EditPositionDone P((Boolean fakeRights));
void PrintOpponents P((FILE *fp));
void PrintPosition P((FILE *fp, int move));
-void StartChessProgram P((ChessProgramState *cps));
void SendToProgram P((char *message, ChessProgramState *cps));
void SendMoveToProgram P((int moveNum, ChessProgramState *cps));
void ReceiveFromProgram P((InputSourceRef isr, VOIDSTAR closure,
Board boards[MAX_MOVES];
/* [HGM] Following 7 needed for accurate legality tests: */
signed char castlingRank[BOARD_FILES]; // and corresponding ranks
-signed char initialRights[BOARD_FILES];
+unsigned char initialRights[BOARD_FILES];
int nrCastlingRights; // For TwoKings, or to implement castling-unknown status
int initialRulePlies, FENrulePlies;
FILE *serverMoves = NULL; // next two for broadcasting (/serverMoves option)
fprintf(debugFP, "Sending premove:\n");
SendToICS(str);
} else if (gotPremove) {
+ int oldFMM = forwardMostMove;
gotPremove = 0;
ClearPremoveHighlights();
if (appData.debugMode)
UserMoveEvent(premoveFromX, premoveFromY,
premoveToX, premoveToY,
premovePromoChar);
+ if(forwardMostMove == oldFMM) { // premove was rejected, highlight last opponent move
+ if(moveList[oldFMM-1][1] != '@')
+ SetHighlights(moveList[oldFMM-1][0]-AAA, moveList[oldFMM-1][1]-ONE,
+ moveList[oldFMM-1][2]-AAA, moveList[oldFMM-1][3]-ONE);
+ else // (drop)
+ SetHighlights(-1, -1, moveList[oldFMM-1][2]-AAA, moveList[oldFMM-1][3]-ONE);
+ }
}
}
} else
if(moveList[moveNum][4] == ';') { // [HGM] lion: move is double-step over intermediate square
char *m = moveList[moveNum];
+ static char c[2];
+ *c = m[7]; // promoChar
if((boards[moveNum][m[6]-ONE][m[5]-AAA] < BlackPawn) == (boards[moveNum][m[1]-ONE][m[0]-AAA] < BlackPawn)) // move is kludge to indicate castling
snprintf(buf, MSG_SIZ, "%c%d%c%d,%c%d%c%d\n", m[0], m[1] - '0', // convert to two moves
m[2], m[3] - '0',
m[5], m[6] - '0',
m[2] + (m[0] > m[5] ? 1 : -1), m[3] - '0');
else
- snprintf(buf, MSG_SIZ, "%c%d%c%d,%c%d%c%d\n", m[0], m[1] - '0', // convert to two moves
+ snprintf(buf, MSG_SIZ, "%c%d%c%d,%c%d%c%d%s\n", m[0], m[1] - '0', // convert to two moves
m[5], m[6] - '0',
m[5], m[6] - '0',
- m[2], m[3] - '0');
+ m[2], m[3] - '0', c);
SendToProgram(buf, cps);
} else
if(BOARD_HEIGHT > 10) { // [HGM] big: convert ranks to double-digit where needed
} else {
sprintf(move, "%c%c%c%c%c\n",
AAA + ff, ONE + rf, AAA + ft, ONE + rt, promoChar);
+ if(killX >= 0 && killY >= 0) {
+ sprintf(move+4, ";%c%c\n", AAA + killX, ONE + killY);
+ if(kill2X >= 0 && kill2Y >= 0) sprintf(move+7, "%c%c%c\n", AAA + killX, ONE + killY, promoChar);
+ }
}
}
}
static ClickType lastClickType;
int
+PieceInString (char *s, ChessSquare piece)
+{
+ char *p, ID = ToUpper(PieceToChar(piece)), suffix = PieceSuffix(piece);
+ while((p = strchr(s, ID))) {
+ if(!suffix || p[1] == suffix) return TRUE;
+ s = p;
+ }
+ return FALSE;
+}
+
+int
Partner (ChessSquare *p)
{ // change piece into promotion partner if one shogi-promotes to the other
ChessSquare partner = promoPartner[*p];
if(PieceToChar(*p) != '+' && PieceToChar(partner) != '+') return 0;
+ if(PieceToChar(*p) == '+') partner = boards[currentMove][fromY][fromX];
*p = partner;
return 1;
}
if(!step) step = -1;
} while(PieceToChar(promoSweep) == '.' || PieceToChar(promoSweep) == '~' ||
!toggleFlag && PieceToChar(promoSweep) == '+' || // skip promoted versions of other
- promoRestrict[0] ? !strchr(promoRestrict, ToUpper(PieceToChar(promoSweep))) : // if choice set available, use it
+ promoRestrict[0] ? !PieceInString(promoRestrict, promoSweep) : // if choice set available, use it
promoSweep == pawn ||
appData.testLegality && (promoSweep == king || gameInfo.variant != VariantChuChess &&
(promoSweep == WhiteLion || promoSweep == BlackLion)));
*toX = currentMoveString[2] - AAA;
*toY = currentMoveString[3] - ONE;
*promoChar = currentMoveString[4];
+ if(*promoChar == ';') *promoChar = currentMoveString[7];
if (*fromX < BOARD_LEFT || *fromX >= BOARD_RGHT || *fromY < 0 || *fromY >= BOARD_HEIGHT ||
*toX < BOARD_LEFT || *toX >= BOARD_RGHT || *toY < 0 || *toY >= BOARD_HEIGHT) {
if (appData.debugMode) {
{
int n = 0;
if(!*escapes) return strlen(s);
- while(*s) n += (*s != '/' && *s != '-' && *s != '^' && *s != '*' && !strchr(escapes, *s)), s++;
+ while(*s) n += (*s != '/' && *s != '-' && *s != '^' && *s != '*' && !strchr(escapes, *s)) - 2*(*s == '='), s++;
return n;
}
/* [HGM] moved here from winboard.c because of its general usefulness */
/* Basically a safe strcpy that uses the last character as King */
{
- int result = FALSE; int NrPieces, offs;
+ int result = FALSE; int NrPieces;
unsigned char partner[EmptySquare];
if( map != NULL && (NrPieces=ptclen(map, escapes)) <= (int) EmptySquare
&& NrPieces >= 12 && !(NrPieces&1)) {
- int i, j = 0; /* [HGM] Accept even length from 12 to 88 */
+ int i, ii, offs, j = 0; /* [HGM] Accept even length from 12 to 88 */
for( i=0; i<(int) EmptySquare; i++ ) table[i] = '.';
for( i=offs=0; i<NrPieces/2-1; i++ ) {
char *p, c=0;
- if(map[j] == '/' && *escapes) offs = WhiteTokin - i, j++;
+ if(map[j] == '/') offs = WhitePBishop - i, j++;
if(*escapes && (map[j] == '*' || map[j] == '-' || map[j] == '^')) c = map[j++];
- table[i + offs] = map[j++];
- if(p = strchr(escapes, map[j])) j++, table[i + offs] += 64*(p - escapes + 1);
- if(c) partner[i + offs] = table[i + offs], table[i + offs] = c;
+ table[i+offs] = map[j++];
+ if(p = strchr(escapes, map[j])) j++, table[i+offs] += 64*(p - escapes + 1);
+ if(c) partner[i+offs] = table[i+offs], table[i+offs] = c;
+ if(*escapes && map[j] == '=') pieceNickName[i+offs] = map[++j], j++;
}
table[(int) WhiteKing] = map[j++];
- for( i=offs=0; i<NrPieces/2-1; i++ ) {
+ for( ii=offs=0; ii<NrPieces/2-1; ii++ ) {
char *p, c=0;
- if(map[j] == '/' && *escapes) offs = WhiteTokin - i, j++;
+ if(map[j] == '/') offs = WhitePBishop - ii, j++;
+ i = WHITE_TO_BLACK ii;
if(*escapes && (map[j] == '*' || map[j] == '-' || map[j] == '^')) c = map[j++];
- table[WHITE_TO_BLACK i + offs] = map[j++];
- if(p = strchr(escapes, map[j])) j++, table[WHITE_TO_BLACK i + offs] += 64*(p - escapes + 1);
- if(c) partner[WHITE_TO_BLACK i + offs] = table[WHITE_TO_BLACK i + offs], table[WHITE_TO_BLACK i + offs] = c;
+ table[i+offs] = map[j++];
+ if(p = strchr(escapes, map[j])) j++, table[i+offs] += 64*(p - escapes + 1);
+ if(c) partner[i+offs] = table[i+offs], table[i+offs] = c;
+ if(*escapes && map[j] == '=') pieceNickName[i+offs] = map[++j], j++;
}
table[(int) BlackKing] = map[j++];
int p;
for(p=0; p<EmptySquare; p++) if(table[p] == partner[i]) break;
if(c == '^') table[i] = '+';
- if(p < EmptySquare) promoPartner[p] = i, promoPartner[i] = p; // marry them
- } else if(c == '*') promoPartner[i] = (i < BlackPawn ? WhiteTokin : BlackTokin); // promotes to Tokin
+ if(p < EmptySquare) {
+ if(promoPartner[promoPartner[p]] == p) promoPartner[promoPartner[p]] = promoPartner[p]; // divorce old partners
+ if(promoPartner[promoPartner[i]] == i) promoPartner[promoPartner[i]] = promoPartner[i];
+ promoPartner[p] = i, promoPartner[i] = p; // and marry this couple
+ }
+ } else if(c == '*') {
+ table[i] = partner[i];
+ promoPartner[i] = (i < BlackPawn ? WhiteTokin : BlackTokin); // promotes to Tokin
+ }
}
}
gameInfo.boardWidth = 12;
gameInfo.boardHeight = 12;
nrCastlingRights = 0;
- SetCharTableEsc(pieceToChar, "P.BRQSEXOGCATHD.VMLIFN/^P.^B^R.^S^E^X^O^G^C^A^T^H^D.^V^M^L^I^FK"
- "p.brqsexogcathd.vmlifn/^p.^b^r.^s^e^x^o^g^c^a^t^h^d.^v^m^l^i^fk", SUFFIXES);
+ SetCharTableEsc(pieceToChar, "P.BRQSEXOGCATHD.VMLIFN.........^T..^L......^A^H/^F^G^M.^E^X^O^I.^P.^B^R..^D^S^C^VK"
+ "p.brqsexogcathd.vmlifn.........^t..^l......^a^h/^f^g^m.^e^x^o^i.^p.^b^r..^d^s^c^vk", SUFFIXES);
break;
case VariantCourier:
pieces = CourierArray;
*promoChoice = PieceToChar(p++);
if(*promoChoice != '.') break;
}
- return FALSE;
+ if(!*engineVariant) return FALSE; // if used as parent variant there might be promotion choice
}
// no sense asking what we must promote to if it is going to explode...
if(gameInfo.variant == VariantAtomic && boards[currentMove][toY][toX] != EmptySquare) {
Boolean addToBookFlag;
void
-UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar)
+UserMoveEvent (int fromX, int fromY, int toX, int toY, int promoChar)
{
ChessMove moveType;
ChessSquare pup;
"fromY %d, toX %d, toY %d\n",
fromX, fromY, toX, toY);
}
+ DrawPosition(TRUE, boards[currentMove]); // [HGM] repair animation damage done by premove (in particular emptying from-square)
return;
}
break;
"fromY %d, toX %d, toY %d\n",
fromX, fromY, toX, toY);
}
+ DrawPosition(TRUE, boards[currentMove]);
return;
}
break;
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;
+ ChessSquare p = boards[0][rf][ff];
+ if(PieceToChar(p) == '+') gatingPiece = CHUDEMOTED(p); else
+ if(PieceToChar(CHUPROMOTED(p)) =='+') gatingPiece = CHUPROMOTED(p);
}
boards[0][toY][toX] = boards[0][fromY][fromX];
if(fromX == BOARD_LEFT-2) { // handle 'moves' out of holdings
}
} else
boards[0][fromY][fromX] = gatingPiece;
+ ClearHighlights();
DrawPosition(FALSE, boards[currentMove]);
return;
}
if(addToBookFlag) { // adding moves to book
char buf[MSG_SIZ], move[MSG_SIZ];
CoordsToAlgebraic(boards[currentMove], PosFlags(currentMove), fromY, fromX, toY, toX, promoChar, move);
- if(killX >= 0) snprintf(move, MSG_SIZ, "%c%dx%c%d-%c%d", fromX + AAA, fromY + ONE - '0', killX + AAA, killY + ONE - '0', toX + AAA, toY + ONE - '0');
+ if(killX >= 0) snprintf(move, MSG_SIZ, "%c%dx%c%d-%c%d%c", fromX + AAA, fromY + ONE - '0',
+ killX + AAA, killY + ONE - '0', toX + AAA, toY + ONE - '0', promoChar);
snprintf(buf, MSG_SIZ, " 0.0%% 1 %s\n", move);
AddBookMove(buf);
addToBookFlag = FALSE;
// some variants have fixed promotion piece, no promotion at all, or another selection mechanism
if(IS_SHOGI(gameInfo.variant) || gameInfo.variant == VariantXiangqi ||
gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat ||
- gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
- gameInfo.variant == VariantMakruk) return FALSE;
+ (gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
+ gameInfo.variant == VariantMakruk) && !*engineVariant) return FALSE;
return (piece == BlackPawn && y <= zone ||
piece == WhitePawn && y >= BOARD_HEIGHT-1-zone ||
piece == BlackLance && y <= zone ||
ClearHighlights();
}
#endif
+ if(PieceToChar(CHUPROMOTED(boards[currentMove][fromY][fromX])) == '+')
+ defaultPromoChoice = CHUPROMOTED(boards[currentMove][fromY][fromX]);
if(gameInfo.variant == VariantChuChess && piece != WhitePawn && piece != BlackPawn) defaultPromoChoice = piece;
if(marker[y][x] == 5) { // [HGM] lion: this was the release of a to-click or drag on a cyan square
dragging *= 2; // flag button-less dragging if we are dragging
}
void
+Wheel (int dir, int x, int y)
+{
+ if(gameMode == EditPosition) {
+ int xSqr = EventToSquare(x, BOARD_WIDTH);
+ int ySqr = EventToSquare(y, BOARD_HEIGHT);
+ if(ySqr < 0 || xSqr < BOARD_LEFT || xSqr >= BOARD_RGHT) return;
+ if(flipView) xSqr = BOARD_WIDTH - 1 - xSqr; else ySqr = BOARD_HEIGHT - 1 - ySqr;
+ do {
+ boards[currentMove][ySqr][xSqr] += dir;
+ if((int) boards[currentMove][ySqr][xSqr] < WhitePawn) boards[currentMove][ySqr][xSqr] = BlackKing;
+ if((int) boards[currentMove][ySqr][xSqr] > BlackKing) boards[currentMove][ySqr][xSqr] = WhitePawn;
+ } while(PieceToChar(boards[currentMove][ySqr][xSqr]) == '.');
+ DrawPosition(FALSE, boards[currentMove]);
+ } else if(dir > 0) ForwardEvent(); else BackwardEvent();
+}
+
+void
SendProgramStatsToFrontend (ChessProgramState * cps, ChessProgramStats * cpstats)
{
// char * hint = lastHint;
ChessMove moveType;
char promoChar, roar;
char *p, *pv=buf1;
- int machineWhite, oldError;
+ int oldError;
char *bookHit;
if(cps == &pairing && sscanf(message, "%d-%d", &savedWhitePlayer, &savedBlackPlayer) == 2) {
} else {
+ int machineWhite = FALSE;
+
switch (gameMode) {
case BeginningOfGame:
/* Extra move from before last reset; ignore */
snprintf(buf1, MSG_SIZ*10, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c via %c%c, %c%c) res=%d",
machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, killX+AAA, killY+ONE, kill2X+AAA, kill2Y+ONE, moveType);
if (gameMode == TwoMachinesPlay) {
- GameEnds(machineWhite ? BlackWins : WhiteWins,
+ GameEnds(cps->twoMachinesColor[0] == 'w' ? BlackWins : WhiteWins,
buf1, GE_XBOARD);
}
return;
if(moveType == IllegalMove) {
snprintf(buf1, MSG_SIZ*10, "Xboard: Forfeit due to illegal move: %s (%c%c%c%c)%c",
machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);
- GameEnds(machineWhite ? BlackWins : WhiteWins,
+ GameEnds(cps->twoMachinesColor[0] == 'w' ? BlackWins : WhiteWins,
buf1, GE_XBOARD);
return;
} else if(!appData.fischerCastling)
return;
}
if(sscanf(message, "choice %s", promoRestrict) == 1 && promoSweep != EmptySquare) {
- promoSweep = PieceToChar(forwardMostMove&1 ? ToLower(*promoRestrict) : ToUpper(*promoRestrict));
+ promoSweep = CharToPiece(currentMove&1 ? ToLower(*promoRestrict) : ToUpper(*promoRestrict));
Sweep(0);
return;
}
[AS] Protect the thinkOutput buffer from overflow... this
is only useful if buf1 hasn't overflowed first!
*/
+ if((gameMode == AnalyzeMode && appData.whitePOV || appData.scoreWhite) && !WhiteOnMove(forwardMostMove)) curscore *= -1;
if(curscore >= MATE_SCORE)
snprintf(score_buf, MSG_SIZ, "#%d", curscore - MATE_SCORE);
else if(curscore <= -MATE_SCORE)
if(killX >= 0 && killY >= 0) x = killX, y = killY; // [HGM] lion: make SAN move to intermediate square, if there is one
(void) CoordsToAlgebraic(boards[forwardMostMove],
PosFlags(forwardMostMove),
- fromY, fromX, y, x, promoChar,
+ fromY, fromX, y, x, (killX < 0)*promoChar,
s);
if(killX >= 0 && killY >= 0)
- sprintf(s + strlen(s), "%c%c%d", p == EmptySquare || toX == fromX && toY == fromY ? '-' : 'x', toX + AAA, toY + ONE - '0');
+ sprintf(s + strlen(s), "%c%c%d%c", p == EmptySquare || toX == fromX && toY == fromY ? '-' : 'x', toX + AAA, toY + ONE - '0', promoChar);
if(serverMoves != NULL) { /* [HGM] write moves on file for broadcasting (should be separate routine, really) */
int timeLeft; static int lastLoadFlag=0; int king, piece;
toX = currentMoveString[2] - AAA;
toY = currentMoveString[3] - ONE;
promoChar = currentMoveString[4];
- if(promoChar == ';') promoChar = NULLCHAR;
+ if(promoChar == ';') promoChar = currentMoveString[7];
break;
case WhiteDrop:
return FALSE;
}
CopyBoard(boards[0], initial_position);
- if(*engineVariant) // [HGM] for now, assume FEN in engine-defined variant game is default initial position
+ if(*engineVariant || gameInfo.variant == VariantFairy) // [HGM] for now, assume FEN in engine-defined variant game is default initial position
CopyBoard(initialPosition, initial_position);
if (blackPlaysFirst) {
currentMove = forwardMostMove = backwardMostMove = 1;
for (i = BOARD_HEIGHT - 1; i >= 0; i--) {
for (j = BOARD_LEFT; j < BOARD_RGHT; j++) {
char c = PieceToChar(boards[move][i][j]);
- fputc(c == 'x' ? '.' : c, fp);
+ fputc(c == '?' ? '.' : c, fp);
fputc(j == BOARD_RGHT - 1 ? '\n' : ' ', fp);
}
}
char *p, *q, buf[MSG_SIZ];
int n, min = (-1)<<31, max = 1<<31, def;
+ opt->target = &opt->value; // OK for spin/slider and checkbox
if(p = strstr(opt->name, " -spin ")) {
if((n = sscanf(p, " -spin %d %d %d", &def, &min, &max)) < 3 ) return FALSE;
if(max < min) max = min; // enforce consistency
} else if((p = strstr(opt->name, " -string "))) {
opt->textValue = p+9;
opt->type = TextBox;
+ opt->target = &opt->textValue;
} else if((p = strstr(opt->name, " -file "))) {
// for now -file is a synonym for -string, to already provide compatibility with future polyglots
- opt->textValue = p+7;
+ opt->target = opt->textValue = p+7;
opt->type = FileName; // FileName;
+ opt->target = &opt->textValue;
} else if((p = strstr(opt->name, " -path "))) {
// for now -file is a synonym for -string, to already provide compatibility with future polyglots
- opt->textValue = p+7;
+ opt->target = opt->textValue = p+7;
opt->type = PathName; // PathName;
+ opt->target = &opt->textValue;
} else if(p = strstr(opt->name, " -check ")) {
if(sscanf(p, " -check %d", &def) < 1) return FALSE;
opt->value = (def != 0);
(cb == TwoMachinesEventIfReady)) {
CancelDelayedEvent();
ScheduleDelayedEvent(cb, val ? 1 : 3600000);
- }
+ } else if(!val && !cps->reload) ClearOptions(cps); // let 'spurious' done=0 clear engine's option list
cps->initDone = val;
- if(val) cps->reload = FALSE;
+ if(val) cps->reload = FALSE, RefreshSettingsDialog(cps, val);
}
/* Parse feature command from engine */