--- xboard-4.2.7/common.h.hilite 2005-06-03 09:04:12.000000000 +0800 +++ xboard-4.2.7/common.h 2005-06-03 09:33:57.000000000 +0800 @@ -130,6 +130,8 @@ int pclose(FILE *); #define DARK_SQUARE_COLOR "#77A26D" #define JAIL_SQUARE_COLOR "#808080" #define HIGHLIGHT_SQUARE_COLOR "#FFFF00" +#define MOVE_SQUARE_COLOR "#4C00FF" +#define THREATENED_SQUARE_COLOR "#D80000" #define PREMOVE_HIGHLIGHT_COLOR "#FF0000" #define BELLCHAR '\007' #define NULLCHAR '\000' @@ -265,6 +267,8 @@ typedef struct { char *darkSquareColor; char *jailSquareColor; char *highlightSquareColor; + char *moveSquareColor; + char *threatenedSquareColor; char *premoveHighlightColor; #else int whitePieceColor; @@ -273,6 +277,7 @@ typedef struct { int darkSquareColor; int jailSquareColor; int highlightSquareColor; + int moveSquareColor; int premoveHighlightColor; #endif int movesPerSession; @@ -424,6 +429,8 @@ typedef struct { char *zippyVariants; int zippyMaxGames; int zippyReplayTimeout; /*seconds*/ + Boolean showLegalMoves; + Boolean showThreatenedPieces; #endif #if LOWTIMEWARNING char *lowTimeWarningColor; --- xboard-4.2.7/xboard.h.hilite 2005-06-03 09:04:12.000000000 +0800 +++ xboard-4.2.7/xboard.h 2005-06-03 09:33:57.000000000 +0800 @@ -113,6 +113,7 @@ typedef struct { typedef int (*FileProc) P((FILE *f, int n, char *title)); void CatchDeleteWindow(Widget w, String procname); +void ShowThreatenedPieces(Board board); #define TOPLEVEL 1 /* preference item; 1 = make popup windows toplevel */ --- xboard-4.2.7/xboard.c.hilite 2005-06-03 09:04:12.000000000 +0800 +++ xboard-4.2.7/xboard.c 2005-06-03 09:45:55.000000000 +0800 @@ -185,6 +185,7 @@ extern char *getenv(); #include "common.h" #include "frontend.h" #include "backend.h" +#include "backendz.h" #include "moves.h" #include "xboard.h" #include "childio.h" @@ -385,6 +386,10 @@ void ShowThinkingProc P((Widget w, XEven Cardinal *nprms)); void TestLegalityProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); +void ShowLegalMovesProc P((Widget w, XEvent *event, String *prms, + Cardinal *nprms)); +void ShowThreatenedPiecesProc P((Widget w, XEvent *event, String *prms, + Cardinal *nprms)); void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); @@ -408,6 +413,9 @@ static void DragPieceEnd P((int x, int y static void DrawDragPiece P((void)); char *ModeToWidgetName P((GameMode mode)); +static void ShowLegalPieceSquares(int boardX,int boardY); +static void UnShowLegalPieceSquares(); + /* * XBoard depends on Xt R4 or higher */ @@ -417,6 +425,7 @@ int xScreen; Display *xDisplay; Window xBoardWindow; Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor, + moveSquareColor, threatenedSquareColor, jailSquareColor, highlightSquareColor, premoveHighlightColor; #if LOWTIMEWARNING Pixel lowTimeWarningColor; @@ -608,6 +617,8 @@ MenuItem optionsMenu[] = { {"Show Coords", ShowCoordsProc}, {"Show Thinking", ShowThinkingProc}, {"Test Legality", TestLegalityProc}, + {"Show Legal Moves",ShowLegalMovesProc}, + {"Show Threatened Pieces",ShowThreatenedPiecesProc}, {NULL, NULL} }; @@ -742,6 +753,12 @@ XtResource clientResources[] = { { "highlightSquareColor", "highlightSquareColor", XtRString, sizeof(String), XtOffset(AppDataPtr, highlightSquareColor), XtRString, HIGHLIGHT_SQUARE_COLOR }, + { "moveSquareColor", "moveSquareColor", XtRString, + sizeof(String), XtOffset(AppDataPtr, moveSquareColor), + XtRString, MOVE_SQUARE_COLOR }, + { "threatenedSquareColor", "threatenedSquareColor", XtRString, + sizeof(String), XtOffset(AppDataPtr, threatenedSquareColor), + XtRString, THREATENED_SQUARE_COLOR }, { "premoveHighlightColor", "premoveHighlightColor", XtRString, sizeof(String), XtOffset(AppDataPtr, premoveHighlightColor), XtRString, PREMOVE_HIGHLIGHT_COLOR }, @@ -1155,6 +1172,8 @@ XrmOptionDescRec shellOptions[] = { { "-lightSquareColor", "lightSquareColor", XrmoptionSepArg, NULL }, { "-darkSquareColor", "darkSquareColor", XrmoptionSepArg, NULL }, { "-highlightSquareColor", "highlightSquareColor", XrmoptionSepArg, NULL }, + { "-moveSquareColor", "moveSquareColor", XrmoptionSepArg, NULL }, + { "-threatenedSquareColor", "threatenedSquareColor", XrmoptionSepArg, NULL }, { "-premoveHighlightColor", "premoveHighlightColor", XrmoptionSepArg,NULL}, { "-movesPerSession", "movesPerSession", XrmoptionSepArg, NULL }, { "-mps", "movesPerSession", XrmoptionSepArg, NULL }, @@ -1537,6 +1556,7 @@ XtActionsRec boardActions[] = { { "ShowCoordsProc", ShowCoordsProc }, { "ShowThinkingProc", ShowThinkingProc }, { "TestLegalityProc", TestLegalityProc }, + { "ShowLegalMovesProc", ShowLegalMovesProc }, { "InfoProc", InfoProc }, { "ManProc", ManProc }, { "HintProc", HintProc }, @@ -2097,6 +2117,30 @@ main(argc, argv) } if (!appData.monoMode) { + vFrom.addr = (caddr_t) appData.moveSquareColor; + vFrom.size = strlen(appData.moveSquareColor); + XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo); + if (vTo.addr == NULL) { + appData.monoMode = True; + forceMono = True; + } else { + moveSquareColor = *(Pixel *) vTo.addr; + } + } + + if (!appData.monoMode) { + vFrom.addr = (caddr_t) appData.threatenedSquareColor; + vFrom.size = strlen(appData.threatenedSquareColor); + XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo); + if (vTo.addr == NULL) { + appData.monoMode = True; + forceMono = True; + } else { + threatenedSquareColor = *(Pixel *) vTo.addr; + } + } + + if (!appData.monoMode) { vFrom.addr = (caddr_t) appData.premoveHighlightColor; vFrom.size = strlen(appData.premoveHighlightColor); XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo); @@ -4315,6 +4359,7 @@ void XDrawPosition(w, repaint, board) /* If piece being dragged around board, must redraw that too */ DrawDragPiece(); + ShowThreatenedPieces(board); XSync(xDisplay, False); } @@ -6306,6 +6351,43 @@ void BlindfoldProc(w, event, prms, nprms DrawPosition(True, NULL); } +/* show legal moves on board when moving/dragging a piece */ +void ShowLegalMovesProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ + Arg args[16]; + appData.showLegalMoves = !appData.showLegalMoves; + + if (appData.showLegalMoves) { + XtSetArg(args[0], XtNleftBitmap, xMarkPixmap); + } else { + XtSetArg(args[0], XtNleftBitmap, None); + } + XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Legal Moves"), + args, 1); +} + +void ShowThreatenedPiecesProc(w, event, prms, nprms) + Widget w; + XEvent *event; + String *prms; + Cardinal *nprms; +{ + Arg args[16]; + appData.showThreatenedPieces = !appData.showThreatenedPieces; + + if (appData.showThreatenedPieces) { + XtSetArg(args[0], XtNleftBitmap, xMarkPixmap); + } else { + XtSetArg(args[0], XtNleftBitmap, None); + } + XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Threatened Pieces"), + args, 1); +} + void TestLegalityProc(w, event, prms, nprms) Widget w; XEvent *event; @@ -8344,6 +8426,7 @@ EndAnimation (anim, finish) 0, 0, squareSize, squareSize, anim->prevFrame.x, anim->prevFrame.y); } + } static void @@ -8464,6 +8547,10 @@ DragPieceBegin(x, y) if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) { player.dragActive = True; BeginAnimation(&player, player.dragPiece, color, &corner); + + /* show the squares where this piece can be legally moved */ + ShowLegalPieceSquares(fromX,fromY); + /* Mark this square as needing to be redrawn. Note that we don't remove the piece though, since logically (ie as seen by opponent) the move hasn't been made yet. */ @@ -8473,6 +8560,93 @@ DragPieceBegin(x, y) } } +/* squares that are highlighted from moving a piece */ +static int xHighlights[BOARD_SIZE*BOARD_SIZE]; +static int yHighlights[BOARD_SIZE*BOARD_SIZE]; + +/* highlight squares where legal moves can be made by current piece */ +static void ShowLegalPieceSquares(boardX,boardY) + int boardX;int boardY; +{ + + int x, y, currHighlight = 0, i = 0; + + if ( ! appData.showLegalMoves ) return; + + for ( i = 0 ; i < BOARD_SIZE; i++ ) + { + xHighlights[i] = -1; + yHighlights[i] = -1; + } + + for ( x = 0; x < BOARD_SIZE ; x++) + { + for ( y = 0 ; y < BOARD_SIZE; y++) + { + int legalmove = LegalityTest(boards[currentMove], + PosFlags(currentMove), + EP_UNKNOWN, fromY, fromX, y,x,0); +#ifdef DEBUG_MOVE_PIECES + printf("Move from %d %d to %d %d == %s - currentMove = %d\n",fromX,fromY,x,y,(legalmove == IllegalMove || legalmove == ImpossibleMove)?"Illegal move":"Legal move",currentMove); + +#endif + + if ( legalmove != IllegalMove && legalmove != ImpossibleMove) + { + XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground + | GCBackground | GCFunction | GCPlaneMask; + XGCValues gc_values; + gc_values.plane_mask = AllPlanes; + gc_values.line_width = lineGap; + gc_values.line_style = LineSolid; + gc_values.function = GXcopy; + +#ifdef DEBUG_MOVE_PIECES + printf("Highlight x = %d y = %d\n",x,y); +#endif + gc_values.foreground = moveSquareColor; + gc_values.background = moveSquareColor; + + drawHighlight(x,y,XtGetGC(shellWidget, value_mask, &gc_values)); + xHighlights[currHighlight] = x; + yHighlights[currHighlight] = y; + currHighlight++; + } + } + } +} + +/* remove highlights from squares that were highlighted + as a result of picking up a piece and showing the legal moves */ +static void UnShowLegalPieceSquares() +{ + int i = 0; + GC clearpieceGC; + XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground + | GCBackground | GCFunction | GCPlaneMask; + XGCValues gc_values; + if ( ! appData.showLegalMoves ) return; + + gc_values.plane_mask = AllPlanes; + gc_values.line_width = lineGap; + gc_values.line_style = LineSolid; + gc_values.function = GXcopy; + + gc_values.foreground = jailSquareColor; + gc_values.background = jailSquareColor; + + for ( i = 0 ; i < BOARD_SIZE*BOARD_SIZE && xHighlights[i] != -1 && yHighlights[i] != -1; i++ ) + { + clearpieceGC = XtGetGC(shellWidget, value_mask, &gc_values); +#ifdef DEBUG_MOVE_PIECES + printf("Erasing %d %d\n",BOARD_SIZE*BOARD_SIZE,xHighlights[i],yHighlights[i]); +#endif + drawHighlight(xHighlights[i], yHighlights[i],clearpieceGC); + xHighlights[i] = -1; + yHighlights[i] = -1; + } +} + static void DragPieceMove(x, y) int x; int y; @@ -8492,7 +8666,8 @@ DragPieceMove(x, y) corner.y = y - player.mouseDelta.y; AnimationFrame(&player, &corner, player.dragPiece); #if HIGHDRAG - if (appData.highlightDragging) { + if (appData.highlightDragging) + { int boardX, boardY; BoardSquare(x, y, &boardX, &boardY); SetHighlights(fromX, fromY, boardX, boardY); @@ -8526,12 +8701,156 @@ DragPieceEnd(x, y) /* This prevents weird things happening with fast successive clicks which on my Sun at least can cause motion events without corresponding press/release. */ + + /* un highlight the squares where the piece can be legally moved */ + UnShowLegalPieceSquares(); player.dragActive = False; } +/* return false (0) if not a white piece, true otherwise */ +static int WhitePiece(piece) + ChessSquare piece; +{ + return (int) piece >= (int) WhitePawn && (int) piece <= (int) WhiteKing; +} + +/* return false (0) if not a black piece, true otherwise */ +static int BlackPiece(piece) + ChessSquare piece; +{ + return (int) piece >= (int) BlackPawn && (int) piece <= (int) BlackKing; +} + +/* used for keeping track of whether a move was made or a + screen refresh has occured */ +static int old_currentMove = -1; +/* 2d array of board positions, used to indicate which + square to highlight as threatened */ +static int threatenedSquares[BOARD_SIZE][BOARD_SIZE]; + +/* called from ShowThreatenedPieces, redraw screen (refresh) */ +static void redrawBoard(Board board) +{ + int i, j; + /* setup colors to show threatened squares */ + XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground + | GCBackground | GCFunction | GCPlaneMask; + XGCValues gc_values; + gc_values.plane_mask = AllPlanes; + gc_values.line_width = lineGap; + gc_values.line_style = LineSolid; + gc_values.function = GXcopy; + + gc_values.foreground = threatenedSquareColor; + gc_values.background = threatenedSquareColor; + + /* iterate through board and highlight threatened pieces */ + for ( i = 0 ; i < BOARD_SIZE ; i++ ) + for ( j = 0 ; j < BOARD_SIZE ; j++ ) + if ( threatenedSquares[i][j] == 1 ) + drawHighlight(j,i,XtGetGC(shellWidget, value_mask, &gc_values)); +} + +void ShowThreatenedPieces(Board board) +{ + int x, y, boardX, boardY; + + if ( !appData.showThreatenedPieces) return; + + if ( old_currentMove == currentMove) + redrawBoard(board); + else /* piece was moved on the board */ + { + int i, j; + + /* setup color for threatened pieces squares */ + old_currentMove = currentMove; + GC clearpieceGC; + XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground + | GCBackground | GCFunction | GCPlaneMask; + XGCValues gc_values; + + gc_values.plane_mask = AllPlanes; + gc_values.line_width = lineGap; + gc_values.line_style = LineSolid; + gc_values.function = GXcopy; + + gc_values.foreground = jailSquareColor; + gc_values.background = jailSquareColor; + + clearpieceGC = XtGetGC(shellWidget, value_mask, &gc_values); + + /* clear previous storage of threatened squares coords */ + for ( i = 0 ; i < BOARD_SIZE ; i++ ) + for ( j = 0 ; j < BOARD_SIZE ; j++ ) + if (threatenedSquares[i][j] == 1 ) + { + drawHighlight(j,i ,clearpieceGC); + threatenedSquares[i][j] = 0 ; + } + + /* determine which squares need to be highlightened + as threatened */ + for(boardX = 0 ; boardX < BOARD_SIZE ; boardX++ ) + for ( boardY = 0 ; boardY < BOARD_SIZE ; boardY++ ) + { + /* not worth continuing if from or to square is blank */ + if ( !WhitePiece(board[boardY][boardX]) && + !BlackPiece(board[boardY][boardX])) + continue; + + for ( toX = 0; toX < BOARD_SIZE ; toX++) + { + for ( toY = 0 ; toY < BOARD_SIZE; toY++) + { + int legalmove, legalmove2; + /* test if it's worth continuing, from piece moving to + opponent piece */ + if ( !WhitePiece(board[toY][toX]) && + !BlackPiece(board[toY][toX])) + continue; + + if ( BlackPiece(board[boardY][boardX]) && + !WhitePiece(board[toY][toX]) ) + continue; + + if ( WhitePiece(board[boardY][boardX]) && + !BlackPiece(board[toY][toX]) ) + continue; + + /* the Posflags in the LegalityTest needs to be -1 because + the LegalityTest is done for the current move, which is updated + when the current piece was put down and switched to the other color + whereas we want the legality test for the old color otherwise + it will be classified as an IllegalMove */ + + /* legal moves for the previous color (user) */ + legalmove = LegalityTest(boards[currentMove], + PosFlags(currentMove)-1, + EP_UNKNOWN, + boardY, boardX, toY,toX,0); + + /* legal moves for the current color (user) */ + legalmove2 = LegalityTest(boards[currentMove], + PosFlags(currentMove), + EP_UNKNOWN, + boardY, boardX, toY,toX,0); + + if ( legalmove != IllegalMove || + legalmove2 != IllegalMove) + threatenedSquares[toY][toX] = 1; + } + } + } + } + /* redraw the board to reflect current changes */ + redrawBoard(board); +} + /* Handle expose event while piece being dragged */ -static void +static +void DrawDragPiece () { if (!player.dragActive || appData.blindfold) --- xboard-4.2.7/backend.c.hilite 2003-11-28 17:37:36.000000000 +0800 +++ xboard-4.2.7/backend.c 2005-06-03 09:33:57.000000000 +0800 @@ -4858,6 +4858,7 @@ ShowMove(fromX, fromY, toX, toY) DrawPosition(FALSE, boards[currentMove]); DisplayBothClocks(); HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1); + ShowThreatenedPieces(boards[currentMove]); }