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,
char cmailMove[CMAIL_MAX_GAMES][MOVE_LEN], cmailMsg[MSG_SIZ];
char bookOutput[MSG_SIZ*10], thinkOutput[MSG_SIZ*10], lastHint[MSG_SIZ];
char thinkOutput1[MSG_SIZ*10];
+char promoRestrict[MSG_SIZ];
ChessProgramState first, second, pairing;
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)
if(fromY == DROP_RANK && k==toY && j==toX) continue; // dropped pieces always stand for themselves
old = (k==toY && j==toX) ? boards[moveNum-1][fromY][fromX] : boards[moveNum-1][k][j]; // trace back mover
if(old == new) continue;
- if(old == PROMOTED new) boards[moveNum][k][j] = old; // prevent promoted pieces to revert to primordial ones
+ if(old == PROMOTED(new)) boards[moveNum][k][j] = old;// prevent promoted pieces to revert to primordial ones
else if(new == WhiteWazir || new == BlackWazir) {
if(old < WhiteCannon || old >= BlackPawn && old < BlackCannon)
- boards[moveNum][k][j] = PROMOTED old; // choose correct type of Gold in promotion
+ boards[moveNum][k][j] = PROMOTED(old); // choose correct type of Gold in promotion
else boards[moveNum][k][j] = old; // preserve type of Gold
} else if((old == WhitePawn || old == BlackPawn) && new != EmptySquare) // Pawn promotions (but not e.p.capture!)
- boards[moveNum][k][j] = PROMOTED new; // use non-primordial representation of chosen piece
+ boards[moveNum][k][j] = PROMOTED(new); // use non-primordial representation of chosen piece
}
} else {
/* Move from ICS was illegal!? Punt. */
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
- int stride = gameInfo.variant == VariantChu ? 22 : 11;
- ChessSquare partner;
- partner = (*p/stride & 1 ? *p - stride : *p + stride);
+ ChessSquare partner = promoPartner[*p];
if(PieceToChar(*p) != '+' && PieceToChar(partner) != '+') return 0;
+ if(PieceToChar(*p) == '+') partner = boards[currentMove][fromY][fromX];
*p = partner;
return 1;
}
else if(promoSweep == BlackPawn && step < 0 && !toggleFlag) promoSweep = WhitePawn;
else if(promoSweep == WhiteKing && step > 0 && !toggleFlag) promoSweep = BlackKing;
if(!step) step = -1;
- } while(PieceToChar(promoSweep) == '.' || PieceToChar(promoSweep) == '~' || promoSweep == pawn ||
+ } while(PieceToChar(promoSweep) == '.' || PieceToChar(promoSweep) == '~' ||
!toggleFlag && PieceToChar(promoSweep) == '+' || // skip promoted versions of other
+ promoRestrict[0] ? !PieceInString(promoRestrict, promoSweep) : // if choice set available, use it
+ promoSweep == pawn ||
appData.testLegality && (promoSweep == king || gameInfo.variant != VariantChuChess &&
(promoSweep == WhiteLion || promoSweep == BlackLion)));
if(toX >= 0) {
}
int
-MultiPV (ChessProgramState *cps)
+MultiPV (ChessProgramState *cps, int kind)
{ // check if engine supports MultiPV, and if so, return the number of the option that sets it
int i;
- for(i=0; i<cps->nrOptions; i++)
- if(!strcmp(cps->option[i].name, "MultiPV") && cps->option[i].type == Spin)
- return i;
+ for(i=0; i<cps->nrOptions; i++) {
+ char *s = cps->option[i].name;
+ if((kind & 1) && !StrCaseCmp(s, "MultiPV") && cps->option[i].type == Spin) return i;
+ if((kind & 2) && StrCaseStr(s, "multi") && StrCaseStr(s, "PV")
+ && StrCaseStr(s, "margin") && cps->option[i].type == Spin) return -i-2;
+ }
return -1;
}
Boolean extendGame; // signals to UnLoadPV() if walked part of PV has to be appended to game
+static int multi, pv_margin;
+static ChessProgramState *activeCps;
Boolean
LoadMultiPV (int x, int y, char *buf, int index, int *start, int *end, int pane)
{
- int startPV, multi, lineStart, origIndex = index;
+ int startPV, lineStart, origIndex = index;
char *p, buf2[MSG_SIZ];
ChessProgramState *cps = (pane ? &second : &first);
do{ while(buf[index] && buf[index] != '\n') index++;
} while(buf[index] == '\n' && buf[index+1] == '\\' && buf[index+2] == ' ' && index++); // join kibitzed PV continuation line
buf[index] = 0;
- if(lineStart == 0 && gameMode == AnalyzeMode && (multi = MultiPV(cps)) >= 0) {
- int n = cps->option[multi].value;
- if(origIndex > 17 && origIndex < 24) { if(n>1) n--; } else if(origIndex > index - 6) n++;
+ if(lineStart == 0 && gameMode == AnalyzeMode) {
+ int n = 0;
+ if(origIndex > 17 && origIndex < 24) n--; else if(origIndex > index - 6) n++;
+ if(n == 0) { // click not on "fewer" or "more"
+ if((multi = -2 - MultiPV(cps, 2)) >= 0) {
+ pv_margin = cps->option[multi].value;
+ activeCps = cps; // non-null signals margin adjustment
+ }
+ } else if((multi = MultiPV(cps, 1)) >= 0) {
+ n += cps->option[multi].value; if(n < 1) n = 1;
snprintf(buf2, MSG_SIZ, "option MultiPV=%d\n", n);
if(cps->option[multi].value != n) SendToProgram(buf2, cps);
cps->option[multi].value = n;
*start = *end = 0;
return FALSE;
+ }
} else if(strstr(buf+lineStart, "exclude:") == buf+lineStart) { // exclude moves clicked
ExcludeClick(origIndex - lineStart);
return FALSE;
UnLoadPV ()
{
int oldFMM = forwardMostMove; // N.B.: this was currentMove before PV was loaded!
+ if(activeCps) {
+ if(pv_margin != activeCps->option[multi].value) {
+ char buf[MSG_SIZ];
+ snprintf(buf, MSG_SIZ, "option %s=%d\n", "Multi-PV Margin", pv_margin);
+ SendToProgram(buf, activeCps);
+ activeCps->option[multi].value = pv_margin;
+ }
+ activeCps = NULL;
+ return;
+ }
if(endPV < 0) return;
if(appData.autoCopyPV) CopyFENToClipboard();
endPV = -1;
{ // step through PV based on mouse coordinates (called on mouse move)
int margin = h>>3, step = 0, threshold = (pieceSweep == EmptySquare ? 10 : 15);
+ if(activeCps) { // adjusting engine's multi-pv margin
+ if(x > lastX) pv_margin++; else
+ if(x < lastX) pv_margin -= (pv_margin > 0);
+ if(x != lastX) {
+ char buf[MSG_SIZ];
+ snprintf(buf, MSG_SIZ, "margin = %d", pv_margin);
+ DisplayMessage(buf, "");
+ }
+ lastX = x;
+ return;
+ }
// we must somehow check if right button is still down (might be released off board!)
if(endPV < 0 && pieceSweep == EmptySquare) return; // needed in XBoard because lastX/Y is shared :-(
if(abs(x - lastX) < threshold && abs(y - lastY) < threshold) return;
{
int n = 0;
if(!*escapes) return strlen(s);
- while(*s) n += (*s != '/' && !strchr(escapes, *s)), s++;
+ while(*s) n += (*s != '-' && *s != '^' && *s != '*' && !strchr(escapes, *s)), s++;
return n;
}
+static int pieceOrder[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // P N B R Q F E A C W M
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, // O H I J G D V L S U Lion
+ 45, 23, 24, 25, 26, 27, 28, 29, 46, 31, 32, // Sword Zebra Camel Tower Wolf Dragon Duck Axe Leopard Gnu Cub
+ 44, 51, 56, 57, 58, 59, 60, 61, 62, 63, 34, // Whale Pegasus Wizard Copper Iron Viking Flag Amazon Wheel Shield Claw
+ 33, 55, 53, 42, 37, 48, 39, 40, 41, 22, 30, // +P +N =B =R +L +S +E +Ph +Kn Butterfly Hat
+ 38, 43, 35, 36, 49, 47, 52, 50, 54, 64, 65 // +V +M =H =D Princess HSword +GB HCrown Wheer Shierd King
+};
+
int
SetCharTableEsc (unsigned char *table, const char * map, char * escapes)
/* [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, 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;
- if(map[j] == '/' && *escapes) offs = WhiteTokin - i, j++;
- table[i + offs] = map[j++];
- if(p = strchr(escapes, map[j])) j++, table[i + offs] += 64*(p - escapes + 1);
+ for( ii=0; ii<NrPieces/2-1; ii++ ) {
+ char *p, c=0;
+ i = pieceOrder[ii];
+ if(*escapes && (map[j] == '*' || map[j] == '-' || map[j] == '^')) c = map[j++];
+ table[i] = map[j++];
+ if(p = strchr(escapes, map[j])) j++, table[i] += 64*(p - escapes + 1);
+ if(c) partner[i] = table[i], table[i] = c;
}
table[(int) WhiteKing] = map[j++];
- for( i=offs=0; i<NrPieces/2-1; i++ ) {
- char *p;
- if(map[j] == '/' && *escapes) offs = WhiteTokin - i, 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);
+ for( ii=0; ii<NrPieces/2-1; ii++ ) {
+ char *p, c=0;
+ i = WHITE_TO_BLACK pieceOrder[ii];
+ if(*escapes && (map[j] == '*' || map[j] == '-' || map[j] == '^')) c = map[j++];
+ table[i] = map[j++];
+ if(p = strchr(escapes, map[j])) j++, table[i] += 64*(p - escapes + 1);
+ if(c) partner[i] = table[i], table[i] = c;
}
table[(int) BlackKing] = map[j++];
+
+ if(*escapes) { // set up promotion pairing
+ for( i=0; i<(int) EmptySquare; i++ ) promoPartner[i] = (i%BlackPawn < 11 ? i + 11 : i%BlackPawn < 22 ? i - 11 : i); // default
+ // pieceToChar entirely filled, so we can look up specified partners
+ for(i=0; i<EmptySquare; i++) { // adjust promotion pairing
+ int c = table[i];
+ if(c == '^' || c == '-') { // has specified partner
+ 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 == '*') {
+ table[i] = partner[i];
+ promoPartner[i] = (i < BlackPawn ? WhiteTokin : BlackTokin); // promotes to Tokin
+ }
+ }
+ }
+
result = TRUE;
}
initialPosition[CASTLING][i] = initialRights[i] = NoRights; /* but no rights yet */
initialPosition[EP_STATUS] = EP_NONE;
initialPosition[TOUCHED_W] = initialPosition[TOUCHED_B] = 0;
- SetCharTable(pieceToChar, "PNBRQ...........Kpnbrq...........k");
+ SetCharTableEsc(pieceToChar, "PNBRQ...........Kpnbrq...........k", SUFFIXES);
if(startVariant == gameInfo.variant) // [HGM] nicks: enable nicknames in original variant
SetCharTable(pieceNickName, appData.pieceNickNames);
else SetCharTable(pieceNickName, "............");
gameInfo.boardWidth = 12;
gameInfo.boardHeight = 12;
nrCastlingRights = 0;
- SetCharTableEsc(pieceToChar, "P.BRQSEXOGCATHD.VMLIFN/+.++.++++++++++.+++++K"
- "p.brqsexogcathd.vmlifn/+.++.++++++++++.+++++k", SUFFIXES);
+ 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);
break;
case VariantCourier:
pieces = CourierArray;
else snprintf(message, MSG_SIZ, "%c%c%d\n", PieceToChar(*bp), AAA + j, ONE + i - '0');
if(message[0] == '+' || message[0] == '~') {
snprintf(message, MSG_SIZ,"%c%c%d+\n",
- PieceToChar((ChessSquare)(DEMOTED *bp)),
+ PieceToChar((ChessSquare)(DEMOTED(*bp))),
AAA + j, ONE + i - '0');
}
if(cps->alphaRank) { /* [HGM] shogi: translate coords */
AAA + j, ONE + i - '0');
if(message[0] == '+' || message[0] == '~') {
snprintf(message, MSG_SIZ,"%c%c%d+\n",
- PieceToChar((ChessSquare)(DEMOTED *bp)),
+ PieceToChar((ChessSquare)(DEMOTED(*bp))),
AAA + j, ONE + i - '0');
}
if(cps->alphaRank) { /* [HGM] shogi: translate coords */
piece = boards[currentMove][fromY][fromX];
if(gameInfo.variant == VariantChu) {
- int p = piece >= BlackPawn ? BLACK_TO_WHITE piece : piece;
promotionZoneSize = BOARD_HEIGHT/3;
- highestPromotingPiece = (p >= WhiteLion || PieceToChar(piece + 22) == '.') ? WhitePawn : WhiteLion;
+ highestPromotingPiece = (PieceToChar(piece) == '+' || PieceToChar(CHUPROMOTED(piece)) != '+') ? WhitePawn : WhiteKing;
} else if(gameInfo.variant == VariantShogi) {
promotionZoneSize = BOARD_HEIGHT/3 +(BOARD_HEIGHT == 8);
highestPromotingPiece = (int)WhiteAlfil;
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];
+ if(CHUPROMOTED(p) < BlackPawn) p = q = CHUPROMOTED(boards[0][rf][ff]);
else p = CHUDEMOTED (q = boards[0][rf][ff]);
if(PieceToChar(q) == '+') gatingPiece = p;
}
if(fromY == DROP_RANK && fromX == EmptySquare && (gameMode == AnalyzeMode || gameMode == EditGame || PosFlags(0) & F_NULL_MOVE)) moveType = NormalMove;
+ if(moveType == IllegalMove && legal[toY][toX] > 1) moveType = NormalMove; // someone explicitly told us this move is legal
+
/* [HGM] but possibly ignore an IllegalMove result */
if (appData.testLegality) {
if (moveType == IllegalMove || moveType == ImpossibleMove) {
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') legal[r][f] = 3; 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(rf == fromY && ff == fromX && (killX < 0 ? !(rt == rf && ft == ff) && legNr & 1 : rt == killY && ft == killX || legNr & 2))
(*m)[rt][ft] = 1 + (board[rt][ft] != EmptySquare
|| kind == WhiteCapturesEnPassant
- || 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;
+ || kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0), legal[rt][ft] = 3;
+ else if(flags & F_MANDATORY_CAPTURE && board[rt][ft] != EmptySquare) (*m)[rt][ft] = 3, legal[rt][ft] = 3;
}
static int hoverSavedValid;
DragPieceBegin(xPix, yPix, FALSE); dragging = 1;
if(appData.sweepSelect && CanPromote(piece = boards[currentMove][fromY][fromX], fromY)) {
promoSweep = defaultPromoChoice;
- selectFlag = 0; lastX = xPix; lastY = yPix;
+ selectFlag = 0; lastX = xPix; lastY = yPix; *promoRestrict = 0;
Sweep(0); // Pawn that is going to promote: preview promotion piece
DisplayMessage("", _("Pull pawn backwards to under-promote"));
}
DragPieceBegin(xPix, yPix, FALSE);
if(appData.sweepSelect && CanPromote(piece = boards[currentMove][y][x], y)) {
promoSweep = defaultPromoChoice;
- selectFlag = 0; lastX = xPix; lastY = yPix;
+ selectFlag = 0; lastX = xPix; lastY = yPix; *promoRestrict = 0;
Sweep(0); // Pawn that is going to promote: preview promotion piece
}
}
if(legal[y][x] == 2 || HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, FALSE)) {
if(appData.sweepSelect) {
promoSweep = defaultPromoChoice;
- if(gameInfo.variant != VariantChuChess && PieceToChar(CHUPROMOTED piece) == '+') promoSweep = CHUPROMOTED piece;
+ if(gameInfo.variant != VariantChuChess && PieceToChar(CHUPROMOTED(piece)) == '+') promoSweep = CHUPROMOTED(piece);
selectFlag = 0; lastX = xPix; lastY = yPix;
+ ReportClick("put", x, y); // extra put to prompt engine for 'choice' command
Sweep(0); // Pawn that is going to promote: preview promotion piece
sweepSelecting = 1;
DisplayMessage("", _("Pull pawn backwards to under-promote"));
}
} else if(sweepSelecting) { // this must be the up-click corresponding to the down-click that started the sweep
sweepSelecting = 0; appData.animate = FALSE; // do not animate, a selected piece already on to-square
+ *promoRestrict = 0;
if (appData.animate || appData.highlightLastMove) {
SetHighlights(fromX, fromY, toX, toY);
} else {
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
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)
if(sscanf(message, "piece %s %s", buf2, buf1) == 2) {
ChessSquare piece = WhitePawn;
char *p=message+6, *q, *s = SUFFIXES, ID = *p;
- if(*p == '+') piece = CHUPROMOTED WhitePawn, ID = *++p;
+ if(*p == '+') piece = CHUPROMOTED(WhitePawn), ID = *++p;
if(q = strchr(s, p[1])) ID += 64*(q - s + 1), p++;
piece += CharToPiece(ID & 255) - WhitePawn;
if(cps != &first || appData.testLegality && *engineVariant == NULLCHAR
}
return;
}
+ if(sscanf(message, "choice %s", promoRestrict) == 1 && promoSweep != EmptySquare) {
+ promoSweep = CharToPiece(currentMove&1 ? ToLower(*promoRestrict) : ToUpper(*promoRestrict));
+ Sweep(0);
+ 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.
*/
board[toY][toX + (killX < fromX ? 1 : -1)] = killed;
board[EP_STATUS] = EP_NONE; // capture was fake!
} else
+ if(nrCastlingRights == 0 && board[toY][toX] < EmptySquare && (piece < BlackPawn) == (board[toY][toX] < BlackPawn)) {
+ board[fromY][fromX] = board[toY][toX]; // capture own will lead to swapping
+ board[toY][toX] = piece;
+ board[EP_STATUS] = EP_NONE; // capture was fake!
+ } else
/* Code added by Tord: */
/* FRC castling assumed when king captures friendly rook. [HGM] or RxK for S-Chess */
if (board[fromY][fromX] == WhiteKing && board[toY][toX] == WhiteRook ||
) {
/* white pawn promotion */
board[toY][toX] = CharToPiece(ToUpper(promoChar));
- if(board[toY][toX] < WhiteCannon && PieceToChar(PROMOTED board[toY][toX]) == '~') /* [HGM] use shadow piece (if available) */
- board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]);
+ if(board[toY][toX] < WhiteCannon && PieceToChar(PROMOTED(board[toY][toX])) == '~') /* [HGM] use shadow piece (if available) */
+ board[toY][toX] = (ChessSquare) (PROMOTED(board[toY][toX]));
board[fromY][fromX] = EmptySquare;
} else if ((fromY >= BOARD_HEIGHT>>1)
&& (oldEP == toX || oldEP == EP_UNKNOWN || appData.testLegality || abs(toX - fromX) > 4)
) {
/* black pawn promotion */
board[toY][toX] = CharToPiece(ToLower(promoChar));
- if(board[toY][toX] < BlackCannon && PieceToChar(PROMOTED board[toY][toX]) == '~') /* [HGM] use shadow piece (if available) */
- board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]);
+ if(board[toY][toX] < BlackCannon && PieceToChar(PROMOTED(board[toY][toX])) == '~') /* [HGM] use shadow piece (if available) */
+ board[toY][toX] = (ChessSquare) (PROMOTED(board[toY][toX]));
board[fromY][fromX] = EmptySquare;
} else if ((fromY < BOARD_HEIGHT>>1)
&& (oldEP == toX || oldEP == EP_UNKNOWN || appData.testLegality || abs(toX - fromX) > 4)
p = (int) captured;
if (p >= (int) BlackPawn) {
p -= (int)BlackPawn;
- if(DEMOTED p >= 0 && PieceToChar(p) == '+') {
+ if(DEMOTED(p) >= 0 && PieceToChar(p) == '+') {
/* Restore shogi-promoted piece to its original first */
- captured = (ChessSquare) (DEMOTED captured);
- p = DEMOTED p;
+ captured = (ChessSquare) (DEMOTED(captured));
+ p = DEMOTED(p);
}
p = PieceToNumber((ChessSquare)p);
if(p >= gameInfo.holdingsSize) { p = 0; captured = BlackPawn; }
board[p][BOARD_WIDTH-1] = BLACK_TO_WHITE captured;
} else {
p -= (int)WhitePawn;
- if(DEMOTED p >= 0 && PieceToChar(p) == '+') {
- captured = (ChessSquare) (DEMOTED captured);
- p = DEMOTED p;
+ if(DEMOTED(p) >= 0 && PieceToChar(p) == '+') {
+ captured = (ChessSquare) (DEMOTED(captured));
+ p = DEMOTED(p);
}
p = PieceToNumber((ChessSquare)p);
if(p >= gameInfo.holdingsSize) { p = 0; captured = WhitePawn; }
} else
if(promoChar == '+') {
/* [HGM] Shogi-style promotions, to piece implied by original (Might overwrite ordinary Pawn promotion) */
- board[toY][toX] = (ChessSquare) (CHUPROMOTED piece);
+ board[toY][toX] = (ChessSquare) (CHUPROMOTED(piece));
if(gameInfo.variant == VariantChuChess && (piece == WhiteKnight || piece == BlackKnight))
board[toY][toX] = piece + WhiteLion - WhiteKnight; // adjust Knight promotions to Lion
} else if(!appData.testLegality && promoChar != NULLCHAR && promoChar != '=') { // without legality testing, unconditionally believe promoChar
ChessSquare newPiece = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar));
- if((newPiece <= WhiteMan || newPiece >= BlackPawn && newPiece <= BlackMan) // unpromoted piece specified
- && pieceToChar[PROMOTED newPiece] == '~') newPiece = PROMOTED newPiece; // but promoted version available
+ if((newPiece <= WhiteMan || newPiece >= BlackPawn && newPiece <= BlackMan) // unpromoted piece specified
+ && pieceToChar[PROMOTED(newPiece)] == '~') newPiece = PROMOTED(newPiece);// but promoted version available
board[toY][toX] = newPiece;
}
if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat || gameInfo.variant == VariantGrand)
case PromotePiece:
if(piece >= (int)WhitePawn && piece < (int)WhiteMan ||
piece >= (int)BlackPawn && piece < (int)BlackMan ) {
- selection = (ChessSquare) (PROMOTED piece);
+ selection = (ChessSquare) (PROMOTED(piece));
} else if(piece == EmptySquare) selection = WhiteSilver;
else selection = (ChessSquare)((int)piece - 1);
goto defaultlabel;
case DemotePiece:
if(piece > (int)WhiteMan && piece <= (int)WhiteKing ||
piece > (int)BlackMan && piece <= (int)BlackKing ) {
- selection = (ChessSquare) (DEMOTED piece);
+ selection = (ChessSquare) (DEMOTED(piece));
} else if(piece == EmptySquare) selection = BlackSilver;
else selection = (ChessSquare)((int)piece + 1);
goto defaultlabel;
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 */
if(PieceToChar(piece) == '+') {
/* [HGM] write promoted pieces as '+<unpromoted>' (Shogi) */
*p++ = '+';
- piece = (ChessSquare)(CHUDEMOTED piece);
+ piece = (ChessSquare)(CHUDEMOTED(piece));
}
*p++ = (piece == DarkSquare ? '*' : PieceToChar(piece));
if(*p = PieceSuffix(piece)) p++;
if(p[-1] == '~') {
/* [HGM] flag promoted pieces as '<promoted>~' (Crazyhouse) */
- p[-1] = PieceToChar((ChessSquare)(CHUDEMOTED piece));
+ p[-1] = PieceToChar((ChessSquare)(CHUDEMOTED(piece)));
*p++ = '~';
}
}
if(q = strchr(s, p[1])) p++;
piece = CharToPiece(c + (q ? 64*(q - s + 1) : 0));
if(piece == EmptySquare) return FALSE; /* unknown piece */
- piece = (ChessSquare) (CHUPROMOTED piece ); p++;
+ piece = (ChessSquare) (CHUPROMOTED(piece)); p++;
if(PieceToChar(piece) != '+') return FALSE; /* unpromotable piece */
} else {
char c = *p++;
if(piece==EmptySquare) return FALSE; /* unknown piece */
if(*p == '~') { /* [HGM] make it a promoted piece for Crazyhouse */
- piece = (ChessSquare) (PROMOTED piece);
+ piece = (ChessSquare) (PROMOTED(piece));
if(PieceToChar(piece) != '~') return FALSE; /* cannot be a promoted piece */
p++;
}