Add forgotten files 1.4.70b
[polyglot.git] / uci.c
diff --git a/uci.c b/uci.c
index 05d60b3..42b5971 100644 (file)
--- a/uci.c
+++ b/uci.c
-\r
-// uci.c\r
-\r
-// includes\r
-\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-#include "board.h"\r
-#include "engine.h"\r
-#include "gui.h"\r
-#include "move.h"\r
-#include "move_do.h"\r
-#include "move_legal.h"\r
-#include "option.h"\r
-#include "parse.h"\r
-#include "line.h"\r
-#include "uci.h"\r
-\r
-\r
-// constants\r
-\r
-static const bool UseDebug = FALSE;\r
-\r
-#define StringSize ((int)4096)\r
-\r
-// variables\r
-\r
-uci_t Uci[1];\r
-\r
-// Hopefully the following confusion is temporary\r
-// Normally we should check for the engine name but this is a hack anyway\r
-// Some of there where provided by Marc Lacrosse\r
-\r
-const char * thread_options[]={\r
-  "number of threads",        // toga\r
-  "number threads",           // Deep Learning Toga\r
-  "threads",                  // glaurung, zappa, cyclone, grapefruit,\r
-                              // Deep Shredder, Deep Junior, bright\r
-  "core threads",             // HIARCS\r
-  "max cpus",                 // rybka\r
-  "cpus",                     // Deep Sjeng, Fruit2.3.5\r
-  "maxthreads",               // Naum \r
-  NULL\r
-};\r
-\r
-// prototypes\r
-\r
-static bool uci_is_ok      (const uci_t * uci);\r
-\r
-static int  parse_bestmove (uci_t * uci, const char string[]);\r
-static void parse_id       (uci_t * uci, const char string[]);\r
-static int  parse_info     (uci_t * uci, const char string[]);\r
-static void parse_option   (uci_t * uci, const char string[]);\r
-static void parse_score    (uci_t * uci, const char string[]);\r
-\r
-static int  mate_score     (int dist);\r
-\r
-// functions\r
-\r
-\r
-// uci_adapt_UCI3()\r
-\r
-static void apply_UCI3_heuristics(option_t *opt){\r
-  if(option_get_int(Option,"UCIVersion")>2){\r
-    return;\r
-  }\r
-  if(!my_string_equal(opt->type,"string")){\r
-    return;\r
-  }\r
-  if(!strncmp(opt->name,"UCI_",4)){\r
-    return;\r
-  }\r
-  if(my_string_case_contains(opt->name,"file")){\r
-    my_string_set(&opt->type,"file");\r
-    return;\r
-  }\r
-  if(my_string_case_contains(opt->name,"path")){\r
-    my_string_set(&opt->type,"path");\r
-    return;\r
-  }\r
-}\r
-\r
-// uci_set_threads()\r
-\r
-void uci_set_threads(uci_t * uci, int n) {\r
-    const char *thread_option=uci_thread_option(uci);\r
-    ASSERT(n>=1);\r
-    if(thread_option){\r
-        uci_send_option(uci,thread_option,"%d",n);\r
-    }\r
-}\r
-\r
-\r
-const char * uci_thread_option(uci_t * uci){\r
-    const char **p = thread_options;\r
-    const char *thread_option;\r
-    option_t *opt;\r
-    while((thread_option = *(p++))){\r
-        if((opt=option_find(uci->option,thread_option))){\r
-            return opt->name;\r
-            break;\r
-        }\r
-    }\r
-    return NULL;\r
-}\r
-\r
-// uci_is_ok()\r
-\r
-static bool uci_is_ok(const uci_t * uci) {\r
-\r
-   if (uci == NULL) return FALSE;\r
-   if (uci->engine == NULL) return FALSE;\r
-   if (!option_is_ok(uci->option)) return FALSE;\r
-   return TRUE;\r
-}\r
-\r
-// uci_open()\r
-\r
-void uci_open(uci_t * uci, engine_t * engine) {\r
-\r
-   char string[StringSize];\r
-   int event;\r
-\r
-   ASSERT(uci!=NULL);\r
-   ASSERT(engine!=NULL);\r
-\r
-   // init\r
-\r
-   uci->engine = engine;\r
-\r
-   uci->name = NULL;\r
-   my_string_set(&uci->name,"<empty>");\r
-   uci->author = NULL;\r
-   my_string_set(&uci->author,"<empty>");\r
-   option_init(uci->option);\r
-\r
-   uci->ready_nb = 0;\r
-   uci->searching = 0;\r
-   uci->pending_nb = 0;\r
-   uci->multipv_mode = FALSE;\r
-   board_start(uci->board);\r
-   uci_clear(uci);\r
-\r
-   // send "uci" and wait for "uciok"\r
-\r
-   engine_send(uci->engine,"uci");\r
-\r
-   do {\r
-      engine_get(uci->engine,string);\r
-      // Handle the case that the engine is really a WB engine somewhat gracefully.\r
-      if((strstr(string,"Illegal") || strstr(string,"Error"))\r
-         &&strstr(string,"uci")){\r
-          my_fatal("uci_open(): Not a UCI engine.\n");\r
-      }\r
-      event = uci_parse(uci,string);\r
-   } while (!engine_eof(Engine) && (event & EVENT_UCI) == 0);\r
-}\r
-\r
-// uci_close()\r
-\r
-void uci_close(uci_t * uci) {\r
-\r
-   ASSERT(uci_is_ok(uci));\r
-   engine_close(uci->engine);\r
-   uci->engine = NULL;\r
-   my_string_clear(&uci->name);\r
-   my_string_clear(&uci->author);\r
-\r
-   option_clear(uci->option);\r
-}\r
-\r
-// uci_clear()\r
-\r
-void uci_clear(uci_t * uci) {\r
-\r
-   ASSERT(uci_is_ok(uci));\r
-\r
-   ASSERT(!uci->searching);\r
-\r
-   uci->best_move = MoveNone;\r
-   uci->ponder_move = MoveNone;\r
-\r
-   uci->score = 0;\r
-   uci->depth = 0;\r
-   uci->sel_depth = 0;\r
-   line_clear(uci->pv);\r
-\r
-   uci->best_score = 0;\r
-   uci->best_depth = 0;\r
-   uci->best_sel_depth = 0;\r
-   line_clear(uci->best_pv);\r
-// make the default 1 instead of 0 so that info lines can be recognized by their node number 0\r
-   uci->node_nb = 1;\r
-   uci->time = 0.0;\r
-   uci->speed = 0.0;\r
-   uci->cpu = 0.0;\r
-   uci->hash = 0.0;\r
-   line_clear(uci->current_line);\r
-\r
-   uci->root_move = MoveNone;\r
-   uci->root_move_pos = 0;\r
-   uci->root_move_nb = board_mobility(uci->board);\r
-\r
-   uci->multipvSP=0;\r
-}\r
-\r
-// uci_send_isready()\r
-\r
-void uci_send_isready(uci_t * uci) {\r
-\r
-   ASSERT(uci!=NULL);\r
-\r
-   engine_send(uci->engine,"isready");\r
-   uci->ready_nb++;\r
-}\r
-\r
-// uci_send_isready_sync()\r
-\r
-void uci_send_isready_sync(uci_t * uci) {\r
-\r
-   char string[StringSize];\r
-   int event;\r
-\r
-   ASSERT(uci_is_ok(uci));\r
-\r
-   // send "isready" and wait for "readyok"\r
-\r
-   uci_send_isready(uci);\r
-\r
-   do {\r
-      engine_get(uci->engine,string);\r
-      event = uci_parse(uci,string);\r
-   } while (!engine_eof(Engine) && (event & EVENT_READY) == 0);\r
-}\r
-\r
-// uci_send_stop()\r
-\r
-void uci_send_stop(uci_t * uci) {\r
-\r
-   ASSERT(uci_is_ok(uci));\r
-\r
-   ASSERT(uci->searching);\r
-   ASSERT(uci->pending_nb>=1);\r
-\r
-   engine_send(Engine,"stop");\r
-   uci->searching = FALSE;\r
-}\r
-\r
-// uci_send_stop_sync()\r
-\r
-void uci_send_stop_sync(uci_t * uci) {\r
-\r
-   char string[StringSize];\r
-   int event;\r
-\r
-   ASSERT(uci_is_ok(uci));\r
-\r
-   ASSERT(uci->searching);\r
-   ASSERT(uci->pending_nb>=1);\r
-\r
-   // send "stop" and wait for "bestmove"\r
-\r
-   uci_send_stop(uci);\r
-\r
-   do {\r
-      engine_get(uci->engine,string);\r
-      event = uci_parse(uci,string);\r
-   } while (!engine_eof(Engine) && (event & EVENT_STOP) == 0);\r
-}\r
-\r
-// uci_send_ucinewgame()\r
-\r
-void uci_send_ucinewgame(uci_t * uci) {\r
-\r
-   ASSERT(uci!=NULL);\r
-\r
-   if (option_get_int(Option,"UCIVersion") >= 2) {\r
-      engine_send(uci->engine,"ucinewgame");\r
-   }\r
-}\r
-\r
-// uci_send_option()\r
-\r
-bool uci_send_option(uci_t * uci, const char option[], const char format[], ...) {\r
-\r
-   char value[FormatBufferSize];\r
-   option_t * opt;\r
-   bool found=FALSE;\r
-\r
-   ASSERT(uci_is_ok(uci));\r
-   ASSERT(option!=NULL);\r
-   ASSERT(format!=NULL);\r
-\r
-   // format\r
-\r
-   CONSTRUCT_ARG_STRING(format,value);\r
-\r
-   if (UseDebug) my_log("POLYGLOT OPTION %s VALUE %s\n",option,value);\r
-\r
-   opt=option_find(uci->option,option);\r
-   if(opt){\r
-       found=TRUE;\r
-       if(!IS_BUTTON(opt->type)){\r
-           if(!my_string_equal(opt->value,value)){\r
-               engine_send(uci->engine,"setoption name %s value %s",\r
-                           opt->name,value);\r
-               my_string_set(&opt->value,value);\r
-           }else{\r
-               my_log("POLYGLOT Not sending option \"%s\" since it "\r
-                      "already has the correct value.\n",opt->name);\r
-           }\r
-       }else{\r
-           engine_send(uci->engine,"setoption name %s",opt->name);\r
-       }\r
-   }\r
-   return found;\r
-}\r
-\r
-// uci_parse()\r
-\r
-int uci_parse(uci_t * uci, const char string[]) {\r
-\r
-   int event;\r
-   parse_t parse[1];\r
-   char command[StringSize];\r
-   char argument[StringSize];\r
-\r
-   ASSERT(uci_is_ok(uci));\r
-   ASSERT(string!=NULL);\r
-\r
-   // init\r
-\r
-   event = EVENT_NONE;\r
-\r
-   // parse\r
-\r
-   parse_open(parse,string);\r
-\r
-   if (parse_get_word(parse,command,StringSize)) {\r
-       \r
-      parse_get_string(parse,argument,StringSize);\r
-      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" ARGUMENT \"%s\"\n",command,argument);\r
-\r
-      if (FALSE) {\r
-\r
-      } else if (my_string_equal(command,"bestmove")) {\r
-\r
-         // search end\r
-\r
-         ASSERT(uci->pending_nb>0);\r
-\r
-         if (uci->searching && uci->pending_nb == 1) {\r
-\r
-            // current search\r
-\r
-            uci->searching = FALSE;\r
-            uci->pending_nb--;\r
-\r
-            event = parse_bestmove(uci,argument); // updates uci->best_move and uci->ponder_move\r
-\r
-         } else {\r
-\r
-            // obsolete search\r
-\r
-            if (uci->pending_nb > 0) {\r
-               uci->pending_nb--;\r
-               if (uci->pending_nb == 0) event = EVENT_STOP;\r
-            }\r
-         }\r
-\r
-      } else if (my_string_equal(command,"id")) {\r
-\r
-         parse_id(uci,argument);\r
-\r
-      } else if (my_string_equal(command,"info")) {\r
-\r
-         // search information\r
-\r
-              if (uci->searching && uci->pending_nb == 1) { // current search\r
-                  event = parse_info(uci,argument);\r
-               }\r
-\r
-      } else if (my_string_equal(command,"option")) {\r
-\r
-         parse_option(uci,argument);\r
-\r
-      } else if (my_string_equal(command,"readyok")) {\r
-\r
-         // engine is ready\r
-\r
-         ASSERT(uci->ready_nb>0);\r
-\r
-         if (uci->ready_nb > 0) {\r
-            uci->ready_nb--;\r
-            if (uci->ready_nb == 0) event = EVENT_READY;\r
-         }\r
-\r
-      } else if (my_string_equal(command,"uciok")) {\r
-\r
-         event = EVENT_UCI;\r
-\r
-      } else {\r
-\r
-         if (UseDebug) my_log("POLYGLOT unknown command \"%s\"\n",command);\r
-      }\r
-   }\r
-\r
-   parse_close(parse);\r
-\r
-   return event;\r
-}\r
-\r
-// parse_bestmove()\r
-\r
-static int parse_bestmove(uci_t * uci, const char string[]) {\r
-\r
-   parse_t parse[1];\r
-   char command[StringSize];\r
-   char option[StringSize];\r
-   char argument[StringSize];\r
-   board_t board[1];\r
-\r
-   ASSERT(uci_is_ok(uci));\r
-   ASSERT(string!=NULL);\r
-\r
-   // init\r
-\r
-   strcpy(command,"bestmove");\r
-\r
-   parse_open(parse,string);\r
-   parse_add_keyword(parse,"ponder");\r
-\r
-   // bestmove\r
-\r
-   uci->bestmove[0]='\0';\r
-   if (!parse_get_string(parse,argument,StringSize)) {\r
-       strcpy(uci->bestmove,"nomove");\r
-       return EVENT_ILLEGAL_MOVE;\r
-//      my_fatal("parse_bestmove(): missing argument\n");\r
-   }\r
-   strncpy(uci->bestmove,argument,UciStringSize);\r
-   uci->bestmove[UciStringSize-1]='\0';\r
-\r
-   uci->best_move = move_from_can(argument,uci->board);\r
-   if (uci->best_move == MoveNone) {\r
-       return EVENT_ILLEGAL_MOVE;\r
-//       my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);\r
-   }\r
-\r
-   if(!move_is_legal(uci->best_move,uci->board)){\r
-       return EVENT_ILLEGAL_MOVE;\r
-   }\r
-   ASSERT(uci->best_move!=MoveNone);\r
-   ASSERT(move_is_legal(uci->best_move,uci->board));\r
-\r
-   // loop\r
-\r
-   while (parse_get_word(parse,option,StringSize)) {\r
-\r
-      parse_get_string(parse,argument,StringSize);\r
-\r
-      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
-\r
-      if (FALSE) {\r
-\r
-      } else if (my_string_equal(option,"ponder")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         board_copy(board,uci->board);\r
-         move_do(board,uci->best_move);\r
-\r
-         uci->ponder_move = move_from_can(argument,board);\r
-         // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);\r
-\r
-         ASSERT(uci->ponder_move!=MoveNone);\r
-         ASSERT(move_is_legal(uci->ponder_move,board));\r
-\r
-      } else {\r
-\r
-         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
-      }\r
-   }\r
-\r
-   parse_close(parse);\r
-\r
-   return EVENT_MOVE;\r
-}\r
-\r
-// parse_id()\r
-\r
-static void parse_id(uci_t * uci, const char string[]) {\r
-\r
-   parse_t parse[1];\r
-   char command[StringSize];\r
-   char option[StringSize];\r
-   char argument[StringSize];\r
-\r
-   ASSERT(uci!=NULL);\r
-   ASSERT(string!=NULL);\r
-\r
-   // init\r
-\r
-   strcpy(command,"id");\r
-\r
-   parse_open(parse,string);\r
-   parse_add_keyword(parse,"author");\r
-   parse_add_keyword(parse,"name");\r
-\r
-   // loop\r
-\r
-   while (parse_get_word(parse,option,StringSize)) {\r
-\r
-      parse_get_string(parse,argument,StringSize);\r
-      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
-\r
-      if (FALSE) {\r
-      } else if (my_string_equal(option,"author")) {\r
-         ASSERT(!my_string_empty(argument));\r
-         my_string_set(&uci->author,argument);\r
-      } else if (my_string_equal(option,"name")) {\r
-         ASSERT(!my_string_empty(argument));\r
-         my_string_set(&uci->name,argument);\r
-      } else {\r
-         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
-      }\r
-   }\r
-\r
-   parse_close(parse);\r
-\r
-   if (UseDebug) my_log("POLYGLOT engine name \"%s\" author \"%s\"\n",uci->name,uci->author);\r
-}\r
-\r
-// parse_info()\r
-\r
-static int parse_info(uci_t * uci, const char string[]) {\r
-\r
-   int event;\r
-   parse_t parse[1];\r
-   char command[StringSize];\r
-   char option[StringSize];\r
-   char argument[StringSize];\r
-   int n;\r
-   int multipvline=0;\r
-   sint64 ln;\r
-\r
-\r
-   \r
-   ASSERT(uci_is_ok(uci));\r
-   ASSERT(string!=NULL);\r
-\r
-   // init\r
-\r
-   event = EVENT_NONE;\r
-\r
-   strcpy(command,"info");\r
-\r
-   parse_open(parse,string);\r
-   parse_add_keyword(parse,"cpuload");\r
-   parse_add_keyword(parse,"currline");\r
-   parse_add_keyword(parse,"currmove");\r
-   parse_add_keyword(parse,"currmovenumber");\r
-   parse_add_keyword(parse,"depth");\r
-   parse_add_keyword(parse,"hashfull");\r
-   parse_add_keyword(parse,"multipv");\r
-   parse_add_keyword(parse,"nodes");\r
-   parse_add_keyword(parse,"nps");\r
-   parse_add_keyword(parse,"pv");\r
-   parse_add_keyword(parse,"refutation");\r
-   parse_add_keyword(parse,"score");\r
-   parse_add_keyword(parse,"seldepth");\r
-   parse_add_keyword(parse,"string");\r
-   parse_add_keyword(parse,"tbhits");\r
-   parse_add_keyword(parse,"time");\r
-\r
-   // loop\r
-\r
-   while (parse_get_word(parse,option,StringSize)) {\r
-\r
-      parse_get_string(parse,argument,StringSize);\r
-\r
-      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
-\r
-      if (FALSE) {\r
-\r
-      } else if (my_string_equal(option,"cpuload")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         n = atoi(argument);\r
-         ASSERT(n>=0);\r
-\r
-         if (n >= 0) uci->cpu = ((double)n) / 1000.0;\r
-\r
-      } else if (my_string_equal(option,"currline")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         line_from_can(uci->current_line,uci->board,argument,LineSize);\r
-\r
-      } else if (my_string_equal(option,"currmove")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         uci->root_move = move_from_can(argument,uci->board);\r
-         ASSERT(uci->root_move!=MoveNone);\r
-\r
-      } else if (my_string_equal(option,"currmovenumber")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         n = atoi(argument);\r
-         ASSERT(n>=1&&n<=uci->root_move_nb);\r
-\r
-         if (n >= 1 && n <= uci->root_move_nb) {\r
-            uci->root_move_pos = n - 1;\r
-            ASSERT(uci->root_move_pos>=0&&uci->root_move_pos<uci->root_move_nb);\r
-         }\r
-\r
-      } else if (my_string_equal(option,"depth")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         n = atoi(argument);\r
-         ASSERT(n>=1);\r
-\r
-         if (n >= 0) {\r
-            if (n > uci->depth) event |= EVENT_DEPTH;\r
-            uci->depth = n;\r
-         }\r
-\r
-      } else if (my_string_equal(option,"hashfull")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         n = atoi(argument);\r
-         ASSERT(n>=0);\r
-\r
-         if (n >= 0) uci->hash = ((double)n) / 1000.0;\r
-\r
-      } else if (my_string_equal(option,"multipv")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         n = atoi(argument);\r
-        multipvline=n;\r
-        \r
-         ASSERT(n>=1);\r
-\r
-      } else if (my_string_equal(option,"nodes")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         ln = my_atoll(argument);\r
-         ASSERT(ln>=0);\r
-\r
-         if (ln >= 0) uci->node_nb = ln;\r
-\r
-      } else if (my_string_equal(option,"nps")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         n = atoi(argument);\r
-         ASSERT(n>=0);\r
-\r
-         if (n >= 0) uci->speed = ((double)n);\r
-\r
-      } else if (my_string_equal(option,"pv")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         line_from_can(uci->pv,uci->board,argument,LineSize);\r
-         event |= EVENT_PV;\r
-\r
-      } else if (my_string_equal(option,"refutation")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         line_from_can(uci->pv,uci->board,argument,LineSize);\r
-\r
-      } else if (my_string_equal(option,"score")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         parse_score(uci,argument);\r
-\r
-      } else if (my_string_equal(option,"seldepth")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         n = atoi(argument);\r
-         ASSERT(n>=0);\r
-\r
-         if (n >= 0) uci->sel_depth = n;\r
-\r
-      } else  if (my_string_equal(option,"string")) {\r
-                 if(my_string_case_equal(argument,"DrawOffer")){\r
-                         event |= EVENT_DRAW;\r
-          }else if(my_string_case_equal(argument,"Resign")){\r
-                         event |= EVENT_RESIGN;\r
-          }else{\r
-              snprintf(uci->info,sizeof(uci->info),"%s",argument);\r
-              uci->info[sizeof(uci->info)-1]='\0';\r
-              event|=EVENT_INFO;\r
-          }\r
-         // TODO: argument to EOS\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-      } else if (my_string_equal(option,"tbhits")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         ln = my_atoll(argument);\r
-         ASSERT(ln>=0);\r
-\r
-      } else if (my_string_equal(option,"time")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         n = atoi(argument);\r
-         ASSERT(n>=0);\r
-\r
-         if (n >= 0) uci->time = ((double)n) / 1000.0;\r
-\r
-      } else {\r
-\r
-         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
-             // This should probably be protected\r
-             // by a "WorkAround" option.\r
-         snprintf(uci->info,sizeof(uci->info),"%s %s",option,argument);\r
-         uci->info[sizeof(uci->info)-1]='\0';\r
-         event|=EVENT_INFO;\r
-      }\r
-   }\r
-\r
-   parse_close(parse);\r
-\r
-\r
-   // code by HGM\r
-   if ((event & EVENT_PV) != 0) {\r
-      uci->best_score = uci->score; \r
-      uci->best_sel_depth = uci->sel_depth;\r
-      line_copy(uci->best_pv,uci->pv);\r
-   }\r
-   if(uci->depth < uci->best_depth){\r
-     // ignore lines of lower depth\r
-     event &= ~EVENT_PV;\r
-   } else {\r
-     if(uci->depth > uci->best_depth) {\r
-       // clear stack when we start new depth\r
-       uci->multipvSP = 0; \r
-     }\r
-     uci->best_depth = uci->depth;\r
-     if(multipvline >= 1) {\r
-       int i;\r
-       for(i=0; i<uci->multipvSP; i++) {\r
-        if(uci->score == uci->multipvScore[i] && uci->pv[0] == uci->multipvMove[i]) {\r
-          event &= ~EVENT_PV; // ignore duplicates\r
-        }\r
-       }\r
-       if(event & EVENT_PV){\r
-        // line is new, try to add to stack\r
-        if(uci->multipvSP<MultiPVStackSize){\r
-          uci->multipvMove[uci->multipvSP] = uci->pv[0];\r
-          uci->multipvScore[uci->multipvSP] = uci->score;\r
-          uci->multipvSP++;\r
-        }else{\r
-          my_fatal("parse_info(): multipv stack overflow.");\r
-        }\r
-       }\r
-     }\r
-   }\r
-\r
-\r
-   return event;\r
-}\r
-\r
-// parse_option()\r
-\r
-static void parse_option(uci_t * uci, const char string[]) {\r
-\r
-   option_t opt[1];\r
-   parse_t parse[1];\r
-   char command[StringSize];\r
-   char option[StringSize];\r
-   char argument[StringSize];\r
-\r
-   ASSERT(uci!=NULL);\r
-   ASSERT(string!=NULL);\r
-\r
-   // init\r
-\r
-   strcpy(command,"option");\r
-\r
-   memset(opt,0,sizeof(option_t));\r
-   \r
-   my_string_set(&opt->value,"<empty>");\r
-   my_string_set(&opt->name,"<empty>");\r
-   my_string_set(&opt->default_,"<empty>");\r
-   my_string_set(&opt->max,"<empty>");\r
-   my_string_set(&opt->min,"<empty>");\r
-   my_string_set(&opt->type,"<empty>");\r
-   opt->var_nb=0;\r
-   opt->mode=0;\r
-   \r
-   parse_open(parse,string);\r
-   parse_add_keyword(parse,"default");\r
-   parse_add_keyword(parse,"max");\r
-   parse_add_keyword(parse,"min");\r
-   parse_add_keyword(parse,"name");\r
-   parse_add_keyword(parse,"type");\r
-   parse_add_keyword(parse,"var");\r
-\r
-   // loop\r
-\r
-   while (parse_get_word(parse,option,StringSize)) {\r
-      parse_get_string(parse,argument,StringSize);\r
-      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
-\r
-      if (FALSE) {\r
-\r
-      } else if (my_string_equal(option,"default")) {\r
-\r
-         // ASSERT(!my_string_empty(argument)); // HACK for Pepito\r
-\r
-         if (!my_string_empty(argument)) {\r
-            my_string_set(&opt->default_,argument);\r
-            my_string_set(&opt->value,argument);\r
-         }\r
-\r
-      } else if (my_string_equal(option,"max")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-         my_string_set(&opt->max,argument);\r
-\r
-      } else if (my_string_equal(option,"min")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-         my_string_set(&opt->min,argument);\r
-\r
-      } else if (my_string_equal(option,"name")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         if (!my_string_empty(argument)) {\r
-            my_string_set(&opt->name,argument);\r
-         }\r
-\r
-      } else if (my_string_equal(option,"type")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-         my_string_set(&opt->type,argument);\r
-\r
-      } else if (my_string_equal(option,"var")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-         my_string_set(&opt->var[opt->var_nb++],argument);\r
-         if(opt->var_nb==VarNb) break;\r
-\r
-      } else {\r
-\r
-         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
-      }\r
-   }\r
-\r
-   parse_close(parse);\r
-\r
-   apply_UCI3_heuristics(opt);\r
-   option_insert(uci->option,opt);\r
-   option_free(opt);\r
-\r
-   if (UseDebug) my_log("POLYGLOT option name \"%s\" default \"%s\"\n",opt->name,opt->default_);\r
-}\r
-\r
-// parse_score()\r
-\r
-static void parse_score(uci_t * uci, const char string[]) {\r
-\r
-   parse_t parse[1];\r
-   char command[StringSize];\r
-   char option[StringSize];\r
-   char argument[StringSize];\r
-   int n;\r
-\r
-   ASSERT(uci_is_ok(uci));\r
-   ASSERT(string!=NULL);\r
-\r
-   // init\r
-\r
-   strcpy(command,"score");\r
-\r
-   parse_open(parse,string);\r
-   parse_add_keyword(parse,"cp");\r
-   parse_add_keyword(parse,"lowerbound");\r
-   parse_add_keyword(parse,"mate");\r
-   parse_add_keyword(parse,"upperbound");\r
-\r
-   // loop\r
-\r
-   while (parse_get_word(parse,option,StringSize)) {\r
-\r
-      parse_get_string(parse,argument,StringSize);\r
-\r
-      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
-\r
-      if (FALSE) {\r
-\r
-      } else if (my_string_equal(option,"cp")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         n = atoi(argument);\r
-\r
-         uci->score = n;\r
-\r
-      } else if (my_string_equal(option,"lowerbound")) {\r
-\r
-         ASSERT(my_string_empty(argument));\r
-\r
-      } else if (my_string_equal(option,"mate")) {\r
-\r
-         ASSERT(!my_string_empty(argument));\r
-\r
-         n = atoi(argument);\r
-         ASSERT(n!=0);\r
-\r
-         uci->score = mate_score(n);\r
-\r
-      } else if (my_string_equal(option,"upperbound")) {\r
-\r
-         ASSERT(my_string_empty(argument));\r
-\r
-      } else {\r
-\r
-         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
-      }\r
-   }\r
-\r
-   parse_close(parse);\r
-}\r
-\r
-// mate_score()\r
-\r
-static int mate_score(int dist) {\r
-\r
-   ASSERT(dist!=0);\r
-\r
-   if (FALSE) {\r
-   } else if (dist > 0) {\r
-       return +option_get_int(Option,"MateScore") - (+dist) * 2 + 1;\r
-   } else if (dist < 0) {\r
-       return -option_get_int(Option,"MateScore") + (-dist) * 2;\r
-   }\r
-\r
-   return 0;\r
-}\r
-\r
-// end of uci.cpp\r
-\r
+
+// uci.c
+
+// includes
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "board.h"
+#include "engine.h"
+#include "gui.h"
+#include "move.h"
+#include "move_do.h"
+#include "move_legal.h"
+#include "option.h"
+#include "parse.h"
+#include "line.h"
+#include "uci.h"
+
+
+// constants
+
+static const bool UseDebug = FALSE;
+
+// variables
+
+uci_t Uci[1];
+
+// Hopefully the following confusion is temporary
+// Normally we should check for the engine name but this is a hack anyway
+// Some of there where provided by Marc Lacrosse
+
+const char * thread_options[]={
+  "number of threads",        // toga
+  "number threads",           // Deep Learning Toga
+  "threads",                  // glaurung, zappa, cyclone, grapefruit,
+                              // Deep Shredder, Deep Junior, bright
+  "core threads",             // HIARCS
+  "max cpus",                 // rybka
+  "cpus",                     // Deep Sjeng, Fruit2.3.5
+  "maxthreads",               // Naum 
+  NULL
+};
+
+// prototypes
+
+static bool uci_is_ok      (const uci_t * uci);
+
+static int  parse_bestmove (uci_t * uci, const char string[]);
+static void parse_id       (uci_t * uci, const char string[]);
+static int  parse_info     (uci_t * uci, const char string[]);
+static void parse_option   (uci_t * uci, const char string[]);
+static void parse_score    (uci_t * uci, const char string[]);
+
+static int  mate_score     (int dist);
+
+// functions
+
+
+// uci_adapt_UCI3()
+
+static void apply_UCI3_heuristics(option_t *opt){
+  if(option_get_int(Option,"UCIVersion")>2){
+    return;
+  }
+  if(!my_string_equal(opt->type,"string")){
+    return;
+  }
+  if(!strncmp(opt->name,"UCI_",4)){
+    return;
+  }
+  if(my_string_case_contains(opt->name,"file")){
+    my_string_set(&opt->type,"file");
+    return;
+  }
+  if(my_string_case_contains(opt->name,"path")){
+    my_string_set(&opt->type,"path");
+    return;
+  }
+}
+
+// uci_set_threads()
+
+void uci_set_threads(uci_t * uci, int n) {
+    const char *thread_option=uci_thread_option(uci);
+    ASSERT(n>=1);
+    if(thread_option){
+        uci_send_option(uci,thread_option,"%d",n);
+    }
+}
+
+
+const char * uci_thread_option(uci_t * uci){
+    const char **p = thread_options;
+    const char *thread_option;
+    option_t *opt;
+    while((thread_option = *(p++))){
+        if((opt=option_find(uci->option,thread_option))){
+            return opt->name;
+            break;
+        }
+    }
+    return NULL;
+}
+
+// uci_is_ok()
+
+static bool uci_is_ok(const uci_t * uci) {
+
+   if (uci == NULL) return FALSE;
+   if (uci->engine == NULL) return FALSE;
+   if (!option_is_ok(uci->option)) return FALSE;
+   return TRUE;
+}
+
+// uci_open()
+
+void uci_open(uci_t * uci, engine_t * engine) {
+
+   char string[StringSize];
+   int event;
+
+   ASSERT(uci!=NULL);
+   ASSERT(engine!=NULL);
+
+   // init
+
+   uci->engine = engine;
+
+   uci->name = NULL;
+   my_string_set(&uci->name,"<empty>");
+   uci->author = NULL;
+   my_string_set(&uci->author,"<empty>");
+   option_init(uci->option);
+
+   uci->ready_nb = 0;
+   uci->searching = 0;
+   uci->pending_nb = 0;
+   uci->multipv_mode = FALSE;
+   board_start(uci->board);
+   uci_clear(uci);
+
+   // send "uci" and wait for "uciok"
+
+   engine_send(uci->engine,"uci");
+
+   do {
+      engine_get(uci->engine,string);
+      // Handle the case that the engine is really a WB engine somewhat gracefully.
+      if((strstr(string,"Illegal") || strstr(string,"Error"))
+         &&strstr(string,"uci")){
+          my_fatal("uci_open(): Not a UCI engine.\n");
+      }
+      event = uci_parse(uci,string);
+   } while (!engine_eof(Engine) && (event & EVENT_UCI) == 0);
+}
+
+// uci_close()
+
+void uci_close(uci_t * uci) {
+
+   ASSERT(uci_is_ok(uci));
+   engine_close(uci->engine);
+   uci->engine = NULL;
+   my_string_clear(&uci->name);
+   my_string_clear(&uci->author);
+
+   option_clear(uci->option);
+}
+
+// uci_clear()
+
+void uci_clear(uci_t * uci) {
+
+   ASSERT(uci_is_ok(uci));
+
+   ASSERT(!uci->searching);
+
+   uci->best_move = MoveNone;
+   uci->ponder_move = MoveNone;
+
+   uci->score = 0;
+   uci->depth = 0;
+   uci->sel_depth = 0;
+   line_clear(uci->pv);
+
+   uci->best_score = 0;
+   uci->best_depth = 0;
+   uci->best_sel_depth = 0;
+   line_clear(uci->best_pv);
+// make the default 1 instead of 0 so that info lines can be recognized by their node number 0
+   uci->node_nb = 1;
+   uci->time = 0.0;
+   uci->speed = 0.0;
+   uci->cpu = 0.0;
+   uci->hash = 0.0;
+   line_clear(uci->current_line);
+
+   uci->root_move = MoveNone;
+   uci->root_move_pos = 0;
+   uci->root_move_nb = board_mobility(uci->board);
+
+   uci->multipvSP=0;
+}
+
+// uci_send_isready()
+
+void uci_send_isready(uci_t * uci) {
+
+   ASSERT(uci!=NULL);
+
+   engine_send(uci->engine,"isready");
+   uci->ready_nb++;
+}
+
+// uci_send_isready_sync()
+
+void uci_send_isready_sync(uci_t * uci) {
+
+   char string[StringSize];
+   int event;
+
+   ASSERT(uci_is_ok(uci));
+
+   // send "isready" and wait for "readyok"
+
+   uci_send_isready(uci);
+
+   do {
+      engine_get(uci->engine,string);
+      event = uci_parse(uci,string);
+   } while (!engine_eof(Engine) && (event & EVENT_READY) == 0);
+}
+
+// uci_send_stop()
+
+void uci_send_stop(uci_t * uci) {
+
+   ASSERT(uci_is_ok(uci));
+
+   ASSERT(uci->searching);
+   ASSERT(uci->pending_nb>=1);
+
+   engine_send(Engine,"stop");
+   uci->searching = FALSE;
+}
+
+// uci_send_stop_sync()
+
+void uci_send_stop_sync(uci_t * uci) {
+
+   char string[StringSize];
+   int event;
+
+   ASSERT(uci_is_ok(uci));
+
+   ASSERT(uci->searching);
+   ASSERT(uci->pending_nb>=1);
+
+   // send "stop" and wait for "bestmove"
+
+   uci_send_stop(uci);
+
+   do {
+      engine_get(uci->engine,string);
+      event = uci_parse(uci,string);
+   } while (!engine_eof(Engine) && (event & EVENT_STOP) == 0);
+}
+
+// uci_send_ucinewgame()
+
+void uci_send_ucinewgame(uci_t * uci) {
+
+   ASSERT(uci!=NULL);
+
+   if (option_get_int(Option,"UCIVersion") >= 2) {
+      engine_send(uci->engine,"ucinewgame");
+   }
+}
+
+// uci_send_option()
+
+bool uci_send_option(uci_t * uci, const char option[], const char format[], ...) {
+
+   char value[FormatBufferSize];
+   option_t * opt;
+   bool found=FALSE;
+
+   ASSERT(uci_is_ok(uci));
+   ASSERT(option!=NULL);
+   ASSERT(format!=NULL);
+
+   // format
+
+   CONSTRUCT_ARG_STRING(format,value);
+
+   if (UseDebug) my_log("POLYGLOT OPTION %s VALUE %s\n",option,value);
+
+   opt=option_find(uci->option,option);
+   if(opt){
+       found=TRUE;
+       if(!IS_BUTTON(opt->type)){
+           if(!my_string_equal(opt->value,value)){
+               engine_send(uci->engine,"setoption name %s value %s",
+                           opt->name,value);
+               my_string_set(&opt->value,value);
+           }else{
+               my_log("POLYGLOT Not sending option \"%s\" since it "
+                      "already has the correct value.\n",opt->name);
+           }
+       }else{
+           engine_send(uci->engine,"setoption name %s",opt->name);
+       }
+   }
+   return found;
+}
+
+// uci_parse()
+
+int uci_parse(uci_t * uci, const char string[]) {
+
+   int event;
+   parse_t parse[1];
+   char command[StringSize];
+   char argument[StringSize];
+
+   ASSERT(uci_is_ok(uci));
+   ASSERT(string!=NULL);
+
+   // init
+
+   event = EVENT_NONE;
+
+   // parse
+
+   parse_open(parse,string);
+
+   if (parse_get_word(parse,command,StringSize)) {
+       
+      parse_get_string(parse,argument,StringSize);
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" ARGUMENT \"%s\"\n",command,argument);
+
+      if (FALSE) {
+
+      } else if (my_string_equal(command,"bestmove")) {
+
+         // search end
+
+         ASSERT(uci->pending_nb>0);
+
+         if (uci->searching && uci->pending_nb == 1) {
+
+            // current search
+
+            uci->searching = FALSE;
+            uci->pending_nb--;
+
+            event = parse_bestmove(uci,argument); // updates uci->best_move, uci->ponder_move 
+
+         } else {
+
+            // obsolete search
+
+            if (uci->pending_nb > 0) {
+               uci->pending_nb--;
+               if (uci->pending_nb == 0) event = EVENT_STOP;
+            }
+         }
+
+      } else if (my_string_equal(command,"id")) {
+
+         parse_id(uci,argument);
+
+      } else if (my_string_equal(command,"info")) {
+
+         // search information
+
+              if (uci->searching && uci->pending_nb == 1) { // current search
+                  event = parse_info(uci,argument);
+               }
+
+      } else if (my_string_equal(command,"option")) {
+
+         parse_option(uci,argument);
+
+      } else if (my_string_equal(command,"readyok")) {
+
+         // engine is ready
+
+         ASSERT(uci->ready_nb>0);
+
+         if (uci->ready_nb > 0) {
+            uci->ready_nb--;
+            if (uci->ready_nb == 0) event = EVENT_READY;
+         }
+
+      } else if (my_string_equal(command,"uciok")) {
+
+         event = EVENT_UCI;
+
+      } else {
+
+         if (UseDebug) my_log("POLYGLOT unknown command \"%s\"\n",command);
+      }
+   }
+
+   parse_close(parse);
+
+   return event;
+}
+
+// parse_bestmove()
+
+static int parse_bestmove(uci_t * uci, const char string[]) {
+
+   parse_t parse[1];
+   char command[StringSize];
+   char option[StringSize];
+   char argument[StringSize];
+   board_t board[1];
+
+   ASSERT(uci_is_ok(uci));
+   ASSERT(string!=NULL);
+
+   // init
+
+   strcpy(command,"bestmove");
+
+   parse_open(parse,string);
+   parse_add_keyword(parse,"ponder");
+
+   // bestmove
+
+   uci->bestmove[0]='\0';
+   if (!parse_get_string(parse,argument,StringSize)) {
+       strcpy(uci->bestmove,"nomove");
+       return EVENT_ILLEGAL_MOVE;
+//      my_fatal("parse_bestmove(): missing argument\n");
+   }
+   strncpy(uci->bestmove,argument,UciStringSize);
+   uci->bestmove[UciStringSize-1]='\0';
+
+   uci->best_move = move_from_can(argument,uci->board);
+   if (uci->best_move == MoveNone) {
+       return EVENT_ILLEGAL_MOVE;
+//       my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);
+   }
+
+   if(!move_is_legal(uci->best_move,uci->board)){
+       return EVENT_ILLEGAL_MOVE;
+   }
+   ASSERT(uci->best_move!=MoveNone);
+   ASSERT(move_is_legal(uci->best_move,uci->board));
+
+   // loop
+
+   while (parse_get_word(parse,option,StringSize)) {
+
+      parse_get_string(parse,argument,StringSize);
+
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
+
+      if (FALSE) {
+
+      } else if (my_string_equal(option,"ponder")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         board_copy(board,uci->board);
+         move_do(board,uci->best_move);
+
+         uci->ponder_move = move_from_can(argument,board);
+
+         // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);
+
+         ASSERT(uci->ponder_move!=MoveNone);
+         ASSERT(move_is_legal(uci->ponder_move,board));
+
+      } else {
+
+         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
+      }
+   }
+
+   parse_close(parse);
+
+   return EVENT_MOVE;
+}
+
+// parse_id()
+
+static void parse_id(uci_t * uci, const char string[]) {
+
+   parse_t parse[1];
+   char command[StringSize];
+   char option[StringSize];
+   char argument[StringSize];
+
+   ASSERT(uci!=NULL);
+   ASSERT(string!=NULL);
+
+   // init
+
+   strcpy(command,"id");
+
+   parse_open(parse,string);
+   parse_add_keyword(parse,"author");
+   parse_add_keyword(parse,"name");
+
+   // loop
+
+   while (parse_get_word(parse,option,StringSize)) {
+
+      parse_get_string(parse,argument,StringSize);
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
+
+      if (FALSE) {
+      } else if (my_string_equal(option,"author")) {
+         ASSERT(!my_string_empty(argument));
+         my_string_set(&uci->author,argument);
+      } else if (my_string_equal(option,"name")) {
+         ASSERT(!my_string_empty(argument));
+         my_string_set(&uci->name,argument);
+      } else {
+         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
+      }
+   }
+
+   parse_close(parse);
+
+   if (UseDebug) my_log("POLYGLOT engine name \"%s\" author \"%s\"\n",uci->name,uci->author);
+}
+
+// parse_info()
+
+static int parse_info(uci_t * uci, const char string[]) {
+
+   int event;
+   parse_t parse[1];
+   char command[StringSize];
+   char option[StringSize];
+   char argument[StringSize];
+   int n;
+   int multipvline=0;
+   sint64 ln;
+
+
+   
+   ASSERT(uci_is_ok(uci));
+   ASSERT(string!=NULL);
+
+   // init
+
+   event = EVENT_NONE;
+
+   strcpy(command,"info");
+
+   parse_open(parse,string);
+   parse_add_keyword(parse,"cpuload");
+   parse_add_keyword(parse,"currline");
+   parse_add_keyword(parse,"currmove");
+   parse_add_keyword(parse,"currmovenumber");
+   parse_add_keyword(parse,"depth");
+   parse_add_keyword(parse,"hashfull");
+   parse_add_keyword(parse,"multipv");
+   parse_add_keyword(parse,"nodes");
+   parse_add_keyword(parse,"nps");
+   parse_add_keyword(parse,"pv");
+   parse_add_keyword(parse,"refutation");
+   parse_add_keyword(parse,"score");
+   parse_add_keyword(parse,"seldepth");
+   parse_add_keyword(parse,"string");
+   parse_add_keyword(parse,"tbhits");
+   parse_add_keyword(parse,"time");
+
+   // loop
+
+   while (parse_get_word(parse,option,StringSize)) {
+
+      parse_get_string(parse,argument,StringSize);
+
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
+
+      if (FALSE) {
+
+      } else if (my_string_equal(option,"cpuload")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         n = atoi(argument);
+         ASSERT(n>=0);
+
+         if (n >= 0) uci->cpu = ((double)n) / 1000.0;
+
+      } else if (my_string_equal(option,"currline")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         line_from_can(uci->current_line,uci->board,argument,LineSize);
+
+      } else if (my_string_equal(option,"currmove")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         uci->root_move = move_from_can(argument,uci->board);
+         ASSERT(uci->root_move!=MoveNone);
+
+      } else if (my_string_equal(option,"currmovenumber")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         n = atoi(argument);
+         ASSERT(n>=1&&n<=uci->root_move_nb);
+
+         if (n >= 1 && n <= uci->root_move_nb) {
+            uci->root_move_pos = n - 1;
+            ASSERT(uci->root_move_pos>=0&&uci->root_move_pos<uci->root_move_nb);
+         }
+
+      } else if (my_string_equal(option,"depth")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         n = atoi(argument);
+         ASSERT(n>=1);
+
+         if (n >= 0) {
+            if (n > uci->depth) event |= EVENT_DEPTH;
+            uci->depth = n;
+         }
+
+      } else if (my_string_equal(option,"hashfull")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         n = atoi(argument);
+         ASSERT(n>=0);
+
+         if (n >= 0) uci->hash = ((double)n) / 1000.0;
+
+      } else if (my_string_equal(option,"multipv")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         n = atoi(argument);
+        multipvline=n;
+        
+         ASSERT(n>=1);
+
+      } else if (my_string_equal(option,"nodes")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         ln = my_atoll(argument);
+         ASSERT(ln>=0);
+
+         if (ln >= 0) uci->node_nb = ln;
+
+      } else if (my_string_equal(option,"nps")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         n = atoi(argument);
+         ASSERT(n>=0);
+
+         if (n >= 0) uci->speed = ((double)n);
+
+      } else if (my_string_equal(option,"pv")) {
+
+         ASSERT(!my_string_empty(argument));
+         line_from_can(uci->pv,uci->board,argument,LineSize);
+         event |= EVENT_PV;
+
+      } else if (my_string_equal(option,"refutation")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         line_from_can(uci->pv,uci->board,argument,LineSize);
+
+      } else if (my_string_equal(option,"score")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         parse_score(uci,argument);
+
+      } else if (my_string_equal(option,"seldepth")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         n = atoi(argument);
+         ASSERT(n>=0);
+
+         if (n >= 0) uci->sel_depth = n;
+
+      } else  if (my_string_equal(option,"string")) {
+                 if(my_string_case_equal(argument,"DrawOffer")){
+                         event |= EVENT_DRAW;
+          }else if(my_string_case_equal(argument,"Resign")){
+                         event |= EVENT_RESIGN;
+          }else{
+              snprintf(uci->info,sizeof(uci->info),"%s",argument);
+              uci->info[sizeof(uci->info)-1]='\0';
+              event|=EVENT_INFO;
+          }
+         // TODO: argument to EOS
+
+         ASSERT(!my_string_empty(argument));
+
+      } else if (my_string_equal(option,"tbhits")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         ln = my_atoll(argument);
+         ASSERT(ln>=0);
+
+      } else if (my_string_equal(option,"time")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         n = atoi(argument);
+         ASSERT(n>=0);
+
+         if (n >= 0) uci->time = ((double)n) / 1000.0;
+
+      } else {
+
+         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
+             // This should probably be protected
+             // by a "WorkAround" option.
+         snprintf(uci->info,sizeof(uci->info),"%s %s",option,argument);
+         uci->info[sizeof(uci->info)-1]='\0';
+         event|=EVENT_INFO;
+      }
+   }
+
+   parse_close(parse);
+
+
+   // code by HGM
+   if ((event & EVENT_PV) != 0) {
+      uci->best_score = uci->score; 
+      uci->best_sel_depth = uci->sel_depth;
+      line_copy(uci->best_pv,uci->pv);
+   }
+   if(uci->depth < uci->best_depth){
+     // ignore lines of lower depth
+     event &= ~EVENT_PV;
+   } else {
+     if(uci->depth > uci->best_depth) {
+       // clear stack when we start new depth
+       uci->multipvSP = 0; 
+     }
+     uci->best_depth = uci->depth;
+     if(multipvline >= 1) {
+       int i;
+       for(i=0; i<uci->multipvSP; i++) {
+        if(uci->score == uci->multipvScore[i] && uci->pv[0] == uci->multipvMove[i]) {
+          event &= ~EVENT_PV; // ignore duplicates
+        }
+       }
+       if(event & EVENT_PV){
+        // line is new, try to add to stack
+        if(uci->multipvSP<MultiPVStackSize){
+          uci->multipvMove[uci->multipvSP] = uci->pv[0];
+          uci->multipvScore[uci->multipvSP] = uci->score;
+          uci->multipvSP++;
+        }else{
+          my_fatal("parse_info(): multipv stack overflow.");
+        }
+       }
+     }
+   }
+
+
+   return event;
+}
+
+// parse_option()
+
+static void parse_option(uci_t * uci, const char string[]) {
+
+   option_t opt[1];
+   parse_t parse[1];
+   char command[StringSize];
+   char option[StringSize];
+   char argument[StringSize];
+
+   ASSERT(uci!=NULL);
+   ASSERT(string!=NULL);
+
+   // init
+
+   strcpy(command,"option");
+
+   memset(opt,0,sizeof(option_t));
+   
+   my_string_set(&opt->value,"<empty>");
+   my_string_set(&opt->name,"<empty>");
+   my_string_set(&opt->default_,"<empty>");
+   my_string_set(&opt->max,"<empty>");
+   my_string_set(&opt->min,"<empty>");
+   my_string_set(&opt->type,"<empty>");
+   opt->var_nb=0;
+   opt->mode=0;
+   
+   parse_open(parse,string);
+   parse_add_keyword(parse,"default");
+   parse_add_keyword(parse,"max");
+   parse_add_keyword(parse,"min");
+   parse_add_keyword(parse,"name");
+   parse_add_keyword(parse,"type");
+   parse_add_keyword(parse,"var");
+
+   // loop
+
+   while (parse_get_word(parse,option,StringSize)) {
+      parse_get_string(parse,argument,StringSize);
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
+
+      if (FALSE) {
+
+      } else if (my_string_equal(option,"default")) {
+
+         // ASSERT(!my_string_empty(argument)); // HACK for Pepito
+
+         if (!my_string_empty(argument)) {
+            my_string_set(&opt->default_,argument);
+            my_string_set(&opt->value,argument);
+         }
+
+      } else if (my_string_equal(option,"max")) {
+
+         ASSERT(!my_string_empty(argument));
+         my_string_set(&opt->max,argument);
+
+      } else if (my_string_equal(option,"min")) {
+
+         ASSERT(!my_string_empty(argument));
+         my_string_set(&opt->min,argument);
+
+      } else if (my_string_equal(option,"name")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         if (!my_string_empty(argument)) {
+            my_string_set(&opt->name,argument);
+         }
+
+      } else if (my_string_equal(option,"type")) {
+
+         ASSERT(!my_string_empty(argument));
+         my_string_set(&opt->type,argument);
+
+      } else if (my_string_equal(option,"var")) {
+
+         ASSERT(!my_string_empty(argument));
+         my_string_set(&opt->var[opt->var_nb++],argument);
+         if(opt->var_nb==VarNb) break;
+
+      } else {
+
+         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
+      }
+   }
+
+   parse_close(parse);
+
+   apply_UCI3_heuristics(opt);
+   option_insert(uci->option,opt);
+   option_free(opt);
+
+   if (UseDebug) my_log("POLYGLOT option name \"%s\" default \"%s\"\n",opt->name,opt->default_);
+}
+
+// parse_score()
+
+static void parse_score(uci_t * uci, const char string[]) {
+
+   parse_t parse[1];
+   char command[StringSize];
+   char option[StringSize];
+   char argument[StringSize];
+   int n;
+
+   ASSERT(uci_is_ok(uci));
+   ASSERT(string!=NULL);
+
+   // init
+
+   strcpy(command,"score");
+
+   parse_open(parse,string);
+   parse_add_keyword(parse,"cp");
+   parse_add_keyword(parse,"lowerbound");
+   parse_add_keyword(parse,"mate");
+   parse_add_keyword(parse,"upperbound");
+
+   // loop
+
+   while (parse_get_word(parse,option,StringSize)) {
+
+      parse_get_string(parse,argument,StringSize);
+
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);
+
+      if (FALSE) {
+
+      } else if (my_string_equal(option,"cp")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         n = atoi(argument);
+
+         uci->score = n;
+
+      } else if (my_string_equal(option,"lowerbound")) {
+
+         ASSERT(my_string_empty(argument));
+
+      } else if (my_string_equal(option,"mate")) {
+
+         ASSERT(!my_string_empty(argument));
+
+         n = atoi(argument);
+         ASSERT(n!=0);
+
+         uci->score = mate_score(n);
+
+      } else if (my_string_equal(option,"upperbound")) {
+
+         ASSERT(my_string_empty(argument));
+
+      } else {
+
+         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);
+      }
+   }
+
+   parse_close(parse);
+}
+
+// mate_score()
+
+static int mate_score(int dist) {
+
+   ASSERT(dist!=0);
+
+   if (FALSE) {
+   } else if (dist > 0) {
+       return +option_get_int(Option,"MateScore") - (+dist) * 2 + 1;
+   } else if (dist < 0) {
+       return -option_get_int(Option,"MateScore") + (-dist) * 2;
+   }
+
+   return 0;
+}
+
+// end of uci.cpp
+