Recognize 'result' command in WB driver
[hachu.git] / hachu.c
diff --git a/hachu.c b/hachu.c
index 5b93431..c59149b 100644 (file)
--- a/hachu.c
+++ b/hachu.c
@@ -46,7 +46,7 @@
 #define EMPTY      0\r
 #define EDGE   (1<<11)\r
 #define TYPE   (WHITE|BLACK|EDGE)\r
-#define ABSENT  4095\r
+#define ABSENT  2047\r
 #define INF     8000\r
 #define NPIECES 2000               /* length of piece list    */\r
 \r
@@ -82,12 +82,12 @@ typedef struct {
 } PieceDesc;\r
 \r
 typedef struct {\r
-  int from, to, piece, victim, new, booty, epSquare, epVictim, ep2Square, ep2Victim, savKeyL, savKeyH;\r
+  int from, to, piece, victim, new, booty, epSquare, epVictim, ep2Square, ep2Victim, revMoveCount, savKeyL, savKeyH;\r
 } UndoInfo;\r
 \r
-int stm, xstm, hashKeyH, hashKeyL, framePtr, msp, nonCapts, rootEval, retMSP, retFirst, pvPtr, level, chuFlag=1;\r
+int stm, xstm, hashKeyH, hashKeyL, framePtr, msp, nonCapts, rootEval, retMSP, retFirst, pvPtr, level, cnt50, chuFlag=1;\r
 int nodes, startTime, tlim1, tlim2;\r
-Move retMove, moveStack[10000], path[100], pv[1000];\r
+Move retMove, moveStack[10000], path[100], repStack[300], pv[1000];\r
 \r
 #define X 36 /* slider              */\r
 #define J -1 /* jump                */\r
@@ -409,6 +409,13 @@ typedef struct {
   char age;\r
 } HashEntry; // hash-table entry\r
 \r
+    // Some global variables that control your engine's behavior\r
+    int ponder;\r
+    int randomize;\r
+    int postThinking;\r
+    int resign;         // engine-defined option\r
+    int contemptFactor; // likewise\r
+\r
 int squareKey[BSIZE];\r
 \r
 int rawBoard[BSIZE + 11*BW + 6];\r
@@ -1004,6 +1011,7 @@ MakeMove(Move m, UndoInfo *u)
   u->piece = board[u->from];\r
   board[u->from] = EMPTY;\r
   u->booty = 0;\r
+  u->revMoveCount = cnt50++;\r
   u->savKeyL = hashKeyL;\r
   u->savKeyH = hashKeyH;\r
 \r
@@ -1015,6 +1023,7 @@ MakeMove(Move m, UndoInfo *u)
       p[u->piece].pos = ABSENT;\r
       u->new = p[u->piece].promo;\r
       u->booty = p[u->new].value - p[u->piece].value;\r
+      cnt50 = 0; // promotion irreversible\r
     }\r
   } else u->new = u->piece;\r
 \r
@@ -1040,12 +1049,13 @@ MakeMove(Move m, UndoInfo *u)
     hashKeyL ^= p[u->ep2Victim].pieceKey * squareKey[u->ep2Square];\r
     hashKeyH ^= p[u->ep2Victim].pieceKey * squareKey[u->ep2Square+BH];\r
     if(p[u->piece].value != 1000 && p[u->epVictim].value == 1000) deferred |= PROMOTE; // flag non-Lion x Lion\r
+    cnt50 = 0; // double capture irreversible\r
   } else u->epVictim = EMPTY;\r
 \r
   u->victim = board[u->to];\r
   p[u->victim].pos = ABSENT;\r
   u->booty += p[u->victim].value + PST[p[u->victim].pst + u->to];\r
-//  if(p[u->victim].value == 1000 && p[u->piece].value != 1000) deferred |= PROMOTE; // flag non-Lion x Lion\r
+  if(u->victim != EMPTY) cnt50 = 0; // capture irreversible\r
 \r
   p[u->new].pos = u->to;\r
   board[u->to] = u->new;\r
@@ -1077,6 +1087,7 @@ UnMake(UndoInfo *u)
   p[u->piece].pos = u->from; // this can be the same as above\r
   board[u->from] = u->piece;\r
 \r
+  cnt50 = u->revMoveCount;\r
   hashKeyL = u->savKeyL;\r
   hashKeyH = u->savKeyH;\r
 }\r
@@ -1285,6 +1296,11 @@ if(flag && depth>= 0) printf("phase=%d: first/curr/last = %d / %d / %d\n", phase
            break;\r
          case 7: // bad captures\r
          case 8: // PV null move\r
+           phase = 9;\r
+           if(nullMove != ABSENT) {\r
+             moveStack[msp++] = nullMove + (nullMove << SQLEN) | DEFER; // kludge: setting DEFER guarantees != 0, and has no effect\r
+           }\r
+printf("# %d. sqr = %08x null = %08x\n", msp, nullMove, moveStack[msp-1]);\r
          case 9:\r
            goto cutoff;\r
        }\r
@@ -1304,10 +1320,18 @@ if(flag & depth >= 0) printf("%2d:%d extract %d/%d\n", depth, iterDep, curMove,
        if(move == 0) continue; // skip invalidated move\r
       }\r
 if(flag & depth >= 0) printf("%2d:%d found %d/%d\n", depth, iterDep, curMove, msp);\r
+\r
       // RECURSION\r
       stm ^= WHITE;\r
-      defer = MakeMove(moveStack[curMove], &tb);\r
-path[level++] = moveStack[curMove];\r
+      defer = MakeMove(move, &tb);\r
+\r
+      for(i=2; i<=cnt50; i+=2) if(repStack[level-i+200] == hashKeyH) {\r
+       moveStack[curMove] = 0; // erase forbidden move\r
+       score = -INF; goto repetition;\r
+      }\r
+      repStack[level+200] = hashKeyH;\r
+\r
+path[level++] = move;\r
 attacks += 2*BSIZE;\r
 MapFromScratch(attacks); // for as long as incremental update does not work.\r
 if(PATH) pmap(attacks, stm);\r
@@ -1320,7 +1344,7 @@ if(PATH) pmap(attacks, stm);
          if(promoSuppress & PROMOTE) score = -INF; // non-Lion captures Lion after opponent did same\r
          defer |= PROMOTE;                         // if we started, flag  he cannot do it in reply\r
        }\r
-        if(score == -INF) { moveStack[curMove] = 0; goto abortMove; }\r
+        if(score == -INF) { moveStack[curMove] = 0; goto abortMove; } // zap illegal moves\r
       }\r
 #if 1\r
       score = -Search(-beta, -iterAlpha, -difEval - tb.booty, replyDep, promoSuppress & ~PROMOTE, defer);\r
@@ -1328,14 +1352,14 @@ if(PATH) pmap(attacks, stm);
       score = 0;\r
 #endif\r
     abortMove:\r
-\r
-\r
 attacks -= 2*BSIZE;\r
 level--;\r
+    repetition:\r
       UnMake(&tb);\r
       xstm = stm; stm ^= WHITE;\r
 #if 1\r
 if(PATH) printf("%d:%2d:%d %3d %6x %-10s %6d %6d\n", level, depth, iterDep, curMove, moveStack[curMove], MoveToText(moveStack[curMove], 0), score, bestScore);\r
+\r
       // ALPHA-BETA STUFF\r
       if(score > bestScore) {\r
        bestScore = score; bestMoveNr = curMove;\r
@@ -1367,6 +1391,12 @@ if(PATH) printf("%d:%2d:%d %3d %6x %-10s %6d %6d\n", level, depth, iterDep, curM
     } // next move\r
   cutoff:\r
     if(!level) { // root node\r
+      if(postThinking > 0) {\r
+        int i;   // WB thinking output\r
+       printf("%d %d %d %d", iterDep, bestScore, (GetTickCount() - startTime)/10, nodes);\r
+       for(i=0; pv[i]; i++) printf(" %s", MoveToText(pv[i], 0));\r
+       printf("\n"); fflush(stdout);\r
+      }\r
       if(GetTickCount() - startTime > tlim1) break; // do not start iteration we can (most likely) not finish\r
     }\r
     replyDep = iterDep;\r
@@ -1482,17 +1512,23 @@ int lastLift, lastPut;
 int\r
 MakeMove2 (int stm, MOVE move)\r
 {\r
+  int i;\r
   sup0 = sup1; sup1 = sup2;\r
   sup2 = MakeMove(move, &undoInfo);\r
   rootEval = -rootEval - undoInfo.booty;\r
+  for(i=0; i<200; i++) repStack[i] = repStack[i+1];\r
+  repStack[199] = hashKeyH;\r
+printf("# makemove %08x %c%d %c%d\n", move, sup1%BW+'a', sup1/BW, sup2%BW+'a', sup2/BW);\r
   return stm ^ WHITE;\r
 }\r
 \r
 void\r
 UnMake2 (MOVE move)\r
 {\r
+  int i;\r
   rootEval = -rootEval - undoInfo.booty;\r
   UnMake(&undoInfo);\r
+  for(i=200; i>0; i--) repStack[i] = repStack[i-1];\r
   sup2 = sup1; sup1 = sup0;\r
 }\r
 \r
@@ -1501,7 +1537,7 @@ Setup2 (char *fen)
 {\r
   SetUp(chuArray, chuPieces);\r
   sup0 = sup1 = sup2 = ABSENT;\r
-  rootEval = hashKeyH = hashKeyL = 0;\r
+  rootEval = cnt50 = hashKeyH = hashKeyL = 0;\r
   return WHITE;\r
 }\r
 \r
@@ -1515,6 +1551,7 @@ MoveToText (MOVE move, int multiLine)
 {\r
   static char buf[50];\r
   int f = move>>SQLEN & SQUARE, g = f, t = move & SQUARE;\r
+  if(f == t) { sprintf(buf, "@@@@"); return buf; } // null-move notation in WB protocol\r
   buf[0] = '\0';\r
   if(t >= SPECIAL) { // kludgy! Print as side effect non-standard WB command to remove victims from double-capture (breaks hint command!)\r
     int e = f + epList[t - SPECIAL];\r
@@ -1547,6 +1584,7 @@ MOVE
 ParseMove (char *moveText)\r
 {\r
   int i, j, f, t, t2, e, ret, deferred=0;\r
+  char c = moveText[0];\r
   moveText += ReadSquare(moveText, &f);\r
   moveText += ReadSquare(moveText, &t); t2 = t;\r
   if(*moveText == ',') {\r
@@ -1563,9 +1601,14 @@ ParseMove (char *moveText)
   }\r
   ret = f<<SQLEN | t2;\r
   if(*moveText == '+') ret |= PROMOTE;\r
+printf("# suppress = %c%d\n", sup1%BW+'a', sup1/BW);\r
 MapFromScratch(attacks);\r
+  postThinking--;\r
   Search(-INF-1, INF+1, 0, 1, sup1, sup2);\r
+  postThinking++;\r
   for(i=retFirst; i<retMSP; i++) {\r
+    if(moveStack[i] == INVALID) continue;\r
+    if(c == '@' && (moveStack[i] & SQUARE) == (moveStack[i] >> SQLEN & SQUARE)) break; // any null move matches @@@@\r
     if((moveStack[i] & (PROMOTE | DEFER-1)) == ret) break;\r
     if((moveStack[i] & DEFER-1) == ret) deferred = i; // promoted version of entered non-promotion is legal\r
   }\r
@@ -1595,7 +1638,9 @@ Highlight(char *coords)
   ReadSquare(coords, &sqr);\r
 MapFromScratch(attacks);\r
 flag=1;\r
+  postThinking--;\r
   Search(-INF-1, INF+1, 0, 1, sup1, sup2);\r
+  postThinking++;\r
 flag=0;\r
   for(i=retFirst; i<retMSP; i++) {\r
     if(sqr == (moveStack[i]>>SQLEN & SQUARE)) {\r
@@ -1662,13 +1707,6 @@ PonderUntilInput (int stm)
 {\r
 }\r
 \r
-    // Some global variables that control your engine's behavior\r
-    int ponder;\r
-    int randomize;\r
-    int postThinking;\r
-    int resign;         // engine-defined option\r
-    int contemptFactor; // likewise\r
-\r
     int TakeBack(int n)\r
     { // reset the game and then replay it to the desired point\r
       int last, stm;\r
@@ -1810,6 +1848,7 @@ printf("in: %s\n", command);
         if(!strcmp(command, "ics"))     { continue; }\r
         if(!strcmp(command, "accepted")){ continue; }\r
         if(!strcmp(command, "rejected")){ continue; }\r
+        if(!strcmp(command, "result"))  { continue; }\r
         if(!strcmp(command, "hover"))   {  continue; }\r
         if(!strcmp(command, ""))  {  continue; }\r
         if(!strcmp(command, "usermove")){\r