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;
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] ? !strchr(promoRestrict, ToUpper(PieceToChar(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;
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
}
}
promoSweep = defaultPromoChoice;
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 {
}
return;
}
+ if(sscanf(message, "choice %s", promoRestrict) == 1 && promoSweep != EmptySquare) {
+ promoSweep = PieceToChar(forwardMostMove&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.
*/