From: H.G. Muller Date: Thu, 9 Jun 2011 07:47:40 +0000 (+0200) Subject: version 1.4w10UCIb20 X-Git-Url: http://winboard.nl/cgi-bin?p=polyglot.git;a=commitdiff_plain;h=5cd5185613348b13625e257efcd7b2f11ca85276 version 1.4w10UCIb20 --- diff --git a/ChangeLog b/ChangeLog index ca28e59..9b3b5ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +=========1.4w10UCIb20=========== +- More refactoring. +- No more polling for GUI input =========1.4w10UCIb18=========== - Two new utilities: info-book and dump-book. =========1.4w10UCIb17=========== @@ -5,7 +8,7 @@ - The main loop (previously in adapter.cpp) is now in its own file mainloop.cpp. - adapter.cpp has been renamed into xboard2uci.cpp. It is #ifdef _WIN32 free. - EOF from the engine no longer kills PG. It should now -be possible to close an engine and reopen another one (if that ever were useful) +be possible to close an engine and reopen another one (if that ever became useful) =========1.4w10UCIb16=========== - xboard options commands - correction of handling of combo boxes in UCI protocol diff --git a/README b/README index 6322277..58c4006 100644 --- a/README +++ b/README @@ -230,9 +230,9 @@ OPTIONS Unconditionally stop the seach after this amount of time. -depth-delta (default: 3) - Stop the search if the best move has been constant for this many - depths, on condition that the mininal depth and minimal time have - been reached. + Stop the search if the solution as been found and the best move has + been constant for this many depths, on condition that the mininal + depth and minimal time have been reached. -min-depth (default: 8) Minimal search depth when the search is stopped using @@ -266,7 +266,7 @@ CONFIG FILE FORMAT option = value ... - Lines starting with "#" are ignored. + The characters "#" and ";" serve as comment characters. NOTE: There can be spaces in option names or values. Do not use quotes. Boolean values are written as "true" or "false". @@ -461,10 +461,19 @@ EXAMPLES polyglot make-book -pgn games.pgn -bin book.bin -max-ply 30 - Merge books "in1.bin" and "in2.bin" into a book "out.bin". + Merge books "w1.bin" and "w2.bin" into a book "w.bin". polyglot merge-book -in1 w1.bin -in2 w2.bin -out w.bin + Inspect lines for white in "w.bin" + + polyglot dump-book -bin w.bin -color white -out w_white.txt + + Test epd file "test.epd" with a (maximum) search time of 7 minutes per + position + + polyglot epd-test -epd test.epd -max-time 420 + The command line for using the UCI engine "fruit" in a GUI which uses the xboard protocol. @@ -494,4 +503,4 @@ SEE ALSO - 2009-01-15 POLYGLOT(6) + 2009-01-16 POLYGLOT(6) diff --git a/book_make.cpp b/book_make.cpp index ba02f51..1b8fe6c 100644 --- a/book_make.cpp +++ b/book_make.cpp @@ -35,16 +35,22 @@ struct entry_t { uint64 key; uint16 move; uint16 count; - union{ // unfortunately minggw32 seems to have a bug with anon unions. - struct { +// Unfortunately the minggw32 cross compiler [4.2.1-sjlj (mingw32-2)] +// seems to have a bug with anon structs contained in unions when using -O2. +// See the ASSERT below in "read_entry_file"... +// To be fair this seems to be illegal in C++ +// although it is hard to understand why, and the compiler does not complain +// even with -Wall. +// union { +// struct { uint16 n; uint16 sum; - }; - struct{ +// }; +// struct { uint8 height; int line; - }; - }; +// }; + // }; uint8 colour; }; diff --git a/config.h b/config.h index f9a4be7..9c350da 100644 --- a/config.h +++ b/config.h @@ -115,13 +115,13 @@ #define PACKAGE_NAME "polyglot" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "polyglot 1.4w10UCIb18" +#define PACKAGE_STRING "polyglot 1.4w10UCIb20" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "polyglot" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.4w10UCIb18" +#define PACKAGE_VERSION "1.4w10UCIb20" /* Define to 1 if the C compiler supports function prototypes. */ #define PROTOTYPES 1 @@ -150,7 +150,7 @@ #define TIME_WITH_SYS_TIME 1 /* Version number of package */ -#define VERSION "1.4w10UCIb18" +#define VERSION "1.4w10UCIb20" /* Define like PROTOTYPES; this can be used by system headers. */ #define __PROTOTYPES 1 diff --git a/configure b/configure index 1dfe736..e1418c0 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for polyglot 1.4w10UCIb18. +# Generated by GNU Autoconf 2.61 for polyglot 1.4w10UCIb20. # # Report bugs to . # @@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='polyglot' PACKAGE_TARNAME='polyglot' -PACKAGE_VERSION='1.4w10UCIb18' -PACKAGE_STRING='polyglot 1.4w10UCIb18' +PACKAGE_VERSION='1.4w10UCIb20' +PACKAGE_STRING='polyglot 1.4w10UCIb20' PACKAGE_BUGREPORT='michel.vandenbergh@uhasselt.be' ac_unique_file="mainloop.cpp" @@ -1216,7 +1216,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures polyglot 1.4w10UCIb18 to adapt to many kinds of systems. +\`configure' configures polyglot 1.4w10UCIb20 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1282,7 +1282,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of polyglot 1.4w10UCIb18:";; + short | recursive ) echo "Configuration of polyglot 1.4w10UCIb20:";; esac cat <<\_ACEOF @@ -1368,7 +1368,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -polyglot configure 1.4w10UCIb18 +polyglot configure 1.4w10UCIb20 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1382,7 +1382,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by polyglot $as_me 1.4w10UCIb18, which was +It was created by polyglot $as_me 1.4w10UCIb20, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -2072,7 +2072,7 @@ fi # Define the identity of the package. PACKAGE='polyglot' - VERSION='1.4w10UCIb18' + VERSION='1.4w10UCIb20' cat >>confdefs.h <<_ACEOF @@ -7344,7 +7344,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by polyglot $as_me 1.4w10UCIb18, which was +This file was extended by polyglot $as_me 1.4w10UCIb20, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -7397,7 +7397,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -polyglot config.status 1.4w10UCIb18 +polyglot config.status 1.4w10UCIb20 configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.ac b/configure.ac index 987344d..998aef2 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([polyglot], [1.4w10UCIb18], [michel.vandenbergh@uhasselt.be]) +AC_INIT([polyglot], [1.4w10UCIb20], [michel.vandenbergh@uhasselt.be]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([mainloop.cpp]) AC_CONFIG_HEADER([config.h]) diff --git a/engine.cpp b/engine.cpp index b674272..f5c53c6 100644 --- a/engine.cpp +++ b/engine.cpp @@ -200,6 +200,18 @@ void engine_close(engine_t * engine) { } +// engine_get_non_blocking() + +bool engine_get_non_blocking(engine_t * engine, char string[], int size){ + if(io_line_ready(engine->io)){ + engine_get(engine,string,StringSize); + return true; + }else{ + string[0]='\0'; + return false; + } +} + // engine_get() void engine_get(engine_t * engine, char string[], int size) { @@ -330,48 +342,49 @@ IDLE_PRIORITY_CLASS 0x00000040 void set_affinity(engine_t *engine, int affin){ if(affin==-1) return; - SetProcessAffinityMask((engine->pipeEngine).hProcess,affin); + SetProcessAffinityMask((engine->io).hProcess,affin); } // Eric Mullins! void engine_set_nice_value(engine_t *engine, int value){ - SetPriorityClass((engine->pipeEngine).hProcess, + SetPriorityClass((engine->io).hProcess, GetWin32Priority(value)); } void engine_send_queue(engine_t * engine,const char *szFormat, ...) { - nQueuePtr += vsprintf(szQueueString + nQueuePtr, szFormat, (va_list) (&szFormat + 1)); + nQueuePtr += vsprintf(szQueueString + nQueuePtr, szFormat, (va_list) (&szFormat + 1)); } void engine_send(engine_t * engine, const char *szFormat, ...) { vsprintf(szQueueString + nQueuePtr, szFormat, (va_list) (&szFormat + 1)); - (engine->pipeEngine).LineOutput(szQueueString); + (engine->io).LineOutput(szQueueString); my_log("Adapter->Engine: %s\n",szQueueString); nQueuePtr = 0; } void engine_close(engine_t * engine){ char string[StringSize]; - (engine->pipeEngine).Close(); + (engine->io).Close(); // TODO: Timeout - while (!engine_eof(Engine)) { - engine_get(Engine,string,StringSize); - } - (engine->pipeEngine).Kill(); + while (!engine_eof(Engine)) { + engine_get_non_blocking(Engine,string,StringSize); + Idle(); + } + (engine->io).Kill(); } void engine_open(engine_t * engine){ - int affinity; + int affinity; char *my_dir; engine->state=0; if( (my_dir = _getcwd( NULL, 0 )) == NULL ) my_fatal("Can't build path: %s\n",strerror(errno)); SetCurrentDirectory(option_get_string("EngineDir")); - (engine->pipeEngine).Open(option_get_string("EngineCommand")); - if((engine->pipeEngine).Active()){ + (engine->io).Open(option_get_string("EngineCommand")); + if((engine->io).Active()){ engine->state|=ENGINE_ACTIVE; //play with affinity (bad idea) affinity=option_get_int("Affinity"); @@ -397,13 +410,12 @@ bool engine_eof(engine_t *engine){ bool engine_get_non_blocking(engine_t * engine, char *szLineStr, int size){ if(engine_eof(engine)){ return false;} - if ((engine->pipeEngine).LineInput(szLineStr)) { + if ((engine->io).GetBuffer(szLineStr)) { my_log("Engine->Adapter: %s\n",szLineStr); return true; } else { szLineStr[0]='\0'; - if(engine->pipeEngine.EOF_()){ - my_log("POLYGLOT EOF received from engine\n"); + if(engine->io.EOF_()){ engine->state|=ENGINE_EOF; } return false; @@ -411,15 +423,9 @@ bool engine_get_non_blocking(engine_t * engine, char *szLineStr, int size){ } void engine_get(engine_t * engine, char *szLineStr, int size){ - bool data_available; - if(engine_eof(engine))return; - while(true){ - data_available=engine_get_non_blocking(engine,szLineStr,size); - if(!data_available && !engine_eof(engine)){ - Idle(); - }else{ - break; - } + (engine->io).LineInput(szLineStr); + if(engine->io.EOF_()){ + engine->state|=ENGINE_EOF; } } diff --git a/engine.h b/engine.h index ee703e9..b3a950c 100644 --- a/engine.h +++ b/engine.h @@ -18,10 +18,10 @@ struct engine_t { #ifndef _WIN32 - io_t io[1]; + io_t io[1]; pid_t pid; #else - PipeStruct pipeEngine; + PipeStruct io; #endif uint32 state; }; diff --git a/epd.cpp b/epd.cpp index 70537da..75a229c 100644 --- a/epd.cpp +++ b/epd.cpp @@ -55,6 +55,8 @@ static double LastTime; static uint64 LastNodeNb; static move_t LastPV[LineSize]; +static my_timer_t Timer[1]; + // prototypes static void epd_test_file (const char file_name[]); @@ -211,6 +213,8 @@ static void epd_test_file(const char file_name[]) { // search + my_timer_start(Timer); // also resets + // which ones of the next two alternatives is best? engine_send(Engine,"go movetime %.0f depth %d",MaxTime*1000.0,MaxDepth); //engine_send(Engine,"go infinite"); @@ -243,25 +247,21 @@ static void epd_test_file(const char file_name[]) { while (!engine_eof(Engine) && engine_step()) { bool stop=false; - // stop search? + // stop search? +// printf("Uci->time=%.2f time=%.2f\n",Uci->time,my_timer_elapsed_real(Timer)); if (Uci->depth > MaxDepth){ my_log("POLYGLOT Maximum depth %d reached\n",MaxDepth); stop=true; - }else if(Uci->time >= MaxTime){ + }else if(my_timer_elapsed_real(Timer) >= MaxTime){ my_log("POLYGLOT Maximum search time %.2fs reached\n",MaxTime); stop=true; }else if(Uci->depth - FirstDepth >= DepthDelta){ - my_log("POLYGLOT DepthDelta (=%d) reached\n",DepthDelta); if(Uci->depth > MinDepth){ - my_log("POLYGLOT Minimum depth %d reached\n",MinDepth); if(Uci->time >= MinTime){ - my_log("POLYGLOT Minimum search time %.2fs reached\n",MinTime); if(is_solution(FirstMove,board,bm,am)){ - my_log("POLYGLOT Solution is correct\n"); + my_log("POLYGLOT Solution found\n",MaxTime); stop=true; - }else{ - my_log("POLYGLOT Solution is not correct\n"); } } } @@ -288,7 +288,7 @@ static void epd_test_file(const char file_name[]) { printf("%2d: %-15s %s %4d",tot,id,correct?"OK":"--",hit); if (!line_to_san(LastPV,Uci->board,pv_string,StringSize)) ASSERT(false); - printf(" [at: depth=%2d time=%6.2f nodes="S64_FORMAT"] score=%+6.2f pv=%s\n",FirstDepth,FirstTime,FirstNodeNb,double(LastScore)/100.0,pv_string); + printf(" score=%+6.2f pv [D=%2d, T=%7.2fs, N=%6dk] =%s\n",double(LastScore)/100.0,FirstDepth,FirstTime,(int)FirstNodeNb/1000,pv_string); } printf("\nscore=%d/%d",hit,tot); diff --git a/gui.cpp b/gui.cpp index 354d276..dac260f 100644 --- a/gui.cpp +++ b/gui.cpp @@ -40,7 +40,7 @@ void gui_init(gui_t *gui){ #endif #ifdef _WIN32 - (gui->pipeStdin).Open(); + (gui->io).Open(); #else gui->io->in_fd = STDIN_FILENO; @@ -54,28 +54,27 @@ void gui_init(gui_t *gui){ // gui_get_non_blocking() -// this is only non_blocking on windows! - bool gui_get_non_blocking(gui_t * gui, char string[], int size) { ASSERT(gui!=NULL); ASSERT(string!=NULL); ASSERT(size>=256); #ifndef _WIN32 - if (!io_get_line(gui->io,string,size)) { // EOF - my_log("POLYGLOT *** EOF from GUI ***\n"); - quit(); + if(io_line_ready(gui->io)){ + gui_get(GUI,string,StringSize); + return true; + }else{ + string[0]='\0'; + return false; } - return true; #else - if ((gui->pipeStdin).LineInput(string)) { + if ((gui->io).GetBuffer(string)) { my_log("GUI->Adapter: %s\n", string); return true; } else { string[0]='\0'; return false; } - #endif } @@ -83,14 +82,15 @@ bool gui_get_non_blocking(gui_t * gui, char string[], int size) { void gui_get(gui_t * gui, char string[], int size) { bool data_available; - while(true){ - data_available=gui_get_non_blocking(gui, string, size); - if(!data_available){ - Idle(); - }else{ - break; - } +#ifdef _WIN32 + (gui->io).LineInput(string); + my_log("GUI->Adapter: %s\n", string); +#else + if (!io_get_line(gui->io,string,size)) { // EOF + my_log("POLYGLOT *** EOF from GUI ***\n"); + quit(); } +#endif } @@ -115,8 +115,7 @@ void gui_send(gui_t * gui, const char format[], ...) { #ifndef _WIN32 io_send(gui->io,"%s",string); #else - printf("%s\n",string); - fflush(stdout); + gui->io.LineOutput(string); my_log("Adapter->GUI: %s\n",string); #endif } diff --git a/gui.h b/gui.h index b984603..6aebbb9 100644 --- a/gui.h +++ b/gui.h @@ -10,9 +10,9 @@ struct gui_t { #ifndef _WIN32 - io_t io[1]; + io_t io[1]; #else - PipeStruct pipeStdin; + PipeStruct io; #endif }; diff --git a/main.cpp b/main.cpp index 83f1019..a4835c9 100644 --- a/main.cpp +++ b/main.cpp @@ -35,7 +35,7 @@ // constants -static const char * const Version = "1.4W10UCIb18"; +static const char * const Version = "1.4W10UCIb20"; static const char * const HelpMessage = "\ SYNTAX\n\ * polyglot [configfile]\n\ @@ -44,7 +44,7 @@ SYNTAX\n\ * polyglot merge-book -in1 inputfile1 -in2 inputfile2 [-out outputfile]\n\ * polyglot info-book [-bin inputfile] [-exact]\n\ * polyglot dumb-book [-bin inputfile] -color color [-out outputfile]\n\ -* polyglot [configfile] epd-test [-epd inputfile] [-min-depth depth] [-max-depth depth] [-max-time time] [-depth-delta delta]\n\ +* polyglot [configfile] epd-test [-epd inputfile] [-min-depth depth] [-max-depth depth] [-min-time time] [-max-time time] [-depth-delta delta]\n\ * polyglot perft [-fen fen] [-max-depth depth]\ "; @@ -253,7 +253,7 @@ static void parse_option() { my_log("POLYGLOT INI file \"%s\"\n",file_name); engine_open(Engine); if(!engine_active(Engine)){ - my_fatal("Could not start \"%s\"",option_get("EngineCommand")); + my_fatal("Could not start \"%s\"\n",option_get("EngineCommand")); } if (option_get_bool("UCI")) { @@ -343,9 +343,11 @@ void quit() { stop_search(); engine_send(Engine,"quit"); + my_log("POLYGLOT Closing engine\n"); engine_close(Engine); } + my_log("POLYGLOT Calling exit\n"); exit(EXIT_SUCCESS); } diff --git a/mainloop.cpp b/mainloop.cpp index 0d5a8f0..ffef0c9 100644 --- a/mainloop.cpp +++ b/mainloop.cpp @@ -26,16 +26,18 @@ static const int StringSize = 4096; // prototypes -static void mainloop_step (); -static void mainloop_init(); +static void mainloop_init (); +static void mainloop_wait_for_event (); static void mainloop_engine_step(char * string); static void mainloop_gui_step(char * string); +// functions + // mainloop_init() static void mainloop_init(){ if(!option_get_bool("UCI")){ - xboard_init(); + xboard2uci_init(); // the default } } @@ -43,9 +45,9 @@ static void mainloop_init(){ static void mainloop_engine_step(char * string){ if(option_get_bool("UCI")){ - uci_engine_step(string); + uci2uci_engine_step(string); }else{ - engine_step(string); + xboard2uci_engine_step(string); } } @@ -53,59 +55,65 @@ static void mainloop_engine_step(char * string){ static void mainloop_gui_step(char * string){ if(option_get_bool("UCI")){ - uci_gui_step(string); + uci2uci_gui_step(string); + }else if(my_string_equal(string,"uci")){ // mode auto detection + my_log("POLYGLOT *** Switching to UCI mode ***\n"); + option_set("UCI","true"); + uci2uci_gui_step(string); }else{ - xboard_step(string); - } + xboard2uci_gui_step(string); + } } - - // mainloop() void mainloop() { + char string[StringSize]; mainloop_init(); - while (!engine_eof(Engine)) mainloop_step(); - my_log("POLYGLOT *** EOF file received from engine ***"); + while (!engine_eof(Engine)) { + // process buffered lines + while(TRUE){ + if(gui_get_non_blocking(GUI,string,StringSize)){ + mainloop_gui_step(string); + }else if(!engine_eof(Engine) && + engine_get_non_blocking(Engine,string,StringSize) ){ + mainloop_engine_step(string); + }else{ + break; + } + } + mainloop_wait_for_event(); + } + my_log("POLYGLOT *** EOF file received from engine ***\n"); } -// adapter_step() + + +// mainloop_wait_for_event() + +static void mainloop_wait_for_event(){ #ifdef _WIN32 -static void mainloop_step(){ // polling! - bool xin,ein; + HANDLE hHandles[2]; char string[StringSize]; - xin=gui_get_non_blocking(GUI,string,StringSize); - if(xin) mainloop_gui_step(string); - ein=engine_get_non_blocking(Engine,string,StringSize); - if(ein) mainloop_engine_step(string); - if(xin==false && ein==false) Idle();//nobody wants me,lets have a beauty nap -} + hHandles[0]=(GUI->io).hEvent; + hHandles[1]=(Engine->io).hEvent; + WaitForMultipleObjects(2, // count + hHandles, // + FALSE, // return if one object is signaled + INFINITE // no timeout + ); #else -static void mainloop_step() { - fd_set set[1]; int fd_max; int val; char string[StringSize]; - - // process buffered lines - - while (io_line_ready(GUI->io)){ - gui_get(GUI,string,StringSize); - mainloop_gui_step(string); - } - while (!engine_eof(Engine) && io_line_ready(Engine->io)){ - engine_get(Engine,string,StringSize); - mainloop_engine_step(string); - } - // init FD_ZERO(set); fd_max = -1; // HACK - // add xboard input + // add gui input ASSERT(GUI->io->in_fd>=0); @@ -128,7 +136,9 @@ static void mainloop_step() { if (val > 0) { if (FD_ISSET(GUI->io->in_fd,set)) io_get_update(GUI->io); // read some xboard input if (FD_ISSET(Engine->io->in_fd,set)) io_get_update(Engine->io); // read some engine input - } -} + } #endif +} + + diff --git a/pipe.cpp b/pipe.cpp index f12a787..163e591 100644 --- a/pipe.cpp +++ b/pipe.cpp @@ -2,135 +2,240 @@ #include "pipe.h" #include "util.h" +// functions + +DWORD WINAPI ThreadProc(LPVOID lpParam){ + PipeStruct *p=(PipeStruct *) lpParam; + while(!p->EOF_()){ + p->ReadInput(); + } + return 0; +} + + + void PipeStruct::Open(const char *szProcFile) { - DWORD dwMode; - HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite; - SECURITY_ATTRIBUTES sa; - STARTUPINFO si; - PROCESS_INFORMATION pi; - state=0; - if (szProcFile == NULL) { - hInput = GetStdHandle(STD_INPUT_HANDLE); - hOutput = GetStdHandle(STD_OUTPUT_HANDLE); - bConsole = GetConsoleMode(hInput, &dwMode); - state|=PIPE_ACTIVE; - - } else { - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0); - CreatePipe(&hStdoutRead, &hStdoutWrite, &sa, 0); - si.cb = sizeof(STARTUPINFO); - si.lpReserved = si.lpDesktop = si.lpTitle = NULL; - si.dwFlags = STARTF_USESTDHANDLES; - si.cbReserved2 = 0; - si.lpReserved2 = NULL; - si.hStdInput = hStdinRead; - si.hStdOutput = hStdoutWrite; - si.hStdError = hStdoutWrite; - if(CreateProcess(NULL, (LPSTR) szProcFile, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)){ - state|=PIPE_ACTIVE; - hProcess=pi.hProcess; - CloseHandle(pi.hThread); - CloseHandle(hStdinRead); - CloseHandle(hStdoutWrite); - hInput = hStdoutRead; - hOutput = hStdinWrite; - bConsole = FALSE; + DWORD dwMode; + HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite; + SECURITY_ATTRIBUTES sa; + STARTUPINFO si; + PROCESS_INFORMATION pi; + state=0; + if (szProcFile == NULL) { + hInput = GetStdHandle(STD_INPUT_HANDLE); + hOutput = GetStdHandle(STD_OUTPUT_HANDLE); + bConsole = GetConsoleMode(hInput, &dwMode); + bPipe=FALSE; + } else { + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0); + CreatePipe(&hStdoutRead, &hStdoutWrite, &sa, 0); + si.cb = sizeof(STARTUPINFO); + si.lpReserved = si.lpDesktop = si.lpTitle = NULL; + si.dwFlags = STARTF_USESTDHANDLES; + si.cbReserved2 = 0; + si.lpReserved2 = NULL; + si.hStdInput = hStdinRead; + si.hStdOutput = hStdoutWrite; + si.hStdError = hStdoutWrite; + if(CreateProcess(NULL, + (LPSTR) szProcFile, + NULL, + NULL, + TRUE, + DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP, + NULL, + NULL, + &si, + &pi)){ + hProcess=pi.hProcess; + CloseHandle(pi.hThread); + CloseHandle(hStdinRead); + CloseHandle(hStdoutWrite); + hInput = hStdoutRead; + hOutput = hStdinWrite; + bConsole = FALSE; + bPipe=TRUE; + }else{ + my_fatal("PipeStruct::Open(): %s",my_error()); + } } - } - if (bConsole) { - SetConsoleMode(hInput, dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT)); - FlushConsoleInputBuffer(hInput); - } else { - nBytesLeft = 0; - } - nReadEnd = 0; + if (bConsole) { + SetConsoleMode(hInput, + dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT)); + FlushConsoleInputBuffer(hInput); + } + nReadEnd = 0; + InitializeCriticalSection(&CriticalSection); + hEvent=CreateEvent(NULL, // default security + FALSE, // auto reset + FALSE, // not signaled + NULL // nameless + ); + hThread=CreateThread(NULL, // default security + 0, // default stacksize + ThreadProc, // worker function + this, // tell worker about ourselves + 0, // run immediately + NULL // nameless + ); + + set_Active(); } + void PipeStruct::Close(void) const { - CloseHandle(hOutput); + CloseHandle(hOutput); } void PipeStruct::Kill(void) const { - CloseHandle(hInput); - CloseHandle(hOutput); - DWORD lpexit; - - if(GetExitCodeProcess(hProcess,&lpexit)){ - if(lpexit==STILL_ACTIVE) - //must be java,hammer it down! - TerminateProcess(hProcess,lpexit); - } + CloseHandle(hInput); + CloseHandle(hOutput); + DWORD lpexit; + + if(GetExitCodeProcess(hProcess,&lpexit)){ + if(lpexit==STILL_ACTIVE) + //must be java,hammer it down! + TerminateProcess(hProcess,lpexit); + } CloseHandle(hProcess); } bool PipeStruct::EOF_(void){ // EOF is defined - return state&PIPE_EOF; + int ret; + EnterCriticalSection(&CriticalSection); + ret=state&PIPE_EOF; + LeaveCriticalSection(&CriticalSection); + return ret; +} + +void PipeStruct::set_EOF_(void){ + EnterCriticalSection(&CriticalSection); + state|=PIPE_EOF; + LeaveCriticalSection(&CriticalSection); } bool PipeStruct::Active(void){ - return state&PIPE_ACTIVE; + int ret; + EnterCriticalSection(&CriticalSection); + ret=state&PIPE_ACTIVE; + LeaveCriticalSection(&CriticalSection); + return ret; } -void PipeStruct::ReadInput(void) { - DWORD dwBytes; - if(ReadFile(hInput, szBuffer + nReadEnd, LINE_INPUT_MAX_CHAR - nReadEnd, &dwBytes, NULL)){ - nReadEnd += dwBytes; - if (nBytesLeft > 0) { - nBytesLeft -= dwBytes; - } - }else{ - state|=PIPE_EOF; // if we are here there should be data! - } +void PipeStruct::set_Active(void){ + EnterCriticalSection(&CriticalSection); + state|=PIPE_ACTIVE; + LeaveCriticalSection(&CriticalSection); } -bool PipeStruct::CheckInput(void) { - DWORD dwEvents, dwBytes; - if (bConsole) { // a tty, or an un-redirected handle - GetNumberOfConsoleInputEvents(hInput, &dwEvents); - if (dwEvents > 1) { - return TRUE; - } else { - return FALSE; + + +int PipeStruct::ReadLine(void){ + DWORD dwBytes; + int ret; + int start=0; + int start1; + + if(!bPipe){ + fgets(lpReadBuffer,LINE_INPUT_MAX_CHAR,stdin); + start=strlen(lpReadBuffer); + if(!start){ + set_EOF_(); + lpReadBuffer[0]='\0'; + } + return start; + }else{ + while(TRUE){ + // Unfortunately we need to use polling here. + // Otherwise Windows returns single bytes if + // the engine runs at low priority. + // This kills performance. + while(TRUE){ + ret=PeekNamedPipe(hInput, + NULL, // don't read anything yet + 0, // no buffer + NULL, // no we don't read anything! + &dwBytes,// now we're talking + NULL); // nono we don't read anything + if(!ret){ + set_EOF_(); + lpReadBuffer[0]='\0'; + return 0; + } + if(dwBytes>0){ + break; + }else{ + Idle(); + } + + } + ret=ReadFile(hInput, + lpReadBuffer+start, + LINE_INPUT_MAX_CHAR-start, + &dwBytes, + NULL); + if(!ret){ + set_EOF_(); + lpReadBuffer[0]='\0'; + return 0; + }else{ + start1=start; + start+=dwBytes; + if (memchr(lpReadBuffer+start1, '\n', dwBytes)){ + lpReadBuffer[start]='\0'; + return start; + } + } + } } - } else { // a handle redirected to a pipe or a file - if (nBytesLeft > 0) { - return TRUE; - } else { - if (PeekNamedPipe(hInput, NULL, 0, NULL, &dwBytes, NULL)) { - nBytesLeft = dwBytes; - return nBytesLeft > 0; // a pipe - } else { - return TRUE; // a file, always TRUE +} + +void PipeStruct::ReadInput(void) { + DWORD dwBytes; + int ret; + ret=ReadLine(); + EnterCriticalSection(&CriticalSection); + if(!EOF_()){ + if(ret+nReadEnd>=LINE_INPUT_MAX_CHAR){ + my_fatal("PipeStruct::ReadInput(): buffer overflow\n"); } - } + memcpy(lpBuffer+nReadEnd,lpReadBuffer,ret); + nReadEnd += ret; } + LeaveCriticalSection(&CriticalSection); + SetEvent(hEvent); } void PipeStruct::LineOutput(const char *szLineStr) const { DWORD dwBytes; int nStrLen; char szWriteBuffer[LINE_INPUT_MAX_CHAR]; - nStrLen = strlen(szLineStr); - memcpy(szWriteBuffer, szLineStr, nStrLen); - szWriteBuffer[nStrLen] = '\r'; - szWriteBuffer[nStrLen + 1] = '\n'; - WriteFile(hOutput, szWriteBuffer, nStrLen + 2, &dwBytes, NULL); + if(bPipe){ + nStrLen = strlen(szLineStr); + memcpy(szWriteBuffer, szLineStr, nStrLen); + szWriteBuffer[nStrLen] = '\r'; + szWriteBuffer[nStrLen + 1] = '\n'; + WriteFile(hOutput, szWriteBuffer, nStrLen + 2, &dwBytes, NULL); + }else{ + printf("%s\n",szLineStr); + fflush(stdout); + } } - - bool PipeStruct::GetBuffer(char *szLineStr) { char *lpFeedEnd; int nFeedEnd; - lpFeedEnd = (char *) memchr(szBuffer, '\n', nReadEnd); + int ret; + EnterCriticalSection(&CriticalSection); + lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd); if (lpFeedEnd == NULL) { - return FALSE; + ret=FALSE; } else { - nFeedEnd = lpFeedEnd - szBuffer; - memcpy(szLineStr, szBuffer, nFeedEnd); + nFeedEnd = lpFeedEnd - lpBuffer; + memcpy(szLineStr, lpBuffer, nFeedEnd); if (szLineStr[nFeedEnd - 1] == '\r') { szLineStr[nFeedEnd - 1] = '\0'; } else { @@ -138,32 +243,20 @@ bool PipeStruct::GetBuffer(char *szLineStr) { } nFeedEnd ++; nReadEnd -= nFeedEnd; - memcpy(szBuffer, szBuffer + nFeedEnd, nReadEnd); - return TRUE; + memcpy(lpBuffer, lpBuffer + nFeedEnd, nReadEnd); + ret=TRUE; } + LeaveCriticalSection(&CriticalSection); + return ret; } -bool PipeStruct::LineInput(char *szLineStr) { - if (GetBuffer(szLineStr)) { - return TRUE; - } - if (CheckInput()) { - ReadInput(); - if (GetBuffer(szLineStr)) { - return TRUE; - } else { - if (nReadEnd == LINE_INPUT_MAX_CHAR) { - memcpy(szLineStr, szBuffer, LINE_INPUT_MAX_CHAR - 1); - szLineStr[LINE_INPUT_MAX_CHAR - 1] = '\0'; - szBuffer[0] = szBuffer[LINE_INPUT_MAX_CHAR - 1]; - nReadEnd = 1; - return TRUE; - } else { - return FALSE; - } +void PipeStruct::LineInput(char *szLineStr) { + while(!EOF_()){ + if (GetBuffer(szLineStr)) { + break; + }else{ + WaitForSingleObject(hEvent,INFINITE); + } } - } else { - return FALSE; - } } #endif diff --git a/pipe.h b/pipe.h index ced06d7..eecfb1c 100644 --- a/pipe.h +++ b/pipe.h @@ -7,7 +7,7 @@ // constants -const int LINE_INPUT_MAX_CHAR = 4096; +const int LINE_INPUT_MAX_CHAR = 10*4096; // defines @@ -20,23 +20,35 @@ struct PipeStruct { HANDLE hInput, hOutput; HANDLE hProcess; - DWORD state; + HANDLE hThread; + HANDLE hEvent; BOOL bConsole; - int nBytesLeft; - int nReadEnd; - char szBuffer[LINE_INPUT_MAX_CHAR]; + BOOL bPipe; + + CRITICAL_SECTION CriticalSection; + + volatile DWORD state; + volatile int nReadEnd; + char lpBuffer[LINE_INPUT_MAX_CHAR]; + char lpReadBuffer[LINE_INPUT_MAX_CHAR]; void Open(const char *szExecFile = NULL); void Close(void) const; void Kill(void) const; bool EOF_(void); + void set_EOF_(void); bool Active(void); + void set_Active(void); void ReadInput(void); + int ReadLine(void); bool CheckInput(void); bool GetBuffer(char *szLineStr); - bool LineInput(char *szLineStr); + void LineInput(char *szLineStr); void LineOutput(const char *szLineStr) const; -}; // pipe + +}; + +// pipe #endif #endif diff --git a/polyglot.man b/polyglot.man index e0dcef7..4dda26b 100644 --- a/polyglot.man +++ b/polyglot.man @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "POLYGLOT 6" -.TH POLYGLOT 6 "2009-01-15" "" "" +.TH POLYGLOT 6 "2009-01-16" "" "" .SH "NAME" PolyGlot \- Winboard protocol to UCI protocol adapter \- book engine for Polyglot books @@ -349,8 +349,9 @@ been reached. Unconditionally stop the seach after this amount of time. .IP "\fB\-depth\-delta\fR (default: 3)" 4 .IX Item "-depth-delta (default: 3)" -Stop the search if the best move has been constant for this many depths, -on condition that the mininal depth and minimal time have been reached. +Stop the search if the solution as been found and the best move has +been constant for this many depths, on condition that the mininal +depth and minimal time have been reached. .IP "\fB\-min\-depth\fR (default: 8)" 4 .IX Item "-min-depth (default: 8)" Minimal search depth when the search is stopped using \*(L"\-depth\-delta\*(R". @@ -384,7 +385,7 @@ The config file is in the traditional \s-1INI\s0 format. \& ... .Ve .PP -Lines starting with \*(L"#\*(R" are ignored. +The characters \*(L"#\*(R" and \*(L";\*(R" serve as comment characters. .PP \&\s-1NOTE:\s0 There can be spaces in option names or values. Do not use quotes. Boolean values are written as \*(L"true\*(R" or \*(L"false\*(R". @@ -579,12 +580,24 @@ most 30 plies. \& polyglot make\-book \-pgn games.pgn \-bin book.bin \-max\-ply 30 .Ve .PP -Merge books \*(L"in1.bin\*(R" and \*(L"in2.bin\*(R" into a book \*(L"out.bin\*(R". +Merge books \*(L"w1.bin\*(R" and \*(L"w2.bin\*(R" into a book \*(L"w.bin\*(R". .PP .Vb 1 \& polyglot merge\-book \-in1 w1.bin \-in2 w2.bin \-out w.bin .Ve .PP +Inspect lines for white in \*(L"w.bin\*(R" +.PP +.Vb 1 +\& polyglot dump\-book \-bin w.bin \-color white \-out w_white.txt +.Ve +.PP +Test epd file \*(L"test.epd\*(R" with a (maximum) search time of 7 minutes per position +.PP +.Vb 1 +\& polyglot epd\-test \-epd test.epd \-max\-time 420 +.Ve +.PP The command line for using the \s-1UCI\s0 engine \*(L"fruit\*(R" in a \s-1GUI\s0 which uses the xboard protocol. .PP diff --git a/polyglot.pod b/polyglot.pod index 0024cd1..71fd17c 100644 --- a/polyglot.pod +++ b/polyglot.pod @@ -265,8 +265,9 @@ Unconditionally stop the seach after this amount of time. =item B<-depth-delta> (default: 3) -Stop the search if the best move has been constant for this many depths, -on condition that the mininal depth and minimal time have been reached. +Stop the search if the solution as been found and the best move has +been constant for this many depths, on condition that the mininal +depth and minimal time have been reached. =item B<-min-depth> (default: 8) @@ -311,7 +312,7 @@ The config file is in the traditional INI format. option = value ... -Lines starting with "#" are ignored. +The characters "#" and ";" serve as comment characters. NOTE: There can be spaces in option names or values. Do not use quotes. Boolean values are written as "true" or "false". @@ -545,10 +546,18 @@ most 30 plies. polyglot make-book -pgn games.pgn -bin book.bin -max-ply 30 -Merge books "in1.bin" and "in2.bin" into a book "out.bin". +Merge books "w1.bin" and "w2.bin" into a book "w.bin". polyglot merge-book -in1 w1.bin -in2 w2.bin -out w.bin +Inspect lines for white in "w.bin" + + polyglot dump-book -bin w.bin -color white -out w_white.txt + +Test epd file "test.epd" with a (maximum) search time of 7 minutes per position + + polyglot epd-test -epd test.epd -max-time 420 + The command line for using the UCI engine "fruit" in a GUI which uses the xboard protocol. diff --git a/polyglot.spec b/polyglot.spec index 959b69d..ae0d193 100644 --- a/polyglot.spec +++ b/polyglot.spec @@ -1,6 +1,6 @@ Summary: A Winboard protocol to UCI protocol adapter Name: polyglot -Version: 1.4w10UCIb18 +Version: 1.4w10UCIb20 Release: 1 License: GPL Group: Amusement/Games diff --git a/search.cpp b/search.cpp index b231882..8b1ae60 100644 --- a/search.cpp +++ b/search.cpp @@ -133,7 +133,7 @@ void search(const board_t * board, int depth_max, double time_max) { // do_perft() void do_perft(int argc,char * argv[]){ - const char * fen=StartFen; + const char * fen=NULL; int depth=1; board_t board[1]; int i; @@ -144,7 +144,7 @@ void do_perft(int argc,char * argv[]){ } else if (my_string_equal(argv[i],"-fen")) { i++; if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n"); - fen=strdup(argv[i]); + my_string_set(&fen,argv[i]); } else if (my_string_equal(argv[i],"-max-depth")){ i++; if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n"); @@ -154,6 +154,9 @@ void do_perft(int argc,char * argv[]){ my_fatal("do_perft(): unknown option \"%s\"\n",argv[i]); } } + if(fen==NULL){ + my_string_set(&fen,StartFen); + } board_from_fen(board,fen); search_perft(board,depth); } diff --git a/uci2uci.cpp b/uci2uci.cpp index a19b4da..edadeb4 100644 --- a/uci2uci.cpp +++ b/uci2uci.cpp @@ -29,6 +29,10 @@ static board_t UCIboard[1]; static bool Init=true; static int SavedMove=MoveNone; +// prototypes + +static void send_uci_options(); + // parse_position() static void parse_position(const char string[]) { @@ -145,7 +149,7 @@ static void format_uci_option_line(char * option_line,option_t *opt){ // send_uci_options() -void send_uci_options() { +static void send_uci_options() { int i; option_t *p=Option; char option_line[StringSize]=""; @@ -191,9 +195,9 @@ static void parse_setoption(const char string[]) { } -// uci_gui_step() +// uci2uci_gui_step() -void uci_gui_step(char string[]) { +void uci2uci_gui_step(char string[]) { int move; if(false){ }else if(match(string,"uci")){ @@ -236,7 +240,7 @@ void uci_gui_step(char string[]) { engine_send(Engine,"%s",string); } -void uci_engine_step(char string[]) { +void uci2uci_engine_step(char string[]) { gui_send(GUI,string); } diff --git a/uci2uci.h b/uci2uci.h index 8a7049d..52f44bb 100644 --- a/uci2uci.h +++ b/uci2uci.h @@ -6,9 +6,8 @@ // functions -extern void uci_gui_step(char string[]); -extern void uci_engine_step(char string[]); -extern void send_uci_options(); +extern void uci2uci_gui_step(char string[]); +extern void uci2uci_engine_step(char string[]); #endif // !defined UCI2UCI_H diff --git a/util.cpp b/util.cpp index 3ec89b7..a7a733c 100644 --- a/util.cpp +++ b/util.cpp @@ -16,9 +16,14 @@ #include "posix.h" #include "util.h" +// + +const int ErrorBufferSize=4096; + // variables static bool Error; +static char ErrorBuffer[ErrorBufferSize]; FILE * LogFile=NULL; @@ -366,3 +371,22 @@ double my_timer_elapsed_real(const my_timer_t * timer) { return elapsed; } + +// my_timer() + +char * my_error(){ +#ifdef _WIN32 + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + LANG_USER_DEFAULT, + ErrorBuffer, + ErrorBufferSize, + NULL); + return ErrorBuffer; +#else + return strerror(errno); +#endif +} + diff --git a/util.h b/util.h index 759cd16..1ce7e32 100644 --- a/util.h +++ b/util.h @@ -130,6 +130,7 @@ extern void my_timer_stop (my_timer_t * timer); extern double my_timer_elapsed_real (const my_timer_t * timer); +extern char * my_error(); #endif // !defined UTIL_H diff --git a/xboard2uci.cpp b/xboard2uci.cpp index 1ffda48..687d632 100644 --- a/xboard2uci.cpp +++ b/xboard2uci.cpp @@ -112,9 +112,9 @@ static void learn (int result); // functions -// xboard_init() +// xboard2uci_init() -void xboard_init() { +void xboard2uci_init() { // init game_clear(Game); @@ -161,26 +161,14 @@ void xboard_init() { XB->opp_time = 300.0; } -void xboard_step(char string[]) { +// xboard2uci_gui_step() + +void xboard2uci_gui_step(char string[]) { int move; char move_string[256]; board_t board[1]; - static bool firsttime=true; - - if(firsttime){ - if((match(string,"uci"))){ - my_log("POLYGLOT *** Switching to UCI mode ***\n"); - send_uci_options(); - option_set("UCI","true"); - return; - }else{ - //uci_send_isready(Uci); // In UCI mode this done by the GUI - //Grrr...Toga can fixes the number of threads after "isready" - //So we delay "isready" - } - firsttime=false; - } + if (false) { } else if (match(string,"accepted *")) { @@ -661,9 +649,9 @@ void xboard_step(char string[]) { return; } -// engine_step() +// xboard2uci_engine_step() -void engine_step(char string[]) { +void xboard2uci_engine_step(char string[]) { int event; event = uci_parse(Uci,string); diff --git a/xboard2uci.h b/xboard2uci.h index bea161a..1e44bb7 100644 --- a/xboard2uci.h +++ b/xboard2uci.h @@ -7,20 +7,14 @@ // includes #include "util.h" -#include "uci2uci.h" // types - - - - // functions -extern void adapter_loop (); -extern void xboard_init (); -extern void xboard_step (char string[]); -extern void engine_step (char string[]); +extern void xboard2uci_init (); +extern void xboard2uci_gui_step (char string[]); +extern void xboard2uci_engine_step (char string[]); #endif // !defined XBOARD2UCI_H