Added URL detection into the console text window for ICS.
[xboard.git] / zippy.c
diff --git a/zippy.c b/zippy.c
index c15b0b3..5626092 100644 (file)
--- a/zippy.c
+++ b/zippy.c
@@ -1,9 +1,13 @@
 /*
  * zippy.c -- Implements Zippy the Pinhead chess player on ICS in XBoard
- * $Id: zippy.c,v 2.2 2003/11/25 05:25:20 mann Exp $
  *
- * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
- * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
+ * Copyright 1991 by Digital Equipment Corporation, Maynard,
+ * Massachusetts. 
+ *
+ * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
+ * 2007, 2008, 2009 Free Software Foundation, Inc.
+ *
+ * Enhancements Copyright 2005 Alessandro Scotti
  *
  * The following terms apply to Digital Equipment Corporation's copyright
  * interest in XBoard:
  * SOFTWARE.
  * ------------------------------------------------------------------------
  *
- * The following terms apply to the enhanced version of XBoard distributed
- * by the Free Software Foundation:
+ * The following terms apply to the enhanced version of XBoard
+ * distributed by the Free Software Foundation:
  * ------------------------------------------------------------------------
- * This program is free software; you can redistribute it and/or modify
+ *
+ * GNU XBoard is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * GNU XBoard is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * ------------------------------------------------------------------------
- */
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ *------------------------------------------------------------------------
+ ** See the file ChangeLog for a revision history.  */
 
 #include "config.h"
 
@@ -88,11 +93,18 @@ extern char *getenv();
 #include "backend.h"
 #include "backendz.h"
 
+char *SendMoveToBookUser P((int nr, ChessProgramState *cps, int initial)); // [HGM] book
+void HandleMachineMove P((char *message, ChessProgramState *cps));
+
 static char zippyPartner[MSG_SIZ];
 static char zippyLastOpp[MSG_SIZ];
+static char zippyOffender[MSG_SIZ]; // [HGM] aborter
 static int zippyConsecGames;
 static time_t zippyLastGameEnd;
 
+extern void mysrandom(unsigned int seed);
+extern int myrandom(void);
+
 void ZippyInit()
 {
     char *p;
@@ -227,7 +239,8 @@ char *swifties[] = {
     "i enthuses:", "i entreats:", "i enunciates:", "i eulogizes:",
     "i exclaims:", "i execrates:", "i exhorts:", "i expatiates:",
     "i explains:", "i explicates:", "i explodes:", "i exposes:",
-    "i exposits:", "i expounds:", "i expresses:", "i extols:",
+    "i exposits:", "i expostulates: ",
+    "i expounds:", "i expresses:", "i extols:",
     "i exults:", "i fantasizes:", "i fibs:", "i filibusters:",
     "i flatters:", "i flutes:", "i fools:", "i free-associates:",
     "i fulminates:", "i gabbles:", "i gabs:", "i gasps:",
@@ -377,6 +390,21 @@ int ZippyCalled(str)
 static char opp_name[128][32];
 static int num_opps=0;
 
+extern ColorClass curColor;
+
+static void SetCurColor( ColorClass color )
+{
+    curColor = color;
+}
+
+static void ColorizeEx( ColorClass color, int cont )
+{
+    if( appData.colorize ) {
+        Colorize( color, cont );
+        SetCurColor( color );
+    }
+}
+
 int ZippyControl(buf, i)
      char *buf;
      int *i;
@@ -390,7 +418,8 @@ int ZippyControl(buf, i)
 
     /* Possibly reject Crafty as opponent */
     if (appData.zippyPlay && appData.zippyNoplayCrafty && forwardMostMove < 4
-       && looking_at(buf, i, "* kibitzes: Hello from Crafty")) {
+       && looking_at(buf, i, "* kibitzes: Hello from Crafty")) 
+    {
         player = StripHighlightAndTitle(star_match[0]);
        if ((gameMode == IcsPlayingWhite &&
             StrCaseCmp(player, gameInfo.black) == 0) ||
@@ -491,7 +520,8 @@ int ZippyControl(buf, i)
     }
 
     if (looking_at(buf, i, "* tells you: *") ||
-       looking_at(buf, i, "* says: *")) {
+       looking_at(buf, i, "* says: *")) 
+    {
        player = StripHighlightAndTitle(star_match[0]);
        if (appData.zippyPassword[0] != NULLCHAR &&
            strncmp(star_match[1], appData.zippyPassword,
@@ -534,14 +564,23 @@ int ZippyControl(buf, i)
                Speak("tell", player);
            }
        }
+
+        ColorizeEx( ColorTell, FALSE );
+
        return TRUE;
     }
 
+    if( appData.colorize && looking_at(buf, i, "* (*) seeking") ) {
+       ColorizeEx(ColorSeek, FALSE);
+        return FALSE;
+    }
+
     if (looking_at(buf, i, "* spoofs you:")) {
         player = StripHighlightAndTitle(star_match[0]);
         sprintf(reply, "spoofedby %s\n", player);
         SendToICS(reply);
     }
+
     return FALSE;
 }
 
@@ -555,7 +594,8 @@ int ZippyConverse(buf, i)
 
     /* Shouts and emotes */
     if (looking_at(buf, i, "--> * *") ||
-       looking_at(buf, i, "* shouts: *")) {
+       looking_at(buf, i, "* shouts: *")) 
+    {
       if (appData.zippyTalk) {
        char *player = StripHighlightAndTitle(star_match[0]);
        if (strcmp(player, ics_handle) == 0) {
@@ -568,6 +608,9 @@ int ZippyConverse(buf, i)
            Speak("shout", NULL);
        }
       }
+
+      ColorizeEx(ColorShout, FALSE);
+
       return TRUE;
     }
 
@@ -578,6 +621,9 @@ int ZippyConverse(buf, i)
            Speak("kibitz", NULL);
        }
       }
+
+      ColorizeEx(ColorKibitz, FALSE);
+
       return TRUE;
     }
 
@@ -588,6 +634,9 @@ int ZippyConverse(buf, i)
            Speak("whisper", NULL);
        }
       }
+
+      ColorizeEx(ColorKibitz, FALSE);
+
       return TRUE;
     }
 
@@ -643,6 +692,8 @@ int ZippyConverse(buf, i)
            Speak("tell", channel);
          }
 #endif
+
+          ColorizeEx( atoi(channel) == 1 ? ColorChannel1 : ColorChannel, FALSE );
        }
        return TRUE;
     }
@@ -720,6 +771,8 @@ void ZippyGameEnd(result, resultDetails)
       SendToICS("\n");
     }
     zippyLastGameEnd = time(0);
+    if(forwardMostMove < appData.zippyShortGame) 
+       strcpy(zippyOffender, zippyLastOpp); else zippyOffender[0] = 0; // [HGM] aborter
 }
 
 /*
@@ -730,7 +783,7 @@ void ZippyHandleChallenge(srated, swild, sbase, sincrement, opponent)
      char *srated, *swild, *sbase, *sincrement, *opponent;
 {
     char buf[MSG_SIZ];
-    int base, increment;
+    int base, increment, i=0;
     char rated;
     VariantClass variant;
     char *varname;
@@ -741,6 +794,9 @@ void ZippyHandleChallenge(srated, swild, sbase, sincrement, opponent)
     base = atoi(sbase);
     increment = atoi(sincrement);
 
+    /* [DM] If icsAnalyzeEngine active we don't accept automatic games */
+    if (appData.icsActive && appData.icsEngineAnalyze) return;
+
     /* If desired, you can insert more code here to decline matches
        based on rated, variant, base, and increment, but it is
        easier to use the ICS formula feature instead. */
@@ -752,10 +808,13 @@ void ZippyHandleChallenge(srated, swild, sbase, sincrement, opponent)
        SendToICS(buf);
        return;
     }
-    if (StrStr(appData.zippyVariants, varname) == NULL) {
+    if (StrStr(appData.zippyVariants, varname) == NULL ||
+              ((i=first.protocolVersion) != 1 && StrStr(first.variants, varname) == NULL) /* [HGM] zippyvar */
+                                                          ) {
         sprintf(buf,
         "%stell %s This computer can't play %s [%s], only %s\n%sdecline %s\n",
-               ics_prefix, opponent, swild, varname, appData.zippyVariants,
+               ics_prefix, opponent, swild, varname, 
+                i ? first.variants : appData.zippyVariants,                               /* [HGM] zippyvar */
                ics_prefix, opponent);
        SendToICS(buf);
        return;
@@ -781,6 +840,17 @@ void ZippyHandleChallenge(srated, swild, sbase, sincrement, opponent)
       return;
     }
 
+    /* [HGM] aborter: opponent is cheater that aborts games he doesn't like on first move. Make him wait */
+    if (strcmp(opponent, zippyOffender) == 0 &&
+       difftime(time(0), zippyLastGameEnd) < appData.zippyReplayTimeout) {
+      sprintf(buf, "%stell %s Sorry, your previous game against %s was rather short. "
+                  " It will wait %d seconds to see if a tougher opponent comes along.\n%sdecline %s\n",
+             ics_prefix, opponent, ics_handle,
+             appData.zippyReplayTimeout, ics_prefix, opponent);
+      SendToICS(buf);
+      return;
+    }
+
     /* Engine not yet initialized or still thinking about last game? */
     if (!first.initDone || first.lastPing != first.lastPong) {
       sprintf(buf, "%stell %s I'm not quite ready for a new game yet; try again soon.\n%sdecline %s\n",
@@ -832,7 +902,10 @@ int ZippyMatch(buf, i)
     if (looking_at(buf, i, "Challenge: * (*) *(*) * * * * Loaded from *")) {
        /* note: star_match[2] can include "[white] " or "[black] "
           before our own name. */
-       ZippyHandleChallenge(star_match[4], star_match[8],
+       if(star_match[8] == NULL || star_match[8][0] == 0) // [HGM] chessd: open-source ICS has file on next line
+            ZippyHandleChallenge(star_match[4], star_match[5],
+                            star_match[6], star_match[7],                           StripHighlightAndTitle(star_match[0]));
+       else ZippyHandleChallenge(star_match[4], star_match[8],
                             star_match[6], star_match[7],
                             StripHighlightAndTitle(star_match[0]));
        return TRUE;
@@ -868,11 +941,20 @@ int ZippyMatch(buf, i)
        return TRUE;
     }
 
-    if (looking_at(buf, i, "offers you a draw")) {
-        if (first.sendDrawOffers && first.initDone) {
-           SendToProgram("draw\n", &first);
-       }
-       return TRUE;
+
+    if (ics_type == ICS_ICC) { // [DM]
+        if (looking_at(buf, i, "Your opponent offers you a draw")) {
+            if (first.sendDrawOffers && first.initDone)
+                SendToProgram("draw\n", &first);
+            return TRUE;
+        }
+    } else {
+        if (looking_at(buf, i, "offers you a draw")) {
+            if (first.sendDrawOffers && first.initDone) {
+                SendToProgram("draw\n", &first);
+            }
+            return TRUE;
+        }
     }
 
     if (looking_at(buf, i, "requests that the game be aborted") ||
@@ -920,6 +1002,7 @@ void ZippyFirstBoard(moveNum, basetime, increment)
     int w, b;
     char *opp = (gameMode==IcsPlayingWhite ? gameInfo.black : gameInfo.white);
     Boolean sentPos = FALSE;
+    char *bookHit = NULL; // [HGM] book
 
     if (!first.initDone) {
       /* Game is starting prematurely.  We can't deal with this */
@@ -990,7 +1073,7 @@ void ZippyFirstBoard(moveNum, basetime, increment)
                  SendTimeRemaining(&first, TRUE);
                }
              }
-             SendToProgram("go\n", &first);
+             bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move
            } else {
                /* Engine's opponent is on move now */
                if (first.usePlayother) {
@@ -1016,7 +1099,8 @@ void ZippyFirstBoard(moveNum, basetime, increment)
                  SendTimeRemaining(&first, TRUE);
                }
              }
-             SendToProgram("go\n", &first);
+//           SendToProgram("go\n", &first);
+             bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move
            }
        }
     } else if (gameMode == IcsPlayingBlack) {
@@ -1040,7 +1124,8 @@ void ZippyFirstBoard(moveNum, basetime, increment)
                  SendTimeRemaining(&first, FALSE);
                }
              }
-             SendToProgram("go\n", &first);
+//           SendToProgram("go\n", &first);
+             bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: send go or retrieve book move
            } else {
                /* Engine's opponent is on move now */
                if (first.usePlayother) {
@@ -1058,6 +1143,18 @@ void ZippyFirstBoard(moveNum, basetime, increment)
            /* Nothing needs to be done here */
        }       
     }
+
+    if(bookHit) { // [HGM] book: simulate book reply
+       static char bookMove[MSG_SIZ]; // a bit generous?
+
+       programStats.depth = programStats.nodes = programStats.time = 
+       programStats.score = programStats.got_only_move = 0;
+       sprintf(programStats.movelist, "%s (xbook)", bookHit);
+
+       strcpy(bookMove, "move ");
+       strcat(bookMove, bookHit);
+       HandleMachineMove(bookMove, &first);
+    }
 }