-\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 "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
-// 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
-// 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
- 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
-\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(!my_string_case_equal(opt->type,"button")){\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
- if (!parse_get_string(parse,argument,StringSize)) {\r
- return EVENT_ILLEGAL_MOVE;\r
-// my_fatal("parse_bestmove(): missing argument\n");\r
- }\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
- if(Uci->multipv_mode) 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
- // update display\r
- //lousy uci,filter out lower depth multipv lines that have been repeated from the engine \r
- if(multipvline>1 && uci->depth<uci->best_depth) event &= ~EVENT_PV;\r
- if ((event & EVENT_PV) != 0) {\r
- uci->best_score = uci->score; \r
- uci->best_depth = uci->depth;\r
- if(multipvline==1)uci->depth=-1; //HACK ,clears the engine outpout window,see send_pv in adapter.cpp \r
- uci->best_sel_depth = uci->sel_depth;\r
- line_copy(uci->best_pv,uci->pv);\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
- 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
+