updated year in copyright info
[xboard.git] / backend.c
index caa8e19..a54c6cc 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -5,7 +5,7 @@
  * Massachusetts.
  *
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
  *
  * Enhancements Copyright 2005 Alessandro Scotti
  *
@@ -2068,9 +2068,11 @@ int suppressKibitz = 0;
 Boolean soughtPending = FALSE;
 Boolean seekGraphUp;
 #define MAX_SEEK_ADS 200
+#define SQUARE 0x80
 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];
+char colorList[MAX_SEEK_ADS];
 int nrOfSeekAds = 0;
 int minRating = 1010, maxRating = 2800;
 int hMargin = 10, vMargin = 20, h, w;
@@ -2081,21 +2083,21 @@ 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;
+           * (h-vMargin-squareSize/8-1) + 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);
+       if(strstr(seekAdList[i], "(C) ")) color |= SQUARE; // plot computer seeks as squares
+       DrawSeekDot(xList[i]=x+3*(color&~SQUARE), yList[i]=h-1-y, colorList[i]=color);
 }
 
 void
@@ -2116,11 +2118,46 @@ AddAd(char *handle, char *rating, int base, int inc,  char rated, char *type, in
            sscanf(rating, "%d", &ratingList[nrOfSeekAds]);
            tcList[nrOfSeekAds] = base + (2./3.)*inc;
            seekNrList[nrOfSeekAds] = nr;
+           zList[nrOfSeekAds] = 0;
            seekAdList[nrOfSeekAds++] = StrSave(buf);
            if(plot) PlotSeekAd(nrOfSeekAds-1);
        }
 }
 
+void
+EraseSeekDot(int i)
+{
+    int x = xList[i], y = yList[i], d=squareSize/4, k;
+    DrawSeekBackground(x-squareSize/8, y-squareSize/8, x+squareSize/8+1, y+squareSize/8+1);
+    if(x < hMargin+d) DrawSeekAxis(hMargin, y-squareSize/8, hMargin, y+squareSize/8+1);
+    // now replot every dot that overlapped
+    for(k=0; k<nrOfSeekAds; k++) if(k != i) {
+       int xx = xList[k], yy = yList[k];
+       if(xx <= x+d && xx > x-d && yy <= y+d && yy > y-d)
+           DrawSeekDot(xx, yy, colorList[k]);
+    }
+}
+
+void
+RemoveSeekAd(int nr)
+{
+       int i;
+       for(i=0; i<nrOfSeekAds; i++) if(seekNrList[i] == nr) {
+           EraseSeekDot(i);
+           if(seekAdList[i]) free(seekAdList[i]);
+           seekAdList[i] = seekAdList[--nrOfSeekAds];
+           seekNrList[i] = seekNrList[nrOfSeekAds];
+           ratingList[i] = ratingList[nrOfSeekAds];
+           colorList[i]  = colorList[nrOfSeekAds];
+           tcList[i] = tcList[nrOfSeekAds];
+           xList[i]  = xList[nrOfSeekAds];
+           yList[i]  = yList[nrOfSeekAds];
+           zList[i]  = zList[nrOfSeekAds];
+           seekAdList[nrOfSeekAds] = NULL;
+           break;
+       }
+}
+
 Boolean
 MatchSoughtLine(char *line)
 {
@@ -2151,7 +2188,7 @@ DrawSeekGraph()
     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;
+       int yy =((double)i - minRating)/(maxRating - minRating)*(h-vMargin-squareSize/8-1) + vMargin;
        yy = h-1-yy;
        DrawSeekAxis(hMargin+5*(i%500==0), yy, hMargin-5, yy); // rating ticks
        if(i%500 == 0) {
@@ -2174,9 +2211,9 @@ DrawSeekGraph()
     return TRUE;
 }
 
-int SeekGraphClick(ClickType click, int x, int y, Boolean moving)
+int SeekGraphClick(ClickType click, int x, int y, int moving)
 {
-    static int lastDown = 0;
+    static int lastDown = 0, displayed = 0, lastSecond;
     if(!seekGraphUp) { // initiate cration of seek graph by requesting seek-ad list
        if(click == Release || moving) return FALSE;
        nrOfSeekAds = 0;
@@ -2184,23 +2221,39 @@ int SeekGraphClick(ClickType click, int x, int y, Boolean moving)
        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;
+       int dist = 10000; int i, closest = 0, second = 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
+           second += (d - zList[i] < 120); // count in-range ads
+           if(click == Press && moving != 1 && zList[i]>0) zList[i] *= 0.8; // age priority
        }
-       if(dist < 300) {
+       if(dist < 120) {
            char buf[MSG_SIZ];
-           if(lastDown != closest) DisplayMessage(seekAdList[closest], "");
+           second = (second > 1);
+           if(displayed != closest || second != lastSecond) {
+               DisplayMessage(second ? "!" : "", seekAdList[closest]);
+               lastSecond = second; displayed = closest;
+           }
            sprintf(buf, "play %d\n", seekNrList[closest]);
-           if(click == Press) { lastDown = closest; return TRUE; } // on press 'hit', only show info
+           if(click == Press) {
+               if(moving == 2) zList[closest] = 100; // right-click; push to back on press
+               lastDown = closest;
+               return TRUE;
+           } // on press 'hit', only show info
+           if(moving == 2) return TRUE; // ignore right up-clicks on dot
            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
+           zList[lastDown] = 100; // make future selection of the rejected ad more difficult
+           if(moving == 2) { // right up-click
+               nrOfSeekAds = 0; // refresh graph
+               soughtPending = TRUE;
+               SendToICS(ics_prefix);
+               SendToICS("sought\n"); // should this be "sought all"?
+           }
            return TRUE;
-       } else if(moving) { if(lastDown >= 0) DisplayMessage("", ""); lastDown = -1; return TRUE; }
+       } else if(moving) { if(displayed >= 0) DisplayMessage("", ""); displayed = -1; return TRUE; }
        // press miss or release hit 'pop down' seek graph
        seekGraphUp = FALSE;
        DrawPosition(TRUE, NULL);
@@ -2456,12 +2509,16 @@ read_from_ics(isr, closure, data, count, error)
                  sprintf(str,
                          "/set-quietly interface %s\n/set-quietly style 12\n",
                          programVersion);
+                 if(appData.seekGraph && appData.autoRefresh) // [HGM] seekgraph
+                     strcat(str, "/set-2 51 1\n/set seek 1\n");
                } else if (ics_type == ICS_CHESSNET) {
                  sprintf(str, "/style 12\n");
                } else {
                  strcpy(str, "alias $ @\n$set interface ");
                  strcat(str, programVersion);
                  strcat(str, "\n$iset startpos 1\n$iset ms 1\n");
+                 if(appData.seekGraph && appData.autoRefresh) // [HGM] seekgraph
+                     strcat(str, "$iset seekremove 1\n$set seek 1\n");
 #ifdef WIN32
                  strcat(str, "$iset nohighlight 1\n");
 #endif
@@ -2590,6 +2647,7 @@ read_from_ics(isr, closure, data, count, error)
                    next_out = leftover_start = i;
                    started = STARTED_CHATTER;
                    suppressKibitz = TRUE;
+                   continue;
                }
                if((gameMode == IcsIdle || gameMode == BeginningOfGame)
                        && looking_at(buf, &i, "* ads displayed")) {
@@ -2598,6 +2656,27 @@ read_from_ics(isr, closure, data, count, error)
                    DrawSeekGraph();
                    continue;
                }
+               if(appData.autoRefresh) {
+                   if(looking_at(buf, &i, "* (*) seeking * * * * *\"play *\" to respond)\n")) {
+                       int s = (ics_type == ICS_ICC); // ICC format differs
+                       if(seekGraphUp)
+                       AddAd(star_match[0], star_match[1], atoi(star_match[2+s]), atoi(star_match[3+s]), 
+                             star_match[4+s][0], star_match[5-3*s], atoi(star_match[7]), TRUE);
+                       looking_at(buf, &i, "*% "); // eat prompt
+                       next_out = i; // suppress
+                       continue;
+                   }
+                   if(looking_at(buf, &i, "Ads removed: *\n") || looking_at(buf, &i, "\031(51 * *\031)")) {
+                       char *p = star_match[0];
+                       while(*p) {
+                           if(seekGraphUp) RemoveSeekAd(atoi(p));
+                           while(*p && *p++ != ' '); // next
+                       }
+                       looking_at(buf, &i, "*% "); // eat prompt
+                       next_out = i;
+                       continue;
+                   }
+               }
            }
 
            /* skip formula vars */
@@ -5470,6 +5549,55 @@ OKToStartUserMove(x, y)
     return TRUE;
 }
 
+Boolean
+OnlyMove(int *x, int *y) {
+    DisambiguateClosure cl;
+    if (appData.zippyPlay) return FALSE;
+    switch(gameMode) {
+      case MachinePlaysBlack:
+      case IcsPlayingWhite:
+      case BeginningOfGame:
+       if(!WhiteOnMove(currentMove)) return FALSE;
+       break;
+      case MachinePlaysWhite:
+      case IcsPlayingBlack:
+       if(WhiteOnMove(currentMove)) return FALSE;
+       break;
+      default:
+       return FALSE;
+    }
+    cl.pieceIn = EmptySquare; 
+    cl.rfIn = *y;
+    cl.ffIn = *x;
+    cl.rtIn = -1;
+    cl.ftIn = -1;
+    cl.promoCharIn = NULLCHAR;
+    Disambiguate(boards[currentMove], PosFlags(currentMove), &cl);
+    if(cl.kind == NormalMove) {
+      fromX = cl.ff;
+      fromY = cl.rf;
+      *x = cl.ft;
+      *y = cl.rt;
+      return TRUE;
+    }
+    if(cl.kind != ImpossibleMove) return FALSE;
+    cl.pieceIn = EmptySquare;
+    cl.rfIn = -1;
+    cl.ffIn = -1;
+    cl.rtIn = *y;
+    cl.ftIn = *x;
+    cl.promoCharIn = NULLCHAR;
+    Disambiguate(boards[currentMove], PosFlags(currentMove), &cl);
+    if(cl.kind == NormalMove) {
+      fromX = cl.ff;
+      fromY = cl.rf;
+      *x = cl.ft;
+      *y = cl.rt;
+      return TRUE;
+    }
+    return FALSE;
+}
+
 FILE *lastLoadGameFP = NULL, *lastLoadPositionFP = NULL;
 int lastLoadGameNumber = 0, lastLoadPositionNumber = 0;
 int lastLoadGameUseList = FALSE;
@@ -5913,9 +6041,9 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
     static int second = 0, promotionChoice = 0;
     char promoChoice = NULLCHAR;
 
-    if(appData.seekGraph && appData.icsActive && 
+    if(appData.seekGraph && appData.icsActive && loggedOn &&
        (gameMode == BeginningOfGame || gameMode == IcsIdle)) {
-       SeekGraphClick(clickType, xPix, yPix, FALSE);
+       SeekGraphClick(clickType, xPix, yPix, 0);
        return;
     }
 
@@ -5960,6 +6088,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
        return;
 
     if (fromX == -1) {
+      if(!appData.oneClick || !OnlyMove(&x, &y)) {
        if (clickType == Press) {
            /* First square */
            if (OKToStartUserMove(x, y)) {
@@ -5974,6 +6103,7 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
            }
        }
        return;
+      }
     }
 
     /* fromX != -1 */
@@ -6123,10 +6253,16 @@ int RightClick(ClickType action, int x, int y, int *fromX, int *fromY)
 {   // front-end-free part taken out of PieceMenuPopup
     int whichMenu; int xSqr, ySqr;
 
+    if(seekGraphUp) { // [HGM] seekgraph
+       if(action == Press)   SeekGraphClick(Press, x, y, 2); // 2 indicates right-click: no pop-down on miss
+       if(action == Release) SeekGraphClick(Release, x, y, 2); // and no challenge on hit
+       return -2;
+    }
+
     xSqr = EventToSquare(x, BOARD_WIDTH);
     ySqr = EventToSquare(y, BOARD_HEIGHT);
     if (action == Release) UnLoadPV(); // [HGM] pv
-    if (action != Press) return -2;
+    if (action != Press) return -2; // return code to be ignored
     switch (gameMode) {
       case IcsExamining:
        if(xSqr < BOARD_LEFT || xSqr >= BOARD_RGHT) return -1;\r