Implement test for perpetual checking
authorH.G. Muller <h.g.muller@hccnet.nl>
Fri, 6 Jan 2012 23:01:36 +0000 (00:01 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Sat, 7 Jan 2012 17:49:01 +0000 (18:49 +0100)
lasker-2.2.3/src/gamedb.c
lasker-2.2.3/src/gamedb.h
lasker-2.2.3/src/gameproc.c

index da255dc..d084f81 100644 (file)
@@ -362,6 +362,10 @@ char *EndString(int g, int personal)
     sprintf(endstr, "%s bared",
            game_globals.garray[g].winner == WHITE ? blackguy : whiteguy);
     break;
+  case END_PERPETUAL:
+    sprintf(endstr, "%s perpetually checking",
+           game_globals.garray[g].winner == WHITE ? blackguy : whiteguy);
+    break;
   case END_RESIGN:
     sprintf(endstr, "%s resigned",
            game_globals.garray[g].winner == WHITE ? blackguy : whiteguy);
@@ -442,6 +446,7 @@ const char *EndSym(int g)
        case END_FLAG:
        case END_ADJWIN:
        case END_BARE:
+       case END_PERPETUAL:
                return ((game_globals.garray[g].winner == WHITE) ? symbols[0] : symbols[1]);
                break;
        case END_AGREEDDRAW:
index d0249b7..3ebd55c 100644 (file)
@@ -69,6 +69,7 @@ GENSTRUCT enum gameend {
        END_ADJWIN,
        END_ADJABORT,
        END_COURTESYADJOURN,
+       END_PERPETUAL,
        END_BARE                // [HGM] bare king
 };
 
index c5f5d35..e7378d2 100644 (file)
@@ -144,6 +144,11 @@ void game_ended(int g, int winner, int why)
     strcpy(EndSymbol, "Bar");
     rate_change = 1;
     break;
+  case END_PERPETUAL:
+    sprintf(tmp, "%s perpetually checking} %s", NameOfLoser, winSymbol);
+    strcpy(EndSymbol, "Per");
+    rate_change = 1;
+    break;
   case END_RESIGN:
     sprintf(tmp, "%s resigns} %s", NameOfLoser, winSymbol);
     strcpy(EndSymbol, "Res");
@@ -882,6 +887,26 @@ static int Check50MoveRule (int p, int g)
   return 0;
 }
 
+static int perp_check(struct game g, int first, int third)
+{
+  struct game_state_t gs = g.game_state; // current position, both first and last of loop
+  int half_move, no_perp = 0;
+printf("perp %d %d\n",first,third);
+  for(half_move=first+1; half_move<third; half_move++) {
+    gs.onMove = CToggle(gs.onMove);
+    if(!in_check(&gs)) no_perp |= (half_move&1) + 1; // 1 = white not in check, 2 = black not in check
+    gs.onMove = CToggle(gs.onMove);
+printf("move%d, p=%d\n",half_move,no_perp);
+    if(no_perp == 3) break;
+    execute_move(&gs, &g.moveList[half_move], 0);
+  }
+  if(no_perp == (third&1) + 1) return END_NOTENDED;  // stm was checking, other not: defer judgement
+  if(no_perp == 2 - (third&1)) return END_PERPETUAL; // stm was not checking, other was: stm wins
+  if(no_perp == 0) return END_REPETITION; // mutual perpertual check, draw
+  // here we should check for chasing
+  return END_REPETITION;
+}
+
 static char *GetFENpos (int g, int half_move)
 {
   if (half_move < 0)
@@ -893,30 +918,46 @@ static int CheckRepetition (int p, int g)
 {
   struct player *pp = &player_globals.parray[p];
   struct pending* pend;
-  int move_num;
+  int move_num, s1, s2, result = END_REPETITION;
   int flag1 = 1, flag2 = 1;
-  char *pos1 = GetFENpos (g, game_globals.garray[g].numHalfMoves - 1);
-  char *pos2 = GetFENpos (g, game_globals.garray[g].numHalfMoves);
+  int numPly = game_globals.garray[g].numHalfMoves;
+  char *pos1 = GetFENpos (g, numPly - 1); // current position
+  char *pos2 = "";
   char *pos;
 
-  if (game_globals.garray[g].numHalfMoves < 8)  /* can't have three repeats any quicker. */
+  if (numPly < 8)  /* can't have three repeats any quicker. */
     return 0;
 
-  for (move_num = game_globals.garray[g].game_state.lastIrreversable - 1; // [HGM] FEN stored in moveList[numHalfMoves-1] !
-       move_num < game_globals.garray[g].numHalfMoves - 1; move_num++) {
+  if((game_globals.garray[g].white == p) != (numPly&1)) { // claimer has the move
+    pos2 = pos1;
+    pos1 = GetFENpos (g, numPly - 2); // also check position before opponent's move (which could have pre-empted him)
+  } // pos1 is now always a position where the opponent has the move
+
+  for (move_num = numPly - 2; // [HGM] FEN stored in moveList[numHalfMoves-1] !
+       move_num >= game_globals.garray[g].game_state.lastIrreversable - 1; move_num--) {
     pos = GetFENpos (g, move_num);
     if (strlen(pos1) == strlen(pos) && !strcmp(pos1, pos))
-      flag1++;
+      flag1++ == 2 && (s1 = move_num);
     if (strlen(pos2) == strlen(pos) && !strcmp(pos2, pos))
-      flag2++;
-printf("%2d. %d-%d %s %s %s\n", move_num, flag1, flag2, pos1,pos2,pos);
+      flag2++ == 2 && (s2 = move_num); // remember start of last two loops
+printf("%2d. %d-%d '%s' '%s' '%s'\n", move_num, flag1, flag2, pos1,pos2,pos);
   }
   if (flag1 >= 3 || flag2 >= 3) {
     if ((pend = find_pend(pp->opponent, p, PEND_DRAW)) != NULL) {
       delete_pending(pend);
       decline_withdraw_offers(p, -1, -1,DO_DECLINE);
     }
-    game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, END_REPETITION);
+    if(game_globals.garray[g].game_state.palace) { // [HGM] in Xiangqi we have to test for perpetuals to determine the outcome
+      if(flag2 >= 3) result = perp_check(game_globals.garray[g], s2, numPly);
+      else  result = perp_check(game_globals.garray[g], s1, numPly - (pos2[0] != 0));
+      if(result == END_NOTENDED) {
+       pprintf(p, "Perpetuals can be claimed only during the turn of the winner\n");
+       return 1;
+      }
+      game_ended(g, (numPly&1) ? BLACK : WHITE, result); // stm wins
+      return 1;
+    }
+    game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, result);
     return 1;
   }
   else return 0;