Set suspected non-standard Chess960 check options
[uci2wb.git] / UCI2WB.c
index 7fd2130..ac6f788 100644 (file)
--- a/UCI2WB.c
+++ b/UCI2WB.c
@@ -1,6 +1,15 @@
-/************************* UCI2WB by H.G.Muller ****************************/\r
-\r
-#define VERSION "1.10"\r
+/****************************************************************************/\r
+/*                           UCI2WB by H.G.Muller                           */\r
+/*                                                                          */\r
+/* UCI2WB is an adapter to run engines that communicate in various dialects */\r
+/* of the Universal Chess Interface in a GUI that supports XBoard protocol  */\r
+/* (CECP). It supports UCI (when used for Xiangqi: the 'Cyclone dialect'),  */\r
+/* as well as USI and UCCI when used with the flags -s or -x, respectively. */\r
+/* This version of UCI2WB is released under the GNU General Public License, */\r
+/* of which you should have received a copy together with this file.        */\r
+/****************************************************************************/\r
+\r
+#define VERSION "2.0"\r
 \r
 #include <stdio.h>\r
 #include <stdlib.h>\r
@@ -32,7 +41,7 @@
 \r
 char move[2000][10], checkOptions[8192], iniPos[256], hashOpt[20], pause, pondering, suspended, ponder, post, hasHash, c, sc='c', *suffix, *variants;\r
 int mps, tc, inc, sTime, depth, myTime, hisTime, stm, computer = NONE, memory, oldMem=0, cores, moveNr, lastDepth, lastScore, startTime, debug;\r
-int statDepth, statScore, statNodes, statTime, currNr, size, collect, nr, sm, inex, on[500];\r
+int statDepth, statScore, statNodes, statTime, currNr, size, collect, nr, sm, inex, on[500], frc;\r
 char currMove[20], moveMap[500][10], /* for analyze mode */ canPonder[20], threadOpt[20];\r
 char board[100];  // XQ board for UCCI\r
 char *nameWord = "name ", *valueWord = "value ", *wTime = "w", *bTime = "b", *wInc = "winc", *bInc = "binc", newGame; // keywords that differ in UCCI\r
@@ -120,7 +129,7 @@ Play(int nr)
        FromFEN(iniPos + 4); // in XQ iniPos always has just "fen " prefix\r
        for(i=0; i<nr; i++) {\r
            int from=Sqr(move[i], 0), to=Sqr(move[i], 2);\r
-           if(board[to]) last = i;\r
+           if(board[to] || (board[from]|32)  == 'p' && move[i][1] != move[i][3]) last = i;\r
            board[to] = board[from]; board[from] = 0;\r
        }\r
        return last;\r
@@ -148,7 +157,7 @@ void
 StopPonder(int pondering)\r
 {\r
        if(!pondering) return;\r
-       pause = 2;\r
+       pause = 1;\r
        fprintf(toE, "stop\n"); fflush(toE); DPRINT("# stop\n"); // note: 'pondering' remains set until engine acknowledges 'stop' with 'bestmove'\r
        Sync(PAUSE); // wait for engine to acknowledge 'stop' with 'bestmove'.\r
 }\r
@@ -236,7 +245,7 @@ Engine2GUI()
        DPRINT("# engine said: %s", line), fflush(stdout);\r
        if(sscanf(line, "%s", command) != 1) continue;\r
        if(!strcmp(command, "bestmove")) {\r
-           if(pause) { pondering = pause = 0; Sync(WAKEUP); continue; } // bestmove was reply to ponder miss or analysis result; ignore.\r
+           if(pause == 1) { pondering = pause = 0; Sync(WAKEUP); continue; } // bestmove was reply to ponder miss or analysis result; ignore.\r
            else if(pondering) { pondering = 0; printf("%d 0 0 0 UCI violation! Engine moves during ponder\n", lastDepth+1); continue; } // ignore ponder search\r
            // move was a move to be played\r
            if(p = strstr(line+8, " draw")) *p = 0, printf("offer draw\n"); // UCCI\r
@@ -258,6 +267,7 @@ Engine2GUI()
            } else move[moveNr][0] = 0;\r
            Move4GUI(line+9);\r
            printf("move %s\n", line+9); // send move to GUI\r
+           if(pause) { pause = 0; Sync(WAKEUP); } // release commands that came in during think\r
            if(lastScore == 100001 && iniPos[0] != 'f') { printf("%s {mate}\n", stm == BLACK ? "1-0" : "0-1"); computer = NONE; }\r
        }\r
        else if(!strcmp(command, "info")) {\r
@@ -297,6 +307,10 @@ Engine2GUI()
            if(p = strstr(line+6, " max "))  sscanf(p+1, "max %d", &max), *p = '\n';\r
            if(p = strstr(line+6, " default "))  sscanf(p+1, "default %[^\n]*", val), *p = '\n';\r
            if(!(p = strstr(line+6, " name "))) p = line+1; sscanf(p+6, "%[^\n]", name); // 'name' is omitted in UCCI\r
+           if(!strcasecmp(name, "UCI_Chess960")) { frc=2; continue; }\r
+           if(frc< 0 && (strstr(name, "960") || strcasestr(name, "frc")) && !strcmp(type, "check")) {\r
+               fprintf(toE, "setoption name %s value true\n", name); strcpy(val, "true"); // set non-standard suspected FRC options\r
+           }\r
            if(!strcasecmp(name, "Threads")) { strcpy(threadOpt, name); continue; }\r
            if(!strcasecmp(name, "Ponder") || !strcasecmp(name, "USI_Ponder")) { strcpy(canPonder, name); continue; }\r
            if(!strcasecmp(name, "Hash") || !strcasecmp(name, "USI_Hash") || !strcasecmp(name, "hashsize")) {\r
@@ -332,6 +346,7 @@ Engine2GUI()
        }\r
        else if(!strcmp(command, "readyok")) { pause = 0; Sync(WAKEUP); } // resume processing of GUI commands\r
        else if(sc == 'x'&& !strcmp(command, "ucciok") || sscanf(command, "u%ciok", &c)==1 && c==sc) {\r
+           if(frc) printf("feature variants=\"normal,fischerandom\" oocastle=%d\n", frc<0); // unannounced FRC uses O-O castling\r
            printf("feature smp=1 memory=%d done=1\n", hasHash);\r
            if(unit == 2) unit = 1, fprintf(toE, "setoption usemillisec true\n");\r
            Sync(WAKEUP); // done with options\r
@@ -378,24 +393,24 @@ GUI2Engine()
                }\r
                fprintf(toE, "\n"); DPRINT("\n");\r
            // code for searchmoves goes here\r
-           } else StartSearch("");\r
+           } else { pause = 2; StartSearch(""); fflush(stdout); fflush(toE); Sync(PAUSE); } // block input during thinking\r
        }\r
       nomove:\r
        fflush(toE); fflush(stdout);\r
        i = 0; while((x = getchar()) != EOF && (line[i] = x) != '\n') i++;\r
-       line[++i] = 0; if(x == EOF) { printf("# EOF\n"); exit(-1); }\r
+       line[++i] = 0; if(x == EOF) { printf("# EOF\n"); fprintf(toE, "quit\n"); exit(-1); }\r
        sscanf(line, "%s", command);\r
        if(!strcmp(command, "new")) {\r
            computer = BLACK; moveNr = 0; depth = -1; move[0][0] = 0;\r
-           stm = WHITE; strcpy(iniPos, "position startpos");\r
-           if(memory != oldMem && hasHash) fprintf(toE, "setoption name %s %s%d\n", hashOpt, valueWord, memory);\r
+           stm = WHITE; strcpy(iniPos, "position startpos"); frc &= ~1;\r
+           if(memory != oldMem && hasHash) fprintf(toE, "setoption %s%s %s%d\n", nameWord, hashOpt, valueWord, memory);\r
            oldMem = memory;\r
            // we can set other options here\r
            if(sc == 'x') { if(newGame) fprintf(toE, "setoption newgame\n"); } else // optional in UCCI\r
-           fprintf(toE, "u%cinewgame\n", sc); fflush(toE);\r
            pause = 1; // wait for option settings to take effect\r
            fprintf(toE, "isready\n"); fflush(toE);\r
            Sync(PAUSE); // wait for readyok\r
+           fprintf(toE, "u%cinewgame\n", sc); fflush(toE);\r
        }\r
        else if(!strcmp(command, "usermove")) {\r
            sscanf(line, "usermove %s", command); // strips off linefeed\r
@@ -405,8 +420,9 @@ GUI2Engine()
            if(pondering || computer == ANALYZE) {\r
                if(pondering && !strcmp(command, move[moveNr])) { // ponder hit\r
                    char *draw = drawOffer ? " draw" : ""; drawOffer = 0;\r
-                   pondering = 0; moveNr++; startTime = GetTickCount(); // clock starts running now\r
-                   fprintf(toE, "ponderhit%s\n", draw); DPRINT("# ponderhit%s\n", draw);\r
+                   pondering = 0; pause = 2; moveNr++; startTime = GetTickCount(); // clock starts running now\r
+                   fprintf(toE, "ponderhit%s\n", draw); DPRINT("# ponderhit%s\n", draw); fflush(toE); fflush(stdout);\r
+                   Sync(PAUSE); // block input during thinking\r
                    goto nomove;\r
                }\r
                StopPonder(1);\r
@@ -430,7 +446,7 @@ GUI2Engine()
        }\r
        else if(!strcmp(command, "protover")) {\r
            if(!variants) variants = sc=='s' ? "shogi,5x5+5_shogi" : VARIANTS;\r
-           printf("feature variants=\"%s\" setboard=1 usermove=1 debug=1 ping=1 reuse=0 exclude=1 pause=1 done=0\n", variants);\r
+           printf("feature variants=\"%s\" setboard=1 usermove=1 debug=1 ping=1 reuse=0 exclude=1 pause=1 sigint=0 sigterm=0 done=0\n", variants);\r
            printf("feature option=\"UCI2WB debug output -check %d\"\n", debug);\r
            fprintf(toE, sc == 'x' ? "ucci\n" : "u%ci\n", sc); fflush(toE); // prompt UCI engine for options\r
            Sync(PAUSE); // wait for uciok\r
@@ -443,6 +459,7 @@ GUI2Engine()
                    else r = strchr(strchr(q+4, ' ') + 1, ' '); // skip to second space (after e.p. square)\r
                    *r = 0; sprintf(command, "%s%s %s %s", line+9, q+1, p, r+1);\r
                 } else strcpy(command, line+9);\r
+               if(frc == -1 && (p = strchr(command, ' '))) strncpy(p+3, "KQkq", 4); // unannounced FRC\r
                sprintf(iniPos, "%s%sfen %s", iniPos[0]=='p' ? "position " : "", sc=='s' ? "s" : "", command);\r
                iniPos[strlen(iniPos)-1] = sm = 0; collect = (computer == ANALYZE);\r
        }\r
@@ -450,6 +467,7 @@ GUI2Engine()
                if(!strcmp(line+8, "shogi\n")) size = 9, strcpy(iniPos, "position startpos");\r
                if(!strcmp(line+8, "5x5+5_shogi\n")) size = 5, strcpy(iniPos, "position startpos");\r
                if(!strcmp(line+8, "xiangqi\n")) strcpy(iniPos, "fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR r");\r
+               if(!strcmp(line+8, "fischerandom\n")) { frc |= 1; if(frc > 0) fprintf(toE, "setoption name UCI_Chess960 value true\n"); }\r
        }\r
        else if(!strcmp(command, "undo") && (i=1) || !strcmp(command, "remove") && (i=2)) {\r
            if(pondering || computer == ANALYZE) StopPonder(1);\r
@@ -486,7 +504,7 @@ GUI2Engine()
        else if(!strcmp(command, "nopost")) post = 0;\r
        else if(!strcmp(command, "easy") && !!*canPonder) ponder = 0, StopPonder(pondering), fprintf(toE, "setoption %s%s %sfalse\n", nameWord, canPonder, valueWord);\r
        else if(!strcmp(command, "hard") && !!*canPonder) ponder = 1, fprintf(toE, "setoption %s%s %strue\n", nameWord, canPonder, valueWord), StartPonder();\r
-       else if(!strcmp(command, "ping"))   { static int done; if(!done) pause = 1, fprintf(toE, "isready\n"), fflush(toE), printf("# send isready\n"), fflush(stdout), Sync(PAUSE); done = 1; printf("pong %s", line+5); }\r
+       else if(!strcmp(command, "ping"))   { /* static int done; if(!done) pause = 1, fprintf(toE, "isready\n"), fflush(toE), printf("# send isready\n"), fflush(stdout), Sync(PAUSE); done = 1;*/ printf("po%s", line+2); }\r
        else if(!strcmp(command, "memory")) sscanf(line, "memory %d", &memory);\r
        else if(!strcmp(command, "cores")&& !!*threadOpt) sscanf(line, "cores %d", &cores), fprintf(toE, "setoption %s%s %s%d\n", nameWord, threadOpt, valueWord, cores);\r
        else if(!strcmp(command, "sd"))     sscanf(line, "sd %d", &depth);\r
@@ -594,6 +612,8 @@ main(int argc, char **argv)
         if(argc > 3) suffix = argv[3];\r
 \r
         if(sc == 'x') nameWord = valueWord = bTime = "", wTime = "opp", bInc = "increment", wInc = "oppincrement", unit = 1000; // switch to UCCI keywords\r
+       else if(sc == 'f' ) frc = -1, sc = 'c';   // UCI for unannounced Chess960\r
+       else if(sc == 'n') sc = 'c'; // UCI for normal Chess\r
 \r
        // spawn engine proc\r
        if(StartEngine(argv[1], dir) != NO_ERROR) { perror(argv[1]), exit(-1); }\r
@@ -604,7 +624,7 @@ main(int argc, char **argv)
 #ifdef WIN32\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Engine2GUI, (LPVOID) NULL, 0, &thread_id);\r
 #else\r
-        { pthread_t t; signal(SIGINT, SIG_IGN); pthread_create(&t, NULL, Engine2GUI, NULL); }\r
+        { pthread_t t; signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); pthread_create(&t, NULL, Engine2GUI, NULL); }\r
 #endif\r
 \r
        // handle GUI->engine traffic in original thread\r