\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 "line.h"\r
#include "uci.h"\r
\r
+\r
// constants\r
\r
static const bool UseDebug = FALSE;\r
\r
-static const int StringSize = 4096;\r
+#define StringSize ((int)4096)\r
\r
// variables\r
\r
"number of threads", // toga\r
"number threads", // Deep Learning Toga\r
"threads", // glaurung, zappa, cyclone, grapefruit,\r
- // Deep Shredder, Deep Junior\r
+ // Deep Shredder, Deep Junior, bright\r
"core threads", // HIARCS\r
"max cpus", // rybka\r
"cpus", // Deep Sjeng, Fruit2.3.5\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_options_copy = thread_options;\r
- const char *thread_option;\r
+ const char *thread_option=uci_thread_option(uci);\r
ASSERT(n>=1);\r
- while((thread_option = *(thread_options_copy++))){\r
- uci_send_option(uci,thread_option,"%d",n); // checks also for existence\r
+ if(thread_option){\r
+ uci_send_option(uci,thread_option,"%d",n);\r
}\r
}\r
\r
-// uci_thread_option_exists()\r
-\r
-bool uci_thread_option_exist(uci_t * uci) {\r
- const char **thread_options_copy = thread_options;\r
- const char *thread_option;\r
- while((thread_option = *(thread_options_copy++))){\r
- if(uci_option_exist(uci,thread_option)) return TRUE;\r
- }\r
- return FALSE;\r
-}\r
\r
const char * uci_thread_option(uci_t * uci){\r
- const char **thread_options_copy = thread_options;\r
+ const char **p = thread_options;\r
const char *thread_option;\r
- int i;\r
- while((thread_option = *(thread_options_copy++))){\r
- i=uci_get_option(uci,thread_option);\r
- if(i>=0){\r
- return Uci->option[i].name;\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
\r
if (uci == NULL) return FALSE;\r
if (uci->engine == NULL) return FALSE;\r
- if (uci->option_nb < 0 || uci->option_nb >= OptionNb) return FALSE;\r
-\r
+ if (!option_is_ok(uci->option)) return FALSE;\r
return TRUE;\r
}\r
\r
my_string_set(&uci->name,"<empty>");\r
uci->author = NULL;\r
my_string_set(&uci->author,"<empty>");\r
- uci->option_nb = 0;\r
+ option_init(uci->option);\r
\r
uci->ready_nb = 0;\r
uci->searching = 0;\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 an UCI engine.\n");\r
+ }\r
event = uci_parse(uci,string);\r
} while (!engine_eof(Engine) && (event & EVENT_UCI) == 0);\r
}\r
\r
void uci_close(uci_t * uci) {\r
\r
- int i;\r
- option_t * opt;\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
- for (i = 0; i < uci->option_nb; i++) {\r
- opt = &uci->option[i];\r
- my_string_clear(&opt->name);\r
- my_string_clear(&opt->default_);\r
- }\r
-\r
- uci->option_nb = 0;\r
+ option_clear(uci->option);\r
}\r
\r
// uci_clear()\r
uci->best_depth = 0;\r
uci->best_sel_depth = 0;\r
line_clear(uci->best_pv);\r
-\r
- uci->node_nb = 0;\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->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
ASSERT(uci!=NULL);\r
\r
- if (option_get_int("UCIVersion") >= 2) {\r
+ if (option_get_int(Option,"UCIVersion") >= 2) {\r
engine_send(uci->engine,"ucinewgame");\r
}\r
}\r
\r
-// uci_option_exist()\r
-\r
-bool uci_option_exist(uci_t * uci, const char option[]) {\r
-\r
- int i;\r
- option_t * opt;\r
-\r
- ASSERT(uci_is_ok(uci));\r
- ASSERT(option!=NULL);\r
-\r
- // scan options\r
-\r
- for (i = 0; i < uci->option_nb; i++) {\r
- opt = &uci->option[i];\r
- if (my_string_case_equal(opt->name,option)) return TRUE;\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
// uci_send_option()\r
\r
-void uci_send_option(uci_t * uci, const char option[], const char format[], ...) {\r
+bool uci_send_option(uci_t * uci, const char option[], const char format[], ...) {\r
\r
- va_list arg_list;\r
- char value[StringSize];\r
- int i;\r
+ char value[FormatBufferSize];\r
option_t * opt;\r
+ bool found=FALSE;\r
\r
ASSERT(uci_is_ok(uci));\r
ASSERT(option!=NULL);\r
\r
// format\r
\r
- va_start(arg_list,format);\r
- vsprintf(value,format,arg_list);\r
- va_end(arg_list);\r
+ CONSTRUCT_ARG_STRING(format,value);\r
\r
if (UseDebug) my_log("POLYGLOT OPTION %s VALUE %s\n",option,value);\r
\r
- // scan options\r
-\r
- for (i = 0; i < uci->option_nb; i++) {\r
-\r
- opt = &uci->option[i];\r
-\r
- if (my_string_case_equal(opt->name,option) && !my_string_equal(opt->default_,value)) {\r
- engine_send(uci->engine,"setoption name %s value %s",opt->name,value);\r
- my_string_set(&opt->default_,value);\r
- break;\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
parse_open(parse,string);\r
\r
if (parse_get_word(parse,command,StringSize)) {\r
-\r
+ \r
parse_get_string(parse,argument,StringSize);\r
if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" ARGUMENT \"%s\"\n",command,argument);\r
\r
\r
// search information\r
\r
- if (uci->searching && uci->pending_nb == 1) { // current search\r
- event = parse_info(uci,argument);\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
// bestmove\r
\r
if (!parse_get_string(parse,argument,StringSize)) {\r
- my_fatal("parse_bestmove(): missing argument\n");\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) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);\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
int multipvline=0;\r
sint64 ln;\r
\r
+\r
+ \r
ASSERT(uci_is_ok(uci));\r
ASSERT(string!=NULL);\r
\r
ASSERT(!my_string_empty(argument));\r
\r
n = atoi(argument);\r
- if(Uci->multipv_mode) multipvline=n;\r
+ multipvline=n;\r
\r
ASSERT(n>=1);\r
\r
\r
if (n >= 0) uci->sel_depth = n;\r
\r
- } else if (my_string_equal(option,"string")) {\r
- if(!strncmp(argument,"DrawOffer",9))\r
+ } else if (my_string_equal(option,"string")) {\r
+ if(my_string_case_equal(argument,"DrawOffer")){\r
event |= EVENT_DRAW;\r
- if(!strncmp(argument,"Resign",6))\r
+ }else if(my_string_case_equal(argument,"Resign")){\r
event |= EVENT_RESIGN;\r
-\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
} 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
+\r
+ // code by HGM\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
-int uci_get_option(uci_t * uci, const char * name){\r
- int i;\r
- for(i=0;i<Uci->option_nb;i++){\r
- if(my_string_case_equal(Uci->option[i].name,name)){\r
- return i;\r
- }\r
- }\r
- return -1;\r
-}\r
-\r
-\r
-\r
-// uci_set_option()\r
-\r
-void uci_set_option(uci_t * uci,\r
- const char * name,\r
- const char * default_,\r
- const char * type,\r
- const char * max,\r
- const char * min,\r
- int var_nb,\r
- const char * var[]){\r
- int i,j;\r
- for(i=0;i<Uci->option_nb;i++){\r
- if(my_string_equal(Uci->option[i].name,name)){\r
- break;\r
- }\r
- }\r
- if(i<OptionNb){\r
- my_string_set(&(Uci->option[i].name),name);\r
- my_string_set(&(Uci->option[i].default_),default_);\r
- my_string_set(&(Uci->option[i].type),type);\r
- my_string_set(&(Uci->option[i].min),min);\r
- my_string_set(&(Uci->option[i].max),max);\r
- Uci->option[i].var_nb=var_nb;\r
- for(j=0;j<var_nb;j++){\r
- my_string_set(&(Uci->option[i].var[j]),var[j]);\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(i==Uci->option_nb){\r
- Uci->option_nb++;\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;\r
+ option_t opt[1];\r
parse_t parse[1];\r
char command[StringSize];\r
char option[StringSize];\r
\r
strcpy(command,"option");\r
\r
- if (uci->option_nb >= OptionNb) return;\r
-\r
- opt = &uci->option[uci->option_nb];\r
- uci->option_nb++;\r
-\r
- opt->value=NULL;\r
+ memset(opt,0,sizeof(option_t));\r
+ \r
my_string_set(&opt->value,"<empty>");\r
- opt->mode=0;\r
-\r
- opt->name = NULL;\r
my_string_set(&opt->name,"<empty>");\r
-\r
- \r
- opt->default_ = NULL;\r
my_string_set(&opt->default_,"<empty>");\r
-\r
- opt->max = NULL;\r
my_string_set(&opt->max,"<empty>");\r
-\r
- opt->min = NULL;\r
my_string_set(&opt->min,"<empty>");\r
-\r
- opt->type = NULL;\r
my_string_set(&opt->type,"<empty>");\r
-\r
opt->var_nb=0;\r
+ opt->mode=0;\r
\r
parse_open(parse,string);\r
parse_add_keyword(parse,"default");\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
\r
if (FALSE) {\r
} else if (dist > 0) {\r
- return +option_get_int("MateScore") - (+dist) * 2 + 1;\r
+ return +option_get_int(Option,"MateScore") - (+dist) * 2 + 1;\r
} else if (dist < 0) {\r
- return -option_get_int("MateScore") + (-dist) * 2;\r
+ return -option_get_int(Option,"MateScore") + (-dist) * 2;\r
}\r
\r
return 0;\r