From 1514fbc6e388eb410d72a5c58a2cb371d2be0d7c Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Wed, 14 Mar 2012 21:06:28 +0100 Subject: [PATCH] Implement exclude moves Dragging a piece by double-clicking it on the from-square in analysis mode will not perform the entered move, but send an exclude or include command to the engine for that move (provided the engine enabled this with feature exclude=1), depending on if the move was already excluded or not. To this end a map of excluded moves is kept, and cleared when we move to another position through moving, undo, setboard or new. The user can see whether he included or excluded the move, as exclude uses premove highlights. Commands "exclude|include all" are sent when we throw a double-clicked piece off board (vertically or horizontally, respectively), but after exclude all the most recent PV move is included again. Remaining problem is that promotions can only be excluded. --- backend.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- backend.h | 1 + 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/backend.c b/backend.c index db52e9c..4ceb598 100644 --- a/backend.c +++ b/backend.c @@ -6405,12 +6405,16 @@ int lastLoadGameNumber = 0, lastLoadPositionNumber = 0; int lastLoadGameUseList = FALSE; char lastLoadGameTitle[MSG_SIZ], lastLoadPositionTitle[MSG_SIZ]; ChessMove lastLoadGameStart = EndOfFile; +int doubleClick, mappedMove = -1; void UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar) { ChessMove moveType; ChessSquare pdown, pup; + static char excludeMap[(BOARD_RANKS*BOARD_FILES*BOARD_RANKS*BOARD_FILES+7)/8]; // [HGM] exclude: bitmap for excluced moves + int ff=fromX, rf=fromY, ft=toX, rt=toY; + /* Check if the user is playing in turn. This is complicated because we let the user "pick up" a piece before it is his turn. So the piece he @@ -6546,6 +6550,18 @@ UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar) return; } + if(doubleClick && (toX == -2 || toY == -2)) { // [HGM] exclude: off-board move means exclude all + int i; // note that drop moves still have holdings coords as from-square at this point + ChessMove moveType; char pc; + for(i=0; i<(BOARD_RANKS*BOARD_FILES*BOARD_RANKS*BOARD_FILES+7)/8; i++) excludeMap[i] = -(toY == -2); + mappedMove = currentMove; + if(toY != -2) { SendToProgram("include all\n", &first); return; } + SendToProgram("exclude all\n", &first); + i = ParseOneMove(lastPV[0], currentMove, &moveType, &fromX, &fromY, &toX, &toY, &pc); + ff=fromX, rf=fromY, ft=toX, rt=toY, promoChar = pc; // make copy that will survive drop encoding + if(!i) return; // kludge: continue with move changed to engine's last-reported best, so it gets included again. + } + if(toX < 0 || toY < 0) return; pdown = boards[currentMove][fromY][fromX]; pup = boards[currentMove][toY][toX]; @@ -6577,6 +6593,21 @@ UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar) } } + if(doubleClick) { // [HGM] exclude: move entered with double-click on from square is for exclusion, not playing + int i=(BOARD_FILES*rf+ff)*BOARD_RANKS*BOARD_FILES + (BOARD_FILES*rt+ft), j; + char buf[MSG_SIZ]; + if(mappedMove != currentMove) + for(j=0; j<(BOARD_RANKS*BOARD_FILES*BOARD_RANKS*BOARD_FILES+7)/8; j++) excludeMap[j] = 0; + j = i%8; i >>= 3; + snprintf(buf, MSG_SIZ, "%sclude ", excludeMap[i] & 1<= 200) fromX = fromY = -1; // second click on piece after altering default promo piece treated as first click if(!promoDefaultAltered) { // determine default promotion piece, based on the side the user is moving for @@ -6914,6 +6948,7 @@ LeftClick (ClickType clickType, int xPix, int yPix) } return; } + doubleClick = FALSE; fromX = x; fromY = y; toX = toY = -1; if(!appData.oneClick || !OnlyMove(&x, &y, FALSE) || // even if only move, we treat as normal when this would trigger a promotion popup, to allow sweep selection @@ -6960,6 +6995,10 @@ LeftClick (ClickType clickType, int xPix, int yPix) !(fromP == BlackKing && toP == BlackRook && frc))) { /* Clicked again on same color piece -- changed his mind */ second = (x == fromX && y == fromY); + if(second && gameMode == AnalyzeMode && SubtractTimeMarks(&lastClickTime, &prevClickTime) < 200) { + second = FALSE; // first double-click rather than scond click + doubleClick = first.excludeMoves; // used by UserMoveEvent to recognize exclude moves + } promoDefaultAltered = FALSE; MarkTargetSquares(1); if(!second || appData.oneClick && !OnlyMove(&x, &y, TRUE)) { @@ -6973,7 +7012,7 @@ LeftClick (ClickType clickType, int xPix, int yPix) (fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) && y == (toP < BlackPawn ? 0 : BOARD_HEIGHT-1)) gatingPiece = boards[currentMove][fromY][fromX]; - else gatingPiece = EmptySquare; + else gatingPiece = doubleClick ? fromP : EmptySquare; fromX = x; fromY = y; dragging = 1; MarkTargetSquares(0); @@ -7095,7 +7134,7 @@ LeftClick (ClickType clickType, int xPix, int yPix) // off-board moves should not be highlighted if(x < 0 || y < 0) ClearHighlights(); - if(gatingPiece != EmptySquare) promoChoice = ToLower(PieceToChar(gatingPiece)); + if(gatingPiece != EmptySquare && gameInfo.variant == VariantSChess) promoChoice = ToLower(PieceToChar(gatingPiece)); if (HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, appData.sweepSelect)) { SetHighlights(fromX, fromY, toX, toY); @@ -10714,6 +10753,7 @@ Reset (int redraw, int init) DisplayMessage("", ""); HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1); lastSavedGame = 0; // [HGM] save: make sure next game counts as unsaved + mappedMove = -1; // [HGM] exclude: invalidate map } void @@ -14304,6 +14344,7 @@ ForwardInner (int target) if ( !matchMode && gameMode != Training) { // [HGM] PV info: routine tests if empty DisplayComment(currentMove - 1, commentList[currentMove]); } + mappedMove = -1; // [HGM] exclude: invalidate map } @@ -14417,6 +14458,7 @@ BackwardInner (int target) HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1); // [HGM] PV info: routine tests if comment empty DisplayComment(currentMove - 1, commentList[currentMove]); + mappedMove = -1; // [HGM] exclude: invalidate map } void @@ -15483,6 +15525,7 @@ ParseFeatures (char *args, ChessProgramState *cps) if (BoolFeature(&p, "playother", &cps->usePlayother, cps)) continue; if (BoolFeature(&p, "colors", &cps->useColors, cps)) continue; if (BoolFeature(&p, "usermove", &cps->useUsermove, cps)) continue; + if (BoolFeature(&p, "exclude", &cps->excludeMoves, cps)) continue; if (BoolFeature(&p, "ics", &cps->sendICS, cps)) continue; if (BoolFeature(&p, "name", &cps->sendName, cps)) continue; if (BoolFeature(&p, "pause", &val, cps)) continue; /* unused at present */ diff --git a/backend.h b/backend.h index 3fef1ea..8fc885a 100644 --- a/backend.h +++ b/backend.h @@ -371,6 +371,7 @@ typedef struct _CPS { int sendName; /* 0=don't use "name" command; 1=do */ int sdKludge; /* 0=use "sd DEPTH" command; 1=use "depth\nDEPTH" */ int stKludge; /* 0=use "st TIME" command; 1=use "level 1 TIME" */ + int excludeMoves;/* 0=don't use "exclude" command; 1=do */ char tidy[MSG_SIZ]; int matchWins; char variants[MSG_SIZ]; -- 1.7.0.4