ColorClass curColor = ColorNormal;
int suppressKibitz = 0;
+// [HGM] seekgraph
+Boolean soughtPending = FALSE;
+Boolean seekGraphUp;
+#define MAX_SEEK_ADS 200
+char *seekAdList[MAX_SEEK_ADS];
+int ratingList[MAX_SEEK_ADS], xList[MAX_SEEK_ADS], yList[MAX_SEEK_ADS], seekNrList[MAX_SEEK_ADS], zList[MAX_SEEK_ADS];
+float tcList[MAX_SEEK_ADS];
+int nrOfSeekAds = 0;
+int minRating = 1010, maxRating = 2800;
+int hMargin = 10, vMargin = 20, h, w;
+extern int squareSize, lineGap;
+
+void
+PlotSeekAd(int i)
+{
+ int x, y, color = 0, r = ratingList[i]; float tc = tcList[i];
+ xList[i] = yList[i] = -100; // outside graph, so cannot be clicked
+ zList[i] = 0;
+ if(r < minRating+100 && r >=0 ) r = minRating+100;
+ if(r > maxRating) r = maxRating;
+ if(tc < 1.) tc = 1.;
+ if(tc > 95.) tc = 95.;
+ x = (w-hMargin)* log(tc)/log(100.) + hMargin;
+ y = ((double)r - minRating)/(maxRating - minRating)
+ * (h-vMargin-squareSize/8) + vMargin;
+ if(ratingList[i] < 0) y = vMargin + squareSize/4;
+ if(strstr(seekAdList[i], " u ")) color = 1;
+ if(!strstr(seekAdList[i], "lightning") && // for now all wilds same color
+ !strstr(seekAdList[i], "bullet") &&
+ !strstr(seekAdList[i], "blitz") &&
+ !strstr(seekAdList[i], "standard") ) color = 2;
+ DrawSeekDot(xList[i]=x+3*color, yList[i]=h-1-y, color);
+}
+
+void
+AddAd(char *handle, char *rating, int base, int inc, char rated, char *type, int nr, Boolean plot)
+{
+ char buf[MSG_SIZ], *ext = "";
+ VariantClass v = StringToVariant(type);
+ if(strstr(type, "wild")) {
+ ext = type + 4; // append wild number
+ if(v == VariantFischeRandom) type = "chess960"; else
+ if(v == VariantLoadable) type = "setup"; else
+ type = VariantName(v);
+ }
+ sprintf(buf, "%s (%s) %d %d %c %s%s", handle, rating, base, inc, rated, type, ext);
+ if(nrOfSeekAds < MAX_SEEK_ADS-1) {
+ if(seekAdList[nrOfSeekAds]) free(seekAdList[nrOfSeekAds]);
+ ratingList[nrOfSeekAds] = -1; // for if seeker has no rating
+ sscanf(rating, "%d", &ratingList[nrOfSeekAds]);
+ tcList[nrOfSeekAds] = base + (2./3.)*inc;
+ seekNrList[nrOfSeekAds] = nr;
+ seekAdList[nrOfSeekAds++] = StrSave(buf);
+ if(plot) PlotSeekAd(nrOfSeekAds-1);
+ }
+}
+
+Boolean
+MatchSoughtLine(char *line)
+{
+ char handle[MSG_SIZ], rating[MSG_SIZ], type[MSG_SIZ];
+ int nr, base, inc, u=0; char dummy;
+
+ if(sscanf(line, "%d %s %s %d %d rated %s", &nr, rating, handle, &base, &inc, type) == 6 ||
+ sscanf(line, "%d %s %s %s %d %d rated %c", &nr, rating, handle, type, &base, &inc, &dummy) == 7 ||
+ (u=1) &&
+ (sscanf(line, "%d %s %s %d %d unrated %s", &nr, rating, handle, &base, &inc, type) == 6 ||
+ sscanf(line, "%d %s %s %s %d %d unrated %c", &nr, rating, handle, type, &base, &inc, &dummy) == 7) ) {
+ // match: compact and save the line
+ AddAd(handle, rating, base, inc, u ? 'u' : 'r', type, nr, FALSE);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int
+DrawSeekGraph()
+{
+ if(!seekGraphUp) return FALSE;
+ int i;
+ h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
+ w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
+
+ DrawSeekBackground(0, 0, w, h);
+ DrawSeekAxis(hMargin, h-1-vMargin, w-5, h-1-vMargin);
+ DrawSeekAxis(hMargin, h-1-vMargin, hMargin, 5);
+ for(i=0; i<4000; i+= 100) if(i>=minRating && i<maxRating) {
+ int yy =((double)i - minRating)/(maxRating - minRating)*(h-vMargin-squareSize/8) + vMargin;
+ yy = h-1-yy;
+ DrawSeekAxis(hMargin+5*(i%500==0), yy, hMargin-5, yy); // rating ticks
+ if(i%500 == 0) {
+ char buf[MSG_SIZ];
+ sprintf(buf, "%d", i);
+ DrawSeekText(buf, hMargin+squareSize/8+7, yy);
+ }
+ }
+ DrawSeekText("unrated", hMargin+squareSize/8+7, h-1-vMargin-squareSize/4);
+ for(i=1; i<100; i+=(i<10?1:5)) {
+ int xx = (w-hMargin)* log((double)i)/log(100.) + hMargin;
+ DrawSeekAxis(xx, h-1-vMargin, xx, h-6-vMargin-3*(i%10==0)); // TC ticks
+ if(i<=5 || (i>40 ? i%20 : i%10) == 0) {
+ char buf[MSG_SIZ];
+ sprintf(buf, "%d", i);
+ DrawSeekText(buf, xx-2-3*(i>9), h-1-vMargin/2);
+ }
+ }
+ for(i=0; i<nrOfSeekAds; i++) PlotSeekAd(i);
+ return TRUE;
+}
+
+int SeekGraphClick(ClickType click, int x, int y, Boolean moving)
+{
+ static int lastDown = 0;
+ if(!seekGraphUp) { // initiate cration of seek graph by requesting seek-ad list
+ if(click == Release || moving) return FALSE;
+ nrOfSeekAds = 0;
+ soughtPending = TRUE;
+ SendToICS(ics_prefix);
+ SendToICS("sought\n"); // should this be "sought all"?
+ } else { // issue challenge based on clicked ad
+ int dist = 10000; int i, closest = 0;
+ for(i=0; i<nrOfSeekAds; i++) {
+ int d = (x-xList[i])*(x-xList[i]) + (y-yList[i])*(y-yList[i]) + zList[i];
+ if(d < dist) { dist = d; closest = i; }
+ if(click == Press && zList[i]>0) zList[i] *= 0.8; // age priority
+ }
+ if(dist < 300) {
+ char buf[MSG_SIZ];
+ if(lastDown != closest) DisplayMessage(seekAdList[closest], "");
+ sprintf(buf, "play %d\n", seekNrList[closest]);
+ if(click == Press) { lastDown = closest; return TRUE; } // on press 'hit', only show info
+ SendToICS(ics_prefix);
+ SendToICS(buf); // should this be "sought all"?
+ } else if(click == Release) { // release 'miss' is ignored
+ zList[lastDown] = 200; // make future selection of the rejected ad more difficult
+ return TRUE;
+ } else if(moving) { if(lastDown >= 0) DisplayMessage("", ""); lastDown = -1; return TRUE; }
+ // press miss or release hit 'pop down' seek graph
+ seekGraphUp = FALSE;
+ DrawPosition(TRUE, NULL);
+ }
+ return TRUE;
+}
+
void
read_from_ics(isr, closure, data, count, error)
InputSourceRef isr;
continue;
}
+ // [HGM] seekgraph: recognize sought lines and end-of-sought message
+ if(appData.seekGraph) {
+ if(soughtPending && MatchSoughtLine(buf+i)) {
+ i = strstr(buf+i, "rated") - buf;
+ next_out = leftover_start = i;
+ started = STARTED_CHATTER;
+ suppressKibitz = TRUE;
+ }
+ if((gameMode == IcsIdle || gameMode == BeginningOfGame)
+ && looking_at(buf, &i, "* ads displayed")) {
+ soughtPending = FALSE;
+ seekGraphUp = TRUE;
+ DrawSeekGraph();
+ continue;
+ }
+ }
+
/* skip formula vars */
if (started == STARTED_NONE &&
buf[i] == 'f' && isdigit(buf[i+1]) && buf[i+2] == ':') {
if (looking_at(buf, &i, "% ") ||
((started == STARTED_MOVES || started == STARTED_MOVES_NOHIDE)
&& looking_at(buf, &i, "}*"))) { char *bookHit = NULL; // [HGM] book
+ if(ics_type == ICS_ICC && soughtPending) { // [HGM] seekgraph: on ICC sought-list has no termination line
+ soughtPending = FALSE;
+ seekGraphUp = TRUE;
+ DrawSeekGraph();
+ }
if(suppressKibitz) next_out = i;
savingComment = FALSE;
suppressKibitz = 0;
}
}
-
+
/* Display the board */
if (!pausing && !appData.noGUI) {
((gameMode == IcsPlayingBlack) && (!WhiteOnMove(currentMove))))
ClearPremoveHighlights();
- DrawPosition(FALSE, boards[currentMove]);
+ j = seekGraphUp; seekGraphUp = FALSE; // [HGM] seekgraph: when we draw a board, it overwrites the seek graph
+ DrawPosition(j, boards[currentMove]);
+
DisplayMove(moveNum - 1);
if (appData.ringBellAfterMoves && /*!ics_user_moved*/ // [HGM] use absolute method to recognize own move
!((gameMode == IcsPlayingWhite) && (!WhiteOnMove(moveNum)) ||
static int second = 0, promotionChoice = 0;
char promoChoice = NULLCHAR;
+ if(appData.seekGraph && appData.icsActive &&
+ (gameMode == BeginningOfGame || gameMode == IcsIdle)) {
+ SeekGraphClick(clickType, xPix, yPix, FALSE);
+ return;
+ }
+
if (clickType == Press) ErrorPopDown();
MarkTargetSquares(1);
Boolean chessProgram;\r
//static int boardX, boardY;\r
int minX, minY; // [HGM] placement: volatile limits on upper-left corner\r
-static int squareSize, lineGap, minorSize;\r
+int squareSize, lineGap, minorSize;\r
static int winW, winH;\r
static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo\r
static int logoHeight = 0;\r
DeleteDC(tmphdc);\r
}\r
\r
+static HDC hdcSeek;\r
+\r
+// [HGM] seekgraph\r
+void DrawSeekAxis( int x, int y, int xTo, int yTo )\r
+{\r
+ POINT stPt;\r
+ HPEN hp = SelectObject( hdcSeek, gridPen );\r
+ MoveToEx( hdcSeek, boardRect.left+x, boardRect.top+y, &stPt );\r
+ LineTo( hdcSeek, boardRect.left+xTo, boardRect.top+yTo );\r
+ SelectObject( hdcSeek, hp );\r
+}\r
+\r
+// front-end wrapper for drawing functions to do rectangles\r
+void DrawSeekBackground( int left, int top, int right, int bottom )\r
+{\r
+ HPEN hp;\r
+ RECT rc;\r
+\r
+ if (hdcSeek == NULL) {\r
+ hdcSeek = GetDC(hwndMain);\r
+ if (!appData.monoMode) {\r
+ SelectPalette(hdcSeek, hPal, FALSE);\r
+ RealizePalette(hdcSeek);\r
+ }\r
+ }\r
+ hp = SelectObject( hdcSeek, gridPen );\r
+ rc.top = boardRect.top+top; rc.left = boardRect.left+left; \r
+ rc.bottom = boardRect.top+bottom; rc.right = boardRect.left+right;\r
+ FillRect( hdcSeek, &rc, lightSquareBrush );\r
+ SelectObject( hdcSeek, hp );\r
+}\r
+\r
+// front-end wrapper for putting text in graph\r
+void DrawSeekText(char *buf, int x, int y)\r
+{\r
+ SIZE stSize;\r
+ SetBkMode( hdcSeek, TRANSPARENT );\r
+ GetTextExtentPoint32( hdcSeek, buf, strlen(buf), &stSize );\r
+ TextOut( hdcSeek, boardRect.left+x-3, boardRect.top+y-stSize.cy/2, buf, strlen(buf) );\r
+}\r
+\r
+void DrawSeekDot(int x, int y, int color)\r
+{\r
+ HBRUSH oldBrush = SelectObject(hdcSeek, \r
+ color == 0 ? markerBrush : color == 1 ? darkSquareBrush : explodeBrush);\r
+ Ellipse(hdcSeek, boardRect.left+x - squareSize/8, boardRect.top+y - squareSize/8,\r
+ boardRect.left+x + squareSize/8, boardRect.top+y + squareSize/8);\r
+ SelectObject(hdcSeek, oldBrush);\r
+}\r
+\r
VOID\r
HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)\r
{\r
*/\r
Boolean fullrepaint = repaint;\r
\r
+ if(DrawSeekGraph()) return; // [HG} seekgraph: suppress printing board if seek graph up\r
+\r
if( DrawPositionNeedsFullRepaint() ) {\r
fullrepaint = TRUE;\r
}\r
break;\r
\r
case WM_MOUSEMOVE:\r
+ if(SeekGraphClick(Press, pt.x - boardRect.left, pt.y - boardRect.top, TRUE)) break;\r
MovePV(pt.x - boardRect.left, pt.y - boardRect.top, boardRect.bottom - boardRect.top);\r
if ((appData.animateDragging || appData.highlightDragging)\r
&& (wParam & MK_LBUTTON)\r
/* Why is the following needed on some versions of X instead
* of a translation? */
- XtAddEventHandler(boardWidget, ExposureMask, False,
+ XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
(XtEventHandler) EventProc, NULL);
/* end why */
if (event->xexpose.count > 0) return; /* no clipping is done */
XDrawPosition(widget, True, NULL);
break;
+ case MotionNotify:
+ if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, TRUE)) break;\r
default:
return;
}
return 0;
}
+// [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
+void DrawSeekAxis( int x, int y, int xTo, int yTo )
+{
+ XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
+}
+
+void DrawSeekBackground( int left, int top, int right, int bottom )
+{
+ XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
+}
+
+void DrawSeekText(char *buf, int x, int y)
+{
+ XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
+}
+
+void DrawSeekDot(int x, int y, int color)
+{
+ XFillArc(xDisplay, xBoardWindow, color == 0 ? prelineGC : color == 1 ? darkSquareGC : highlineGC,
+ x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
+}
+
static int damage[BOARD_RANKS][BOARD_FILES];
/*
Arg args[16];
int rrow, rcol;
+ if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
+
if (board == NULL) {
if (!lastBoardValid) return;
board = lastBoard;