From 6442b61046f46f65bfc4bf0b3727abe2dc27acb8 Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Thu, 9 Jun 2011 09:44:50 +0200 Subject: [PATCH] version 1.4w10UCIb17 --- ChangeLog | 6 + Makefile.am | 2 +- Makefile.in | 9 +- README | 9 +- config.h | 6 +- configure | 22 +- configure.ac | 4 +- engine.cpp | 66 ++- engine.h | 8 + epd.cpp | 2 +- gui.cpp | 22 +- io.cpp | 1 - main.cpp | 393 +++++++-------- mainloop.cpp | 134 +++++ mainloop.h | 26 + pipe.cpp | 53 ++- pipe.h | 37 +- polyglot.man | 11 +- polyglot.pod | 6 +- polyglot.spec | 2 +- search.cpp | 2 +- uci.cpp | 6 +- uci2uci.cpp | 7 - uci2uci.h | 4 - xboard2uci.cpp | 1528 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ xboard2uci.h | 28 + 26 files changed, 2094 insertions(+), 300 deletions(-) create mode 100644 mainloop.cpp create mode 100644 mainloop.h create mode 100644 xboard2uci.cpp create mode 100644 xboard2uci.h diff --git a/ChangeLog b/ChangeLog index 83ac8ec..ab9261c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +=========1.4w10UCIb17=========== +- More refactoring. main.cpp is now #ifdef _WIN32 free. +- 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) =========1.4w10UCIb16=========== - xboard options commands - correction of handling of combo boxes in UCI protocol diff --git a/Makefile.am b/Makefile.am index 49e424b..85c63ce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ #AM_CXXFLAGS=-g bin_PROGRAMS = polyglot -polyglot_SOURCES = adapter.cpp attack.cpp board.cpp book.cpp book_make.cpp book_merge.cpp colour.cpp engine.cpp epd.cpp fen.cpp gui.cpp game.cpp hash.cpp io.cpp line.cpp list.cpp main.cpp move.cpp move_do.cpp move_gen.cpp move_legal.cpp option.cpp parse.cpp pgn.cpp piece.cpp pipe.cpp posix.cpp random.cpp san.cpp search.cpp square.cpp uci.cpp uci2uci.cpp util.cpp adapter.h colour.h hash.h move_gen.h piece.h uci2uci.h attack.h config.h gui.h io.h move.h pipe.h posix.h uci.h board.h engine.h line.h move_legal.h random.h util.h book.h epd.h list.h option.h san.h book_make.h fen.h main.h parse.h search.h book_merge.h game.h move_do.h pgn.h square.h +polyglot_SOURCES = mainloop.cpp attack.cpp board.cpp book.cpp book_make.cpp book_merge.cpp colour.cpp engine.cpp epd.cpp fen.cpp gui.cpp game.cpp hash.cpp io.cpp line.cpp list.cpp main.cpp move.cpp move_do.cpp move_gen.cpp move_legal.cpp option.cpp parse.cpp pgn.cpp piece.cpp pipe.cpp posix.cpp random.cpp san.cpp search.cpp square.cpp uci.cpp uci2uci.cpp util.cpp xboard2uci.cpp mainloop.h colour.h hash.h move_gen.h piece.h uci2uci.h attack.h config.h gui.h io.h move.h pipe.h posix.h uci.h board.h engine.h line.h move_legal.h random.h util.h book.h epd.h list.h option.h san.h book_make.h fen.h main.h parse.h search.h book_merge.h game.h move_do.h pgn.h square.h xboard2uci.h dist_doc_DATA = README README1.3 README1.4 README1.4w README1.4w10UCI book_format.html diff --git a/Makefile.in b/Makefile.in index 3dc2037..702e4d5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -54,7 +54,7 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man6dir)" \ "$(DESTDIR)$(docdir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) -am_polyglot_OBJECTS = adapter.$(OBJEXT) attack.$(OBJEXT) \ +am_polyglot_OBJECTS = mainloop.$(OBJEXT) attack.$(OBJEXT) \ board.$(OBJEXT) book.$(OBJEXT) book_make.$(OBJEXT) \ book_merge.$(OBJEXT) colour.$(OBJEXT) engine.$(OBJEXT) \ epd.$(OBJEXT) fen.$(OBJEXT) gui.$(OBJEXT) game.$(OBJEXT) \ @@ -64,7 +64,7 @@ am_polyglot_OBJECTS = adapter.$(OBJEXT) attack.$(OBJEXT) \ parse.$(OBJEXT) pgn.$(OBJEXT) piece.$(OBJEXT) pipe.$(OBJEXT) \ posix.$(OBJEXT) random.$(OBJEXT) san.$(OBJEXT) \ search.$(OBJEXT) square.$(OBJEXT) uci.$(OBJEXT) \ - uci2uci.$(OBJEXT) util.$(OBJEXT) + uci2uci.$(OBJEXT) util.$(OBJEXT) xboard2uci.$(OBJEXT) polyglot_OBJECTS = $(am_polyglot_OBJECTS) polyglot_LDADD = $(LDADD) DEFAULT_INCLUDES = -I.@am__isrc@ @@ -193,7 +193,7 @@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -polyglot_SOURCES = adapter.cpp attack.cpp board.cpp book.cpp book_make.cpp book_merge.cpp colour.cpp engine.cpp epd.cpp fen.cpp gui.cpp game.cpp hash.cpp io.cpp line.cpp list.cpp main.cpp move.cpp move_do.cpp move_gen.cpp move_legal.cpp option.cpp parse.cpp pgn.cpp piece.cpp pipe.cpp posix.cpp random.cpp san.cpp search.cpp square.cpp uci.cpp uci2uci.cpp util.cpp adapter.h colour.h hash.h move_gen.h piece.h uci2uci.h attack.h config.h gui.h io.h move.h pipe.h posix.h uci.h board.h engine.h line.h move_legal.h random.h util.h book.h epd.h list.h option.h san.h book_make.h fen.h main.h parse.h search.h book_merge.h game.h move_do.h pgn.h square.h +polyglot_SOURCES = mainloop.cpp attack.cpp board.cpp book.cpp book_make.cpp book_merge.cpp colour.cpp engine.cpp epd.cpp fen.cpp gui.cpp game.cpp hash.cpp io.cpp line.cpp list.cpp main.cpp move.cpp move_do.cpp move_gen.cpp move_legal.cpp option.cpp parse.cpp pgn.cpp piece.cpp pipe.cpp posix.cpp random.cpp san.cpp search.cpp square.cpp uci.cpp uci2uci.cpp util.cpp xboard2uci.cpp mainloop.h colour.h hash.h move_gen.h piece.h uci2uci.h attack.h config.h gui.h io.h move.h pipe.h posix.h uci.h board.h engine.h line.h move_legal.h random.h util.h book.h epd.h list.h option.h san.h book_make.h fen.h main.h parse.h search.h book_merge.h game.h move_do.h pgn.h square.h xboard2uci.h dist_doc_DATA = README README1.3 README1.4 README1.4w README1.4w10UCI book_format.html man6_MANS = polyglot.man EXTRA_DIST = makefile.gcc polyglot.man polyglot.pod polyglot.spec debian/changelog debian/control debian/docs debian/README debian/compat debian/copyright debian/files debian/polyglot.substvars debian/rules @@ -285,7 +285,6 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adapter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attack.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/board.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/book.Po@am__quote@ @@ -302,6 +301,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/line.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mainloop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/move.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/move_do.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/move_gen.Po@am__quote@ @@ -319,6 +319,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uci.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uci2uci.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xboard2uci.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/README b/README index 0b313e9..fa7080c 100644 --- a/README +++ b/README @@ -405,7 +405,12 @@ EXAMPLES polyglot merge-book -in1 w1.bin -in2 w2.bin -out w.bin - Here is a minimal config file + The command line for using the UCI engine "fruit" in a GUI which uses + the xboard protocol. + + polyglot -ec fruit + + The equivalent config file: [PolyGlot] EngineCommand = fruit @@ -429,4 +434,4 @@ SEE ALSO - 2009-01-13 POLYGLOT(6) + 2009-01-14 POLYGLOT(6) diff --git a/config.h b/config.h index b05211e..2de88c9 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.4w10UCIb16" +#define PACKAGE_STRING "polyglot 1.4w10UCIb17" /* 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.4w10UCIb16" +#define PACKAGE_VERSION "1.4w10UCIb17" /* 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.4w10UCIb16" +#define VERSION "1.4w10UCIb17" /* Define like PROTOTYPES; this can be used by system headers. */ #define __PROTOTYPES 1 diff --git a/configure b/configure index 1e4b0f7..77ab853 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.4w10UCIb16. +# Generated by GNU Autoconf 2.61 for polyglot 1.4w10UCIb17. # # Report bugs to . # @@ -574,11 +574,11 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='polyglot' PACKAGE_TARNAME='polyglot' -PACKAGE_VERSION='1.4w10UCIb16' -PACKAGE_STRING='polyglot 1.4w10UCIb16' +PACKAGE_VERSION='1.4w10UCIb17' +PACKAGE_STRING='polyglot 1.4w10UCIb17' PACKAGE_BUGREPORT='michel.vandenbergh@uhasselt.be' -ac_unique_file="adapter.cpp" +ac_unique_file="mainloop.cpp" # Factoring default headers for most tests. ac_includes_default="\ #include @@ -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.4w10UCIb16 to adapt to many kinds of systems. +\`configure' configures polyglot 1.4w10UCIb17 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.4w10UCIb16:";; + short | recursive ) echo "Configuration of polyglot 1.4w10UCIb17:";; 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.4w10UCIb16 +polyglot configure 1.4w10UCIb17 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.4w10UCIb16, which was +It was created by polyglot $as_me 1.4w10UCIb17, 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.4w10UCIb16' + VERSION='1.4w10UCIb17' 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.4w10UCIb16, which was +This file was extended by polyglot $as_me 1.4w10UCIb17, 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.4w10UCIb16 +polyglot config.status 1.4w10UCIb17 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 db02fca..1973b38 100644 --- a/configure.ac +++ b/configure.ac @@ -2,9 +2,9 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([polyglot], [1.4w10UCIb16], [michel.vandenbergh@uhasselt.be]) +AC_INIT([polyglot], [1.4w10UCIb17], [michel.vandenbergh@uhasselt.be]) AM_INIT_AUTOMAKE -AC_CONFIG_SRCDIR([adapter.cpp]) +AC_CONFIG_SRCDIR([mainloop.cpp]) AC_CONFIG_HEADER([config.h]) # Checks for programs. diff --git a/engine.cpp b/engine.cpp index 921683c..a898049 100644 --- a/engine.cpp +++ b/engine.cpp @@ -160,11 +160,24 @@ void engine_open(engine_t * engine) { engine->io->out_fd = to_engine[1]; engine->io->name = "Engine"; engine->pid=pid; + engine->state|=ENGINE_ACTIVE; // can we test if this really true? io_init(engine->io); } } +// engine_active + +bool engine_active(engine_t *engine){ + return (engine->state & ENGINE_ACTIVE)!=0; +} + +// engine_eof + +bool engine_eof(engine_t *engine){ + return (engine->state & ENGINE_EOF)!=0; +} + // engine_set_nice_value() void engine_set_nice_value(engine_t * engine, int value){ @@ -178,7 +191,13 @@ void engine_close(engine_t * engine) { ASSERT(engine_is_ok(engine)); + char string[StringSize]; io_close(engine->io); + // TODO: timeout + while (!engine_eof(engine)) { + engine_get(engine,string,StringSize); + } + } // engine_get() @@ -194,8 +213,7 @@ void engine_get(engine_t * engine, char string[], int size) { } if (!io_get_line(engine->io,string,size)) { // EOF - my_log("POLYGLOT *** EOF from Engine ***\n"); - exit(EXIT_SUCCESS); + engine->state|=ENGINE_EOF; } } @@ -335,45 +353,69 @@ void engine_send(engine_t * engine, const char *szFormat, ...) { } void engine_close(engine_t * engine){ + char string[StringSize]; (engine->pipeEngine).Close(); + // TODO: Timeout + while (!engine_eof(Engine)) { + engine_get(Engine,string,StringSize); + } + (engine->pipeEngine).Kill(); } void engine_open(engine_t * engine){ 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")); - //play with affinity (bad idea) - affinity=option_get_int("Affinity"); - if(affinity!=-1) set_affinity(engine,affinity); //AAA - //lets go back - SetCurrentDirectory(my_dir); - // set a low priority - if (option_get_bool("UseNice")){ - my_log("POLYGLOT Adjust Engine Piority\n"); - engine_set_nice_value(engine, option_get_int("NiceValue")); + if((engine->pipeEngine).Active()){ + engine->state|=ENGINE_ACTIVE; + //play with affinity (bad idea) + affinity=option_get_int("Affinity"); + if(affinity!=-1) set_affinity(engine,affinity); //AAA + //lets go back + SetCurrentDirectory(my_dir); + // set a low priority + if (option_get_bool("UseNice")){ + my_log("POLYGLOT Adjust Engine Piority\n"); + engine_set_nice_value(engine, option_get_int("NiceValue")); + } } } +bool engine_active(engine_t *engine){ + return (engine->state & ENGINE_ACTIVE)!=0; +} + +bool engine_eof(engine_t *engine){ + return (engine->state & ENGINE_EOF)!=0; +} + bool engine_get_non_blocking(engine_t * engine, char *szLineStr, int size){ + if(engine_eof(engine)){ return false;} if ((engine->pipeEngine).LineInput(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"); + engine->state|=ENGINE_EOF; + } return false; } } 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){ + if(!data_available && !engine_eof(engine)){ Idle(); }else{ break; diff --git a/engine.h b/engine.h index 5414d8a..ee703e9 100644 --- a/engine.h +++ b/engine.h @@ -3,6 +3,11 @@ #ifndef ENGINE_H #define ENGINE_H +// defines + +#define ENGINE_EOF 1 +#define ENGINE_ACTIVE 2 + // includes #include "io.h" @@ -18,6 +23,7 @@ struct engine_t { #else PipeStruct pipeEngine; #endif + uint32 state; }; @@ -31,6 +37,8 @@ extern engine_t Engine[1]; extern bool engine_is_ok (const engine_t * engine); extern void engine_open (engine_t * engine); extern void engine_close (engine_t * engine); +extern bool engine_active (engine_t * engine); +extern bool engine_eof (engine_t * engine); extern void engine_send (engine_t * engine, const char format[], ...); extern void engine_send_queue (engine_t * engine, const char format[], ...); extern bool engine_get_non_blocking(engine_t * engine, char string[], int size); diff --git a/epd.cpp b/epd.cpp index 18c5190..70537da 100644 --- a/epd.cpp +++ b/epd.cpp @@ -241,7 +241,7 @@ static void epd_test_file(const char file_name[]) { // parse engine output - while (engine_step()) { + while (!engine_eof(Engine) && engine_step()) { bool stop=false; // stop search? diff --git a/gui.cpp b/gui.cpp index 9905800..354d276 100644 --- a/gui.cpp +++ b/gui.cpp @@ -3,6 +3,7 @@ // includes #include +#include #include "gui.h" #include "main.h" @@ -17,18 +18,35 @@ gui_t GUI[1]; // functions +// sig_quit() + +static void sig_quit(int dummy){ + my_log("POLYGLOT *** SIGINT Received ***\n"); + quit(); +} + // gui_init() void gui_init(gui_t *gui){ - #ifdef _WIN32 + +// the following is nice if the "GUI" is a console! + signal(SIGINT,sig_quit); +#ifdef _WIN32 + signal(SIGTERM,SIG_IGN); +#ifdef SIGPIPE + signal(SIGPIPE,SIG_IGN); +#endif +#endif + +#ifdef _WIN32 (gui->pipeStdin).Open(); #else gui->io->in_fd = STDIN_FILENO; gui->io->out_fd = STDOUT_FILENO; gui->io->name = "GUI"; - + io_init(gui->io); #endif } diff --git a/io.cpp b/io.cpp index 0a9345d..7246e89 100644 --- a/io.cpp +++ b/io.cpp @@ -100,7 +100,6 @@ void io_get_update(io_t * io) { if (size <= 0) my_fatal("io_get_update(): buffer overflow\n"); // read as many data as possible - n = my_read(io->in_fd,&io->in_buffer[pos],size); if (UseDebug) my_log("POLYGLOT read %d byte%s from %s\n",n,(n>1)?"s":"",io->name); diff --git a/main.cpp b/main.cpp index ce6c235..b46be4a 100644 --- a/main.cpp +++ b/main.cpp @@ -4,18 +4,10 @@ // includes #include -#include #include #include #include -#ifdef _WIN32 - #include -#else - #include -#endif - -#include "adapter.h" #include "attack.h" #include "board.h" #include "book.h" @@ -28,6 +20,7 @@ #include "hash.h" #include "list.h" #include "main.h" +#include "mainloop.h" #include "move.h" #include "move_gen.h" #include "option.h" @@ -36,10 +29,13 @@ #include "square.h" #include "uci.h" #include "util.h" +#include "xboard2uci.h" +#include "uci2uci.h" + // constants -static const char * const Version = "1.4W10UCIb16"; +static const char * const Version = "1.4W10UCIb17"; static const char * const HelpMessage = "\ SYNTAX\n\ polyglot [configfile]\n\ @@ -49,13 +45,14 @@ polyglot [configfile] epd-test [-epd inputfile] [-min-depth depth] [-max-depth d polyglot perft [-fen fen] [-max-depth depth]\ "; - - static const int SearchDepth = 63; static const double SearchTime = 3600.0; static const int StringSize = 4096; + // variables + static bool Init; + // prototypes static void parse_option (); @@ -78,82 +75,77 @@ int main(int argc, char * argv[]) { } // init - Init = false; - - signal(SIGINT,sig_quit); - -#ifdef _WIN32 - signal(SIGTERM,SIG_IGN); -#ifdef SIGPIPE - signal(SIGPIPE,SIG_IGN); -#endif -#endif - - util_init(); - printf("PolyGlot %s by Fabien Letouzey\n",Version); - - option_init(); - - square_init(); - piece_init(); - attack_init(); - - hash_init(); - - my_random_init(); - - // build book - - if (argc >= 2 && my_string_equal(argv[1],"make-book")) { - book_make(argc,argv); - return EXIT_SUCCESS; - } - - if (argc >= 2 && my_string_equal(argv[1],"merge-book")) { - book_merge(argc,argv); - return EXIT_SUCCESS; - } - - if (argc >= 2 && my_string_equal(argv[1],"perft")) { - do_perft(argc,argv); - return EXIT_SUCCESS; - } - - if (argc >= 3 && my_string_equal(argv[1],"-ec")) { - option_set("EngineCommand",argv[2]); - Init=true; - engine_open(Engine); - gui_init(GUI); - uci_open(Uci,Engine); - if (my_string_equal(option_get_string("EngineName"),"")) { + Init = false; + + util_init(); + printf("PolyGlot %s by Fabien Letouzey\n",Version); + + option_init(); + + square_init(); + piece_init(); + attack_init(); + + hash_init(); + + my_random_init(); + + // build book + + if (argc >= 2 && my_string_equal(argv[1],"make-book")) { + book_make(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 2 && my_string_equal(argv[1],"merge-book")) { + book_merge(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 2 && my_string_equal(argv[1],"perft")) { + do_perft(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 3 && my_string_equal(argv[1],"-ec")) { + option_set("EngineCommand",argv[2]); + engine_open(Engine); + if(!engine_active(Engine)){ + my_fatal("Could not start \"%s\"\n",option_get("EngineCommand")); + } + Init=true; + gui_init(GUI); + uci_open(Uci,Engine); + if (my_string_equal(option_get_string("EngineName"),"")) { option_set("EngineName",Uci->name); - } - adapter_loop(); - return EXIT_SUCCESS; // we don't get here - } - - // read options - - if (argc == 2) option_set("OptionFile",argv[1]); // HACK for compatibility - - parse_option(); // HACK: also launches the engine + } + mainloop(); + return EXIT_SUCCESS; + } + + // read options + + if (argc == 2) option_set("OptionFile",argv[1]); // HACK for compatibility + + parse_option(); // HACK: also launches the engine + + // EPD test + + if (argc >= 2 && my_string_equal(argv[1],"epd-test")){ + epd_test(argc,argv); + return EXIT_SUCCESS; + }else if(argc >= 3 && my_string_equal(argv[2],"epd-test")){ + epd_test(argc-1,argv+1); + return EXIT_SUCCESS; + } + + if (argc >= 3) my_fatal("Too many arguments\n"); - // EPD test - if (argc >= 2 && my_string_equal(argv[1],"epd-test")){ - epd_test(argc,argv); - return EXIT_SUCCESS; - }else if(argc >= 3 && my_string_equal(argv[2],"epd-test")){ - epd_test(argc-1,argv+1); - return EXIT_SUCCESS; - } - - init_book(); - // adapter - - gui_init(GUI); - adapter_loop(); - return EXIT_SUCCESS; // we never get here.... + init_book(); + gui_init(GUI); + mainloop(); + return EXIT_SUCCESS; } // polyglot_set_option @@ -210,49 +202,51 @@ static void init_book(){ static void parse_option() { - const char * file_name; - FILE * file; - char line[256]; - char * name, * value; + const char * file_name; + FILE * file; + char line[256]; + char * name, * value; file_name = option_get_string("OptionFile"); - - file = fopen(file_name,"r"); - if (file == NULL) { - my_fatal("Can't open file \"%s\": %s\n",file_name,strerror(errno)); - } - - // PolyGlot options (assumed first) - + + file = fopen(file_name,"r"); + if (file == NULL) { + my_fatal("Can't open file \"%s\": %s\n",file_name,strerror(errno)); + } + + // PolyGlot options (assumed first) + while (true) { - - if (!my_file_read_line(file,line,256)) { - my_fatal("parse_option(): missing [Engine] section\n"); - } - - if(line[0]=='#') continue; - - if (my_string_case_equal(line,"[engine]")) break; - - if (parse_line(line,&name,&value)) { - option_set(name,value); - option_set_default(name,value); - } + + if (!my_file_read_line(file,line,256)) { + my_fatal("parse_option(): missing [Engine] section\n"); + } + + if(line[0]=='#') continue; + + if (my_string_case_equal(line,"[engine]")) break; + + if (parse_line(line,&name,&value)) { + option_set(name,value); + option_set_default(name,value); + } } - + if (option_get_bool("Log")) { - my_log_open(option_get_string("LogFile")); + my_log_open(option_get_string("LogFile")); } - + my_log("POLYGLOT *** START ***\n"); 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")); + } + if (option_get_bool("UCI")) { my_log("POLYGLOT *** Switching to UCI mode ***\n"); } - - - Init = true; uci_open(Uci,Engine); + Init = true; while (my_file_read_line(file,line,256)) { if (line[0] == '[') my_fatal("parse_option(): unknown section %s\n",line); if (line[0]=='#') continue; @@ -266,117 +260,102 @@ static void parse_option() { } } if (my_string_equal(option_get_string("EngineName"),"")) { - option_set("EngineName",Uci->name); + option_set("EngineName",Uci->name); } - + fclose(file); } // parse_line() static bool parse_line(char line[], char * * name_ptr, char * * value_ptr) { - - char * ptr; - char * name, * value; - - ASSERT(line!=NULL); - ASSERT(name_ptr!=NULL); - ASSERT(value_ptr!=NULL); - - // remove comments - - ptr = strchr(line,';'); - if (ptr != NULL) *ptr = '\0'; - - ptr = strchr(line,'#'); - if (ptr != NULL) *ptr = '\0'; - - // split at '=' - - ptr = strchr(line,'='); - if (ptr == NULL) return false; - - name = line; - value = ptr+1; - - // cleanup name - - while (*name == ' ') name++; // remove leading spaces - - while (ptr > name && ptr[-1] == ' ') ptr--; // remove trailing spaces - *ptr = '\0'; - - if (*name == '\0') return false; - - // cleanup value - - ptr = &value[strlen(value)]; // pointer to string terminator - - while (*value == ' ') value++; // remove leading spaces - - while (ptr > value && ptr[-1] == ' ') ptr--; // remove trailing spaces - *ptr = '\0'; - - if (*value == '\0') return false; - - // end - - *name_ptr = name; - *value_ptr = value; - - return true; -} - -static void sig_quit(int dummy){ - my_log("POLYGLOT *** SIGINT Received ***\n"); - quit(); + + char * ptr; + char * name, * value; + + ASSERT(line!=NULL); + ASSERT(name_ptr!=NULL); + ASSERT(value_ptr!=NULL); + + // remove comments + + ptr = strchr(line,';'); + if (ptr != NULL) *ptr = '\0'; + + ptr = strchr(line,'#'); + if (ptr != NULL) *ptr = '\0'; + + // split at '=' + + ptr = strchr(line,'='); + if (ptr == NULL) return false; + + name = line; + value = ptr+1; + + // cleanup name + + while (*name == ' ') name++; // remove leading spaces + + while (ptr > name && ptr[-1] == ' ') ptr--; // remove trailing spaces + *ptr = '\0'; + + if (*name == '\0') return false; + + // cleanup value + + ptr = &value[strlen(value)]; // pointer to string terminator + + while (*value == ' ') value++; // remove leading spaces + + while (ptr > value && ptr[-1] == ' ') ptr--; // remove trailing spaces + *ptr = '\0'; + + if (*value == '\0') return false; + + // end + + *name_ptr = name; + *value_ptr = value; + + return true; } - // quit() void quit() { - char string[StringSize]; - - my_log("POLYGLOT *** QUIT ***\n"); - - if (Init) { - - stop_search(); - engine_send(Engine,"quit"); - - // wait for the engine to quit - while (true) { - engine_get(Engine,string,StringSize); // HACK: calls exit() on receiving EOF - } - } - exit(EXIT_SUCCESS); + my_log("POLYGLOT *** QUIT ***\n"); + + if (Init) { + + stop_search(); + engine_send(Engine,"quit"); + engine_close(Engine); + + } + exit(EXIT_SUCCESS); } // stop_search() static void stop_search() { - - if (Init && Uci->searching) { - - ASSERT(Uci->searching); - ASSERT(Uci->pending_nb>=1); - - my_log("POLYGLOT STOP SEARCH\n"); - -/* - engine_send(Engine,"stop"); - Uci->searching = false; -*/ - - if (option_get_bool("SyncStop")) { - uci_send_stop_sync(Uci); - } else { - uci_send_stop(Uci); - } - } + + if (Init && Uci->searching) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + my_log("POLYGLOT STOP SEARCH\n"); + + if (option_get_bool("SyncStop")) { + uci_send_stop_sync(Uci); + } else { + uci_send_stop(Uci); + } + } } + // end of main.cpp diff --git a/mainloop.cpp b/mainloop.cpp new file mode 100644 index 0000000..0d5a8f0 --- /dev/null +++ b/mainloop.cpp @@ -0,0 +1,134 @@ +// mainloop.cpp + +// constants + +static const int StringSize = 4096; + +// includes + +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#include // Mac OS X needs this one +#include +#endif + +#include "main.h" +#include "engine.h" +#include "gui.h" +#include "option.h" +#include "xboard2uci.h" +#include "uci2uci.h" + +// prototypes + +static void mainloop_step (); +static void mainloop_init(); +static void mainloop_engine_step(char * string); +static void mainloop_gui_step(char * string); + +// mainloop_init() + +static void mainloop_init(){ + if(!option_get_bool("UCI")){ + xboard_init(); + } +} + +// mainloop_engine_step() + +static void mainloop_engine_step(char * string){ + if(option_get_bool("UCI")){ + uci_engine_step(string); + }else{ + engine_step(string); + } +} + +// mainloop_gui_step() + +static void mainloop_gui_step(char * string){ + if(option_get_bool("UCI")){ + uci_gui_step(string); + }else{ + xboard_step(string); + } +} + + + +// mainloop() + +void mainloop() { + mainloop_init(); + while (!engine_eof(Engine)) mainloop_step(); + my_log("POLYGLOT *** EOF file received from engine ***"); +} + +// adapter_step() + +#ifdef _WIN32 +static void mainloop_step(){ // polling! + bool xin,ein; + 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 +} +#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 + + ASSERT(GUI->io->in_fd>=0); + + FD_SET(GUI->io->in_fd,set); + if (GUI->io->in_fd > fd_max) fd_max = GUI->io->in_fd; + + // add engine input + + ASSERT(Engine->io->in_fd>=0); + + FD_SET(Engine->io->in_fd,set); + if (Engine->io->in_fd > fd_max) fd_max = Engine->io->in_fd; + + // wait for something to read (no timeout) + + ASSERT(fd_max>=0); + val = select(fd_max+1,set,NULL,NULL,NULL); + if (val == -1 && errno != EINTR) my_fatal("adapter_step(): select(): %s\n",strerror(errno)); + + 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/mainloop.h b/mainloop.h new file mode 100644 index 0000000..709b3c9 --- /dev/null +++ b/mainloop.h @@ -0,0 +1,26 @@ + +// mainloop.h + +#ifndef MAINLOOP_H +#define MAINLOOP_H + +// includes + +#include "util.h" +#include "uci2uci.h" + +// types + + + + + +// functions + +extern void mainloop (); + + +#endif // !defined MAINLOOP_H + +// end of mainloop.h + diff --git a/pipe.cpp b/pipe.cpp index 3f8da2e..f12a787 100644 --- a/pipe.cpp +++ b/pipe.cpp @@ -1,17 +1,20 @@ #ifdef _WIN32 #include "pipe.h" #include "util.h" + 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; @@ -26,17 +29,16 @@ void PipeStruct::Open(const char *szProcFile) { 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)){ - my_fatal("PipeStruct::Open(): Could not start \"%s\"\n",szProcFile); + 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; } - hProcess=pi.hProcess; - //CloseHandle(pi.hProcess);//not here,baby,but in pipe.close - CloseHandle(pi.hThread); - CloseHandle(hStdinRead); - CloseHandle(hStdoutWrite); - hInput = hStdoutRead; - hOutput = hStdinWrite; - bConsole = FALSE; } if (bConsole) { SetConsoleMode(hInput, dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT)); @@ -48,30 +50,39 @@ void PipeStruct::Open(const char *szProcFile) { } void PipeStruct::Close(void) const { + CloseHandle(hOutput); +} + +void PipeStruct::Kill(void) const { CloseHandle(hInput); CloseHandle(hOutput); DWORD lpexit; - my_log("POLYGLOT Closing child\n"); if(GetExitCodeProcess(hProcess,&lpexit)){ if(lpexit==STILL_ACTIVE) - my_log("POLYGLOT Process still active after \"quit\" "); //must be java,hammer it down! TerminateProcess(hProcess,lpexit); } CloseHandle(hProcess); } +bool PipeStruct::EOF_(void){ // EOF is defined + return state&PIPE_EOF; +} + +bool PipeStruct::Active(void){ + return state&PIPE_ACTIVE; +} + void PipeStruct::ReadInput(void) { DWORD dwBytes; - if(!ReadFile(hInput, szBuffer + nReadEnd, LINE_INPUT_MAX_CHAR - nReadEnd, &dwBytes, NULL)){ - // TODO move this comment to a more suitable place - my_log("POLYGLOT *** EOF from Engine or GUI ***\n"); - exit(EXIT_SUCCESS); // if we are here there should be data! - } - nReadEnd += dwBytes; - if (nBytesLeft > 0) { - nBytesLeft -= 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! } } diff --git a/pipe.h b/pipe.h index b13f513..ced06d7 100644 --- a/pipe.h +++ b/pipe.h @@ -5,28 +5,37 @@ #include - // constants const int LINE_INPUT_MAX_CHAR = 4096; +// defines + +#define PIPE_EOF 1 +#define PIPE_ACTIVE 2 + // types struct PipeStruct { - HANDLE hInput, hOutput; + + HANDLE hInput, hOutput; HANDLE hProcess; - BOOL bConsole; - int nBytesLeft; - int nReadEnd; - char szBuffer[LINE_INPUT_MAX_CHAR]; - - void Open(const char *szExecFile = NULL); - void Close(void) const; - void ReadInput(void); - bool CheckInput(void); - bool GetBuffer(char *szLineStr); - bool LineInput(char *szLineStr); - void LineOutput(const char *szLineStr) const; + DWORD state; + BOOL bConsole; + int nBytesLeft; + int nReadEnd; + char szBuffer[LINE_INPUT_MAX_CHAR]; + + void Open(const char *szExecFile = NULL); + void Close(void) const; + void Kill(void) const; + bool EOF_(void); + bool Active(void); + void ReadInput(void); + bool CheckInput(void); + bool GetBuffer(char *szLineStr); + bool LineInput(char *szLineStr); + void LineOutput(const char *szLineStr) const; }; // pipe #endif diff --git a/polyglot.man b/polyglot.man index de6739d..e6d0ca8 100644 --- a/polyglot.man +++ b/polyglot.man @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "POLYGLOT 6" -.TH POLYGLOT 6 "2009-01-13" "" "" +.TH POLYGLOT 6 "2009-01-14" "" "" .SH "NAME" PolyGlot \- Winboard protocol to UCI protocol adapter \- book engine for Polyglot books @@ -527,7 +527,14 @@ Merge books \*(L"in1.bin\*(R" and \*(L"in2.bin\*(R" into a book \*(L"out.bin\*(R \& polyglot merge\-book \-in1 w1.bin \-in2 w2.bin \-out w.bin .Ve .PP -Here is a minimal config file +The command line for using the \s-1UCI\s0 engine \*(L"fruit\*(R" in a \s-1GUI\s0 which uses the +xboard protocol. +.PP +.Vb 1 +\& polyglot \-ec fruit +.Ve +.PP +The equivalent config file: .PP .Vb 3 \& [PolyGlot] diff --git a/polyglot.pod b/polyglot.pod index cd4cb21..db61280 100644 --- a/polyglot.pod +++ b/polyglot.pod @@ -476,8 +476,12 @@ Merge books "in1.bin" and "in2.bin" into a book "out.bin". polyglot merge-book -in1 w1.bin -in2 w2.bin -out w.bin +The command line for using the UCI engine "fruit" in a GUI which uses the +xboard protocol. -Here is a minimal config file + polyglot -ec fruit + +The equivalent config file: [PolyGlot] EngineCommand = fruit diff --git a/polyglot.spec b/polyglot.spec index f413891..67a4465 100644 --- a/polyglot.spec +++ b/polyglot.spec @@ -1,6 +1,6 @@ Summary: A Winboard protocol to UCI protocol adapter Name: polyglot -Version: 1.4w10UCIb16 +Version: 1.4w10UCIb17 Release: 1 License: GPL Group: Amusement/Games diff --git a/search.cpp b/search.cpp index a867d24..b231882 100644 --- a/search.cpp +++ b/search.cpp @@ -105,7 +105,7 @@ void search(const board_t * board, int depth_max, double time_max) { // wait for feed-back - while (true) { + while (!engine_eof(Engine)) { engine_get(Engine,string,256); diff --git a/uci.cpp b/uci.cpp index a84628e..d7f63b4 100644 --- a/uci.cpp +++ b/uci.cpp @@ -139,7 +139,7 @@ void uci_open(uci_t * uci, engine_t * engine) { do { engine_get(uci->engine,string,StringSize); event = uci_parse(uci,string); - } while ((event & EVENT_UCI) == 0); + } while (!engine_eof(Engine) && (event & EVENT_UCI) == 0); } // uci_close() @@ -223,7 +223,7 @@ void uci_send_isready_sync(uci_t * uci) { do { engine_get(uci->engine,string,StringSize); event = uci_parse(uci,string); - } while ((event & EVENT_READY) == 0); + } while (!engine_eof(Engine) && (event & EVENT_READY) == 0); } // uci_send_stop() @@ -258,7 +258,7 @@ void uci_send_stop_sync(uci_t * uci) { do { engine_get(uci->engine,string,StringSize); event = uci_parse(uci,string); - } while ((event & EVENT_STOP) == 0); + } while (!engine_eof(Engine) && (event & EVENT_STOP) == 0); } // uci_send_ucinewgame() diff --git a/uci2uci.cpp b/uci2uci.cpp index e28d815..5dab703 100644 --- a/uci2uci.cpp +++ b/uci2uci.cpp @@ -6,7 +6,6 @@ #include #include "util.h" -#include "adapter.h" #include "board.h" #include "engine.h" #include "fen.h" @@ -30,12 +29,6 @@ static board_t UCIboard[1]; static bool Init=true; static int SavedMove=MoveNone; -// defines - -#ifdef _WIN32 -#define strcasecmp lstrcmpi -#endif - // parse_position() static void parse_position(const char string[]) { diff --git a/uci2uci.h b/uci2uci.h index 2e9e0a6..8a7049d 100644 --- a/uci2uci.h +++ b/uci2uci.h @@ -4,10 +4,6 @@ #ifndef UCI2UCI_H #define UCI2UCI_H -// constants - -const char * const PolyglotBookFile="Polyglot BookFile"; - // functions extern void uci_gui_step(char string[]); diff --git a/xboard2uci.cpp b/xboard2uci.cpp new file mode 100644 index 0000000..ed241a0 --- /dev/null +++ b/xboard2uci.cpp @@ -0,0 +1,1528 @@ + +// xboard2uci.cpp + +// includes + +#include +#include +#include +#include + + +#include "board.h" +#include "book.h" +#include "colour.h" +#include "engine.h" +#include "fen.h" +#include "game.h" +#include "gui.h" +#include "line.h" +#include "main.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "option.h" +#include "parse.h" +#include "san.h" +#include "uci.h" +#include "uci2uci.h" +#include "util.h" + +// constants + +static const bool UseDebug = false; +static const bool DelayPong = false; + +static const int StringSize = 4096; + +// types + +struct state_t { + int state; + bool computer[ColourNb]; + int exp_move; + int resign_nb; + my_timer_t timer[1]; +}; + +struct xb_t { + bool has_feature_memory; + bool has_feature_smp; + bool has_feature_egt; + bool analyse; + bool computer; + const char * name; + bool ics; + bool new_hack; // "new" is a C++ keyword + bool ponder; + int ping; + bool post; + int proto_ver; + bool result; + + int mps; + double base; + double inc; + + bool time_limit; + double time_max; + + bool depth_limit; + int depth_max; + + double my_time; + double opp_time; +}; + +enum dummy_state_t { WAIT, THINK, PONDER, ANALYSE }; + +// variables + +static state_t State[1]; +static xb_t XB[1]; + +// prototypes + +static void comp_move (int move); +static void move_step (int move); +static void board_update (); + +static void mess (); +static void no_mess (int move); + +static void search_update (); +static void search_clear (); +static void update_remaining_time(); +static void start_protected_command(); +static void end_protected_command(); + +static bool active (); +static bool ponder (); +static bool ponder_ok (int ponder_move); + +static void stop_search (); + +static void send_board (int extra_move); +static void send_pv (); + +static void send_xboard_options (); + +static void learn (int result); + + +// functions + +// xboard_init() + +void xboard_init() { + // init + + game_clear(Game); + + // state + + State->state = WAIT; + + State->computer[White] = false; + State->computer[Black] = true; + + State->exp_move = MoveNone; + State->resign_nb = 0; + my_timer_reset(State->timer); + + // yes there are engines that do not have the "Hash" option.... + XB->has_feature_memory= uci_option_exist(Uci,"Hash"); + XB->has_feature_smp = uci_thread_option_exist(Uci); + // TODO: support for other types of table bases + XB->has_feature_egt = uci_option_exist(Uci,"NalimovPath"); + XB->analyse = false; + XB->computer = false; + XB->name = NULL; + my_string_set(&XB->name,""); + XB->ics = false; + XB->new_hack = true; + XB->ping = -1; + XB->ponder = false; + XB->post = false; + XB->proto_ver = 1; + XB->result = false; + + XB->mps = 0; + XB->base = 300.0; + XB->inc = 0.0; + + XB->time_limit = false; + XB->time_max = 5.0; + + XB->depth_limit = false; + XB->depth_max = 127; + + XB->my_time = 300.0; + XB->opp_time = 300.0; +} + +void xboard_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 *")) { + + // ignore + + } else if (match(string,"analyze")) { + + State->computer[White] = false; + State->computer[Black] = false; + + XB->analyse = true; + XB->new_hack = false; + ASSERT(!XB->result); + XB->result = false; + + mess(); + + } else if (match(string,"bk")) { + + if (option_get_bool("Book")) { + game_get_board(Game,board); + book_disp(board); + } + + } else if (match(string,"black")) { + + if (colour_is_black(game_turn(Game))) { + + State->computer[White] = true; + State->computer[Black] = false; + + XB->new_hack = true; + XB->result = false; + + mess(); + } + + } else if (match(string,"computer")) { + + XB->computer = true; + + } else if (match(string,"draw")) { + if(uci_option_exist(Uci,"UCI_DrawOffers")){ + my_log("POLYGLOT draw from XB received"); + uci_send_option(Uci,"DrawOffer","%s","draw");} + } else if (match(string,"easy")) { + + XB->ponder = false; + + mess(); + + } else if (match(string,"edit")) { + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (match(string,"exit")) { + + State->computer[White] = false; + State->computer[Black] = false; + + XB->analyse = false; + + mess(); + + } else if (match(string,"force")) { + + State->computer[White] = false; + State->computer[Black] = false; + + mess(); + + } else if (match(string,"go")) { + + State->computer[game_turn(Game)] = true; + State->computer[colour_opp(game_turn(Game))] = false; + + XB->new_hack = false; + ASSERT(!XB->result); + XB->result = false; + + mess(); + + } else if (match(string,"hard")) { + + XB->ponder = true; + + mess(); + + } else if (match(string,"hint")) { + + if (option_get_bool("Book")) { + + game_get_board(Game,board); + move = book_move(board,false); + + if (move != MoveNone && move_is_legal(move,board)) { + move_to_san(move,board,move_string,256); + gui_send(GUI,"Hint: %s",move_string); + } + } + + } else if (match(string,"ics *")) { + + XB->ics = true; + + } else if (match(string,"level * *:* *")) { + + XB->mps = atoi(Star[0]); + XB->base = double(atoi(Star[1])) * 60.0 + double(atoi(Star[2])); + XB->inc = double(atoi(Star[3])); + + } else if (match(string,"level * * *")) { + + XB->mps = atoi(Star[0]); + XB->base = double(atoi(Star[1])) * 60.0; + XB->inc = double(atoi(Star[2])); + + } else if (match(string,"name *")) { + + my_string_set(&XB->name,Star[0]); + + } else if (match(string,"new")) { + + uci_send_isready(Uci); + my_log("POLYGLOT NEW GAME\n"); + + option_set("Chess960","false"); + + game_clear(Game); + + if (XB->analyse) { + State->computer[White] = false; + State->computer[Black] = false; + } else { + State->computer[White] = false; + State->computer[Black] = true; + } + + XB->new_hack = true; + XB->result = false; + + XB->depth_limit = false; + + XB->computer = false; + my_string_set(&XB->name,""); + + board_update(); + mess(); + + uci_send_ucinewgame(Uci); + + } else if (match(string,"nopost")) { + + XB->post = false; + + } else if (match(string,"otim *")) { + + XB->opp_time = double(atoi(Star[0])) / 100.0; + if (XB->opp_time < 0.0) XB->opp_time = 0.0; + + } else if (match(string,"pause")) { + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (match(string,"ping *")) { + + // HACK; TODO: answer only after an engine move + + if (DelayPong) { + if (XB->ping >= 0) gui_send(GUI,"pong %d",XB->ping); // HACK: get rid of old ping + XB->ping = atoi(Star[0]); + uci_send_isready(Uci); + } else { + ASSERT(XB->ping==-1); + gui_send(GUI,"pong %s",Star[0]); + } + + } else if (match(string,"playother")) { + + State->computer[game_turn(Game)] = false; + State->computer[colour_opp(game_turn(Game))] = true; + + XB->new_hack = false; + ASSERT(!XB->result); + XB->result = false; + + mess(); + + } else if (match(string,"post")) { + + XB->post = true; + + } else if (match(string,"protover *")) { + + send_xboard_options(); + + } else if (match(string,"quit")) { + my_log("POLYGLOT *** \"quit\" from GUI ***\n"); + quit(); + } else if (match(string,"random")) { + + // ignore + + } else if (match(string,"rating * *")) { + + // ignore + + } else if (match(string,"remove")) { + + if (game_pos(Game) >= 2) { + + game_goto(Game,game_pos(Game)-2); + + ASSERT(!XB->new_hack); + XB->new_hack = false; // HACK? + XB->result = false; + + board_update(); + mess(); + } + + } else if (match(string,"rejected *")) { + + // ignore + + } else if (match(string,"reset")) { // protover 3? + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (false + || match(string,"result * {*}") + || match(string,"result * {* }") + || match(string,"result * { *}") + || match(string,"result * { * }")) { + + my_log("POLYGLOT GAME END\n"); + + XB->result = true; + + mess(); + + // book learning + + if (option_get_bool("Book") && option_get_bool("BookLearn")) { + + if (false) { + } else if (my_string_equal(Star[0],"1-0")) { + learn(+1); + } else if (my_string_equal(Star[0],"0-1")) { + learn(-1); + } else if (my_string_equal(Star[0],"1/2-1/2")) { + learn(0); + } + } + } else if (match(string,"resume")) { + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (match(string,"option *=*")){ + char *name=Star[0]; + char *value=Star[1]; + if(match(name, "Polyglot *")){ + char *pg_name=Star[0]; + polyglot_set_option(pg_name,value); + }else{ + start_protected_command(); + engine_send(Engine,"setoption name %s value %s",name,value); + end_protected_command(); + } + } else if (match(string,"option *")){ + char *name=Star[0]; + start_protected_command(); + engine_send(Engine,"setoption name %s",name); + end_protected_command(); + } else if (XB->has_feature_smp && match(string,"cores *")){ + int cores=atoi(Star[0]); + if(cores>=1){ + // updating the number of cores + my_log("POLYGLOT setting the number of cores to %d\n",cores); + start_protected_command(); + uci_set_threads(Uci,cores); + end_protected_command(); + } else{ + // refuse + gui_send(GUI,"Error (unknown command): %s",string); + } + } else if (XB->has_feature_egt && match(string,"egtpath * *")){ + char *type=Star[0]; + char *path=Star[1]; + if(!my_string_case_equal(Star[0],"nalimov")){ + // refuse + gui_send(GUI,"Error (unsupported table base format): %s",string); + }else if(my_string_empty(path)){ + // refuse + gui_send(GUI,"Error (unknown command): %s",string); + }else{ + // updating NalimovPath + my_log("POLYGLOT setting the Nalimov path to %s\n",path); + start_protected_command(); + uci_send_option(Uci,"NalimovPath","%s",path); + end_protected_command(); + } + } else if (XB->has_feature_memory && match(string,"memory *")){ + int memory = atoi(Star[0]); + int nalimov_cache; + int real_memory; + if(memory>=1){ + // updating the available memory + my_log("POLYGLOT setting the amount of memory to %dMb\n",memory); + if(uci_get_option(Uci,"NalimovCache")>=0){ + nalimov_cache=atoi(Uci->option[uci_get_option(Uci,"NalimovCache")].value); + }else{ + nalimov_cache=0; + } + my_log("POLYGLOT Nalimov Cache is %dMb\n",nalimov_cache); + real_memory=memory-nalimov_cache; + if(real_memory>0){ + start_protected_command(); + uci_send_option(Uci,"Hash", "%d", real_memory); + end_protected_command(); + } + }else{ + // refuse + gui_send(GUI,"Error (unknown command): %s",string); + } + + } else if (match(string,"sd *")) { + + XB->depth_limit = true; + XB->depth_max = atoi(Star[0]); + + } else if (match(string,"setboard *")) { + + my_log("POLYGLOT FEN %s\n",Star[0]); + + if (!game_init(Game,Star[0])) my_fatal("xboard_step(): bad FEN \"%s\"\n",Star[0]); + + State->computer[White] = false; + State->computer[Black] = false; + + XB->new_hack = true; // HACK? + XB->result = false; + + board_update(); + mess(); + + } else if (match(string,"st *")) { + + XB->time_limit = true; + XB->time_max = double(atoi(Star[0])); + + } else if (match(string,"time *")) { + + XB->my_time = double(atoi(Star[0])) / 100.0; + if (XB->my_time < 0.0) XB->my_time = 0.0; + + } else if (match(string,"undo")) { + + if (game_pos(Game) >= 1) { + + game_goto(Game,game_pos(Game)-1); + + ASSERT(!XB->new_hack); + XB->new_hack = false; // HACK? + XB->result = false; + + board_update(); + mess(); + } + + } else if (match(string,"usermove *")) { + + game_get_board(Game,board); + move = move_from_san(Star[0],board); + + if (move != MoveNone && move_is_legal(move,board)) { + + XB->new_hack = false; + ASSERT(!XB->result); + XB->result = false; + + move_step(move); + no_mess(move); + + } else { + + gui_send(GUI,"Illegal move: %s",Star[0]); + } + + } else if (match(string,"variant *")) { + + if (my_string_equal(Star[0],"fischerandom")) { + option_set("Chess960","true"); + } else { + option_set("Chess960","false"); + } + + } else if (match(string,"white")) { + + if (colour_is_white(game_turn(Game))) { + + State->computer[White] = false; + State->computer[Black] = true; + + XB->new_hack = true; + XB->result = false; + + mess(); + } + + } else if (match(string,"xboard")) { + + // ignore + + } else if (match(string,".")) { // analyse info + + if (State->state == ANALYSE) { + int depth=Uci->best_depth;//HACK: don't clear engine-output window... + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + if (Uci->root_move != MoveNone && move_is_legal(Uci->root_move,Uci->board)) { + move_to_san(Uci->root_move,Uci->board,move_string,256); + gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d %s",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,Uci->root_move_nb-(Uci->root_move_pos+1),Uci->root_move_nb,move_string); + } else { + gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,0,0); // HACK + } + } + + } else if (match(string,"?")) { // move now + + if (State->state == THINK) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + // HACK: just send "stop" to the engine + + if (Uci->searching) { + my_log("POLYGLOT STOP SEARCH\n"); + engine_send(Engine,"stop"); + } + } + + } else { // unknown command, maybe a move? + + game_get_board(Game,board); + move = move_from_san(string,board); + + if (move != MoveNone && move_is_legal(move,board)) { + + XB->new_hack = false; + ASSERT(!XB->result); + XB->result = false; + + move_step(move); + no_mess(move); + + } else if (move != MoveNone) { + + gui_send(GUI,"Illegal move: %s",string); + + } else { + + gui_send(GUI,"Error (unknown command): %s",string); + } + } + return; +} + +// engine_step() + +void engine_step(char string[]) { + + int event; + event = uci_parse(Uci,string); + + // react to events + + if ((event & EVENT_READY) != 0) { + + // the engine is now ready + + if (!Uci->ready) { + Uci->ready = true; + // if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1"); + } + + if (!DelayPong && XB->ping >= 0) { + gui_send(GUI,"pong %d",XB->ping); + XB->ping = -1; + } + } + + if ((event & EVENT_MOVE) != 0 && State->state == THINK) { + + // the engine is playing a move + + // MEGA HACK: estimate remaining time because XBoard won't send it! + + my_timer_stop(State->timer); + + XB->my_time -= my_timer_elapsed_real(State->timer); + XB->my_time += XB->inc; + if (XB->mps != 0 && (game_move_nb(Game) + 1) % XB->mps == 0) XB->my_time += XB->base; + + if (XB->my_time < 0.0) XB->my_time = 0.0; + + // play the engine move + + comp_move(Uci->best_move); + } + + if ((event & EVENT_PV) != 0) { + + // the engine has sent a new PV + + send_pv(); + } + if((event & (EVENT_DRAW|EVENT_RESIGN))!=0){ + my_log("POYGLOT draw offer/resign from engine\n"); + if(uci_option_exist(Uci,"UCI_DrawOffers")){ + if(event & EVENT_DRAW) + gui_send(GUI,"offer draw"); + else + gui_send(GUI,"resign"); + } + } +} + +// format_xboard_option_line + +void format_xboard_option_line(char * option_line, option_t *opt){ + int j; + char option_string[StringSize]; + strcpy(option_line,""); + strcat(option_line,"feature option=\""); + if(opt->mode&PG){ + strcat(option_line,"Polyglot "); + } + sprintf(option_string,"%s",opt->name); + strcat(option_line,option_string); + sprintf(option_string," -%s",opt->type); + strcat(option_line,option_string); + if(strcmp(opt->type,"button") && strcmp(opt->type,"combo")){ + if(strcmp(opt->type,"check")){ + sprintf(option_string," %s",opt->default_); + }else{ + sprintf(option_string," %d", + strcmp(opt->default_,"true")?0:1); + } + strcat(option_line,option_string); + } + if(!strcmp(opt->type,"spin")){ + sprintf(option_string," %s",opt->min); + strcat(option_line,option_string); + } + if(!strcmp(opt->type,"spin")){ + sprintf(option_string," %s",opt->max); + strcat(option_line,option_string); + } + for(j=0;jvar_nb;j++){ + if(!strcmp(opt->var[j],opt->default_)){ + sprintf(option_string," *%s",opt->var[j]); + }else{ + sprintf(option_string," %s",opt->var[j]); + } + strcat(option_line,option_string); + if(j!=opt->var_nb-1){ + strcat(option_line," ///"); + } + } + strcat(option_line,"\""); +} + +// send_xboard_options + +static void send_xboard_options(){ + int i; + char option_line[StringSize]=""; + option_t *p=Option; + const char * name; + XB->proto_ver = atoi(Star[0]); + ASSERT(XB->proto_ver>=2); + + gui_send(GUI,"feature done=0"); + + gui_send(GUI,"feature analyze=1"); + gui_send(GUI,"feature colors=0"); + gui_send(GUI,"feature draw=1"); + gui_send(GUI,"feature ics=1"); + gui_send(GUI,"feature myname=\"%s\"",option_get_string("EngineName")); + gui_send(GUI,"feature name=1"); + gui_send(GUI,"feature pause=0"); + gui_send(GUI,"feature ping=1"); + gui_send(GUI,"feature playother=1"); + gui_send(GUI,"feature reuse=1"); + gui_send(GUI,"feature san=0"); + gui_send(GUI,"feature setboard=1"); + gui_send(GUI,"feature sigint=0"); + gui_send(GUI,"feature sigterm=0"); + gui_send(GUI,"feature time=1"); + gui_send(GUI,"feature usermove=1"); + if (XB->has_feature_memory){ + gui_send(GUI,"feature memory=1"); + }else{ + gui_send(GUI,"feature memory=0"); + } + if (XB->has_feature_smp){ + gui_send(GUI,"feature smp=1"); + }else{ + gui_send(GUI,"feature smp=0"); + } + if (XB->has_feature_egt){ + // TODO: support for other types of table bases + gui_send(GUI,"feature egt=\"nalimov\""); + }else{ + gui_send(GUI,"feature egt=\"\""); + } + + if (uci_option_exist(Uci,"UCI_Chess960")) { + gui_send(GUI,"feature variants=\"normal,fischerandom\""); + } else { + gui_send(GUI,"feature variants=\"normal\""); + } + + for(i=0;ioption_nb;i++){ + if(my_string_case_equal(Uci->option[i].name,"UCI_AnalyseMode")) continue; + if(my_string_case_equal(Uci->option[i].name,"Ponder")) continue; + if(my_string_case_equal(Uci->option[i].name,"Hash")) continue; + if(my_string_case_equal(Uci->option[i].name,"NalimovPath")) continue; + if((name=uci_thread_option(Uci))!=NULL && my_string_case_equal(Uci->option[i].name,name)) continue; + format_xboard_option_line(option_line,Uci->option+i); + + gui_send(GUI,"%s",option_line); + + } + while(p->name){ + if(p->mode &XBOARD){ + format_xboard_option_line(option_line,p); + gui_send(GUI,"%s",option_line); + } + p++; + } + gui_send(GUI,"feature done=1"); + +} + +// comp_move() + +static void comp_move(int move) { + + board_t board[1]; + char string[256]; + + ASSERT(move_is_ok(move)); + + ASSERT(State->state==THINK); + ASSERT(!XB->analyse); + + if(option_get_bool("RepeatPV")==true) + send_pv(); // to update time and nodes + + // send the move + + game_get_board(Game,board); + + if (move_is_castle(move,board) && option_get_bool("Chess960")) { + if (!move_to_san(move,board,string,256)) my_fatal("comp_move(): move_to_san() failed\n"); // O-O/O-O-O + } else { + if (!move_to_can(move,board,string,256)) my_fatal("comp_move(): move_to_can() failed\n"); + } + + gui_send(GUI,"move %s",string); + + // resign? + + if (option_get_bool("Resign") && Uci->root_move_nb > 1) { + + if (Uci->best_score <= -abs(option_get_int("ResignScore"))) { + + State->resign_nb++; + my_log("POLYGLOT %d move%s with resign score\n",State->resign_nb,(State->resign_nb>1)?"s":""); + + if (State->resign_nb >= option_get_int("ResignMoves")) { + my_log("POLYGLOT *** RESIGN ***\n"); + gui_send(GUI,"resign"); + } + + } else { + + if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb); + State->resign_nb = 0; + } + } + + // play the move + + move_step(move); + no_mess(move); +} + +// move_step() + +static void move_step(int move) { + + board_t board[1]; + char move_string[256]; + + ASSERT(move_is_ok(move)); + + // log + + game_get_board(Game,board); + + if (move != MoveNone && move_is_legal(move,board)) { + + move_to_san(move,board,move_string,256); + my_log("POLYGLOT MOVE %s\n",move_string); + + } else { + + move_to_can(move,board,move_string,256); + my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string); + board_disp(board); + + my_fatal("move_step(): illegal move \"%s\"\n",move_string); + } + + // play the move + + game_add_move(Game,move); + board_update(); +} + +// board_update() + +static void board_update() { + + // handle game end + + ASSERT(!XB->result); + + switch (game_status(Game)) { + case PLAYING: + break; + case WHITE_MATES: + gui_send(GUI,"1-0 {White mates}"); + break; + case BLACK_MATES: + gui_send(GUI,"0-1 {Black mates}"); + break; + case STALEMATE: + gui_send(GUI,"1/2-1/2 {Stalemate}"); + break; + case DRAW_MATERIAL: + gui_send(GUI,"1/2-1/2 {Draw by insufficient material}"); + break; + case DRAW_FIFTY: + gui_send(GUI,"1/2-1/2 {Draw by fifty-move rule}"); + break; + case DRAW_REPETITION: + gui_send(GUI,"1/2-1/2 {Draw by repetition}"); + break; + default: + ASSERT(false); + break; + } +} + +// mess() + +static void mess() { + + // clear state variables + + State->resign_nb = 0; + State->exp_move = MoveNone; + my_timer_reset(State->timer); + + // abort a possible search + + stop_search(); + + // calculate the new state + + if (false) { + } else if (!active()) { + State->state = WAIT; + my_log("POLYGLOT WAIT\n"); + } else if (XB->analyse) { + State->state = ANALYSE; + my_log("POLYGLOT ANALYSE\n"); + } else if (State->computer[game_turn(Game)]) { + State->state = THINK; + my_log("POLYGLOT THINK\n"); + } else { + State->state = WAIT; + my_log("POLYGLOT WAIT\n"); + } + + search_update(); +} + +// no_mess() + +static void no_mess(int move) { + + ASSERT(move_is_ok(move)); + + // just received a move, calculate the new state + + if (false) { + + } else if (!active()) { + + stop_search(); // abort a possible search + + State->state = WAIT; + State->exp_move = MoveNone; + + my_log("POLYGLOT WAIT\n"); + + } else if (State->state == WAIT) { + + ASSERT(State->computer[game_turn(Game)]); + ASSERT(!State->computer[colour_opp(game_turn(Game))]); + ASSERT(!XB->analyse); + + my_log("POLYGLOT WAIT -> THINK\n"); + + State->state = THINK; + State->exp_move = MoveNone; + + } else if (State->state == THINK) { + + ASSERT(!State->computer[game_turn(Game)]); + ASSERT(State->computer[colour_opp(game_turn(Game))]); + ASSERT(!XB->analyse); + + if (ponder() && ponder_ok(Uci->ponder_move)) { + + my_log("POLYGLOT THINK -> PONDER\n"); + + State->state = PONDER; + State->exp_move = Uci->ponder_move; + + } else { + + my_log("POLYGLOT THINK -> WAIT\n"); + + State->state = WAIT; + State->exp_move = MoveNone; + } + + } else if (State->state == PONDER) { + + ASSERT(State->computer[game_turn(Game)]); + ASSERT(!State->computer[colour_opp(game_turn(Game))]); + ASSERT(!XB->analyse); + + if (move == State->exp_move && Uci->searching) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + my_timer_start(State->timer);//also resets + + my_log("POLYGLOT PONDER -> THINK (*** HIT ***)\n"); + engine_send(Engine,"ponderhit"); + + State->state = THINK; + State->exp_move = MoveNone; + + send_pv(); // update display + + return; // do not launch a new search + + } else { + + my_log("POLYGLOT PONDER -> THINK (miss)\n"); + + stop_search(); + + State->state = THINK; + State->exp_move = MoveNone; + } + + } else if (State->state == ANALYSE) { + + ASSERT(XB->analyse); + + my_log("POLYGLOT ANALYSE -> ANALYSE\n"); + + stop_search(); + + } else { + + ASSERT(false); + } + + search_update(); +} + +// start_protected_command() + +static void start_protected_command(){ + stop_search(); +} + +static void end_protected_command(){ + if(Uci->ready){ // not init faze + uci_send_isready_sync(Uci); // gobble up spurious "bestmove" + } + update_remaining_time(); + search_update(); // relaunch search if necessary +} + +// update_remaining_time() + +static void update_remaining_time(){ + double reduce; + if(State->timer->running){ + my_timer_stop(State->timer); + reduce = my_timer_elapsed_real(State->timer); + my_log("POLYGLOT reducing remaing time by %f seconds\n",reduce); + XB->my_time -= reduce; + if(XB->my_time<0.0){ + XB->my_time=0.0; + } + } +} + + +// search_update() + +static void search_update() { + + int move; + int move_nb; + board_t board[1]; + int nalimov_cache; + int real_memory; + + ASSERT(!Uci->searching); + + + + + // launch a new search if needed + + + + if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) { + + // opening book + + if (State->state == THINK && option_get_bool("Book")) { + + game_get_board(Game,Uci->board); + + move = book_move(Uci->board,option_get_bool("BookRandom")); + + if (move != MoveNone && move_is_legal(move,Uci->board)) { + + my_log("POLYGLOT *BOOK MOVE*\n"); + + search_clear(); // clears Uci->ponder_move + Uci->best_move = move; + + board_copy(board,Uci->board); + move_do(board,move); + Uci->ponder_move = book_move(board,false); // expected move = best book move + + Uci->best_pv[0] = Uci->best_move; + Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone + Uci->best_pv[2] = MoveNone; + + comp_move(Uci->best_move); + + return; + } + } + + // engine search + + my_log("POLYGLOT START SEARCH\n"); + + // options + + uci_send_option(Uci,"UCI_Chess960","%s",option_get_bool("Chess960")?"true":"false"); + + if (option_get_int("UCIVersion") >= 2) { + uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name); + uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false"); + } + + uci_send_option(Uci,"Ponder","%s",ponder()?"true":"false"); + + // position + + move = (State->state == PONDER) ? State->exp_move : MoveNone; + send_board(move); // updates Uci->board global variable + + // search + + if (State->state == THINK || State->state == PONDER) { + + engine_send_queue(Engine,"go"); + + if (XB->time_limit) { + + // fixed time per move + + engine_send_queue(Engine," movetime %.0f",XB->time_max*1000.0); + + } else { + + // time controls + + if (colour_is_white(Uci->board->turn)) { + engine_send_queue(Engine," wtime %.0f btime %.0f",XB->my_time*1000.0,XB->opp_time*1000.0); + } else { + engine_send_queue(Engine," wtime %.0f btime %.0f",XB->opp_time*1000.0,XB->my_time*1000.0); + } + + if (XB->inc != 0.0) engine_send_queue(Engine," winc %.0f binc %.0f",XB->inc*1000.0,XB->inc*1000.0); + + if (XB->mps != 0) { + + move_nb = XB->mps - (Uci->board->move_nb % XB->mps); + ASSERT(move_nb>=1&&move_nb<=XB->mps); + + engine_send_queue(Engine," movestogo %d",move_nb); + } + } + + if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max); + + if (State->state == PONDER) engine_send_queue(Engine," ponder"); + + engine_send(Engine,""); // newline + + } else if (State->state == ANALYSE) { + + engine_send(Engine,"go infinite"); + + } else { + + ASSERT(false); + } + + // init search info + + ASSERT(!Uci->searching); + + search_clear(); + + Uci->searching = true; + Uci->pending_nb++; + } +} + +// search_clear() + +static void search_clear() { + + uci_clear(Uci); + + // TODO: MOVE ME + + my_timer_start(State->timer);//also resets +} + +// active() + +static bool active() { + + // position state + + if (game_status(Game) != PLAYING) return false; // game ended + + // xboard state + + if (XB->analyse) return true; // analysing + if (!State->computer[White] && !State->computer[Black]) return false; // force mode + if (XB->new_hack || XB->result) return false; // unstarted or ended game + + return true; // playing +} + +// ponder() + +static bool ponder() { + + return XB->ponder && (option_get_bool("CanPonder") || uci_option_exist(Uci,"Ponder")); +} +// ponder_ok() + +static bool ponder_ok(int move) { + int status; + board_t board[1]; + + ASSERT(move==MoveNone||move_is_ok(move)); + + // legal ponder move? + + if (move == MoveNone) return false; + + game_get_board(Game,board); + if (!move_is_legal(move,board)) return false; + + // UCI-legal resulting position? + + game_add_move(Game,move); + + game_get_board(Game,board); + status = game_status(Game); + + game_rem_move(Game); + + if (status != PLAYING) return false; // game ended + + if (option_get_bool("Book") && is_in_book(board)) { + return false; + } + + return true; +} + +// stop_search() + +static void stop_search() { + + if (Uci->searching) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + my_log("POLYGLOT STOP SEARCH\n"); + +/* + engine_send(Engine,"stop"); + Uci->searching = false; +*/ + + if (option_get_bool("SyncStop")) { + uci_send_stop_sync(Uci); + } else { + uci_send_stop(Uci); + } + } +} + +// send_board() + +static void send_board(int extra_move) { + + char fen[256]; + int start, end; + board_t board[1]; + int pos; + int move; + char string[256]; + + ASSERT(extra_move==MoveNone||move_is_ok(extra_move)); + + ASSERT(!Uci->searching); + + // init + + game_get_board(Game,Uci->board); + if (extra_move != MoveNone) move_do(Uci->board,extra_move); + + board_to_fen(Uci->board,fen,256); + my_log("POLYGLOT FEN %s\n",fen); + + ASSERT(board_can_play(Uci->board)); + + // more init + + start = 0; + end = game_pos(Game); + ASSERT(end>=start); + + // position + + game_get_board(Game,board,start); + board_to_fen(board,string,256); + + engine_send_queue(Engine,"position"); + + if (my_string_equal(string,StartFen)) { + engine_send_queue(Engine," startpos"); + } else { + engine_send_queue(Engine," fen %s",string); + } + + // move list + + if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves"); + + for (pos = start; pos < end; pos++) { // game moves + + move = game_move(Game,pos); + + move_to_can(move,board,string,256); + engine_send_queue(Engine," %s",string); + + move_do(board,move); + } + + if (extra_move != MoveNone) { // move to ponder on + move_to_can(extra_move,board,string,256); + engine_send_queue(Engine," %s",string); + } + + // end + + engine_send(Engine,""); // newline +} + +// send_pv() + +static void send_pv() { + + char pv_string[StringSize]; + board_t board[1]; + int move; + char move_string[StringSize]; + + ASSERT(State->state!=WAIT); + + if (Uci->best_depth == 0) return; + + // xboard search information + + if (XB->post) { + + if (State->state == THINK || State->state == ANALYSE) { + + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + + if(Uci->depth==-1) //hack to clear the engine output window + gui_send(GUI,"%d %+d %.0f "S64_FORMAT" ",0,Uci->best_score,Uci->time*100.0,Uci->node_nb); + + gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth,Uci->best_score,Uci->time*100.0,Uci->node_nb,pv_string); + + } else if (State->state == PONDER && option_get_bool("ShowPonder")) { + + game_get_board(Game,board); + move = State->exp_move; + + if (move != MoveNone && move_is_legal(move,board)) { + move_to_san(move,board,move_string,256); + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + gui_send(GUI,"%d %+d %.0f "S64_FORMAT" (%s) %s",Uci->best_depth,Uci->best_score,Uci->time*100.0,Uci->node_nb,move_string,pv_string); + } + } + } + + // kibitz + + if ((Uci->searching && option_get_bool("KibitzPV") && Uci->time >= option_get_double("KibitzDelay")) + || (!Uci->searching && option_get_bool("KibitzMove"))) { + + if (State->state == THINK || State->state == ANALYSE) { + + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + gui_send(GUI,"%s depth=%d time=%.2f node="S64_FORMAT" speed=%.0f score=%+.2f pv=\"%s\"",option_get_string("KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,double(Uci->best_score)/100.0,pv_string); + + } else if (State->state == PONDER) { + + game_get_board(Game,board); + move = State->exp_move; + + if (move != MoveNone && move_is_legal(move,board)) { + move_to_san(move,board,move_string,256); + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + gui_send(GUI,"%s depth=%d time=%.2f node="S64_FORMAT" speed=%.0f score=%+.2f pv=\"(%s) %s\"",option_get_string("KibitzCommand"),Uci->best_depth,Uci->time,Uci->node_nb,Uci->speed,double(Uci->best_score)/100.0,move_string,pv_string); + } + } + } +} + +// learn() + +static void learn(int result) { + + int pos; + board_t board[1]; + int move; + + ASSERT(result>=-1&&result<=+1); + + ASSERT(XB->result); + ASSERT(State->computer[White]||State->computer[Black]); + + // init + + pos = 0; + + if (false) { + } else if (State->computer[White]) { + pos = 0; + } else if (State->computer[Black]) { + pos = 1; + result = -result; + } else { + my_fatal("learn(): unknown side\n"); + } + + if (false) { + } else if (result > 0) { + my_log("POLYGLOT *LEARN WIN*\n"); + } else if (result < 0) { + my_log("POLYGLOT *LEARN LOSS*\n"); + } else { + my_log("POLYGLOT *LEARN DRAW*\n"); + } + + // loop + + for (; pos < Game->size; pos += 2) { + + game_get_board(Game,board,pos); + move = game_move(Game,pos); + + book_learn_move(board,move,result); + } + + book_flush(); +} + +// end of adapter.cpp diff --git a/xboard2uci.h b/xboard2uci.h new file mode 100644 index 0000000..bea161a --- /dev/null +++ b/xboard2uci.h @@ -0,0 +1,28 @@ + +// xboard2uci.h + +#ifndef XBOARD2UCI_H +#define XBOARD2UCI_H + +// 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[]); + +#endif // !defined XBOARD2UCI_H + +// end of xboard2uci.h + -- 1.7.0.4