version 1.4.30b
authorH.G. Muller <h.g.muller@hccnet.nl>
Thu, 9 Jun 2011 07:52:55 +0000 (09:52 +0200)
committerH.G. Muller <h.g.muller@hccnet.nl>
Thu, 9 Jun 2011 07:52:55 +0000 (09:52 +0200)
64 files changed:
ChangeLog
Makefile.am
Makefile.in
attack.c [new file with mode: 0644]
attack.h
board.c [new file with mode: 0644]
board.h
book.c [new file with mode: 0644]
book_make.c [new file with mode: 0644]
book_merge.c [new file with mode: 0644]
colour.c [new file with mode: 0644]
colour.h
config.h
configure
configure.ac
engine.c [new file with mode: 0644]
engine.h
epd.c [new file with mode: 0644]
fen.c [new file with mode: 0644]
game.c [new file with mode: 0644]
game.h
gui.c [new file with mode: 0644]
gui.h
hash.c [new file with mode: 0644]
hash.h
io.c [new file with mode: 0644]
io.h
line.c [new file with mode: 0644]
line.h
list.c [new file with mode: 0644]
list.h
main.c [new file with mode: 0644]
mainloop.c [new file with mode: 0644]
makefile.gcc
move.c [new file with mode: 0644]
move.h
move_do.c [new file with mode: 0644]
move_gen.c [new file with mode: 0644]
move_legal.c [new file with mode: 0644]
option.c [new file with mode: 0644]
option.h
parse.c [new file with mode: 0644]
parse.h
pgn.c [new file with mode: 0644]
pgn.h
piece.c [new file with mode: 0644]
piece.h
pipex.h [new file with mode: 0644]
pipex_posix.c [new file with mode: 0644]
pipex_win32.c [new file with mode: 0644]
polyglot.spec
random.c [new file with mode: 0644]
random.h
san.c [new file with mode: 0644]
search.c [new file with mode: 0644]
search.h
square.c [new file with mode: 0644]
square.h
uci.c [new file with mode: 0644]
uci.h
uci2uci.c [new file with mode: 0644]
util.c [new file with mode: 0644]
util.h
xboard2uci.c [new file with mode: 0644]

index 5198de5..ba23d6d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+=========1.4.30b================\r
+- Some more meaningful error messages added.\r
+- Some buffer overflow checks added.\r
+- Simplification of strange signal kludge in gui.c. \r
+- Removal of obsolete code in engine.c and gui.c. Platform specific code has been abstracted and pushed into pipex_win32.c and pipex_posix.c\r
+- The format of the version number has changed once again. Debian was unhappy with the previous one.\r
+=========1.4b29================\r
+- Conversion from C++ to C (suggested by E.M.)\r
+- More refactoring. The win32 and posix I/O now have a uniform interface (see pipex.h). \r
+=========1.4b28================\r
+- Some comments added to explain the exact behaviour of some of the public functions in pipe.cpp. \r
+- LineInput now returns a bool which is FALSE in case of EOF. \r
 =========1.4b27================\r
 - Option "ScoreWhite" : report score from white's point of view (suggested by E.M.).\r
 - Option "KibitzInterval" : try to wait this many seconds between kibitzes (suggested by E.M.)\r
index 251418c..6fc2377 100644 (file)
@@ -2,7 +2,7 @@
 #AM_CXXFLAGS=-g
 
 bin_PROGRAMS = polyglot
-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
+polyglot_SOURCES = mainloop.c attack.c board.c book.c book_make.c book_merge.c colour.c  engine.c epd.c fen.c gui.c game.c hash.c io.c line.c list.c main.c move.c move_do.c move_gen.c move_legal.c option.c parse.c pgn.c piece.c pipex_posix.c pipex_win32.c random.c san.c search.c square.c uci.c uci2uci.c util.c xboard2uci.c mainloop.h colour.h hash.h move_gen.h piece.h uci2uci.h attack.h config.h gui.h io.h move.h pipex.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
 
index 0db7deb..131f851 100644 (file)
@@ -61,20 +61,15 @@ am_polyglot_OBJECTS = mainloop.$(OBJEXT) attack.$(OBJEXT) \
        hash.$(OBJEXT) io.$(OBJEXT) line.$(OBJEXT) list.$(OBJEXT) \
        main.$(OBJEXT) move.$(OBJEXT) move_do.$(OBJEXT) \
        move_gen.$(OBJEXT) move_legal.$(OBJEXT) option.$(OBJEXT) \
-       parse.$(OBJEXT) pgn.$(OBJEXT) piece.$(OBJEXT) pipe.$(OBJEXT) \
-       posix.$(OBJEXT) random.$(OBJEXT) san.$(OBJEXT) \
-       search.$(OBJEXT) square.$(OBJEXT) uci.$(OBJEXT) \
+       parse.$(OBJEXT) pgn.$(OBJEXT) piece.$(OBJEXT) \
+       pipex_posix.$(OBJEXT) pipex_win32.$(OBJEXT) random.$(OBJEXT) \
+       san.$(OBJEXT) search.$(OBJEXT) square.$(OBJEXT) uci.$(OBJEXT) \
        uci2uci.$(OBJEXT) util.$(OBJEXT) xboard2uci.$(OBJEXT)
 polyglot_OBJECTS = $(am_polyglot_OBJECTS)
 polyglot_LDADD = $(LDADD)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
-CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
-       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
-CXXLD = $(CXX)
-CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
-       -o $@
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
        $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 CCLD = $(CC)
@@ -116,9 +111,6 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
-CXX = @CXX@
-CXXDEPMODE = @CXXDEPMODE@
-CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
@@ -156,7 +148,6 @@ abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
 abs_top_srcdir = @abs_top_srcdir@
 ac_ct_CC = @ac_ct_CC@
-ac_ct_CXX = @ac_ct_CXX@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -193,7 +184,7 @@ sysconfdir = @sysconfdir@
 target_alias = @target_alias@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-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
+polyglot_SOURCES = mainloop.c attack.c board.c book.c book_make.c book_merge.c colour.c  engine.c epd.c fen.c gui.c game.c hash.c io.c line.c list.c main.c move.c move_do.c move_gen.c move_legal.c option.c parse.c pgn.c piece.c pipex_posix.c pipex_win32.c random.c san.c search.c square.c uci.c uci2uci.c util.c xboard2uci.c mainloop.h colour.h hash.h move_gen.h piece.h uci2uci.h attack.h config.h gui.h io.h move.h pipex.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 makefile.ms 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
@@ -201,7 +192,7 @@ all: config.h
        $(MAKE) $(AM_MAKEFLAGS) all-am
 
 .SUFFIXES:
-.SUFFIXES: .cpp .o .obj
+.SUFFIXES: .c .o .obj
 am--refresh:
        @:
 $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
@@ -277,7 +268,7 @@ clean-binPROGRAMS:
        -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
 polyglot$(EXEEXT): $(polyglot_OBJECTS) $(polyglot_DEPENDENCIES) 
        @rm -f polyglot$(EXEEXT)
-       $(CXXLINK) $(polyglot_OBJECTS) $(polyglot_LDADD) $(LIBS)
+       $(LINK) $(polyglot_OBJECTS) $(polyglot_LDADD) $(LIBS)
 
 mostlyclean-compile:
        -rm -f *.$(OBJEXT)
@@ -310,8 +301,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgn.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/piece.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pipe.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pipex_posix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pipex_win32.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/san.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search.Po@am__quote@
@@ -321,19 +312,19 @@ distclean-compile:
 @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 $@ $<
-@am__fastdepCXX_TRUE@  mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
-
-.cpp.obj:
-@am__fastdepCXX_TRUE@  $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
-@am__fastdepCXX_TRUE@  mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+.c.o:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
 install-man6: $(man6_MANS) $(man_MANS)
        @$(NORMAL_INSTALL)
        test -z "$(man6dir)" || $(MKDIR_P) "$(DESTDIR)$(man6dir)"
diff --git a/attack.c b/attack.c
new file mode 100644 (file)
index 0000000..ecaa14a
--- /dev/null
+++ b/attack.c
@@ -0,0 +1,224 @@
+\r
+// attack.c\r
+\r
+// includes\r
+\r
+#include "board.h"\r
+#include "colour.h"\r
+#include "move.h"\r
+#include "attack.h"\r
+#include "piece.h"\r
+#include "util.h"\r
+\r
+// macros\r
+\r
+#define DELTA_INC(delta)  (DeltaInc[128+(delta)])\r
+#define DELTA_MASK(delta) (DeltaMask[128+(delta)])\r
+\r
+// "constants"\r
+\r
+const sint8 KnightInc[8+1] = {\r
+   -33, -31, -18, -14, +14, +18, +31, +33, 0\r
+};\r
+\r
+const sint8 BishopInc[4+1] = {\r
+   -17, -15, +15, +17, 0\r
+};\r
+\r
+const sint8 RookInc[4+1] = {\r
+   -16, -1, +1, +16, 0\r
+};\r
+\r
+const sint8 QueenInc[8+1] = {\r
+   -17, -16, -15, -1, +1, +15, +16, +17, 0\r
+};\r
+\r
+const sint8 KingInc[8+1] = {\r
+   -17, -16, -15, -1, +1, +15, +16, +17, 0\r
+};\r
+\r
+// variables\r
+\r
+static sint8 DeltaInc[256];\r
+static uint8 DeltaMask[256];\r
+\r
+// prototypes\r
+\r
+static bool delta_is_ok (int delta);\r
+static bool inc_is_ok   (int inc);\r
+\r
+// functions\r
+\r
+// attack_init()\r
+\r
+void attack_init() {\r
+\r
+   int delta;\r
+   int dir, inc, dist;\r
+\r
+   for (delta = -128; delta < +128; delta++) {\r
+      DeltaInc[128+delta] = IncNone;\r
+      DeltaMask[128+delta] = 0;\r
+   }\r
+\r
+   DeltaMask[128-17] |= BlackPawnFlag;\r
+   DeltaMask[128-15] |= BlackPawnFlag;\r
+\r
+   DeltaMask[128+15] |= WhitePawnFlag;\r
+   DeltaMask[128+17] |= WhitePawnFlag;\r
+\r
+   for (dir = 0; dir < 8; dir++) {\r
+      delta = KnightInc[dir];\r
+      ASSERT(delta_is_ok(delta));\r
+      DeltaMask[128+delta] |= KnightFlag;\r
+   }\r
+\r
+   for (dir = 0; dir < 4; dir++) {\r
+      inc = BishopInc[dir];\r
+      ASSERT(inc!=IncNone);\r
+      for (dist = 1; dist < 8; dist++) {\r
+         delta = inc*dist;\r
+         ASSERT(delta_is_ok(delta));\r
+         ASSERT(DeltaInc[128+delta]==IncNone);\r
+         DeltaInc[128+delta] = inc;\r
+         DeltaMask[128+delta] |= BishopFlag;\r
+      }\r
+   }\r
+\r
+   for (dir = 0; dir < 4; dir++) {\r
+      inc = RookInc[dir];\r
+      ASSERT(inc!=IncNone);\r
+      for (dist = 1; dist < 8; dist++) {\r
+         delta = inc*dist;\r
+         ASSERT(delta_is_ok(delta));\r
+         ASSERT(DeltaInc[128+delta]==IncNone);\r
+         DeltaInc[128+delta] = inc;\r
+         DeltaMask[128+delta] |= RookFlag;\r
+      }\r
+   }\r
+\r
+   for (dir = 0; dir < 8; dir++) {\r
+      delta = KingInc[dir];\r
+      ASSERT(delta_is_ok(delta));\r
+      DeltaMask[128+delta] |= KingFlag;\r
+   }\r
+}\r
+\r
+// delta_is_ok()\r
+\r
+static bool delta_is_ok(int delta) {\r
+\r
+   if (delta < -119 || delta > +119) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// inc_is_ok()\r
+\r
+static bool inc_is_ok(int inc) {\r
+\r
+   int dir;\r
+\r
+   for (dir = 0; dir < 8; dir++) {\r
+      if (KingInc[dir] == inc) return TRUE;\r
+   }\r
+\r
+   return FALSE;\r
+}\r
+\r
+// is_in_check()\r
+\r
+bool is_in_check(const board_t * board, int colour) {\r
+\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(colour_is_ok(colour));\r
+\r
+   return is_attacked(board,king_pos(board,colour),colour_opp(colour));\r
+}\r
+\r
+// is_attacked()\r
+\r
+bool is_attacked(const board_t * board, int to, int colour) {\r
+\r
+   const uint8 * ptr;\r
+   int from, piece;\r
+\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(square_is_ok(to));\r
+   ASSERT(colour_is_ok(colour));\r
+\r
+   for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) {\r
+\r
+      piece = board->square[from];\r
+      ASSERT(colour_equal(piece,colour));\r
+\r
+      if (piece_attack(board,piece,from,to)) return TRUE;\r
+   }\r
+\r
+   return FALSE;\r
+}\r
+\r
+// piece_attack()\r
+\r
+bool piece_attack(const board_t * board, int piece, int from, int to) {\r
+\r
+   int delta;\r
+   int inc, sq;\r
+\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(piece_is_ok(piece));\r
+   ASSERT(square_is_ok(from));\r
+   ASSERT(square_is_ok(to));\r
+\r
+   delta = to - from;\r
+   ASSERT(delta_is_ok(delta));\r
+\r
+   if ((piece & DELTA_MASK(delta)) == 0) return FALSE; // no pseudo-attack\r
+\r
+   if (!piece_is_slider(piece)) return TRUE;\r
+\r
+   inc = DELTA_INC(delta);\r
+   ASSERT(inc_is_ok(inc));\r
+\r
+   for (sq = from+inc; sq != to; sq += inc) {\r
+      ASSERT(square_is_ok(sq));\r
+      if (board->square[sq] != Empty) return FALSE; // blocker\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+// is_pinned()\r
+\r
+bool is_pinned(const board_t * board, int from, int to, int colour) {\r
+\r
+   int king;\r
+   int inc;\r
+   int sq, piece;\r
+\r
+   ASSERT(board!=NULL);\r
+   ASSERT(square_is_ok(from));\r
+   ASSERT(square_is_ok(to));\r
+   ASSERT(colour_is_ok(colour));\r
+\r
+   king = king_pos(board,colour);\r
+\r
+   inc = DELTA_INC(king-from);\r
+   if (inc == IncNone) return FALSE; // not a line\r
+\r
+   sq = from;\r
+   do sq += inc; while (board->square[sq] == Empty);\r
+\r
+   if (sq != king) return FALSE; // blocker\r
+\r
+   sq = from;\r
+   do sq -= inc; while ((piece=board->square[sq]) == Empty);\r
+\r
+   return square_is_ok(sq)\r
+       && (piece & DELTA_MASK(king-sq)) != 0\r
+       && piece_colour(piece) == colour_opp(colour)\r
+       && DELTA_INC(king-to) != inc;\r
+}\r
+\r
+// end of attack.cpp\r
+\r
index 7e664a6..c111cdc 100644 (file)
--- a/attack.h
+++ b/attack.h
@@ -9,9 +9,9 @@
 #include "board.h"\r
 #include "util.h"\r
 \r
-// constants\r
+// defines \r
 \r
-const int IncNone = 0;\r
+#define IncNone 0\r
 \r
 // "constants"\r
 \r
diff --git a/board.c b/board.c
new file mode 100644 (file)
index 0000000..b17d354
--- /dev/null
+++ b/board.c
@@ -0,0 +1,492 @@
+\r
+// board.c\r
+\r
+// includes\r
+\r
+#include <stdio.h>\r
+\r
+#include "attack.h"\r
+#include "board.h"\r
+#include "colour.h"\r
+#include "fen.h"\r
+#include "hash.h"\r
+#include "list.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_gen.h"\r
+#include "move_legal.h"\r
+#include "piece.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const bool UseSlowDebug = FALSE;\r
+\r
+// functions\r
+\r
+// board_is_ok()\r
+\r
+bool board_is_ok(const board_t * board) {\r
+\r
+   int sq, piece;\r
+   int colour, pos;\r
+   int king, rook;\r
+\r
+   if (board == NULL) return FALSE;\r
+\r
+   // optional heavy DEBUG mode\r
+\r
+   if (!UseSlowDebug) return TRUE;\r
+\r
+   // squares\r
+\r
+   for (sq = 0; sq < SquareNb; sq++) {\r
+      piece = board->square[sq];\r
+      if (square_is_ok(sq)) {\r
+         pos = board->pos[sq];\r
+         if (piece == Empty) {\r
+            if (pos != -1) return FALSE;\r
+         } else {\r
+            if (pos < 0) return FALSE;\r
+            if (board->list[piece_colour(piece)][pos] != sq) return FALSE;\r
+         }\r
+      } else {\r
+         if (piece != Knight64) return FALSE;\r
+      }\r
+   }\r
+\r
+   // white piece list\r
+\r
+   colour = White;\r
+   pos = 0;\r
+\r
+   if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return FALSE;\r
+\r
+   sq = board->list[colour][pos];\r
+   if (sq == SquareNone) return FALSE;\r
+   if (board->pos[sq] != pos) return FALSE;\r
+   piece = board->square[sq];\r
+   if (!colour_equal(piece,colour) || !piece_is_king(piece)) return FALSE;\r
+\r
+   for (pos++; pos < board->list_size[colour]; pos++) {\r
+      sq = board->list[colour][pos];\r
+      if (sq == SquareNone) return FALSE;\r
+      if (board->pos[sq] != pos) return FALSE;\r
+      if (!colour_equal(board->square[sq],colour)) return FALSE;\r
+   }\r
+\r
+   sq = board->list[colour][pos];\r
+   if (sq != SquareNone) return FALSE;\r
+\r
+   // black piece list\r
+\r
+   colour = Black;\r
+   pos = 0;\r
+\r
+   if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return FALSE;\r
+\r
+   sq = board->list[colour][pos];\r
+   if (sq == SquareNone) return FALSE;\r
+   if (board->pos[sq] != pos) return FALSE;\r
+   piece = board->square[sq];\r
+   if (!colour_equal(piece,colour) || !piece_is_king(piece)) return FALSE;\r
+\r
+   for (pos++; pos < board->list_size[colour]; pos++) {\r
+      sq = board->list[colour][pos];\r
+      if (sq == SquareNone) return FALSE;\r
+      if (board->pos[sq] != pos) return FALSE;\r
+      if (!colour_equal(board->square[sq],colour)) return FALSE;\r
+   }\r
+\r
+   sq = board->list[colour][pos];\r
+   if (sq != SquareNone) return FALSE;\r
+\r
+   // TODO: material\r
+\r
+   if (board->number[WhiteKing12] != 1) return FALSE;\r
+   if (board->number[BlackKing12] != 1) return FALSE;\r
+\r
+   if (!colour_is_ok(board->turn)) return FALSE;\r
+\r
+   // castling status\r
+\r
+   if (board->castle[White][SideH] != SquareNone) {\r
+\r
+      king = board->list[White][0];\r
+      if ((king < A1) || (king > H1)) return FALSE;\r
+      if (board->square[king] != WhiteKing256) return FALSE;\r
+\r
+      rook = board->castle[White][SideH];\r
+      if ((rook < A1) || (rook > H1)) return FALSE;\r
+      if (board->square[rook] != WhiteRook256) return FALSE;\r
+\r
+      if (rook <= king) return FALSE;\r
+   }\r
+\r
+   if (board->castle[White][SideA] != SquareNone) {\r
+\r
+      king = board->list[White][0];\r
+      if ((king < A1) || (king > H1)) return FALSE;\r
+      if (board->square[king] != WhiteKing256) return FALSE;\r
+\r
+      rook = board->castle[White][SideA];\r
+      if ((rook < A1) || (rook > H1)) return FALSE;\r
+      if (board->square[rook] != WhiteRook256) return FALSE;\r
+\r
+      if (rook >= king) return FALSE;\r
+   }\r
+\r
+   if (board->castle[Black][SideH] != SquareNone) {\r
+\r
+      king = board->list[Black][0];\r
+      if ((king < A8) || (king > H8)) return FALSE;\r
+      if (board->square[king] != BlackKing256) return FALSE;\r
+\r
+      rook = board->castle[Black][SideH];\r
+      if ((rook < A8) || (rook > H8)) return FALSE;\r
+      if (board->square[rook] != BlackRook256) return FALSE;\r
+\r
+      if (rook <= king) return FALSE;\r
+   }\r
+\r
+   if (board->castle[Black][SideA] != SquareNone) {\r
+\r
+      king = board->list[Black][0];\r
+      if (king < A8 || king > H8) return FALSE;\r
+      if (board->square[king] != BlackKing256) return FALSE;\r
+\r
+      rook = board->castle[Black][SideA];\r
+      if (rook < A8 || rook > H8) return FALSE;\r
+      if (board->square[rook] != BlackRook256) return FALSE;\r
+\r
+      if (rook >= king) return FALSE;\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+// board_clear()\r
+\r
+void board_clear(board_t * board) {\r
+\r
+   int file, rank, sq;\r
+   int colour, pos;\r
+   int piece;\r
+\r
+   ASSERT(board!=NULL);\r
+\r
+   // edge squares\r
+\r
+   for (sq = 0; sq < SquareNb; sq++) {\r
+      board->square[sq] = Knight64; // HACK: uncoloured knight\r
+      board->pos[sq] = -1;\r
+   }\r
+\r
+   // empty squares\r
+\r
+   for (rank = 0; rank < 8; rank++) {\r
+      for (file = 0; file < 8; file++) {\r
+         sq = square_make(file,rank);\r
+         board->square[sq] = Empty;\r
+      }\r
+   }\r
+\r
+   // piece lists\r
+\r
+   for (colour = 0; colour < 3; colour++) {\r
+      for (pos = 0; pos < 32; pos++) { // HACK\r
+         board->list[colour][pos] = SquareNone;\r
+      }\r
+      board->list_size[colour] = 0;\r
+   }\r
+\r
+   // material\r
+\r
+   for (piece = 0; piece < 12; piece++) {\r
+      board->number[piece] = 0;\r
+   }\r
+\r
+   // rest\r
+\r
+   board->turn = ColourNone;\r
+   board->castle[White][SideH] = SquareNone;\r
+   board->castle[White][SideA] = SquareNone;\r
+   board->castle[Black][SideH] = SquareNone;\r
+   board->castle[Black][SideA] = SquareNone;\r
+   board->ep_square = SquareNone;\r
+\r
+   board->ply_nb = 0;\r
+   board->move_nb = 0;\r
+\r
+   board->key = 0;\r
+}\r
+\r
+// board_start()\r
+\r
+void board_start(board_t * board) {\r
+\r
+   ASSERT(board!=NULL);\r
+\r
+   if (!board_from_fen(board,StartFen)) ASSERT(FALSE);\r
+}\r
+\r
+// board_copy()\r
+\r
+void board_copy(board_t * dst, const board_t * src) {\r
+\r
+   ASSERT(dst!=NULL);\r
+   ASSERT(board_is_ok(src));\r
+\r
+   *dst = *src;\r
+}\r
+\r
+// board_equal()\r
+\r
+bool board_equal(const board_t * board_1, const board_t * board_2) {\r
+\r
+   int sq_64, sq;\r
+\r
+   ASSERT(board_is_ok(board_1));\r
+   ASSERT(board_is_ok(board_2));\r
+\r
+   // fast comparison\r
+\r
+   if (board_1->key != board_2->key) return FALSE;\r
+\r
+   // slow comparison\r
+\r
+   for (sq_64 = 0; sq_64 < 64; sq_64++) {\r
+      sq = square_from_64(sq_64);\r
+      if (board_1->square[sq] != board_2->square[sq]) return FALSE;\r
+   }\r
+\r
+   if (board_1->turn != board_2->turn) return FALSE;\r
+   if (board_1->castle[White][SideH] != board_2->castle[White][SideH]) return FALSE;\r
+   if (board_1->castle[White][SideA] != board_2->castle[White][SideA]) return FALSE;\r
+   if (board_1->castle[Black][SideH] != board_2->castle[Black][SideH]) return FALSE;\r
+   if (board_1->castle[Black][SideA] != board_2->castle[Black][SideA]) return FALSE;\r
+   if (board_1->ep_square != board_2->ep_square) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// board_init_list()\r
+\r
+void board_init_list(board_t * board) {\r
+\r
+   int sq_64, sq, piece;\r
+   int colour, pos;\r
+\r
+   ASSERT(board!=NULL);\r
+\r
+   // init\r
+\r
+   for (sq_64 = 0; sq_64 < 64; sq_64++) {\r
+      sq = square_from_64(sq_64);\r
+      board->pos[sq] = -1;\r
+   }\r
+\r
+   for (piece = 0; piece < 12; piece++) board->number[piece] = 0;\r
+\r
+   // white piece list\r
+\r
+   colour = White;\r
+   pos = 0;\r
+\r
+   for (sq_64 = 0; sq_64 < 64; sq_64++) {\r
+      sq = square_from_64(sq_64);\r
+      piece = board->square[sq];\r
+      ASSERT(pos>=0&&pos<=16);\r
+      if (colour_equal(piece,colour) && piece_is_king(piece)) {\r
+         board->pos[sq] = pos;\r
+         board->list[colour][pos] = sq;\r
+         pos++;\r
+         board->number[piece_to_12(piece)]++;\r
+      }\r
+   }\r
+   ASSERT(pos==1);\r
+\r
+   for (sq_64 = 0; sq_64 < 64; sq_64++) {\r
+      sq = square_from_64(sq_64);\r
+      piece = board->square[sq];\r
+      ASSERT(pos>=0&&pos<=16);\r
+      if (colour_equal(piece,colour) && !piece_is_king(piece)) {\r
+         board->pos[sq] = pos;\r
+         board->list[colour][pos] = sq;\r
+         pos++;\r
+         board->number[piece_to_12(piece)]++;\r
+      }\r
+   }\r
+\r
+   ASSERT(pos>=1&&pos<=16);\r
+   board->list[colour][pos] = SquareNone;\r
+   board->list_size[colour] = pos;\r
+\r
+   // black piece list\r
+\r
+   colour = Black;\r
+   pos = 0;\r
+\r
+   for (sq_64 = 0; sq_64 < 64; sq_64++) {\r
+      sq = square_from_64(sq_64);\r
+      piece = board->square[sq];\r
+      ASSERT(pos>=0&&pos<=16);\r
+      if (colour_equal(piece,colour) && piece_is_king(piece)) {\r
+         board->pos[sq] = pos;\r
+         board->list[colour][pos] = sq;\r
+         pos++;\r
+         board->number[piece_to_12(piece)]++;\r
+      }\r
+   }\r
+   ASSERT(pos==1);\r
+\r
+   for (sq_64 = 0; sq_64 < 64; sq_64++) {\r
+      sq = square_from_64(sq_64);\r
+      piece = board->square[sq];\r
+      ASSERT(pos>=1&&pos<=16);\r
+      if (colour_equal(piece,colour) && !piece_is_king(piece)) {\r
+         board->pos[sq] = pos;\r
+         board->list[colour][pos] = sq;\r
+         pos++;\r
+         board->number[piece_to_12(piece)]++;\r
+      }\r
+   }\r
+\r
+   ASSERT(pos>=1&&pos<=16);\r
+   board->list[colour][pos] = SquareNone;\r
+   board->list_size[colour] = pos;\r
+\r
+   // hash key\r
+\r
+   board->key = hash_key(board);\r
+}\r
+\r
+// board_flags()\r
+\r
+int board_flags(const board_t * board) {\r
+\r
+   int flags;\r
+\r
+   flags = 0;\r
+\r
+   if (board->castle[White][SideH] != SquareNone) flags |= 1 << 0;\r
+   if (board->castle[White][SideA] != SquareNone) flags |= 1 << 1;\r
+   if (board->castle[Black][SideH] != SquareNone) flags |= 1 << 2;\r
+   if (board->castle[Black][SideA] != SquareNone) flags |= 1 << 3;\r
+\r
+   return flags;\r
+}\r
+\r
+// board_can_play()\r
+\r
+bool board_can_play(const board_t * board) {\r
+\r
+   list_t list[1];\r
+   int i, move;\r
+\r
+   ASSERT(board_is_ok(board));\r
+\r
+   gen_moves(list,board);\r
+\r
+   for (i = 0; i < list_size(list); i++) {\r
+      move = list_move(list,i);\r
+      if (pseudo_is_legal(move,board)) return TRUE;\r
+   }\r
+\r
+   return FALSE; // no legal move\r
+}\r
+\r
+// board_mobility()\r
+\r
+int board_mobility(const board_t * board) {\r
+\r
+   list_t list[1];\r
+\r
+   ASSERT(board_is_ok(board));\r
+\r
+   gen_legal_moves(list,board);\r
+\r
+   return list_size(list);\r
+}\r
+\r
+// board_is_check()\r
+\r
+bool board_is_check(const board_t * board) {\r
+\r
+   ASSERT(board_is_ok(board));\r
+\r
+   return is_in_check(board,board->turn);\r
+}\r
+\r
+// board_is_mate()\r
+\r
+bool board_is_mate(const board_t * board) {\r
+\r
+   ASSERT(board_is_ok(board));\r
+\r
+   if (!board_is_check(board)) return FALSE;\r
+   if (board_can_play(board)) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// board_is_stalemate()\r
+\r
+bool board_is_stalemate(const board_t * board) {\r
+\r
+   ASSERT(board_is_ok(board));\r
+\r
+   if (board_is_check(board)) return FALSE;\r
+   if (board_can_play(board)) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// king_pos()\r
+\r
+int king_pos(const board_t * board, int colour) {\r
+\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(colour_is_ok(colour));\r
+\r
+   return board->list[colour][0];\r
+}\r
+\r
+// board_disp()\r
+\r
+void board_disp(const board_t * board) {\r
+\r
+   int file, rank, sq;\r
+   int piece, c;\r
+   char fen[256];\r
+\r
+   ASSERT(board!=NULL);\r
+\r
+   if (!board_to_fen(board,fen,256)) ASSERT(FALSE);\r
+   my_log("POLYGLOT %s\n",fen);\r
+   my_log("POLYGLOT\n");\r
+\r
+   for (rank = 7; rank >= 0; rank--) {\r
+\r
+      my_log("POLYGLOT ");\r
+\r
+      for (file = 0; file < 8; file++) {\r
+\r
+         sq = square_make(file,rank);\r
+         piece = board->square[sq];\r
+\r
+         c = (piece != Empty) ? piece_to_char(piece) : '-';\r
+         my_log("%c ",c);\r
+      }\r
+\r
+      my_log("\n");\r
+   }\r
+\r
+   my_log("POLYGLOT\n");\r
+\r
+   my_log("POLYGLOT %s to play\n",(colour_is_black(board->turn))?"black":"white");\r
+   my_log("POLYGLOT\n");\r
+}\r
+\r
+// end of board.cpp\r
+\r
diff --git a/board.h b/board.h
index 9a9a503..4223e83 100644 (file)
--- a/board.h
+++ b/board.h
 #include "square.h"\r
 #include "util.h"\r
 \r
-// constants\r
+// defines\r
 \r
-const int Empty = 0;\r
-\r
-const int SideH = 0;\r
-const int SideA = 1;\r
-const int SideNb = 2;\r
+#define Empty  0\r
+#define SideH  0\r
+#define SideA  1\r
+#define SideNb 2\r
 \r
 // types\r
 \r
-struct board_t {\r
+typedef struct {\r
 \r
    uint8 square[SquareNb];\r
    sint8 pos[SquareNb];\r
@@ -38,7 +37,7 @@ struct board_t {
    sint16 move_nb;\r
 \r
    uint64 key;\r
-};\r
+} board_t;\r
 \r
 // functions\r
 \r
diff --git a/book.c b/book.c
new file mode 100644 (file)
index 0000000..73fb2d2
--- /dev/null
+++ b/book.c
@@ -0,0 +1,384 @@
+\r
+// book.c\r
+\r
+// includes\r
+\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "board.h"\r
+#include "book.h"\r
+#include "move.h"\r
+#include "move_legal.h"\r
+#include "san.h"\r
+#include "util.h"\r
+#include "option.h"\r
+\r
+// types\r
+\r
+typedef struct {\r
+   uint64 key;\r
+   uint16 move;\r
+   uint16 count;\r
+   uint16 n;\r
+   uint16 sum;\r
+} entry_t;\r
+\r
+// variables\r
+\r
+static FILE * BookFile;\r
+static int BookSize;\r
+\r
+// prototypes\r
+\r
+static int    find_pos      (uint64 key);\r
+\r
+static void   read_entry    (entry_t * entry, int n);\r
+static void   write_entry   (const entry_t * entry, int n);\r
+\r
+static uint64 read_integer  (FILE * file, int size);\r
+static void   write_integer (FILE * file, int size, uint64 n);\r
+\r
+// functions\r
+\r
+// book_clear()\r
+\r
+void book_clear() {\r
+\r
+   BookFile = NULL;\r
+   BookSize = 0;\r
+}\r
+\r
+bool book_is_open(){\r
+    return BookFile!=NULL;\r
+}\r
+\r
+// book_open()\r
+\r
+void book_open(const char file_name[]) {\r
+\r
+   ASSERT(file_name!=NULL);\r
+   if(option_get_bool("BookLearn")){\r
+       BookFile = fopen(file_name,"rb+");\r
+   }else{\r
+       BookFile = fopen(file_name,"rb");\r
+   }\r
+      \r
+//   if (BookFile == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno));\r
+   if (BookFile == NULL)  return; \r
+\r
+   if (fseek(BookFile,0,SEEK_END) == -1) {\r
+      my_fatal("book_open(): fseek(): %s\n",strerror(errno));\r
+   }\r
+\r
+   BookSize = ftell(BookFile) / 16;\r
+//   if (BookSize == 0) my_fatal("book_open(): empty file\n");\r
+   if (BookSize == 0) {\r
+      book_close();\r
+      book_clear(); \r
+   };\r
+}\r
+\r
+// book_close()\r
+\r
+void book_close() {\r
+\r
+   if(BookFile==NULL) return;\r
+\r
+   if (fclose(BookFile) == EOF) {\r
+      my_fatal("book_close(): fclose(): %s\n",strerror(errno));\r
+   }\r
+}\r
+\r
+// is_in_book()\r
+\r
+bool is_in_book(const board_t * board) {\r
+\r
+   int pos;\r
+   entry_t entry[1];\r
+\r
+   if(BookFile==NULL) return FALSE;\r
+\r
+   ASSERT(board!=NULL);\r
+\r
+   for (pos = find_pos(board->key); pos < BookSize; pos++) {\r
+      read_entry(entry,pos);\r
+      if (entry->key == board->key) return TRUE;\r
+   }\r
+\r
+   return FALSE;\r
+}\r
+\r
+// book_move()\r
+\r
+int book_move(const board_t * board, bool random) {\r
+\r
+   int best_move;\r
+   int best_score;\r
+   int pos;\r
+   entry_t entry[1];\r
+   int move;\r
+   int score;\r
+\r
+   if(BookFile==NULL) return MoveNone;\r
+\r
+   ASSERT(board!=NULL);\r
+   ASSERT(random==TRUE||random==FALSE);\r
+\r
+\r
+   best_move = MoveNone;\r
+   best_score = 0;\r
+   for (pos = find_pos(board->key); pos < BookSize; pos++) {\r
+\r
+      read_entry(entry,pos);\r
+      if (entry->key != board->key) break;\r
+\r
+      move = entry->move;\r
+      score = entry->count;\r
+\r
+      if (move != MoveNone && move_is_legal(move,board)) {\r
+\r
+         // pick this move?\r
+\r
+         ASSERT(score>0);\r
+\r
+         if (random) {\r
+            best_score += score;\r
+            if (my_random_int(best_score) < score) best_move = move;\r
+         } else {\r
+            if (score > best_score) {\r
+               best_move = move;\r
+               best_score = score;\r
+            }\r
+         }\r
+\r
+      } else {\r
+\r
+         ASSERT(FALSE);\r
+      }\r
+   }\r
+\r
+   return best_move;\r
+}\r
+\r
+// book_disp()\r
+\r
+void book_disp(const board_t * board) {\r
+\r
+   int first_pos;\r
+   int sum;\r
+   int pos;\r
+   entry_t entry[1];\r
+   int move;\r
+   int score;\r
+   char move_string[256];\r
+\r
+   ASSERT(board!=NULL);\r
+\r
+   if(BookFile==NULL) return; \r
+\r
+   first_pos = find_pos(board->key);\r
+\r
+   // sum\r
+\r
+   sum = 0;\r
+\r
+   for (pos = first_pos; pos < BookSize; pos++) {\r
+\r
+      read_entry(entry,pos);\r
+      if (entry->key != board->key) break;\r
+\r
+      sum += entry->count;\r
+   }\r
+\r
+   // disp\r
+\r
+   for (pos = first_pos; pos < BookSize; pos++) {\r
+\r
+      read_entry(entry,pos);\r
+      if (entry->key != board->key) break;\r
+\r
+      move = entry->move;\r
+      score = entry->count;\r
+\r
+      if (score > 0 && move != MoveNone && move_is_legal(move,board)) {\r
+         move_to_san(move,board,move_string,256);\r
+         printf(" %s (%.0f%%)\n",move_string,((double)score)/((double)sum)*100.0);\r
+      }\r
+   }\r
+\r
+   printf("\n");\r
+}\r
+\r
+// book_learn_move()\r
+\r
+void book_learn_move(const board_t * board, int move, int result) {\r
+\r
+   int pos;\r
+   entry_t entry[1];\r
+\r
+   if(BookFile==NULL) return;\r
+\r
+   ASSERT(board!=NULL);\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(result>=-1&&result<=+1);\r
+\r
+   ASSERT(move_is_legal(move,board));\r
+\r
+   for (pos = find_pos(board->key); pos < BookSize; pos++) {\r
+\r
+      read_entry(entry,pos);\r
+      if (entry->key != board->key) break;\r
+\r
+      if (entry->move == move) {\r
+\r
+         entry->n++;\r
+         entry->sum += result+1;\r
+\r
+         write_entry(entry,pos);\r
+\r
+         break;\r
+      }\r
+   }\r
+}\r
+\r
+// book_flush()\r
+\r
+void book_flush() {\r
+\r
+   if(BookFile==NULL) return;\r
+\r
+   if (fflush(BookFile) == EOF) {\r
+      my_fatal("book_flush(): fflush(): %s\n",strerror(errno));\r
+   }\r
+}\r
+\r
+// find_pos()\r
+\r
+static int find_pos(uint64 key) {\r
+\r
+   int left, right, mid;\r
+   entry_t entry[1];\r
+\r
+   // binary search (finds the leftmost entry)\r
+\r
+   left = 0;\r
+   right = BookSize-1;\r
+\r
+   ASSERT(left<=right);\r
+\r
+   while (left < right) {\r
+\r
+      mid = (left + right) / 2;\r
+      ASSERT(mid>=left&&mid<right);\r
+\r
+      read_entry(entry,mid);\r
+\r
+      if (key <= entry->key) {\r
+         right = mid;\r
+      } else {\r
+         left = mid+1;\r
+      }\r
+   }\r
+\r
+   ASSERT(left==right);\r
+\r
+   read_entry(entry,left);\r
+\r
+   return (entry->key == key) ? left : BookSize;\r
+}\r
+\r
+// read_entry()\r
+\r
+static void read_entry(entry_t * entry, int n) {\r
+\r
+   ASSERT(entry!=NULL);\r
+   ASSERT(n>=0&&n<BookSize);\r
+\r
+   if (fseek(BookFile,n*16,SEEK_SET) == -1) {\r
+      my_fatal("read_entry(): fseek(): %s\n",strerror(errno));\r
+   }\r
+\r
+   entry->key   = read_integer(BookFile,8);\r
+   entry->move  = read_integer(BookFile,2);\r
+   entry->count = read_integer(BookFile,2);\r
+   entry->n     = read_integer(BookFile,2);\r
+   entry->sum   = read_integer(BookFile,2);\r
+}\r
+\r
+// write_entry()\r
+\r
+static void write_entry(const entry_t * entry, int n) {\r
+\r
+   ASSERT(entry!=NULL);\r
+   ASSERT(n>=0&&n<BookSize);\r
+\r
+   if (fseek(BookFile,n*16,SEEK_SET) == -1) {\r
+      my_fatal("write_entry(): fseek(): %s\n",strerror(errno));\r
+   }\r
+\r
+   write_integer(BookFile,8,entry->key);\r
+   write_integer(BookFile,2,entry->move);\r
+   write_integer(BookFile,2,entry->count);\r
+   write_integer(BookFile,2,entry->n);\r
+   write_integer(BookFile,2,entry->sum);\r
+}\r
+\r
+// read_integer()\r
+\r
+static uint64 read_integer(FILE * file, int size) {\r
+\r
+   uint64 n;\r
+   int i;\r
+   int b;\r
+\r
+   ASSERT(file!=NULL);\r
+   ASSERT(size>0&&size<=8);\r
+\r
+   n = 0;\r
+\r
+   for (i = 0; i < size; i++) {\r
+\r
+      b = fgetc(file);\r
+\r
+      if (b == EOF) {\r
+         if (feof(file)) {\r
+            my_fatal("read_integer(): fgetc(): EOF reached\n");\r
+         } else { // error\r
+            my_fatal("read_integer(): fgetc(): %s\n",strerror(errno));\r
+         }\r
+      }\r
+\r
+      ASSERT(b>=0&&b<256);\r
+      n = (n << 8) | b;\r
+   }\r
+\r
+   return n;\r
+}\r
+\r
+// write_integer()\r
+\r
+static void write_integer(FILE * file, int size, uint64 n) {\r
+\r
+   int i;\r
+   int b;\r
+\r
+   ASSERT(file!=NULL);\r
+   ASSERT(size>0&&size<=8);\r
+   ASSERT(size==8||n>>(size*8)==0);\r
+\r
+   for (i = size-1; i >= 0; i--) {\r
+\r
+      b = (n >> (i*8)) & 0xFF;\r
+      ASSERT(b>=0&&b<256);\r
+\r
+      if (fputc(b,file) == EOF) {\r
+         my_fatal("write_integer(): fputc(): %s\n",strerror(errno));\r
+      }\r
+   }\r
+}\r
+\r
+// end of book.cpp\r
+\r
diff --git a/book_make.c b/book_make.c
new file mode 100644 (file)
index 0000000..ac9a66c
--- /dev/null
@@ -0,0 +1,1084 @@
+// book_make.c\r
+\r
+// includes\r
+\r
+#include <errno.h>\r
+#include <math.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "board.h"\r
+#include "book_make.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_gen.h"\r
+#include "move_legal.h"\r
+#include "pgn.h"\r
+#include "san.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const int COUNT_MAX = 16384;\r
+static const int StringSize = 4096;\r
+\r
+static const int NIL = -1;\r
+\r
+// defines\r
+\r
+#define opp_search(s) ((s)==BOOK?ALL:BOOK)\r
+\r
+// types\r
+\r
+typedef struct {\r
+    uint64 key;\r
+    uint16 move;\r
+    uint16 count;\r
+// Unfortunately the minggw32 cross compiler [4.2.1-sjlj (mingw32-2)] \r
+// seems to have a bug with anon structs contained in unions when using -O2.\r
+// See the ASSERT below in "read_entry_file"...\r
+// To be fair this seems to be illegal in C++\r
+// although it is hard to understand why, and the compiler does not complain\r
+// even with -Wall.\r
+//    union {   \r
+//        struct { \r
+            uint16 n;\r
+            uint16 sum;\r
+//        };\r
+//        struct {\r
+            uint8 height;\r
+            int line;\r
+//        };\r
+//   };\r
+    uint8 colour;\r
+} entry_t;\r
+\r
+typedef struct {\r
+   int size;\r
+   int alloc;\r
+   uint32 mask;\r
+   entry_t * entry;\r
+   sint32 * hash;\r
+} book_t;\r
+\r
+typedef enum {\r
+    BOOK,\r
+    ALL\r
+} search_t;\r
+\r
+typedef struct {\r
+    int height;\r
+    int line;\r
+    int initial_color;\r
+    bool book_trans_only;\r
+    bool extended_search;\r
+    uint16 moves[1024];\r
+    double probs[1024];\r
+    uint64 keys[1024];\r
+    FILE *output;\r
+} info_t;\r
+\r
+\r
+// variables\r
+\r
+static int MaxPly;\r
+static int MinGame;\r
+static double MinScore;\r
+static bool RemoveWhite, RemoveBlack;\r
+static bool Uniform;\r
+static bool Quiet=FALSE;\r
+\r
+static book_t Book[1];\r
+\r
+// prototypes\r
+\r
+static void   book_clear    ();\r
+static void   book_insert   (const char file_name[]);\r
+static void   book_filter   ();\r
+static void   book_sort     ();\r
+static void   book_save     (const char file_name[]);\r
+\r
+static int    find_entry    (const board_t * board, int move);\r
+static void   resize        ();\r
+static void   halve_stats   (uint64 key);\r
+\r
+static bool   keep_entry    (int pos);\r
+\r
+static int    entry_score    (const entry_t * entry);\r
+\r
+static int    key_compare   (const void * p1, const void * p2);\r
+\r
+static void   write_integer (FILE * file, int size, uint64 n);\r
+static uint64 read_integer(FILE * file, int size);\r
+\r
+static void read_entry_file(FILE *f, entry_t *entry);\r
+static void write_entry_file(FILE * f, const entry_t * entry);\r
+\r
+// functions\r
+\r
+// book_make()\r
+\r
+void book_make(int argc, char * argv[]) {\r
+\r
+   int i;\r
+   const char * pgn_file;\r
+   const char * bin_file;\r
+\r
+   pgn_file = NULL;\r
+   my_string_set(&pgn_file,"book.pgn");\r
+\r
+   bin_file = NULL;\r
+   my_string_set(&bin_file,"book.bin");\r
+\r
+   MaxPly = 1024;\r
+   MinGame = 3;\r
+   MinScore = 0.0;\r
+   RemoveWhite = FALSE;\r
+   RemoveBlack = FALSE;\r
+   Uniform = FALSE;\r
+\r
+   for (i = 1; i < argc; i++) {\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (my_string_equal(argv[i],"make-book")) {\r
+\r
+         // skip\r
+\r
+      } else if (my_string_equal(argv[i],"-pgn")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");\r
+\r
+         my_string_set(&pgn_file,argv[i]);\r
+\r
+      } else if (my_string_equal(argv[i],"-bin")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");\r
+\r
+         my_string_set(&bin_file,argv[i]);\r
+\r
+      } else if (my_string_equal(argv[i],"-max-ply")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");\r
+\r
+         MaxPly = atoi(argv[i]);\r
+         ASSERT(MaxPly>=0);\r
+\r
+      } else if (my_string_equal(argv[i],"-min-game")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");\r
+\r
+         MinGame = atoi(argv[i]);\r
+         ASSERT(MinGame>0);\r
+\r
+      } else if (my_string_equal(argv[i],"-min-score")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");\r
+\r
+         MinScore = atof(argv[i]) / 100.0;\r
+         ASSERT(MinScore>=0.0&&MinScore<=1.0);\r
+\r
+      } else if (my_string_equal(argv[i],"-only-white")) {\r
+\r
+         RemoveWhite = FALSE;\r
+         RemoveBlack = TRUE;\r
+\r
+      } else if (my_string_equal(argv[i],"-only-black")) {\r
+\r
+         RemoveWhite = TRUE;\r
+         RemoveBlack = FALSE;\r
+\r
+      } else if (my_string_equal(argv[i],"-uniform")) {\r
+\r
+         Uniform = TRUE;\r
+\r
+      } else {\r
+\r
+         my_fatal("book_make(): unknown option \"%s\"\n",argv[i]);\r
+      }\r
+   }\r
+\r
+   book_clear();\r
+\r
+   printf("inserting games ...\n");\r
+   book_insert(pgn_file);\r
+\r
+   printf("filtering entries ...\n");\r
+   book_filter();\r
+\r
+   printf("sorting entries ...\n");\r
+   book_sort();\r
+\r
+   printf("saving entries ...\n");\r
+   book_save(bin_file);\r
+\r
+   printf("all done!\n");\r
+}\r
+\r
+// book_clear()\r
+\r
+static void book_clear() {\r
+\r
+   int index;\r
+\r
+   Book->alloc = 1;\r
+   Book->mask = (Book->alloc * 2) - 1;\r
+\r
+   Book->entry = (entry_t *) my_malloc(Book->alloc*sizeof(entry_t));\r
+   Book->size = 0;\r
+\r
+   Book->hash = (sint32 *) my_malloc((Book->alloc*2)*sizeof(sint32));\r
+   for (index = 0; index < Book->alloc*2; index++) {\r
+      Book->hash[index] = NIL;\r
+   }\r
+}\r
+\r
+// book_insert()\r
+\r
+static void book_insert(const char file_name[]) {\r
+\r
+   pgn_t pgn[1];\r
+   board_t board[1];\r
+   int ply;\r
+   int result;\r
+   char string[256];\r
+   int move;\r
+   int pos;\r
+\r
+   ASSERT(file_name!=NULL);\r
+\r
+   // init\r
+\r
+   pgn->game_nb=1;\r
+   // scan loop\r
+\r
+   pgn_open(pgn,file_name);\r
+\r
+   while (pgn_next_game(pgn)) {\r
+\r
+      board_start(board);\r
+      ply = 0;\r
+      result = 0;\r
+\r
+      if (FALSE) {\r
+      } else if (my_string_equal(pgn->result,"1-0")) {\r
+         result = +1;\r
+      } else if (my_string_equal(pgn->result,"0-1")) {\r
+         result = -1;\r
+      }\r
+\r
+      while (pgn_next_move(pgn,string,256)) {\r
+\r
+         if (ply < MaxPly) {\r
+\r
+            move = move_from_san(string,board);\r
+\r
+            if (move == MoveNone || !move_is_legal(move,board)) {\r
+               my_fatal("book_insert(): illegal move \"%s\" at line %d, column %d,game %d\n",string,pgn->move_line,pgn->move_column,pgn->game_nb);\r
+            }\r
+\r
+            pos = find_entry(board,move);\r
+\r
+            Book->entry[pos].n++;\r
+            Book->entry[pos].sum += result+1;\r
+\r
+            if (Book->entry[pos].n >= COUNT_MAX) {\r
+               halve_stats(board->key);\r
+            }\r
+\r
+            move_do(board,move);\r
+            ply++;\r
+            result = -result;\r
+         }\r
+      }\r
+         pgn->game_nb++;\r
+      if (pgn->game_nb % 10000 == 0) printf("%d games ...\n",pgn->game_nb);\r
+   }\r
+\r
+   pgn_close(pgn);\r
+\r
+   printf("%d game%s.\n",pgn->game_nb,(pgn->game_nb>2)?"s":"");\r
+   printf("%d entries.\n",Book->size);\r
+\r
+   return;\r
+}\r
+\r
+// book_filter()\r
+\r
+static void book_filter() {\r
+\r
+   int src, dst;\r
+\r
+   // entry loop\r
+\r
+   dst = 0;\r
+\r
+   for (src = 0; src < Book->size; src++) {\r
+      if (keep_entry(src)) Book->entry[dst++] = Book->entry[src];\r
+   }\r
+\r
+   ASSERT(dst>=0&&dst<=Book->size);\r
+   Book->size = dst;\r
+\r
+   printf("%d entries.\n",Book->size);\r
+}\r
+\r
+// book_sort()\r
+\r
+static void book_sort() {\r
+\r
+   // sort keys for binary search\r
+\r
+   qsort(Book->entry,Book->size,sizeof(entry_t),&key_compare);\r
+}\r
+\r
+// book_save()\r
+\r
+static void book_save(const char file_name[]) {\r
+\r
+   FILE * file;\r
+   int pos;\r
+\r
+   ASSERT(file_name!=NULL);\r
+\r
+   file = fopen(file_name,"wb");\r
+   if (file == NULL) my_fatal("book_save(): can't open file \"%s\" for writing: %s\n",file_name,strerror(errno));\r
+\r
+   // entry loop\r
+\r
+   for (pos = 0; pos < Book->size; pos++) {\r
+\r
+      ASSERT(keep_entry(pos));\r
+\r
+      write_integer(file,8,Book->entry[pos].key);\r
+      write_integer(file,2,Book->entry[pos].move);\r
+      write_integer(file,2,entry_score(&Book->entry[pos]));\r
+      write_integer(file,2,0);\r
+      write_integer(file,2,0);\r
+   }\r
+\r
+   fclose(file);\r
+}\r
+\r
+// find_entry()\r
+\r
+static int find_entry(const board_t * board, int move) {\r
+\r
+   uint64 key;\r
+   int index;\r
+   int pos;\r
+\r
+   ASSERT(board!=NULL);\r
+   ASSERT(move==MoveNone || move_is_ok(move));\r
+\r
+   ASSERT(move==MoveNone || move_is_legal(move,board));\r
+\r
+   // init\r
+\r
+   key = board->key;\r
+\r
+   // search\r
+\r
+   for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {\r
+\r
+      ASSERT(pos>=0&&pos<Book->size);\r
+\r
+      if (Book->entry[pos].key == key && Book->entry[pos].move == move) {\r
+         return pos; // found\r
+      }\r
+   }\r
+\r
+   // not found\r
+\r
+   ASSERT(Book->size<=Book->alloc);\r
+\r
+   if (Book->size == Book->alloc) {\r
+\r
+      // allocate more memory\r
+\r
+      resize();\r
+\r
+      for (index = key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask)\r
+         ;\r
+   }\r
+\r
+   // create a new entry\r
+\r
+   ASSERT(Book->size<Book->alloc);\r
+   pos = Book->size++;\r
+\r
+   Book->entry[pos].key = key;\r
+   Book->entry[pos].move = move;\r
+   Book->entry[pos].n = 0;\r
+   Book->entry[pos].sum = 0;\r
+   Book->entry[pos].colour = board->turn;\r
+\r
+   // insert into the hash table\r
+\r
+   ASSERT(index>=0&&index<Book->alloc*2);\r
+   ASSERT(Book->hash[index]==NIL);\r
+   Book->hash[index] = pos;\r
+\r
+   ASSERT(pos>=0&&pos<Book->size);\r
+\r
+   return pos;\r
+}\r
+\r
+// rebuild_hash_table\r
+\r
+static void rebuild_hash_table(){\r
+    int index,pos;\r
+    for (index = 0; index < Book->alloc*2; index++) {\r
+        Book->hash[index] = NIL;\r
+    }\r
+    for (pos = 0; pos < Book->size; pos++) {\r
+        for (index = Book->entry[pos].key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask)\r
+         ;\r
+        ASSERT(index>=0&&index<Book->alloc*2);\r
+        Book->hash[index] = pos;\r
+    }\r
+}\r
+\r
+static void resize() {\r
+\r
+   int size;\r
+\r
+   ASSERT(Book->size==Book->alloc);\r
+\r
+   Book->alloc *= 2;\r
+   Book->mask = (Book->alloc * 2) - 1;\r
+\r
+   size = 0;\r
+   size += Book->alloc * sizeof(entry_t);\r
+   size += (Book->alloc*2) * sizeof(sint32);\r
+\r
+   if (size >= 1048576) if(!Quiet){\r
+           printf("allocating %gMB ...\n",((double)size)/1048576.0);\r
+       }\r
+\r
+   // resize arrays\r
+\r
+   Book->entry = (entry_t *) my_realloc(Book->entry,Book->alloc*sizeof(entry_t));\r
+   Book->hash = (sint32 *) my_realloc(Book->hash,(Book->alloc*2)*sizeof(sint32));\r
+\r
+   // rebuild hash table\r
+\r
+   rebuild_hash_table();\r
+}\r
+\r
+\r
+// halve_stats()\r
+\r
+static void halve_stats(uint64 key) {\r
+\r
+   int index;\r
+   int pos;\r
+\r
+   // search\r
+\r
+   for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {\r
+\r
+      ASSERT(pos>=0&&pos<Book->size);\r
+\r
+      if (Book->entry[pos].key == key) {\r
+         Book->entry[pos].n = (Book->entry[pos].n + 1) / 2;\r
+         Book->entry[pos].sum = (Book->entry[pos].sum + 1) / 2;\r
+      }\r
+   }\r
+}\r
+\r
+// keep_entry()\r
+\r
+static bool keep_entry(int pos) {\r
+\r
+   const entry_t * entry;\r
+   int colour;\r
+   double score;\r
+\r
+   ASSERT(pos>=0&&pos<Book->size);\r
+\r
+   entry = &Book->entry[pos];\r
+\r
+   // if (entry->n == 0) return FALSE;\r
+   if (entry->n < MinGame) return FALSE;\r
+\r
+   if (entry->sum == 0) return FALSE;\r
+\r
+   score = (((double)entry->sum) / ((double)entry->n)) / 2.0;\r
+   ASSERT(score>=0.0&&score<=1.0);\r
+\r
+   if (score < MinScore) return FALSE;\r
+\r
+   colour = entry->colour;\r
+\r
+   if ((RemoveWhite && colour_is_white(colour))\r
+    || (RemoveBlack && colour_is_black(colour))) {\r
+      return FALSE;\r
+   }\r
+\r
+   if (entry_score(entry) == 0) return FALSE; // REMOVE ME?\r
+\r
+   return TRUE;\r
+}\r
+\r
+// entry_score()\r
+\r
+static int entry_score(const entry_t * entry) {\r
+\r
+   int score;\r
+\r
+   ASSERT(entry!=NULL);\r
+\r
+   // score = entry->n; // popularity\r
+   score = entry->sum; // "expectancy"\r
+\r
+   if (Uniform) score = 1;\r
+\r
+   ASSERT(score>=0);\r
+\r
+   return score;\r
+}\r
+\r
+// key_compare()\r
+\r
+static int key_compare(const void * p1, const void * p2) {\r
+\r
+   const entry_t * entry_1, * entry_2;\r
+\r
+   ASSERT(p1!=NULL);\r
+   ASSERT(p2!=NULL);\r
+\r
+   entry_1 = (const entry_t *) p1;\r
+   entry_2 = (const entry_t *) p2;\r
+\r
+   if (entry_1->key > entry_2->key) {\r
+      return +1;\r
+   } else if (entry_1->key < entry_2->key) {\r
+      return -1;\r
+   } else {\r
+      return entry_score(entry_2) - entry_score(entry_1); // highest score first\r
+   }\r
+}\r
+\r
+// write_integer()\r
+\r
+static void write_integer(FILE * file, int size, uint64 n) {\r
+\r
+   int i;\r
+   int b;\r
+\r
+   ASSERT(file!=NULL);\r
+   ASSERT(size>0&&size<=8);\r
+   ASSERT(size==8||n>>(size*8)==0);\r
+\r
+   for (i = size-1; i >= 0; i--) {\r
+      b = (n >> (i*8)) & 0xFF;\r
+      ASSERT(b>=0&&b<256);\r
+      fputc(b,file);\r
+   }\r
+}\r
+\r
+// read_integer()\r
+\r
+static uint64 read_integer(FILE * file, int size) {\r
+   uint64 n;\r
+   int i;\r
+   int b;\r
+   ASSERT(file!=NULL);\r
+   ASSERT(size>0&&size<=8);\r
+   n = 0;\r
+   for (i = 0; i < size; i++) {\r
+      b = fgetc(file);\r
+      if (b == EOF) {\r
+         if (feof(file)) {\r
+            my_fatal("read_integer(): fgetc(): EOF reached\n");\r
+         } else { // error\r
+            my_fatal("read_integer(): fgetc(): %s\n",strerror(errno));\r
+         }\r
+      }\r
+      ASSERT(b>=0&&b<256);\r
+      n = (n << 8) | b;\r
+   }\r
+   return n;\r
+}\r
+\r
+// read_entry_file\r
+\r
+static void read_entry_file(FILE *f, entry_t *entry){\r
+    uint64 n;\r
+    ASSERT(entry!=NULL);\r
+    n = entry->key   = read_integer(f,8);\r
+    entry->move  = read_integer(f,2);\r
+    entry->count = read_integer(f,2);\r
+    entry->n     = read_integer(f,2);\r
+    entry->sum   = read_integer(f,2);\r
+    ASSERT(n==entry->key); // test for mingw compiler bug with anon structs\r
+}\r
+\r
+// write_entry_file\r
+\r
+static void write_entry_file(FILE * f, const entry_t * entry) {\r
+   ASSERT(entry!=NULL);\r
+   write_integer(f,8,entry->key);\r
+   write_integer(f,2,entry->move);\r
+   write_integer(f,2,entry->count);\r
+   write_integer(f,2,entry->n);\r
+   write_integer(f,2,entry->sum);\r
+}\r
+\r
+static void print_list(const board_t *board, list_t *list){\r
+    int i;\r
+    uint16 move;\r
+    char move_string[256];\r
+    for (i = 0; i < list_size(list); i++) {\r
+        move = list_move(list,i);\r
+        move_to_san(move,board,move_string,256);\r
+        printf("%s",move_string);\r
+    }\r
+    printf("\n");\r
+}\r
+\r
+// book_load()\r
+// loads a polyglot book\r
+\r
+static void book_load(const char filename[]){\r
+    FILE* f;\r
+    entry_t entry[1];\r
+    int size;\r
+    int i;\r
+    int pos;\r
+    int index;\r
+    ASSERT(filename!=NULL);\r
+    if(!(f=fopen(filename,"rb"))){\r
+        my_fatal("book_load() : can't open file \"%s\" for reading: %s\n",filename,strerror(errno));\r
+    }\r
+    fseek(f,0L,SEEK_END);   // superportable way to get size of book!\r
+    size=ftell(f)/16;\r
+    fseek(f,0,SEEK_SET);\r
+    for(i=0L;i<size;i++){\r
+        read_entry_file(f,entry);\r
+        ASSERT(Book->size<=Book->alloc);\r
+        if (Book->size == Book->alloc) {\r
+                // allocate more memoryx\r
+            resize();\r
+        }\r
+            // insert into the book\r
+        pos = Book->size++;\r
+        Book->entry[pos].key = entry->key;\r
+        ASSERT(entry->move!=MoveNone);\r
+        Book->entry[pos].move = entry->move;\r
+        Book->entry[pos].count = entry->count;\r
+        Book->entry[pos].n = entry->n;\r
+        Book->entry[pos].sum = entry->sum;\r
+        Book->entry[pos].colour = ColourNone;\r
+            // find free hash table spot\r
+        for (index = entry->key & (uint64) Book->mask;\r
+             Book->hash[index] != NIL;\r
+             index = (index+1) & Book->mask);\r
+            // insert into the hash table\r
+        ASSERT(index>=0&&index<Book->alloc*2);\r
+        ASSERT(Book->hash[index]==NIL);\r
+        Book->hash[index] = pos;\r
+        ASSERT(pos>=0&&pos<Book->size);\r
+    }\r
+    fclose(f);\r
+}\r
+\r
+// gen_book_moves()\r
+// similar signature as gen_legal_moves\r
+static int gen_book_moves(list_t * list, const board_t * board){\r
+    int first_pos, pos, index;\r
+    entry_t entry[1];\r
+    list_clear(list);\r
+    bool found;\r
+    found=FALSE;\r
+    for (index = board->key & (uint64) Book->mask; (first_pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {\r
+        ASSERT(first_pos>=0&&first_pos<Book->size);\r
+        if (Book->entry[first_pos].key == board->key) {\r
+            found=TRUE;\r
+            break; // found\r
+        }\r
+    }\r
+    if(!found) return -1;\r
+    if(Book->entry[first_pos].move==MoveNone) return -1;\r
+    for (pos = first_pos; pos < Book->size; pos++) {\r
+        *entry=Book->entry[pos];\r
+        if (entry->key != board->key) break;\r
+        if (entry->count > 0 &&\r
+            entry->move != MoveNone &&\r
+            move_is_legal(entry->move,board)) {\r
+            list_add_ex(list,entry->move,entry->count);\r
+        }\r
+    }\r
+    return first_pos;\r
+}\r
+\r
+// gen_opp_book_moves()\r
+// moves to which opponent has a reply in book\r
+// similar signature as gen_legal_moves\r
+static void gen_opp_book_moves(list_t * list, const board_t * board){\r
+    int move;\r
+    list_t new_list[1], legal_moves[1];\r
+    board_t new_board[1];\r
+    int i;\r
+    list_clear(list);\r
+    gen_legal_moves(legal_moves,board);\r
+    for (i = 0; i < list_size(legal_moves); i++) {\r
+        move = list_move(legal_moves,i);\r
+            // scratch_board\r
+        memcpy(new_board, board, sizeof(board_t));\r
+        move_do(new_board,move);\r
+        gen_book_moves(new_list,new_board); // wasteful in time but tested!\r
+        if(list_size(new_list)!=0){\r
+            list_add(list,move);\r
+        }\r
+    }\r
+}\r
+\r
+static void print_moves(info_t *info){\r
+    board_t board[1];\r
+    char move_string[256];\r
+    int i;\r
+    int color=White;\r
+    if(!info->output){\r
+        return;\r
+    }\r
+    board_start(board);\r
+    for(i=0;i<info->height;i++){\r
+        if(color==White){\r
+            fprintf(info->output,"%d. ",i/2+1);\r
+            color=Black;\r
+        }else{\r
+            color=White;\r
+        }\r
+        move_to_san(info->moves[i],board,move_string,256);\r
+        fprintf(info->output,"%s", move_string);\r
+        if(color==colour_opp(info->initial_color)){\r
+            fprintf(info->output,"{%.0f%%} ",100*info->probs[i]);\r
+        }else{\r
+            fprintf(info->output," ");\r
+        }\r
+        move_do(board,info->moves[i]);\r
+    }\r
+}\r
+\r
+static int search_book(board_t *board, info_t *info, search_t search){\r
+    list_t list[1];\r
+    board_t new_board[1];\r
+    uint16 move;\r
+    int count;\r
+    int ret;\r
+    int i;\r
+    int offset;\r
+    int pos;\r
+    int size;\r
+    int prob_sum;\r
+    double probs[256];\r
+    for(i=0;i<256;i++){\r
+        probs[i]=0.0;  // kill compiler warnings\r
+    }\r
+    for(i=0;i<info->height;i++){\r
+        if(board->key==info->keys[i]){\r
+            if(info->output){\r
+                fprintf(info->output,"%d: ",info->line);\r
+                print_moves(info);\r
+                fprintf(info->output,"{cycle: ply=%d}\n",i);\r
+            }\r
+            info->line++;\r
+            return 1; // end of line because of cycle\r
+        }\r
+    }\r
+    if(!info->book_trans_only || (info->book_trans_only && search==BOOK)){\r
+        info->keys[info->height]=board->key;\r
+        size=Book->size;  // hack\r
+        pos=find_entry(board,MoveNone);\r
+        if(size==Book->size){\r
+            if(info->output){\r
+                fprintf(info->output,"%d: ",info->line);\r
+                print_moves(info);\r
+                fprintf(info->output,"{trans: line=%d, ply=%d}\n",\r
+                        Book->entry[pos].line,\r
+                        Book->entry[pos].height);\r
+            }\r
+            info->line++;\r
+            return 1; // end of line because of transposition\r
+        }else{\r
+            Book->entry[pos].height=info->height;\r
+            Book->entry[pos].line=info->line;\r
+        }\r
+    }\r
+    count=0;\r
+    if(search==BOOK){\r
+        offset=gen_book_moves(list,board);\r
+        if(info->extended_search){\r
+            gen_legal_moves(list,board);\r
+        }\r
+//        ASSERT(offset!=-1);\r
+        if(offset!=-1){ // only FALSE in starting position for black book\r
+            Book->entry[offset].colour=board->turn;\r
+            prob_sum=0;\r
+            if(!info->extended_search){\r
+                for(i=0;i<list_size(list);i++){\r
+                    prob_sum+=((uint16)list_value(list,i));\r
+                }\r
+                for(i=0;i<list_size(list);i++){\r
+                    probs[i]=((double)((uint16)list_value(list,i)))/((double)prob_sum);\r
+                }\r
+            }\r
+        }\r
+    }else{\r
+        gen_opp_book_moves(list,board);\r
+    }\r
+    for (i = 0; i < list_size(list); i++) {\r
+        move = list_move(list,i);\r
+        memcpy(new_board, board, sizeof(board_t));\r
+        ASSERT(move_is_legal(move,new_board));\r
+        move_do(new_board,move);\r
+        ASSERT(search!=opp_search(search));\r
+        info->moves[info->height++]=move;\r
+        if(search==BOOK){\r
+            info->probs[info->height-1]=probs[i];\r
+        }\r
+        ret=search_book(new_board, info, opp_search(search));\r
+        if(ret==0 && search==BOOK){\r
+            if(info->output){\r
+                fprintf(info->output,"%d: ",info->line);\r
+                print_moves(info);\r
+                fprintf(info->output,"\n");\r
+            }\r
+            info->line++;\r
+            ret=1; // end of line book move counts for 1\r
+        }\r
+        info->height--;\r
+        ASSERT(info->height>=0);\r
+        count+=ret;\r
+    }\r
+    return count;\r
+}\r
+\r
+void init_info(info_t *info){\r
+    info->line=1;\r
+    info->height=0;\r
+    info->output=NULL;\r
+    info->initial_color=White;\r
+    info->book_trans_only=FALSE;\r
+}\r
+\r
+// book_clean()\r
+// remove MoveNone entries from book and rebuild hash table\r
+void book_clean(){\r
+    int read_ptr,write_ptr;\r
+    write_ptr=0;\r
+    for(read_ptr=0;read_ptr<Book->size;read_ptr++){\r
+        if(Book->entry[read_ptr].move!=MoveNone){\r
+            Book->entry[write_ptr++]=Book->entry[read_ptr];\r
+        }\r
+    }\r
+    Book->size=write_ptr;\r
+    rebuild_hash_table();\r
+}\r
+\r
+// book_dump()\r
+\r
+void book_dump(int argc, char * argv[]) {\r
+    const char * bin_file=NULL;\r
+    const char * txt_file=NULL;\r
+    char string[StringSize];\r
+    int color=ColourNone;\r
+    board_t board[1];\r
+    info_t info[1];\r
+    int i;\r
+    FILE *f;\r
+    my_string_set(&bin_file,"book.bin");\r
+    for (i = 1; i < argc; i++) {\r
+        if (FALSE) {\r
+        } else if (my_string_equal(argv[i],"dump-book")) {\r
+                // skip\r
+        } else if (my_string_equal(argv[i],"-bin")) {\r
+            i++;\r
+            if (i==argc) my_fatal("book_dump(): missing argument\n");\r
+            my_string_set(&bin_file,argv[i]);\r
+        } else if (my_string_equal(argv[i],"-out")) {\r
+            i++;\r
+            if (i==argc) my_fatal("book_dump(): missing argument\n");\r
+            my_string_set(&txt_file,argv[i]);\r
+        } else if (my_string_equal(argv[i],"-color") || my_string_equal(argv[i],"-colour")) {\r
+            i++;\r
+            if (i == argc) my_fatal("book_dump(): missing argument\n");\r
+            if(my_string_equal(argv[i],"white")){\r
+                color=White;\r
+            }else if (my_string_equal(argv[i],"black")){\r
+                color=Black;\r
+            }else{\r
+                my_fatal("book_dump(): unknown color \"%s\"\n",argv[i]);\r
+            }\r
+        } else {\r
+            my_fatal("book_dump(): unknown option \"%s\"\n",argv[i]);\r
+        }\r
+    }\r
+    if(color==ColourNone){\r
+        my_fatal("book_dump(): you must specify a color\n");\r
+    }\r
+    if(txt_file==NULL){\r
+        snprintf(string,StringSize,"book_%s.txt",color?"white":"black");\r
+        my_string_set(&txt_file,string);\r
+    }\r
+\r
+    book_clear();\r
+    if(!Quiet){printf("loading book ...\n");}\r
+    book_load(bin_file);\r
+    board_start(board);\r
+    init_info(info);\r
+    info->initial_color=color;\r
+    if(!(f=fopen(txt_file,"w"))){\r
+        my_fatal("book_dump(): can't open file \"%s\" for writing: %s",\r
+                 txt_file,strerror(errno));\r
+    }\r
+    info->output=f;\r
+    fprintf(info->output,"Dump of \"%s\" for %s.\n",\r
+            bin_file,color==White?"white":"black");\r
+    if(color==White){\r
+        if(!Quiet){printf("generating lines for white...\n");}\r
+        search_book(board,info, BOOK);\r
+    }else{\r
+        if(!Quiet){printf("generating lines for black...\n");}\r
+        search_book(board,info, ALL);\r
+    }\r
+}\r
+\r
+// book_info()\r
+\r
+void book_info(int argc,char* argv[]){\r
+    const char *bin_file=NULL;\r
+    board_t board[1];\r
+    info_t info[1];\r
+    uint64 last_key;\r
+    int pos;\r
+    int white_pos,black_pos,total_pos,white_pos_extended,\r
+        black_pos_extended,white_pos_extended_diff,black_pos_extended_diff;\r
+    int s;\r
+    bool extended_search=FALSE;\r
+    int i;\r
+    Quiet=TRUE;\r
+    my_string_set(&bin_file,"book.bin");\r
+\r
+    for (i = 1; i < argc; i++) {\r
+        if (FALSE) {\r
+        } else if (my_string_equal(argv[i],"info-book")) {\r
+                // skip\r
+        } else if (my_string_equal(argv[i],"-bin")) {\r
+            i++;\r
+            if (i==argc) my_fatal("book_info(): missing argument\n");\r
+            my_string_set(&bin_file,argv[i]);\r
+        } else if (my_string_equal(argv[i],"-exact")) {\r
+            extended_search=TRUE;\r
+        } else {\r
+            my_fatal("book_info(): unknown option \"%s\"\n",argv[i]);\r
+        }\r
+    }\r
+    book_clear();\r
+    if(!Quiet){printf("loading book ...\n");}\r
+    book_load(bin_file);\r
+    s=Book->size;\r
+\r
+    board_start(board);\r
+    init_info(info);\r
+    info->book_trans_only=FALSE;\r
+    info->initial_color=White;\r
+    info->extended_search=FALSE;\r
+    search_book(board,info, BOOK);\r
+    printf("Lines for white                : %8d\n",info->line-1);\r
+\r
+\r
+    info->line=1;\r
+    info->height=0;\r
+    info->initial_color=Black;\r
+    book_clean();\r
+    ASSERT(Book->size==s);\r
+    board_start(board);\r
+    search_book(board,info, ALL);\r
+    printf("Lines for black                : %8d\n",info->line-1);\r
+\r
+    book_clean();\r
+    ASSERT(Book->size==s);\r
+    white_pos=0;\r
+    black_pos=0;\r
+    total_pos=0;\r
+    last_key=0;\r
+    for(pos=0;pos<Book->size;pos++){\r
+        if(Book->entry[pos].key==last_key){\r
+            ASSERT(Book->entry[pos].colour==ColourNone);\r
+            continue;\r
+        }\r
+        last_key=Book->entry[pos].key;\r
+        total_pos++;\r
+        if(Book->entry[pos].colour==White){\r
+            white_pos++;\r
+        }else if(Book->entry[pos].colour==Black){\r
+            black_pos++;\r
+        }\r
+    }\r
+    printf("Positions on lines for white   : %8d\n",white_pos);\r
+    printf("Positions on lines for black   : %8d\n",black_pos);\r
+\r
+    \r
+    if(extended_search){\r
+        init_info(info);\r
+        info->book_trans_only=TRUE;\r
+        info->initial_color=White;\r
+        info->extended_search=TRUE;\r
+        book_clean();\r
+        board_start(board);\r
+        search_book(board,info, BOOK);\r
+\r
+        init_info(info);\r
+        info->book_trans_only=TRUE;\r
+        info->initial_color=Black;\r
+        info->extended_search=TRUE;\r
+        book_clean();\r
+        board_start(board);\r
+        search_book(board,info, ALL);\r
+        book_clean();\r
+        ASSERT(Book->size==s);\r
+        white_pos_extended=0;\r
+        black_pos_extended=0;\r
+        last_key=0;\r
+        for(pos=0;pos<Book->size;pos++){\r
+            if(Book->entry[pos].key==last_key){\r
+                ASSERT(Book->entry[pos].colour==ColourNone);\r
+                continue;\r
+            }\r
+            last_key=Book->entry[pos].key;\r
+            if(Book->entry[pos].colour==White){\r
+                white_pos_extended++;\r
+            }else if(Book->entry[pos].colour==Black){\r
+                black_pos_extended++;\r
+            }\r
+        }\r
+        white_pos_extended_diff=white_pos_extended-white_pos;\r
+        black_pos_extended_diff=black_pos_extended-black_pos;\r
+        printf("Unreachable white positions(?) : %8d\n",\r
+               white_pos_extended_diff);\r
+        printf("Unreachable black positions(?) : %8d\n",\r
+               black_pos_extended_diff);\r
+\r
+    }\r
+    if(extended_search){\r
+        printf("Isolated positions             : %8d\n",\r
+               total_pos-white_pos_extended-black_pos_extended);\r
+    }else{\r
+        printf("Isolated positions             : %8d\n",\r
+               total_pos-white_pos-black_pos);\r
+    }\r
+}\r
+\r
+\r
+\r
+// end of book_make.cpp\r
+\r
diff --git a/book_merge.c b/book_merge.c
new file mode 100644 (file)
index 0000000..f68e2cc
--- /dev/null
@@ -0,0 +1,304 @@
+\r
+// book_merge.c\r
+\r
+// includes\r
+\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "book_merge.h"\r
+#include "util.h"\r
+\r
+// types\r
+\r
+typedef struct {\r
+   FILE * file;\r
+   int size;\r
+} book_t;\r
+\r
+typedef struct {\r
+   uint64 key;\r
+   uint16 move;\r
+   uint16 count;\r
+   uint16 n;\r
+   uint16 sum;\r
+} entry_t;\r
+\r
+// variables\r
+\r
+static book_t In1[1];\r
+static book_t In2[1];\r
+static book_t Out[1];\r
+\r
+// prototypes\r
+\r
+static void   book_clear    (book_t * book);\r
+\r
+static void   book_open     (book_t * book, const char file_name[], const char mode[]);\r
+static void   book_close    (book_t * book);\r
+\r
+static bool   read_entry    (book_t * book, entry_t * entry, int n);\r
+static void   write_entry   (book_t * book, const entry_t * entry);\r
+\r
+static uint64 read_integer  (FILE * file, int size);\r
+static void   write_integer (FILE * file, int size, uint64 n);\r
+\r
+// functions\r
+\r
+// book_merge()\r
+\r
+void book_merge(int argc, char * argv[]) {\r
+\r
+   int i;\r
+   const char * in_file_1;\r
+   const char * in_file_2;\r
+   const char * out_file;\r
+   int i1, i2;\r
+   bool b1, b2;\r
+   entry_t e1[1], e2[1];\r
+   int skip;\r
+\r
+   in_file_1 = NULL;\r
+   my_string_clear(&in_file_1);\r
+\r
+   in_file_2 = NULL;\r
+   my_string_clear(&in_file_2);\r
+\r
+   out_file = NULL;\r
+   my_string_set(&out_file,"out.bin");\r
+\r
+   for (i = 1; i < argc; i++) {\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (my_string_equal(argv[i],"merge-book")) {\r
+\r
+         // skip\r
+\r
+      } else if (my_string_equal(argv[i],"-in1")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n");\r
+\r
+         my_string_set(&in_file_1,argv[i]);\r
+\r
+      } else if (my_string_equal(argv[i],"-in2")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n");\r
+\r
+         my_string_set(&in_file_2,argv[i]);\r
+\r
+      } else if (my_string_equal(argv[i],"-out")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n");\r
+\r
+         my_string_set(&out_file,argv[i]);\r
+\r
+      } else {\r
+\r
+         my_fatal("book_merge(): unknown option \"%s\"\n",argv[i]);\r
+      }\r
+   }\r
+\r
+   book_clear(In1);\r
+   book_clear(In2);\r
+   book_clear(Out);\r
+\r
+   book_open(In1,in_file_1,"rb");\r
+   book_open(In2,in_file_2,"rb");\r
+   book_open(Out,out_file,"wb");\r
+\r
+   skip = 0;\r
+\r
+   i1 = 0;\r
+   i2 = 0;\r
+\r
+   while (TRUE) {\r
+\r
+      b1 = read_entry(In1,e1,i1);\r
+      b2 = read_entry(In2,e2,i2);\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (!b1 && !b2) {\r
+\r
+         break;\r
+\r
+      } else if (b1 && !b2) {\r
+\r
+         write_entry(Out,e1);\r
+         i1++;\r
+\r
+      } else if (b2 && !b1) {\r
+\r
+         write_entry(Out,e2);\r
+         i2++;\r
+\r
+      } else {\r
+\r
+         ASSERT(b1);\r
+         ASSERT(b2);\r
+\r
+         if (FALSE) {\r
+         } else if (e1->key < e2->key) {\r
+            write_entry(Out,e1);\r
+            i1++;\r
+         } else if (e1->key > e2->key) {\r
+            write_entry(Out,e2);\r
+            i2++;\r
+         } else {\r
+            ASSERT(e1->key==e2->key);\r
+            skip++;\r
+            i2++;\r
+         }\r
+      }\r
+   }\r
+\r
+   book_close(In1);\r
+   book_close(In2);\r
+   book_close(Out);\r
+\r
+   if (skip != 0) {\r
+      printf("skipped %d entr%s.\n",skip,(skip>1)?"ies":"y");\r
+   }\r
+\r
+   printf("done!\n");\r
+}\r
+\r
+// book_clear()\r
+\r
+static void book_clear(book_t * book) {\r
+\r
+   ASSERT(book!=NULL);\r
+\r
+   book->file = NULL;\r
+   book->size = 0;\r
+}\r
+\r
+// book_open()\r
+\r
+static void book_open(book_t * book, const char file_name[], const char mode[]) {\r
+\r
+   ASSERT(book!=NULL);\r
+   ASSERT(file_name!=NULL);\r
+   ASSERT(mode!=NULL);\r
+\r
+   book->file = fopen(file_name,mode);\r
+   if (book->file == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno));\r
+\r
+   if (fseek(book->file,0,SEEK_END) == -1) {\r
+      my_fatal("book_open(): fseek(): %s\n",strerror(errno));\r
+   }\r
+\r
+   book->size = ftell(book->file) / 16;\r
+}\r
+\r
+// book_close()\r
+\r
+static void book_close(book_t * book) {\r
+\r
+   ASSERT(book!=NULL);\r
+\r
+   if (fclose(book->file) == EOF) {\r
+      my_fatal("book_close(): fclose(): %s\n",strerror(errno));\r
+   }\r
+}\r
+\r
+// read_entry()\r
+\r
+static bool read_entry(book_t * book, entry_t * entry, int n) {\r
+\r
+   ASSERT(book!=NULL);\r
+   ASSERT(entry!=NULL);\r
+\r
+   if (n < 0 || n >= book->size) return FALSE;\r
+\r
+   ASSERT(n>=0&&n<book->size);\r
+\r
+   if (fseek(book->file,n*16,SEEK_SET) == -1) {\r
+      my_fatal("read_entry(): fseek(): %s\n",strerror(errno));\r
+   }\r
+\r
+   entry->key   = read_integer(book->file,8);\r
+   entry->move  = read_integer(book->file,2);\r
+   entry->count = read_integer(book->file,2);\r
+   entry->n     = read_integer(book->file,2);\r
+   entry->sum   = read_integer(book->file,2);\r
+\r
+   return TRUE;\r
+}\r
+\r
+// write_entry()\r
+\r
+static void write_entry(book_t * book, const entry_t * entry) {\r
+\r
+   ASSERT(book!=NULL);\r
+   ASSERT(entry!=NULL);\r
+\r
+   write_integer(book->file,8,entry->key);\r
+   write_integer(book->file,2,entry->move);\r
+   write_integer(book->file,2,entry->count);\r
+   write_integer(book->file,2,entry->n);\r
+   write_integer(book->file,2,entry->sum);\r
+}\r
+\r
+// read_integer()\r
+\r
+static uint64 read_integer(FILE * file, int size) {\r
+\r
+   uint64 n;\r
+   int i;\r
+   int b;\r
+\r
+   ASSERT(file!=NULL);\r
+   ASSERT(size>0&&size<=8);\r
+\r
+   n = 0;\r
+\r
+   for (i = 0; i < size; i++) {\r
+\r
+      b = fgetc(file);\r
+\r
+      if (b == EOF) {\r
+         if (feof(file)) {\r
+            my_fatal("read_integer(): fgetc(): EOF reached\n");\r
+         } else { // error\r
+            my_fatal("read_integer(): fgetc(): %s\n",strerror(errno));\r
+         }\r
+      }\r
+\r
+      ASSERT(b>=0&&b<256);\r
+      n = (n << 8) | b;\r
+   }\r
+\r
+   return n;\r
+}\r
+\r
+// write_integer()\r
+\r
+static void write_integer(FILE * file, int size, uint64 n) {\r
+\r
+   int i;\r
+   int b;\r
+\r
+   ASSERT(file!=NULL);\r
+   ASSERT(size>0&&size<=8);\r
+   ASSERT(size==8||n>>(size*8)==0);\r
+\r
+   for (i = size-1; i >= 0; i--) {\r
+\r
+      b = (n >> (i*8)) & 0xFF;\r
+      ASSERT(b>=0&&b<256);\r
+\r
+      if (fputc(b,file) == EOF) {\r
+         my_fatal("write_integer(): fputc(): %s\n",strerror(errno));\r
+      }\r
+   }\r
+}\r
+\r
+// end of book_merge.cpp\r
+\r
diff --git a/colour.c b/colour.c
new file mode 100644 (file)
index 0000000..e0936b9
--- /dev/null
+++ b/colour.c
@@ -0,0 +1,55 @@
+\r
+// colour.c\r
+\r
+// includes\r
+\r
+#include "colour.h"\r
+#include "util.h"\r
+\r
+// functions\r
+\r
+// colour_is_ok()\r
+\r
+bool colour_is_ok(int colour) {\r
+\r
+   return colour == Black || colour == White;\r
+}\r
+\r
+// colour_is_white()\r
+\r
+bool colour_is_white(int colour) {\r
+\r
+   ASSERT(colour_is_ok(colour));\r
+\r
+   return colour == White;\r
+}\r
+\r
+// colour_is_black()\r
+\r
+bool colour_is_black(int colour) {\r
+\r
+   ASSERT(colour_is_ok(colour));\r
+\r
+   return colour == Black;\r
+}\r
+\r
+// colour_equal()\r
+\r
+bool colour_equal(int colour_1, int colour_2) {\r
+\r
+   ASSERT(colour_is_ok(colour_2));\r
+\r
+   return (colour_1 & colour_2) != 0;\r
+}\r
+\r
+// colour_opp()\r
+\r
+int colour_opp(int colour) {\r
+\r
+   ASSERT(colour_is_ok(colour));\r
+\r
+   return colour ^ (BlackFlag^WhiteFlag);\r
+}\r
+\r
+// end of colour.cpp\r
+\r
index 5cb7b02..82a7d7b 100644 (file)
--- a/colour.h
+++ b/colour.h
@@ -8,15 +8,14 @@
 \r
 #include "util.h"\r
 \r
-// constants\r
-\r
-const int BlackFlag = 1 << 0;\r
-const int WhiteFlag = 1 << 1;\r
-\r
-const int ColourNone = 0;\r
-const int Black      = BlackFlag;\r
-const int White      = WhiteFlag;\r
-const int ColourNb   = 3;\r
+// defines\r
+\r
+#define BlackFlag (1 << 0)\r
+#define WhiteFlag (1 << 1)\r
+#define ColourNone 0\r
+#define Black BlackFlag\r
+#define White WhiteFlag\r
+#define ColourNb 3\r
 \r
 // functions\r
 \r
index 9064aad..259287a 100644 (file)
--- a/config.h
+++ b/config.h
 #define PACKAGE_NAME "polyglot"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "polyglot 1.4b27"
+#define PACKAGE_STRING "polyglot 1.4.30b"
 
 /* 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.4b27"
+#define PACKAGE_VERSION "1.4.30b"
 
 /* Define to 1 if the C compiler supports function prototypes. */
 #define PROTOTYPES 1
 #define TIME_WITH_SYS_TIME 1
 
 /* Version number of package */
-#define VERSION "1.4b27"
+#define VERSION "1.4.30b"
 
 /* Define like PROTOTYPES; this can be used by system headers. */
 #define __PROTOTYPES 1
index a5adf30..cf92c98 100755 (executable)
--- 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.4b27.
+# Generated by GNU Autoconf 2.61 for polyglot 1.4.30b.
 #
 # Report bugs to <michel.vandenbergh@uhasselt.be>.
 #
@@ -574,11 +574,11 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='polyglot'
 PACKAGE_TARNAME='polyglot'
-PACKAGE_VERSION='1.4b27'
-PACKAGE_STRING='polyglot 1.4b27'
+PACKAGE_VERSION='1.4.30b'
+PACKAGE_STRING='polyglot 1.4.30b'
 PACKAGE_BUGREPORT='michel.vandenbergh@uhasselt.be'
 
-ac_unique_file="mainloop.cpp"
+ac_unique_file="mainloop.c"
 # Factoring default headers for most tests.
 ac_includes_default="\
 #include <stdio.h>
@@ -674,11 +674,11 @@ am__leading_dot
 AMTAR
 am__tar
 am__untar
-CXX
-CXXFLAGS
+CC
+CFLAGS
 LDFLAGS
 CPPFLAGS
-ac_ct_CXX
+ac_ct_CC
 EXEEXT
 OBJEXT
 DEPDIR
@@ -687,12 +687,6 @@ am__quote
 AMDEP_TRUE
 AMDEP_FALSE
 AMDEPBACKSLASH
-CXXDEPMODE
-am__fastdepCXX_TRUE
-am__fastdepCXX_FALSE
-CC
-CFLAGS
-ac_ct_CC
 CCDEPMODE
 am__fastdepCC_TRUE
 am__fastdepCC_FALSE
@@ -705,14 +699,11 @@ ac_subst_files=''
       ac_precious_vars='build_alias
 host_alias
 target_alias
-CXX
-CXXFLAGS
+CC
+CFLAGS
 LDFLAGS
 LIBS
 CPPFLAGS
-CCC
-CC
-CFLAGS
 CPP'
 
 
@@ -1216,7 +1207,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.4b27 to adapt to many kinds of systems.
+\`configure' configures polyglot 1.4.30b to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1282,7 +1273,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of polyglot 1.4b27:";;
+     short | recursive ) echo "Configuration of polyglot 1.4.30b:";;
    esac
   cat <<\_ACEOF
 
@@ -1293,15 +1284,13 @@ Optional Features:
   --enable-dependency-tracking   do not reject slow dependency extractors
 
 Some influential environment variables:
-  CXX         C++ compiler command
-  CXXFLAGS    C++ compiler flags
+  CC          C compiler command
+  CFLAGS      C compiler flags
   LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
               nonstandard directory <lib dir>
   LIBS        libraries to pass to the linker, e.g. -l<library>
   CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
               you have headers in a nonstandard directory <include dir>
-  CC          C compiler command
-  CFLAGS      C compiler flags
   CPP         C preprocessor
 
 Use these variables to override the choices made by `configure' or to help
@@ -1368,7 +1357,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-polyglot configure 1.4b27
+polyglot configure 1.4.30b
 generated by GNU Autoconf 2.61
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1382,7 +1371,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.4b27, which was
+It was created by polyglot $as_me 1.4.30b, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   $ $0 $@
@@ -2072,7 +2061,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='polyglot'
- VERSION='1.4b27'
+ VERSION='1.4.30b'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -2223,27 +2212,217 @@ ac_config_headers="$ac_config_headers config.h"
 
 
 # Checks for programs.
-ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-if test -z "$CXX"; then
-  if test -n "$CCC"; then
-    CXX=$CCC
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
   else
-    if test -n "$ac_tool_prefix"; then
-  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
 { echo "$as_me:$LINENO: checking for $ac_word" >&5
 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
-if test "${ac_cv_prog_CXX+set}" = set; then
+if test "${ac_cv_prog_CC+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
-  if test -n "$CXX"; then
-  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -2252,7 +2431,7 @@ do
   test -z "$as_dir" && as_dir=.
   for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
     echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -2262,32 +2441,32 @@ IFS=$as_save_IFS
 
 fi
 fi
-CXX=$ac_cv_prog_CXX
-if test -n "$CXX"; then
-  { echo "$as_me:$LINENO: result: $CXX" >&5
-echo "${ECHO_T}$CXX" >&6; }
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
 else
   { echo "$as_me:$LINENO: result: no" >&5
 echo "${ECHO_T}no" >&6; }
 fi
 
 
-    test -n "$CXX" && break
+    test -n "$CC" && break
   done
 fi
-if test -z "$CXX"; then
-  ac_ct_CXX=$CXX
-  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 { echo "$as_me:$LINENO: checking for $ac_word" >&5
 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
-if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
-  if test -n "$ac_ct_CXX"; then
-  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -2296,7 +2475,7 @@ do
   test -z "$as_dir" && as_dir=.
   for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    ac_cv_prog_ac_ct_CC="$ac_prog"
     echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -2306,21 +2485,21 @@ IFS=$as_save_IFS
 
 fi
 fi
-ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
-if test -n "$ac_ct_CXX"; then
-  { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
-echo "${ECHO_T}$ac_ct_CXX" >&6; }
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
 else
   { echo "$as_me:$LINENO: result: no" >&5
 echo "${ECHO_T}no" >&6; }
 fi
 
 
-  test -n "$ac_ct_CXX" && break
+  test -n "$ac_ct_CC" && break
 done
 
-  if test "x$ac_ct_CXX" = x; then
-    CXX="g++"
+  if test "x$ac_ct_CC" = x; then
+    CC=""
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
@@ -2332,14 +2511,21 @@ whose name does not start with the host triplet.  If you think this
 configuration is useful to you, please write to autoconf@gnu.org." >&2;}
 ac_tool_warned=yes ;;
 esac
-    CXX=$ac_ct_CXX
+    CC=$ac_ct_CC
   fi
 fi
 
-  fi
 fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
 # Provide some information about the compiler.
-echo "$as_me:$LINENO: checking for C++ compiler version" >&5
+echo "$as_me:$LINENO: checking for C compiler version" >&5
 ac_compiler=`set X $ac_compile; echo $2`
 { (ac_try="$ac_compiler --version >&5"
 case "(($ac_try" in
@@ -2392,8 +2578,8 @@ ac_clean_files="$ac_clean_files a.out a.exe b.out"
 # Try to create an executable without -o first, disregard a.out.
 # It will help us diagnose broken compilers, and finding out an intuition
 # of exeext.
-{ echo "$as_me:$LINENO: checking for C++ compiler default output file name" >&5
-echo $ECHO_N "checking for C++ compiler default output file name... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }
 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
 #
 # List of possible output files, starting from the most likely.
@@ -2466,9 +2652,9 @@ if test -z "$ac_file"; then
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-{ { echo "$as_me:$LINENO: error: C++ compiler cannot create executables
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
 See \`config.log' for more details." >&5
-echo "$as_me: error: C++ compiler cannot create executables
+echo "$as_me: error: C compiler cannot create executables
 See \`config.log' for more details." >&2;}
    { (exit 77); exit 77; }; }
 fi
@@ -2477,8 +2663,8 @@ ac_exeext=$ac_cv_exeext
 
 # Check that the compiler produces executables we can run.  If not, either
 # the compiler is broken, or we cross compile.
-{ echo "$as_me:$LINENO: checking whether the C++ compiler works" >&5
-echo $ECHO_N "checking whether the C++ compiler works... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }
 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0
 # If not cross compiling, check that we can run a simple program.
 if test "$cross_compiling" != yes; then
@@ -2497,10 +2683,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
     if test "$cross_compiling" = maybe; then
        cross_compiling=yes
     else
-       { { echo "$as_me:$LINENO: error: cannot run C++ compiled programs.
+       { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
 If you meant to cross compile, use \`--host'.
 See \`config.log' for more details." >&5
-echo "$as_me: error: cannot run C++ compiled programs.
+echo "$as_me: error: cannot run C compiled programs.
 If you meant to cross compile, use \`--host'.
 See \`config.log' for more details." >&2;}
    { (exit 1); exit 1; }; }
@@ -2615,737 +2801,6 @@ fi
 echo "${ECHO_T}$ac_cv_objext" >&6; }
 OBJEXT=$ac_cv_objext
 ac_objext=$OBJEXT
-{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
-echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; }
-if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-#ifndef __GNUC__
-       choke me
-#endif
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_compiler_gnu=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_compiler_gnu=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
-echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; }
-GXX=`test $ac_compiler_gnu = yes && echo yes`
-ac_test_CXXFLAGS=${CXXFLAGS+set}
-ac_save_CXXFLAGS=$CXXFLAGS
-{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
-echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; }
-if test "${ac_cv_prog_cxx_g+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
-   ac_cxx_werror_flag=yes
-   ac_cv_prog_cxx_g=no
-   CXXFLAGS="-g"
-   cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_prog_cxx_g=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       CXXFLAGS=""
-      cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cxx_werror_flag=$ac_save_cxx_werror_flag
-        CXXFLAGS="-g"
-        cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_prog_cxx_g=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
-fi
-{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
-echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; }
-if test "$ac_test_CXXFLAGS" = set; then
-  CXXFLAGS=$ac_save_CXXFLAGS
-elif test $ac_cv_prog_cxx_g = yes; then
-  if test "$GXX" = yes; then
-    CXXFLAGS="-g -O2"
-  else
-    CXXFLAGS="-g"
-  fi
-else
-  if test "$GXX" = yes; then
-    CXXFLAGS="-O2"
-  else
-    CXXFLAGS=
-  fi
-fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-DEPDIR="${am__leading_dot}deps"
-
-ac_config_commands="$ac_config_commands depfiles"
-
-
-am_make=${MAKE-make}
-cat > confinc << 'END'
-am__doit:
-       @echo done
-.PHONY: am__doit
-END
-# If we don't find an include directive, just comment out the code.
-{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
-echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; }
-am__include="#"
-am__quote=
-_am_result=none
-# First try GNU make style include.
-echo "include confinc" > confmf
-# We grep out `Entering directory' and `Leaving directory'
-# messages which can occur if `w' ends up in MAKEFLAGS.
-# In particular we don't look at `^make:' because GNU make might
-# be invoked under some other name (usually "gmake"), in which
-# case it prints its new name instead of `make'.
-if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
-   am__include=include
-   am__quote=
-   _am_result=GNU
-fi
-# Now try BSD make style include.
-if test "$am__include" = "#"; then
-   echo '.include "confinc"' > confmf
-   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
-      am__include=.include
-      am__quote="\""
-      _am_result=BSD
-   fi
-fi
-
-
-{ echo "$as_me:$LINENO: result: $_am_result" >&5
-echo "${ECHO_T}$_am_result" >&6; }
-rm -f confinc confmf
-
-# Check whether --enable-dependency-tracking was given.
-if test "${enable_dependency_tracking+set}" = set; then
-  enableval=$enable_dependency_tracking;
-fi
-
-if test "x$enable_dependency_tracking" != xno; then
-  am_depcomp="$ac_aux_dir/depcomp"
-  AMDEPBACKSLASH='\'
-fi
- if test "x$enable_dependency_tracking" != xno; then
-  AMDEP_TRUE=
-  AMDEP_FALSE='#'
-else
-  AMDEP_TRUE='#'
-  AMDEP_FALSE=
-fi
-
-
-
-depcc="$CXX"  am_compiler_list=
-
-{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
-echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; }
-if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
-  # We make a subdir and do the tests there.  Otherwise we can end up
-  # making bogus files that we don't know about and never remove.  For
-  # instance it was reported that on HP-UX the gcc test will end up
-  # making a dummy file named `D' -- because `-MD' means `put the output
-  # in D'.
-  mkdir conftest.dir
-  # Copy depcomp to subdir because otherwise we won't find it if we're
-  # using a relative directory.
-  cp "$am_depcomp" conftest.dir
-  cd conftest.dir
-  # We will build objects and dependencies in a subdirectory because
-  # it helps to detect inapplicable dependency modes.  For instance
-  # both Tru64's cc and ICC support -MD to output dependencies as a
-  # side effect of compilation, but ICC will put the dependencies in
-  # the current directory while Tru64 will put them in the object
-  # directory.
-  mkdir sub
-
-  am_cv_CXX_dependencies_compiler_type=none
-  if test "$am_compiler_list" = ""; then
-     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
-  fi
-  for depmode in $am_compiler_list; do
-    # Setup a source with many dependencies, because some compilers
-    # like to wrap large dependency lists on column 80 (with \), and
-    # we should not choose a depcomp mode which is confused by this.
-    #
-    # We need to recreate these files for each test, as the compiler may
-    # overwrite some of them when testing with obscure command lines.
-    # This happens at least with the AIX C compiler.
-    : > sub/conftest.c
-    for i in 1 2 3 4 5 6; do
-      echo '#include "conftst'$i'.h"' >> sub/conftest.c
-      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
-      # Solaris 8's {/usr,}/bin/sh.
-      touch sub/conftst$i.h
-    done
-    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
-
-    case $depmode in
-    nosideeffect)
-      # after this tag, mechanisms are not by side-effect, so they'll
-      # only be used when explicitly requested
-      if test "x$enable_dependency_tracking" = xyes; then
-       continue
-      else
-       break
-      fi
-      ;;
-    none) break ;;
-    esac
-    # We check with `-c' and `-o' for the sake of the "dashmstdout"
-    # mode.  It turns out that the SunPro C++ compiler does not properly
-    # handle `-M -o', and we need to detect this.
-    if depmode=$depmode \
-       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
-       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
-       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
-         >/dev/null 2>conftest.err &&
-       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
-       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
-       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
-       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
-      # icc doesn't choke on unknown options, it will just issue warnings
-      # or remarks (even with -Werror).  So we grep stderr for any message
-      # that says an option was ignored or not supported.
-      # When given -MP, icc 7.0 and 7.1 complain thusly:
-      #   icc: Command line warning: ignoring option '-M'; no argument required
-      # The diagnosis changed in icc 8.0:
-      #   icc: Command line remark: option '-MP' not supported
-      if (grep 'ignoring option' conftest.err ||
-          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
-        am_cv_CXX_dependencies_compiler_type=$depmode
-        break
-      fi
-    fi
-  done
-
-  cd ..
-  rm -rf conftest.dir
-else
-  am_cv_CXX_dependencies_compiler_type=none
-fi
-
-fi
-{ echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5
-echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6; }
-CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
-
- if
-  test "x$enable_dependency_tracking" != xno \
-  && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
-  am__fastdepCXX_TRUE=
-  am__fastdepCXX_FALSE='#'
-else
-  am__fastdepCXX_TRUE='#'
-  am__fastdepCXX_FALSE=
-fi
-
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_CC="${ac_tool_prefix}gcc"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6; }
-else
-  { echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
-  ac_ct_CC=$CC
-  # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  if test -n "$ac_ct_CC"; then
-  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_ac_ct_CC="gcc"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
-  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6; }
-else
-  { echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6; }
-fi
-
-  if test "x$ac_ct_CC" = x; then
-    CC=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
-ac_tool_warned=yes ;;
-esac
-    CC=$ac_ct_CC
-  fi
-else
-  CC="$ac_cv_prog_CC"
-fi
-
-if test -z "$CC"; then
-          if test -n "$ac_tool_prefix"; then
-    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_CC="${ac_tool_prefix}cc"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6; }
-else
-  { echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6; }
-fi
-
-
-  fi
-fi
-if test -z "$CC"; then
-  # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-  ac_prog_rejected=no
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
-       ac_prog_rejected=yes
-       continue
-     fi
-    ac_cv_prog_CC="cc"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-if test $ac_prog_rejected = yes; then
-  # We found a bogon in the path, so make sure we never use it.
-  set dummy $ac_cv_prog_CC
-  shift
-  if test $# != 0; then
-    # We chose a different compiler from the bogus one.
-    # However, it has the same basename, so the bogon will be chosen
-    # first if we set CC to just the basename; use the full file name.
-    shift
-    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
-  fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6; }
-else
-  { echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6; }
-fi
-
-
-fi
-if test -z "$CC"; then
-  if test -n "$ac_tool_prefix"; then
-  for ac_prog in cl.exe
-  do
-    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6; }
-else
-  { echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6; }
-fi
-
-
-    test -n "$CC" && break
-  done
-fi
-if test -z "$CC"; then
-  ac_ct_CC=$CC
-  for ac_prog in cl.exe
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  if test -n "$ac_ct_CC"; then
-  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_ac_ct_CC="$ac_prog"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
-  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6; }
-else
-  { echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6; }
-fi
-
-
-  test -n "$ac_ct_CC" && break
-done
-
-  if test "x$ac_ct_CC" = x; then
-    CC=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
-ac_tool_warned=yes ;;
-esac
-    CC=$ac_ct_CC
-  fi
-fi
-
-fi
-
-
-test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&5
-echo "$as_me: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
-
-# Provide some information about the compiler.
-echo "$as_me:$LINENO: checking for C compiler version" >&5
-ac_compiler=`set X $ac_compile; echo $2`
-{ (ac_try="$ac_compiler --version >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_compiler --version >&5") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -v >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_compiler -v >&5") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -V >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_compiler -V >&5") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-
 { echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
 if test "${ac_cv_c_compiler_gnu+set}" = set; then
@@ -3675,6 +3130,68 @@ ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+       @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+   am__include=include
+   am__quote=
+   _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+      am__include=.include
+      am__quote="\""
+      _am_result=BSD
+   fi
+fi
+
+
+{ echo "$as_me:$LINENO: result: $_am_result" >&5
+echo "${ECHO_T}$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
 
 depcc="$CC"   am_compiler_list=
 
@@ -3786,12 +3303,12 @@ fi
 
 
 # Checks for libraries.
-# FIXME: Replace `main' with a function in `-lm':
 
 
-{ echo "$as_me:$LINENO: checking for sin in -lm" >&5
-echo $ECHO_N "checking for sin in -lm... $ECHO_C" >&6; }
-if test "${ac_cv_lib_m_sin+set}" = set; then
+
+{ echo "$as_me:$LINENO: checking for main in -lm" >&5
+echo $ECHO_N "checking for main in -lm... $ECHO_C" >&6; }
+if test "${ac_cv_lib_m_main+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   ac_check_lib_save_LIBS=$LIBS
@@ -3803,17 +3320,11 @@ cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char sin ();
+
 int
 main ()
 {
-return sin ();
+return main ();
   ;
   return 0;
 }
@@ -3836,21 +3347,21 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
         test ! -s conftest.err
        } && test -s conftest$ac_exeext &&
        $as_test_x conftest$ac_exeext; then
-  ac_cv_lib_m_sin=yes
+  ac_cv_lib_m_main=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_cv_lib_m_sin=no
+       ac_cv_lib_m_main=no
 fi
 
 rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
       conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ echo "$as_me:$LINENO: result: $ac_cv_lib_m_sin" >&5
-echo "${ECHO_T}$ac_cv_lib_m_sin" >&6; }
-if test $ac_cv_lib_m_sin = yes; then
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_m_main" >&5
+echo "${ECHO_T}$ac_cv_lib_m_main" >&6; }
+if test $ac_cv_lib_m_main = yes; then
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBM 1
 _ACEOF
@@ -7030,13 +6541,6 @@ echo "$as_me: error: conditional \"AMDEP\" was never defined.
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
-if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
-  { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
-   { (exit 1); exit 1; }; }
-fi
 if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
   { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
 Usually this means the macro was only invoked conditionally." >&5
@@ -7344,7 +6848,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.4b27, which was
+This file was extended by polyglot $as_me 1.4.30b, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -7397,7 +6901,7 @@ Report bugs to <bug-autoconf@gnu.org>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-polyglot config.status 1.4b27
+polyglot config.status 1.4.30b
 configured by $0, generated by GNU Autoconf 2.61,
   with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
@@ -7635,11 +7139,11 @@ am__leading_dot!$am__leading_dot$ac_delim
 AMTAR!$AMTAR$ac_delim
 am__tar!$am__tar$ac_delim
 am__untar!$am__untar$ac_delim
-CXX!$CXX$ac_delim
-CXXFLAGS!$CXXFLAGS$ac_delim
+CC!$CC$ac_delim
+CFLAGS!$CFLAGS$ac_delim
 LDFLAGS!$LDFLAGS$ac_delim
 CPPFLAGS!$CPPFLAGS$ac_delim
-ac_ct_CXX!$ac_ct_CXX$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
 EXEEXT!$EXEEXT$ac_delim
 OBJEXT!$OBJEXT$ac_delim
 DEPDIR!$DEPDIR$ac_delim
@@ -7648,12 +7152,6 @@ am__quote!$am__quote$ac_delim
 AMDEP_TRUE!$AMDEP_TRUE$ac_delim
 AMDEP_FALSE!$AMDEP_FALSE$ac_delim
 AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim
-CXXDEPMODE!$CXXDEPMODE$ac_delim
-am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim
-am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim
-CC!$CC$ac_delim
-CFLAGS!$CFLAGS$ac_delim
-ac_ct_CC!$ac_ct_CC$ac_delim
 CCDEPMODE!$CCDEPMODE$ac_delim
 am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim
 am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim
@@ -7664,7 +7162,7 @@ LIBOBJS!$LIBOBJS$ac_delim
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 86; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 80; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
index 03d2aa1..13bbd54 100644 (file)
@@ -2,18 +2,17 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.61)
-AC_INIT([polyglot], [1.4b27], [michel.vandenbergh@uhasselt.be])
+AC_INIT([polyglot], [1.4.30b], [michel.vandenbergh@uhasselt.be])
 AM_INIT_AUTOMAKE
-AC_CONFIG_SRCDIR([mainloop.cpp])
+AC_CONFIG_SRCDIR([mainloop.c])
 AC_CONFIG_HEADER([config.h])
 
 # Checks for programs.
-AC_PROG_CXX
 AC_PROG_CC
 
 # Checks for libraries.
-# FIXME: Replace `main' with a function in `-lm':
-AC_CHECK_LIB([m], [sin])
+
+AC_CHECK_LIB([m], [main])
 
 # Checks for header files.
 AC_HEADER_STDC
diff --git a/engine.c b/engine.c
new file mode 100644 (file)
index 0000000..4dffd4a
--- /dev/null
+++ b/engine.c
@@ -0,0 +1,120 @@
+// engine.c\r
+\r
+// includes\r
+\r
+#include <stdlib.h>\r
+#include <stdarg.h>\r
+#include <string.h>\r
+#include <errno.h>\r
+\r
+\r
+#include "engine.h"\r
+#include "option.h"\r
+#include "pipex.h"\r
+#include "util.h"\r
+\r
+// defines\r
+\r
+#define StringSize 4096\r
+\r
+// variables\r
+\r
+static int write_index = 0;\r
+static char write_buffer[StringSize];\r
+engine_t Engine[1];\r
+\r
+// functions\r
+\r
+// set_affinity()\r
+\r
+void set_affinity(engine_t *engine, int value){\r
+    pipex_set_affinity(engine->pipex,value);\r
+}\r
+\r
+// engine_set_nice_value()\r
+\r
+void engine_set_nice_value(engine_t *engine, int value){\r
+    pipex_set_priority(engine->pipex,value);\r
+}\r
+\r
+// engine_send_queue()\r
+\r
+void engine_send_queue(engine_t * engine, const char *format, ...) {\r
+    if(write_index>=StringSize){\r
+        my_fatal("engine_send_queue(): write_buffer overflow\n");\r
+    }\r
+    write_index += vsnprintf(write_buffer + write_index,\r
+                            StringSize-write_index,\r
+                             format,\r
+                            (va_list) (&format + 1));\r
+}\r
+\r
+// engine_send()\r
+\r
+void engine_send(engine_t * engine, const char *format, ...) {\r
+    if(write_index>=StringSize){\r
+        my_fatal("engine_send(): write_buffer overflow\n");\r
+    }\r
+    vsnprintf(write_buffer + write_index,\r
+              StringSize-write_index,\r
+              format,\r
+              (va_list) (&format + 1));\r
+    pipex_writeln(engine->pipex,write_buffer);\r
+    write_index = 0;\r
+}\r
+\r
+// engine_close()\r
+\r
+void engine_close(engine_t * engine){\r
+    char string[StringSize];\r
+    pipex_send_eof(engine->pipex);\r
+        // TODO: Timeout\r
+    while (!engine_eof(engine)) { \r
+      engine_get(Engine,string);\r
+    }\r
+    pipex_exit(engine->pipex);\r
+}\r
+\r
+// engine_open()\r
+\r
+void engine_open(engine_t * engine){\r
+    int affinity;\r
+    char *my_dir;\r
+    if( (my_dir = my_getcwd( NULL, 0 )) == NULL )\r
+        my_fatal("engine_open(): no current directory: %s\n",strerror(errno));\r
+    if(my_chdir(option_get_string("EngineDir"))){\r
+        my_fatal("engine_open(): cannot change directory: %s\n",strerror(errno));\r
+    }\r
+    pipex_open(engine->pipex,"Engine",option_get_string("EngineCommand"));\r
+    if(pipex_active(engine->pipex)){\r
+            //play with affinity (bad idea)\r
+        affinity=option_get_int("Affinity");\r
+        if(affinity!=-1) set_affinity(engine,affinity); //AAA\r
+            //lets go back\r
+        my_chdir(my_dir);\r
+            // set a low priority\r
+        if (option_get_bool("UseNice")){\r
+            my_log("POLYGLOT Adjust Engine Piority\n");\r
+            engine_set_nice_value(engine, option_get_int("NiceValue"));\r
+        }\r
+    }\r
+    \r
+}\r
+\r
+bool engine_active(engine_t *engine){\r
+    return pipex_active(engine->pipex);\r
+}\r
+\r
+bool engine_eof(engine_t *engine){\r
+    return pipex_eof(engine->pipex);\r
+}\r
+\r
+bool engine_get_non_blocking(engine_t * engine, char *string){\r
+    return pipex_readln_nb(engine->pipex,string);\r
+ }\r
+\r
+void engine_get(engine_t * engine, char *string){\r
+    pipex_readln(engine->pipex,string);\r
+}\r
+\r
+\r
index b3a950c..2a408e3 100644 (file)
--- a/engine.h
+++ b/engine.h
@@ -3,28 +3,17 @@
 #ifndef ENGINE_H\r
 #define ENGINE_H\r
 \r
-// defines\r
-\r
-#define ENGINE_EOF 1\r
-#define ENGINE_ACTIVE 2\r
-\r
 // includes\r
 \r
 #include "io.h"\r
 #include "util.h"\r
-#include "pipe.h"\r
+#include "pipex.h"\r
 \r
 // types\r
 \r
-struct engine_t {\r
-#ifndef _WIN32\r
-    io_t io[1];\r
-    pid_t pid;\r
-#else\r
-    PipeStruct io;\r
-#endif\r
-    uint32 state;\r
-};\r
+typedef struct {\r
+    pipex_t pipex[1];\r
+} engine_t;\r
 \r
 \r
 \r
@@ -41,8 +30,8 @@ extern bool engine_active     (engine_t * engine);
 extern bool engine_eof        (engine_t * engine);\r
 extern void engine_send       (engine_t * engine, const char format[], ...);\r
 extern void engine_send_queue (engine_t * engine, const char format[], ...);\r
-extern bool engine_get_non_blocking(engine_t * engine, char string[], int size);\r
-extern void engine_get        (engine_t * engine, char string[], int size);\r
+extern bool engine_get_non_blocking(engine_t * engine, char string[]);\r
+extern void engine_get        (engine_t * engine, char string[]);\r
 extern void engine_set_nice_value(engine_t * engine, int value);\r
 \r
 #endif // !defined ENGINE_H\r
diff --git a/epd.c b/epd.c
new file mode 100644 (file)
index 0000000..c79c399
--- /dev/null
+++ b/epd.c
@@ -0,0 +1,444 @@
+\r
+// epd.c\r
+\r
+// includes\r
+\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "board.h"\r
+#include "engine.h"\r
+#include "epd.h"\r
+#include "fen.h"\r
+#include "line.h"\r
+#include "main.h"\r
+#include "move.h"\r
+#include "move_legal.h"\r
+#include "option.h"\r
+#include "parse.h"\r
+#include "san.h"\r
+#include "uci.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const bool UseDebug = FALSE;\r
+static const bool UseTrace = FALSE;\r
+\r
+static const int StringSize = 4096;\r
+\r
+// variables\r
+\r
+static int MinDepth;\r
+static int MaxDepth;\r
+\r
+static double MaxTime;\r
+static double MinTime;\r
+\r
+static int DepthDelta;\r
+\r
+static int FirstMove;\r
+static int FirstDepth;\r
+static int FirstSelDepth;\r
+static int FirstScore;\r
+static double FirstTime;\r
+static uint64 FirstNodeNb;\r
+static move_t FirstPV[LineSize];\r
+\r
+static int LastMove;\r
+static int LastDepth;\r
+static int LastSelDepth;\r
+static int LastScore;\r
+static double LastTime;\r
+static uint64 LastNodeNb;\r
+static move_t LastPV[LineSize];\r
+\r
+static my_timer_t Timer[1];\r
+\r
+// prototypes\r
+\r
+static void epd_test_file  (const char file_name[]);\r
+\r
+static bool is_solution    (int move, const board_t * board, const char bm[], const char am[]);\r
+static bool string_contain (const char string[], const char substring[]);\r
+\r
+static bool engine_step    ();\r
+\r
+// functions\r
+\r
+// epd_test()\r
+\r
+void epd_test(int argc, char * argv[]) {\r
+\r
+   int i;\r
+   const char * epd_file;\r
+\r
+   epd_file = NULL;\r
+   my_string_set(&epd_file,"wac.epd");\r
+\r
+   MinDepth = 8;\r
+   MaxDepth = 63;\r
+\r
+   MinTime = 1.0;\r
+   MaxTime = 5.0;\r
+\r
+   DepthDelta = 3;\r
+\r
+   for (i = 1; i < argc; i++) {\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (my_string_equal(argv[i],"epd-test")) {\r
+\r
+         // skip\r
+\r
+      } else if (my_string_equal(argv[i],"-epd")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
+\r
+         my_string_set(&epd_file,argv[i]);\r
+\r
+      } else if (my_string_equal(argv[i],"-min-depth")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
+\r
+         MinDepth = atoi(argv[i]);\r
+\r
+      } else if (my_string_equal(argv[i],"-max-depth")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
+\r
+         MaxDepth = atoi(argv[i]);\r
+\r
+      } else if (my_string_equal(argv[i],"-min-time")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
+\r
+         MinTime = atof(argv[i]);\r
+\r
+      } else if (my_string_equal(argv[i],"-max-time")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
+\r
+         MaxTime = atof(argv[i]);\r
+\r
+      } else if (my_string_equal(argv[i],"-depth-delta")) {\r
+\r
+         i++;\r
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
+\r
+         DepthDelta = atoi(argv[i]);\r
+\r
+      } else {\r
+\r
+         my_fatal("epd_test(): unknown option \"%s\"\n",argv[i]);\r
+      }\r
+   }\r
+\r
+   if(MinTime>MaxTime){\r
+       MaxTime=MinTime;\r
+   }\r
+  \r
+   epd_test_file(epd_file);\r
+}\r
+\r
+// epd_test_file()\r
+\r
+static void epd_test_file(const char file_name[]) {\r
+\r
+   FILE * file;\r
+   int hit, tot;\r
+   char epd[StringSize];\r
+   char am[StringSize], bm[StringSize], id[StringSize];\r
+   board_t board[1];\r
+   char string[StringSize];\r
+   int move;\r
+   char pv_string[StringSize];\r
+   bool correct;\r
+   double depth_tot, time_tot, node_tot;\r
+   int line=0;\r
+\r
+   ASSERT(file_name!=NULL);\r
+\r
+   // init\r
+\r
+   file = fopen(file_name,"r");\r
+   if (file == NULL) my_fatal("epd_test_file(): can't open file \"%s\": %s\n",file_name,strerror(errno));\r
+\r
+   hit = 0;\r
+   tot = 0;\r
+\r
+   depth_tot = 0.0;\r
+   time_tot = 0.0;\r
+   node_tot = 0.0;\r
+\r
+   printf("\nEngineName=%s\n",option_get_string("EngineName"));\r
+\r
+   printf("\n[Search parameters: MaxDepth=%d   MaxTime=%.1f   DepthDelta=%d   MinDepth=%d   MinTime=%.1f]\n\n",MaxDepth,MaxTime,DepthDelta,MinDepth,MinTime);\r
+\r
+   // loop\r
+\r
+   while (my_file_read_line(file,epd,StringSize)) {\r
+       line++;\r
+       if(my_string_whitespace(epd)) continue;\r
+      if (UseTrace) printf("%s\n",epd);\r
+\r
+      if (!epd_get_op(epd,"am",am,StringSize)) strcpy(am,"");\r
+      if (!epd_get_op(epd,"bm",bm,StringSize)) strcpy(bm,"");\r
+      if (!epd_get_op(epd,"id",id,StringSize)) strcpy(id,"");\r
+\r
+      if (my_string_empty(am) && my_string_empty(bm)) {\r
+          my_fatal("epd_test(): no am or bm field at line %d\n",line);\r
+      }\r
+\r
+      // init\r
+\r
+      uci_send_ucinewgame(Uci);\r
+      uci_send_isready_sync(Uci);\r
+\r
+      ASSERT(!Uci->searching);\r
+\r
+      // position\r
+      if (!board_from_fen(board,epd)) ASSERT(FALSE);\r
+      if (!board_to_fen(board,string,StringSize)) ASSERT(FALSE);\r
+\r
+      engine_send(Engine,"position fen %s");\r
+\r
+      // search\r
+\r
+      my_timer_start(Timer); // also resets\r
+      \r
+      // which ones of the next two alternatives is best?\r
+      engine_send(Engine,"go movetime %.0f depth %d",MaxTime*1000.0,MaxDepth);\r
+      //engine_send(Engine,"go infinite");\r
+\r
+      // engine data\r
+\r
+      board_copy(Uci->board,board);\r
+\r
+      uci_clear(Uci);\r
+      Uci->searching = TRUE;\r
+      Uci->pending_nb++;\r
+\r
+      FirstMove = MoveNone;\r
+      FirstDepth = 0;\r
+      FirstSelDepth = 0;\r
+      FirstScore = 0;\r
+      FirstTime = 0.0;\r
+      FirstNodeNb = 0;\r
+      line_clear(FirstPV);\r
+\r
+      LastMove = MoveNone;\r
+      LastDepth = 0;\r
+      LastSelDepth = 0;\r
+      LastScore = 0;\r
+      LastTime = 0.0;\r
+      LastNodeNb = 0;\r
+      line_clear(LastPV);\r
+\r
+      // parse engine output\r
+\r
+      while (!engine_eof(Engine) && engine_step()) {\r
+          bool stop=FALSE;\r
+\r
+         // stop search?\r
+//          printf("Uci->time=%.2f time=%.2f\n",Uci->time,my_timer_elapsed_real(Timer));\r
+          if (Uci->depth > MaxDepth){\r
+              my_log("POLYGLOT Maximum depth %d reached\n",MaxDepth);\r
+              stop=TRUE;\r
+          }else if(my_timer_elapsed_real(Timer) >= MaxTime){\r
+              my_log("POLYGLOT Maximum search time %.2fs reached\n",MaxTime);\r
+              stop=TRUE;\r
+          }else if(Uci->depth - FirstDepth >= DepthDelta){\r
+              if(Uci->depth > MinDepth){\r
+                  if(Uci->time >= MinTime){\r
+                      if(is_solution(FirstMove,board,bm,am)){\r
+                          my_log("POLYGLOT Solution found\n",MaxTime);\r
+                          stop=TRUE;\r
+                      }\r
+                  }\r
+              }\r
+          }\r
+          if(stop){\r
+              my_log("POLYGLOT Stopping engine\n");\r
+              engine_send(Engine,"stop");\r
+              break;\r
+          }\r
+      }\r
+      \r
+      move = FirstMove;\r
+      correct = is_solution(move,board,bm,am);\r
+\r
+      if (correct) hit++;\r
+      tot++;\r
+\r
+      if (correct) {\r
+          depth_tot += ((double)FirstDepth);\r
+         time_tot += FirstTime;\r
+         node_tot += ((double)((sint64)FirstNodeNb));\r
+      }\r
+\r
+      printf("%2d: %-15s %s %4d",tot,id,correct?"OK":"--",hit);\r
+\r
+      if (!line_to_san(LastPV,Uci->board,pv_string,StringSize)) ASSERT(FALSE);\r
+      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);\r
+   }\r
+\r
+   printf("\nscore=%d/%d",hit,tot);\r
+\r
+   if (hit != 0) {\r
+\r
+       depth_tot /= ((double)hit);\r
+       time_tot /= ((double)hit);\r
+       node_tot /= ((double)hit);\r
+\r
+      printf(" [averages on correct positions: depth=%.1f time=%.2f nodes=%.0f]",depth_tot,time_tot,node_tot);\r
+   }\r
+\r
+   printf("\n");\r
+\r
+   fclose(file);\r
+   quit();\r
+}\r
+\r
+// is_solution()\r
+\r
+static bool is_solution(int move, const board_t * board, const char bm[], const char am[]) {\r
+\r
+   char move_string[256];\r
+   bool correct;\r
+\r
+   ASSERT(move!=MoveNone);\r
+   ASSERT(bm!=NULL);\r
+   ASSERT(am!=NULL);\r
+\r
+   if (!move_is_legal(move,board)) {\r
+      board_disp(board);\r
+      move_disp(move,board);\r
+      printf("\n\n");\r
+   }\r
+\r
+   ASSERT(move_is_legal(move,board));\r
+\r
+   if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE);\r
+\r
+   correct = FALSE;\r
+   if (!my_string_empty(bm)) {\r
+      correct = string_contain(bm,move_string);\r
+   } else if (!my_string_empty(am)) {\r
+      correct = !string_contain(am,move_string);\r
+   } else {\r
+      ASSERT(FALSE);\r
+   }\r
+\r
+   return correct;\r
+}\r
+\r
+// epd_get_op()\r
+\r
+bool epd_get_op(const char record[], const char opcode[], char string[], int size) {\r
+\r
+   char op[256];\r
+   int len;\r
+   const char *p_start, *p_end;\r
+\r
+   ASSERT(record!=NULL);\r
+   ASSERT(opcode!=NULL);\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>0);\r
+\r
+   // find the opcode\r
+\r
+   sprintf(op," %s ",opcode); \r
+\r
+   p_start = strstr(record,op);\r
+   if (p_start == NULL){\r
+          sprintf(op,";%s ",opcode); \r
+          p_start = strstr(record,op);\r
+          if (p_start == NULL){\r
+              return FALSE;\r
+          }\r
+   }\r
+\r
+   // skip the opcode\r
+\r
+   p_start += strlen(op);\r
+\r
+   // find the end\r
+   p_end = strchr(p_start,';');\r
+   if (p_end == NULL) return FALSE;\r
+\r
+   // calculate the length\r
+\r
+   len = p_end - p_start;\r
+   if (size < len+1) my_fatal("epd_get_op(): size < len+1\n");\r
+\r
+   strncpy(string,p_start,len);\r
+   string[len] = '\0';\r
+\r
+   return TRUE;\r
+}\r
+\r
+// string_contain()\r
+\r
+static bool string_contain(const char string[], const char substring[]) {\r
+\r
+   char new_string[StringSize], *p;\r
+\r
+   strcpy(new_string,string); // HACK\r
+\r
+   for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) {\r
+      if (my_string_equal(p,substring)) return TRUE;\r
+   }\r
+\r
+   return FALSE;\r
+}\r
+\r
+// engine_step()\r
+\r
+static bool engine_step() {\r
+\r
+   char string[StringSize];\r
+   int event;\r
+\r
+   engine_get(Engine,string);\r
+   event = uci_parse(Uci,string);\r
+\r
+   if ((event & EVENT_MOVE) != 0) {\r
+\r
+      return FALSE;\r
+   }\r
+\r
+   if ((event & EVENT_PV) != 0) {\r
+\r
+      LastMove = Uci->best_pv[0];\r
+      LastDepth = Uci->best_depth;\r
+      LastSelDepth = Uci->best_sel_depth;\r
+      LastScore = Uci->best_score;\r
+      LastTime = Uci->time;\r
+      LastNodeNb = Uci->node_nb;\r
+      line_copy(LastPV,Uci->best_pv);\r
+\r
+      if (LastMove != FirstMove) {\r
+         FirstMove = LastMove;\r
+         FirstDepth = LastDepth;\r
+         FirstSelDepth = LastSelDepth;\r
+         FirstScore = LastScore;\r
+         FirstTime = LastTime;\r
+         FirstNodeNb = LastNodeNb;\r
+         line_copy(FirstPV,LastPV);\r
+      }\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+// end of epd.cpp\r
+\r
diff --git a/fen.c b/fen.c
new file mode 100644 (file)
index 0000000..be3ec17
--- /dev/null
+++ b/fen.c
@@ -0,0 +1,392 @@
+\r
+// fen.c\r
+\r
+// includes\r
+\r
+#include <ctype.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#include "board.h"\r
+#include "colour.h"\r
+#include "fen.h"\r
+#include "option.h"\r
+#include "piece.h"\r
+#include "square.h"\r
+#include "util.h"\r
+\r
+// "constants"\r
+\r
+// const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1";\r
+const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";\r
+\r
+// variables\r
+\r
+static const bool Strict = FALSE;\r
+\r
+// macros\r
+\r
+#define skip_white_space() \\r
+        c=string[pos];\\r
+        if (c != ' ' && c!='\t') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); \\r
+        while(c==' ' || c=='\t') c=string[++pos];\r
+\r
+\r
+// functions\r
+\r
+// board_from_fen()\r
+\r
+bool board_from_fen(board_t * board, const char string[]) {\r
+\r
+   int pos;\r
+   int file, rank, sq;\r
+   int c;\r
+   int i, len;\r
+   int piece;\r
+   int king_pos[ColourNb];\r
+\r
+   ASSERT(board!=NULL);\r
+   ASSERT(string!=NULL);\r
+\r
+   board_clear(board);\r
+\r
+   king_pos[White] = SquareNone;\r
+   king_pos[Black] = SquareNone;\r
+\r
+   pos = 0;\r
+   c = string[pos];\r
+\r
+   // piece placement\r
+\r
+   for (rank = 7; rank >= 0; rank--) {\r
+\r
+      for (file = 0; file < 8;) {\r
+\r
+         sq = square_make(file,rank);\r
+\r
+         if (c >= '1' && c <= '8') { // empty square(s)\r
+\r
+            len = c - '0';\r
+            if (file + len > 8) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+\r
+            for (i = 0; i < len; i++) {\r
+               board->square[sq++] = Empty;\r
+               file++;\r
+            }\r
+\r
+         } else { // piece\r
+\r
+            piece = piece_from_char(c);\r
+            if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+\r
+            if (piece_is_king(piece)) king_pos[piece_colour(piece)] = sq;\r
+\r
+            board->square[sq++] = piece;\r
+            file++;\r
+         }\r
+\r
+         c = string[++pos];\r
+      }\r
+\r
+      if (rank > 0) {\r
+         if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+         c = string[++pos];\r
+     }\r
+   }\r
+\r
+   // active colour\r
+\r
+   skip_white_space();\r
+\r
+   switch (c) {\r
+   case 'w':\r
+      board->turn = White;\r
+      break;\r
+   case 'b':\r
+      board->turn = Black;\r
+      break;\r
+   default:\r
+      my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+      break;\r
+   }\r
+\r
+   c = string[++pos];\r
+\r
+   // castling\r
+\r
+   skip_white_space();\r
+\r
+   board->castle[White][SideH] = SquareNone;\r
+   board->castle[White][SideA] = SquareNone;\r
+   board->castle[Black][SideH] = SquareNone;\r
+   board->castle[Black][SideA] = SquareNone;\r
+\r
+   if (c == '-') { // no castling rights\r
+\r
+      c = string[++pos];\r
+\r
+   } else {\r
+\r
+      // TODO: filter out illegal rights\r
+\r
+      do {\r
+\r
+         if (FALSE) {\r
+\r
+         } else if (c == 'K') {\r
+\r
+            for (sq = H1; sq > king_pos[White]; sq--) {\r
+               if (board->square[sq] == WhiteRook256) {\r
+                  board->castle[White][SideH] = sq;\r
+                  break;\r
+               }\r
+            }\r
+\r
+         } else if (c == 'Q') {\r
+\r
+            for (sq = A1; sq < king_pos[White]; sq++) {\r
+               if (board->square[sq] == WhiteRook256) {\r
+                  board->castle[White][SideA] = sq;\r
+                  break;\r
+               }\r
+            }\r
+\r
+         } else if (c == 'k') {\r
+\r
+            for (sq = H8; sq > king_pos[Black]; sq--) {\r
+               if (board->square[sq] == BlackRook256) {\r
+                  board->castle[Black][SideH] = sq;\r
+                  break;\r
+               }\r
+            }\r
+\r
+         } else if (c == 'q') {\r
+\r
+            for (sq = A8; sq < king_pos[Black]; sq++) {\r
+               if (board->square[sq] == BlackRook256) {\r
+                  board->castle[Black][SideA] = sq;\r
+                  break;\r
+               }\r
+            }\r
+\r
+         } else if (c >= 'A' && c <= 'H') {\r
+\r
+            // white castling right\r
+\r
+            sq = square_make(file_from_char(tolower(c)),Rank1);\r
+\r
+            if (sq > king_pos[White]) { // h side\r
+               board->castle[White][SideH] = sq;\r
+            } else { // a side\r
+               board->castle[White][SideA] = sq;\r
+            }\r
+\r
+         } else if (c >= 'a' && c <= 'h') {\r
+\r
+            // black castling right\r
+\r
+            sq = square_make(file_from_char(tolower(c)),Rank8);\r
+\r
+            if (sq > king_pos[Black]) { // h side\r
+               board->castle[Black][SideH] = sq;\r
+            } else { // a side\r
+               board->castle[Black][SideA] = sq;\r
+            }\r
+\r
+         } else {\r
+\r
+            my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+         }\r
+\r
+         c = string[++pos];\r
+\r
+      } while (c != ' ');\r
+   }\r
+\r
+   // en-passant\r
+\r
+   skip_white_space();\r
+\r
+   if (c == '-') { // no en-passant\r
+\r
+      sq = SquareNone;\r
+      c = string[++pos];\r
+\r
+   } else {\r
+\r
+      if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+      file = file_from_char(c);\r
+      c = string[++pos];\r
+\r
+      if (c < '1' || c > '8') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+      rank = rank_from_char(c);\r
+      c = string[++pos];\r
+\r
+      sq = square_make(file,rank);\r
+   }\r
+\r
+   board->ep_square = sq;\r
+\r
+   // halfmove clock\r
+\r
+   board->ply_nb = 0;\r
+   board->move_nb = 0; // HACK, in case of broken syntax\r
+\r
+   if (c != ' ') {\r
+      if (!Strict) goto update;\r
+      my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+   }\r
+   c = string[++pos];\r
+\r
+   if (!isdigit(c)) {\r
+      if (!Strict) goto update;\r
+      my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+   }\r
+\r
+   board->ply_nb = atoi(&string[pos]);\r
+   do c = string[++pos]; while (isdigit(c));\r
+\r
+   // fullmove number\r
+\r
+   board->move_nb = 0;\r
+\r
+   if (c != ' ') {\r
+      if (!Strict) goto update;\r
+      my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+   }\r
+   c = string[++pos];\r
+\r
+   if (!isdigit(c)) {\r
+      if (!Strict) goto update;\r
+      my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos);\r
+   }\r
+\r
+   board->move_nb = atoi(&string[pos]) - 1;\r
+   do c = string[++pos]; while (isdigit(c));\r
+\r
+   // board update\r
+\r
+update:\r
+   board_init_list(board);\r
+\r
+   return TRUE;\r
+}\r
+\r
+// board_to_fen()\r
+\r
+bool board_to_fen(const board_t * board, char string[], int size) {\r
+\r
+   int pos;\r
+   int file, rank;\r
+   int sq, piece;\r
+   int c;\r
+   int len;\r
+   int old_pos;\r
+\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=92);\r
+\r
+   // init\r
+\r
+   if (size < 92) return FALSE;\r
+\r
+   pos = 0;\r
+\r
+   // piece placement\r
+\r
+   for (rank = 7; rank >= 0; rank--) {\r
+\r
+      for (file = 0; file < 8;) {\r
+\r
+         sq = square_make(file,rank);\r
+         piece = board->square[sq];\r
+         ASSERT(piece==Empty||piece_is_ok(piece));\r
+\r
+         if (piece == Empty) {\r
+\r
+            len = 0;\r
+            for (; file < 8 && board->square[square_make(file,rank)] == Empty; file++) {\r
+               len++;\r
+            }\r
+\r
+            ASSERT(len>=1&&len<=8);\r
+            c = '0' + len;\r
+\r
+         } else {\r
+\r
+            c = piece_to_char(piece);\r
+            file++;\r
+         }\r
+\r
+         string[pos++] = c;\r
+      }\r
+\r
+      string[pos++] = '/';\r
+   }\r
+\r
+   string[pos-1] = ' '; // HACK: remove the last '/'\r
+\r
+   // active colour\r
+\r
+   string[pos++] = (colour_is_white(board->turn)) ? 'w' : 'b';\r
+   string[pos++] = ' ';\r
+\r
+   // castling\r
+\r
+   old_pos = pos;\r
+\r
+   if (option_get_bool("Chess960")) {\r
+\r
+      // FEN-960\r
+\r
+      if (board->castle[White][SideH] != SquareNone) {\r
+         string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideH])));\r
+      }\r
+\r
+      if (board->castle[White][SideA] != SquareNone) {\r
+         string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideA])));\r
+      }\r
+\r
+      if (board->castle[Black][SideH] != SquareNone) {\r
+         string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideH])));\r
+      }\r
+\r
+      if (board->castle[Black][SideA] != SquareNone) {\r
+         string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideA])));\r
+      }\r
+\r
+   } else {\r
+\r
+      // FEN\r
+\r
+      if (board->castle[White][SideH] != SquareNone) string[pos++] = 'K';\r
+      if (board->castle[White][SideA] != SquareNone) string[pos++] = 'Q';\r
+      if (board->castle[Black][SideH] != SquareNone) string[pos++] = 'k';\r
+      if (board->castle[Black][SideA] != SquareNone) string[pos++] = 'q';\r
+   }\r
+\r
+   if (pos == old_pos) string[pos++] = '-';\r
+\r
+   string[pos++] = ' ';\r
+\r
+   // en-passant\r
+\r
+   if (board->ep_square == SquareNone) {\r
+      string[pos++] = '-';\r
+   } else {\r
+      if (!square_to_string(board->ep_square,&string[pos],3)) return FALSE;\r
+      pos += 2;\r
+   }\r
+\r
+   string[pos++] = ' ';\r
+\r
+   // halfmove clock and fullmove number\r
+\r
+   sprintf(&string[pos],"%d %d",board->ply_nb,board->move_nb+1);\r
+\r
+   return TRUE;\r
+}\r
+\r
+// end of fen.cpp\r
+\r
diff --git a/game.c b/game.c
new file mode 100644 (file)
index 0000000..199d344
--- /dev/null
+++ b/game.c
@@ -0,0 +1,361 @@
+\r
+// game.c\r
+\r
+// includes\r
+\r
+#include "attack.h"\r
+#include "board.h"\r
+#include "fen.h"\r
+#include "game.h"\r
+#include "list.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_legal.h"\r
+#include "piece.h"\r
+#include "square.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const bool UseSlowDebug = FALSE;\r
+\r
+// variables\r
+\r
+game_t Game[1];\r
+\r
+// prototypes\r
+\r
+static void game_update      (game_t * game);\r
+static int  game_comp_status (const game_t * game);\r
+\r
+// functions\r
+\r
+// game_is_ok()\r
+\r
+bool game_is_ok(const game_t * game) {\r
+\r
+   board_t board[1];\r
+   int pos, move;\r
+\r
+   if (game == NULL) return FALSE;\r
+\r
+   if (game->size < 0 || game->size > GameSize) return FALSE;\r
+   if (game->pos < 0 || game->pos > game->size) return FALSE;\r
+\r
+   // optional heavy DEBUG mode\r
+\r
+   if (!UseSlowDebug) return TRUE;\r
+\r
+   if (!board_is_ok(game->start_board)) return FALSE;\r
+\r
+   board_copy(board,game->start_board);\r
+\r
+   for (pos = 0; pos <= game->size; pos++) {\r
+\r
+      if (pos == game->pos) {\r
+         if (!board_equal(game->board,board)) return FALSE;\r
+      }\r
+\r
+      if (pos >= game->size) break;\r
+\r
+      if (game->key[pos] != board->key) return FALSE;\r
+\r
+      move = game->move[pos];\r
+      //if (!move_is_legal(move,board));  //huh??\r
+         if (!move_is_legal(move,board)) return FALSE;  \r
+\r
+      move_do(board,move);\r
+   }\r
+\r
+   if (game->status != game_comp_status(game)) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// game_clear()\r
+\r
+void game_clear(game_t * game) {\r
+\r
+   ASSERT(game!=NULL);\r
+\r
+   game_init(game,StartFen);\r
+}\r
+\r
+// game_init()\r
+\r
+bool game_init(game_t * game, const char fen[]) {\r
+\r
+   ASSERT(game!=NULL);\r
+   ASSERT(fen!=NULL);\r
+\r
+   if (!board_from_fen(game->start_board,fen)) return FALSE;\r
+\r
+   game->size = 0;\r
+\r
+   board_copy(game->board,game->start_board);\r
+   game->pos = 0;\r
+\r
+   game_update(game);\r
+\r
+   return TRUE;\r
+}\r
+\r
+// game_status()\r
+\r
+int game_status(const game_t * game) {\r
+\r
+   ASSERT(game!=NULL);\r
+\r
+   return game->status;\r
+}\r
+\r
+// game_size()\r
+\r
+int game_size(const game_t * game) {\r
+\r
+   ASSERT(game!=NULL);\r
+\r
+   return game->size;\r
+}\r
+\r
+// game_pos()\r
+\r
+int game_pos(const game_t * game) {\r
+\r
+   ASSERT(game!=NULL);\r
+\r
+   return game->pos;\r
+}\r
+\r
+// game_move()\r
+\r
+int game_move(const game_t * game, int pos) {\r
+\r
+   ASSERT(game!=NULL);\r
+   ASSERT(pos>=0&&pos<game->pos);\r
+\r
+   return game->move[pos];\r
+}\r
+\r
+// game_get_board()\r
+\r
+void game_get_board(const game_t * game, board_t * board) {\r
+    game_get_board_ex(game, board, -1);\r
+}\r
+\r
+// game_get_board_ex()\r
+\r
+void game_get_board_ex(const game_t * game, board_t * board, int pos) {\r
+\r
+   int start;\r
+   int i;\r
+\r
+   ASSERT(game!=NULL);\r
+   ASSERT(board!=NULL);\r
+   ASSERT(pos==-1||(pos>=0&&pos<=game->size)); // HACK\r
+\r
+   if (pos < 0) pos = game->pos;\r
+\r
+   if (pos >= game->pos) { // forward from current position\r
+      start = game->pos;\r
+      board_copy(board,game->board);\r
+   } else { // backward => replay the whole game\r
+      start = 0;\r
+      board_copy(board,game->start_board);\r
+   }\r
+\r
+   for (i = start; i < pos; i++) move_do(board,game->move[i]);\r
+}\r
+\r
+// game_turn()\r
+\r
+int game_turn(const game_t * game) {\r
+\r
+   ASSERT(game!=NULL);\r
+\r
+   return game->board->turn;\r
+}\r
+\r
+// game_move_nb()\r
+\r
+int game_move_nb(const game_t * game) {\r
+\r
+   ASSERT(game!=NULL);\r
+\r
+   return game->board->move_nb;\r
+}\r
+\r
+// game_add_move()\r
+\r
+void game_add_move(game_t * game, int move) {\r
+\r
+   ASSERT(game!=NULL);\r
+   ASSERT(move_is_ok(move));\r
+\r
+   ASSERT(move_is_legal(move,game->board));\r
+\r
+   if (game->pos >= GameSize) my_fatal("game_add_move(): game overflow\n");\r
+\r
+   game->move[game->pos] = move;\r
+   game->key[game->pos] = game->board->key;\r
+\r
+   move_do(game->board,move);\r
+   game->pos++;\r
+\r
+   game->size = game->pos; // truncate game, HACK: before calling game_is_ok() in game_update()\r
+\r
+   game_update(game);\r
+}\r
+\r
+// game_rem_move()\r
+\r
+void game_rem_move(game_t * game) {\r
+\r
+   ASSERT(game!=NULL);\r
+\r
+   game_goto(game,game->pos-1);\r
+\r
+   game->size = game->pos; // truncate game\r
+}\r
+\r
+// game_goto()\r
+\r
+void game_goto(game_t * game, int pos) {\r
+\r
+   int i;\r
+\r
+   ASSERT(game!=NULL);\r
+   ASSERT(pos>=0&&pos<=game->size);\r
+\r
+   if (pos < game->pos) { // going backward => replay the whole game\r
+      board_copy(game->board,game->start_board);\r
+      game->pos = 0;\r
+   }\r
+\r
+   for (i = game->pos; i < pos; i++) move_do(game->board,game->move[i]);\r
+   ASSERT(i==pos);\r
+\r
+   game->pos = pos;\r
+\r
+   game_update(game);\r
+}\r
+\r
+// game_disp()\r
+\r
+void game_disp(const game_t * game) {\r
+\r
+   board_t board[1];\r
+   int i, move;\r
+\r
+   ASSERT(game_is_ok(game));\r
+\r
+   board_copy(board,game->start_board);\r
+\r
+   board_disp(board);\r
+\r
+   for (i = 0; i < game->pos; i++) {\r
+\r
+      move = game->move[i];\r
+      move_disp(move,board);\r
+\r
+      move_do(board,move);\r
+   }\r
+\r
+   my_log("POLYGLOT\n");\r
+\r
+   board_disp(board);\r
+}\r
+\r
+// game_update()\r
+\r
+static void game_update(game_t * game) {\r
+\r
+   ASSERT(game!=NULL);\r
+\r
+   game->status = game_comp_status(game);\r
+\r
+   ASSERT(game_is_ok(game));\r
+}\r
+\r
+// game_comp_status()\r
+\r
+static int game_comp_status(const game_t * game) {\r
+\r
+   int i, n;\r
+   int wb, bb;\r
+   const board_t * board;\r
+   uint64 key;\r
+   int start;\r
+\r
+   ASSERT(game!=NULL);\r
+\r
+   // init\r
+\r
+   board = game->board;\r
+\r
+   // mate and stalemate\r
+\r
+   if (!board_can_play(board)) {\r
+      if (FALSE) {\r
+      } else if (is_in_check(board,Black)) { // HACK\r
+         return WHITE_MATES;\r
+      } else if (is_in_check(board,White)) { // HACK\r
+         return BLACK_MATES;\r
+      } else {\r
+         return STALEMATE;\r
+      }\r
+   }\r
+\r
+   // insufficient material\r
+\r
+   if (board->number[WhitePawn12]  == 0\r
+    && board->number[BlackPawn12]  == 0\r
+    && board->number[WhiteQueen12] == 0\r
+    && board->number[BlackQueen12] == 0\r
+    && board->number[WhiteRook12]  == 0\r
+    && board->number[BlackRook12]  == 0) {\r
+\r
+      if (board->number[WhiteBishop12]\r
+        + board->number[BlackBishop12]\r
+        + board->number[WhiteKnight12]\r
+        + board->number[BlackKnight12] <= 1) { // KK, KBK and KNK\r
+\r
+         return DRAW_MATERIAL;\r
+\r
+      } else if (board->number[WhiteBishop12] == 1\r
+              && board->number[BlackBishop12] == 1\r
+              && board->number[WhiteKnight12] == 0\r
+              && board->number[BlackKnight12] == 0) {\r
+\r
+         wb = board->list[White][1]; // HACK\r
+         bb = board->list[Black][1]; // HACK\r
+\r
+         if (square_colour(wb) == square_colour(bb)) { // KBKB\r
+            return DRAW_MATERIAL;\r
+         }\r
+      }\r
+   }\r
+\r
+   // 50-move rule\r
+\r
+   if (board->ply_nb >= 100) return DRAW_FIFTY;\r
+\r
+   // position repetition\r
+\r
+   key = board->key;\r
+   n = 0;\r
+\r
+   start = game->pos - board->ply_nb;\r
+   if (start < 0) start = 0;\r
+\r
+   for (i = game->pos-4; i >= start; i -= 2) {\r
+      if (game->key[i] == key) {\r
+         if (++n == 2) return DRAW_REPETITION;\r
+      }\r
+   }\r
+\r
+   return PLAYING;\r
+}\r
+\r
+// end of game.cpp\r
+\r
diff --git a/game.h b/game.h
index ec50ab2..e0fce79 100644 (file)
--- a/game.h
+++ b/game.h
 #include "move.h"\r
 #include "util.h"\r
 \r
-// constants\r
+// defines\r
 \r
-const int GameSize = 4096;\r
+#define GameSize 4096\r
 \r
-enum status_t {\r
+// types\r
+\r
+typedef enum {\r
    PLAYING,\r
    WHITE_MATES,\r
    BLACK_MATES,\r
@@ -22,11 +24,11 @@ enum status_t {
    DRAW_MATERIAL,\r
    DRAW_FIFTY,\r
    DRAW_REPETITION\r
-};\r
+} status_t;\r
 \r
 // types\r
 \r
-struct game_t {\r
+typedef struct {\r
    board_t start_board[1];\r
    board_t board[1];\r
    sint16 size;\r
@@ -34,7 +36,7 @@ struct game_t {
    sint8 status;\r
    move_t move[GameSize];\r
    uint64 key[GameSize];\r
-};\r
+} game_t;\r
 \r
 // variables\r
 \r
@@ -53,7 +55,8 @@ extern int  game_size      (const game_t * game);
 extern int  game_pos       (const game_t * game);\r
 extern int  game_move      (const game_t * game, int pos);\r
 \r
-extern void game_get_board (const game_t * game, board_t * board, int pos = -1);\r
+extern void game_get_board (const game_t * game, board_t * board);\r
+extern void game_get_board_ex (const game_t * game, board_t * board, int pos);\r
 extern int  game_turn      (const game_t * game);\r
 extern int  game_move_nb   (const game_t * game);\r
 \r
diff --git a/gui.c b/gui.c
new file mode 100644 (file)
index 0000000..9dbe6f5
--- /dev/null
+++ b/gui.c
@@ -0,0 +1,104 @@
+// gui.c
+
+// includes
+
+#include <stdarg.h>
+#include <signal.h>
+
+#include "gui.h"
+#include "main.h"
+
+// constants
+
+static const int StringSize = 4096;
+
+// variables
+
+gui_t GUI[1];
+
+// functions
+
+// sig_int()
+
+static void sig_int(int dummy){
+    my_log("POLYGLOT *** SIGINT Received ***\n");
+    quit();
+}
+
+// sig_pipe()
+
+static void sig_pipe(int dummy){
+    my_log("POLYGLOT *** SIGPIPE Received ***\n");
+    quit();
+}
+
+// sig_term()
+
+static void sig_term(int dummy){
+    my_log("POLYGLOT *** SIGTERM Received ***\n");
+    quit();
+}
+
+
+// gui_init()
+
+void gui_init(gui_t *gui){
+
+// the following is nice if the "GUI" is a console!
+    signal(SIGINT,sig_int);
+#ifdef SIGTERM
+    signal(SIGTERM,sig_term);
+#endif 
+#ifdef SIGPIPE
+    signal(SIGPIPE,sig_pipe);
+#endif
+    pipex_open(gui->pipex,"GUI",NULL);
+}
+
+
+// gui_get_non_blocking()
+
+bool gui_get_non_blocking(gui_t * gui, char *string) {
+
+   ASSERT(gui!=NULL);
+   ASSERT(string!=NULL);
+
+   if(pipex_eof(gui->pipex)){
+        quit();
+        return TRUE; // we never get here
+   }
+   return pipex_readln_nb(gui->pipex,string);
+}
+
+// gui_get()
+
+void gui_get(gui_t * gui, char *string) {
+    if(pipex_eof(gui->pipex)){
+        quit();
+    }
+    pipex_readln(gui->pipex,string);
+}
+
+
+// gui_send()
+
+void gui_send(gui_t * gui, const char format[], ...) {
+
+   va_list arg_list;
+   char string[StringSize];
+
+   ASSERT(gui!=NULL);
+   ASSERT(format!=NULL);
+
+   // format
+
+   va_start(arg_list,format);
+   vsprintf(string,format,arg_list);
+   va_end(arg_list);
+
+   // send
+
+   pipex_writeln(gui->pipex,string);
+
+}
+
diff --git a/gui.h b/gui.h
index 6aebbb9..4a98d85 100644 (file)
--- a/gui.h
+++ b/gui.h
@@ -5,16 +5,14 @@
 
 // includes
 
-#include "pipe.h"
+#include "pipex.h"
 #include "io.h"
 
-struct gui_t {
-#ifndef _WIN32
-    io_t io[1];
-#else
-    PipeStruct io;
-#endif
-};
+// types
+
+typedef struct {
+    pipex_t pipex[1];
+} gui_t;
 
 // variables
 
@@ -23,9 +21,9 @@ extern gui_t GUI[1];
 // functions
 
 extern void gui_init(gui_t * gui);
-extern void gui_send(gui_t * gui, const char format[], ...);
-extern void gui_get        (gui_t * gui, char string[], int size); 
-extern bool gui_get_non_blocking (gui_t * gui, char string[], int size); 
+extern void gui_send(gui_t * gui, const char *format, ...);
+extern void gui_get        (gui_t * gui, char *string); 
+extern bool gui_get_non_blocking (gui_t * gui, char *string); 
 
 
 #endif
diff --git a/hash.c b/hash.c
new file mode 100644 (file)
index 0000000..4baa0aa
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,128 @@
+\r
+// hash.c\r
+\r
+// includes\r
+\r
+#include "board.h"\r
+#include "hash.h"\r
+#include "piece.h"\r
+#include "random.h"\r
+#include "square.h"\r
+#include "util.h"\r
+\r
+// variables\r
+\r
+static uint64 Castle64[16];\r
+\r
+// prototypes\r
+\r
+static uint64 hash_castle_key_debug (int flags);\r
+\r
+// functions\r
+\r
+// hash_init()\r
+\r
+void hash_init() {\r
+\r
+   int i;\r
+\r
+   for (i = 0; i < 16; i++) Castle64[i] = hash_castle_key_debug(i);\r
+}\r
+\r
+// hash_key()\r
+\r
+uint64 hash_key(const board_t * board) {\r
+\r
+   uint64 key;\r
+   int colour;\r
+   const uint8 * ptr;\r
+   int sq, piece;\r
+\r
+   ASSERT(board_is_ok(board));\r
+\r
+   // init\r
+\r
+   key = 0;\r
+\r
+   // pieces\r
+\r
+   for (colour = 1; colour <= 2; colour++) { // HACK\r
+      for (ptr = board->list[colour]; (sq=*ptr) != SquareNone; ptr++) {\r
+         piece = board->square[sq];\r
+         key ^= hash_piece_key(piece,sq);\r
+      }\r
+   }\r
+\r
+   // castle flags\r
+\r
+   key ^= hash_castle_key(board_flags(board));\r
+\r
+   // en-passant square\r
+\r
+   sq = board->ep_square;\r
+   if (sq != SquareNone) key ^= hash_ep_key(sq);\r
+\r
+   // turn\r
+\r
+   key ^= hash_turn_key(board->turn);\r
+\r
+   return key;\r
+}\r
+\r
+// hash_piece_key()\r
+\r
+uint64 hash_piece_key(int piece, int square) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+   ASSERT(square_is_ok(square));\r
+\r
+   return random_64(RandomPiece+piece_to_12(piece)*64+square_to_64(square));\r
+}\r
+\r
+// hash_castle_key()\r
+\r
+uint64 hash_castle_key(int flags) {\r
+\r
+   ASSERT((flags&~0xF)==0);\r
+\r
+   return Castle64[flags];\r
+}\r
+\r
+// hash_castle_key_debug()\r
+\r
+static uint64 hash_castle_key_debug(int flags) {\r
+\r
+   uint64 key;\r
+   int i;\r
+\r
+   ASSERT((flags&~0xF)==0);\r
+\r
+   key = 0;\r
+\r
+   for (i = 0; i < 4; i++) {\r
+      if ((flags & (1<<i)) != 0) key ^= random_64(RandomCastle+i);\r
+   }\r
+\r
+   return key;\r
+}\r
+\r
+// hash_ep_key()\r
+\r
+uint64 hash_ep_key(int square) {\r
+\r
+   ASSERT(square_is_ok(square));\r
+\r
+   return random_64(RandomEnPassant+square_file(square));\r
+}\r
+\r
+// hash_turn_key()\r
+\r
+uint64 hash_turn_key(int colour) {\r
+\r
+   ASSERT(colour_is_ok(colour));\r
+\r
+   return (colour_is_white(colour)) ? random_64(RandomTurn) : 0;\r
+}\r
+\r
+// end of hash.cpp\r
+\r
diff --git a/hash.h b/hash.h
index 0986d13..5a77eb2 100644 (file)
--- a/hash.h
+++ b/hash.h
@@ -9,12 +9,16 @@
 #include "board.h"\r
 #include "util.h"\r
 \r
-// constants\r
-\r
-const int RandomPiece     =   0; // 12 * 64\r
-const int RandomCastle    = 768; // 4\r
-const int RandomEnPassant = 772; // 8\r
-const int RandomTurn      = 780; // 1\r
+// defines\r
+\r
+#define RandomPiece          0\r
+// 12 * 64\r
+#define RandomCastle       768\r
+// 4\r
+#define RandomEnPassant    772\r
+// 8\r
+#define  RandomTurn        780\r
+// 1\r
 \r
 // functions\r
 \r
diff --git a/io.c b/io.c
new file mode 100644 (file)
index 0000000..88eb045
--- /dev/null
+++ b/io.c
@@ -0,0 +1,334 @@
+#ifndef _WIN32
+
+// io.c
+
+// includes
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "io.h"
+#include "util.h"
+
+// constants
+
+static const bool UseDebug = FALSE;
+static const bool UseCR = FALSE;
+
+static const int StringSize = 4096;
+
+static const char LF = '\n';
+static const char CR = '\r';
+
+// prototypes
+
+static int  my_read  (int fd, char string[], int size);
+static void my_write (int fd, const char string[], int size);
+
+// functions
+
+// io_is_ok()
+
+bool io_is_ok(const io_t * io) {
+
+   if (io == NULL) return FALSE;
+
+   if (io->name == NULL) return FALSE;
+
+   if (io->in_eof != TRUE && io->in_eof != FALSE) return FALSE;
+
+   if (io->in_size < 0 || io->in_size > BufferSize) return FALSE;
+   if (io->out_size < 0 || io->out_size > BufferSize) return FALSE;
+
+   return TRUE;
+}
+
+// io_init()
+
+void io_init(io_t * io) {
+
+   ASSERT(io!=NULL);
+
+   io->in_eof = FALSE;
+
+   io->in_size = 0;
+   io->out_size = 0;
+
+   ASSERT(io_is_ok(io));
+}
+
+// io_close()
+
+void io_close(io_t * io) {
+
+   ASSERT(io_is_ok(io));
+
+   ASSERT(io->out_fd>=0);
+
+   my_log("Adapter>%s: EOF\n",io->name);
+
+   if (close(io->out_fd) == -1) {
+      my_fatal("io_close(): close(): %s\n",strerror(errno));
+   }
+
+   io->out_fd = -1;
+}
+
+// io_get_update()
+
+void io_get_update(io_t * io) {
+
+   int pos, size;
+   int n;
+
+   ASSERT(io_is_ok(io));
+
+   ASSERT(io->in_fd>=0);
+   ASSERT(!io->in_eof);
+
+   // init
+
+   pos = io->in_size;
+
+   size = BufferSize - pos;
+   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);
+
+   if (n > 0) { // at least one character was read
+
+      // update buffer size
+
+      ASSERT(n>=1&&n<=size);
+
+      io->in_size += n;
+      ASSERT(io->in_size>=0&&io->in_size<=BufferSize);
+
+   } else { // EOF
+
+      ASSERT(n==0);
+
+      io->in_eof = TRUE;
+   }
+}
+
+// io_line_ready()
+
+bool io_line_ready(const io_t * io) {
+
+   ASSERT(io_is_ok(io));
+
+   if (io->in_eof) return TRUE;
+
+   if (memchr(io->in_buffer,LF,io->in_size) != NULL) return TRUE; // buffer contains LF
+
+   return FALSE;
+}
+
+// io_get_line()
+
+bool io_get_line(io_t * io, char string[], int size) {
+
+   int src, dst;
+   int c;
+
+   ASSERT(io_is_ok(io));
+   ASSERT(string!=NULL);
+   ASSERT(size>=256);
+
+   src = 0;
+   dst = 0;
+
+   while (TRUE) {
+
+      // test for end of buffer
+
+      if (src >= io->in_size) {
+         if (io->in_eof) {
+            my_log("%s->Adapter: EOF\n",io->name);
+            return FALSE;
+         } else {
+            my_fatal("io_get_line(): no EOL in buffer\n");
+         }
+      }
+
+      // test for end of string
+
+      if (dst >= size) my_fatal("io_get_line(): buffer overflow\n");
+
+      // copy the next character
+
+      c = io->in_buffer[src++];
+
+      if (c == LF) { // LF => line complete
+         string[dst] = '\0';
+         break;
+      } else if (c != CR) { // skip CRs
+         string[dst++] = c;
+      }
+   }
+
+   // shift the buffer
+
+   ASSERT(src>0);
+
+   io->in_size -= src;
+   ASSERT(io->in_size>=0);
+
+   if (io->in_size > 0) memmove(&io->in_buffer[0],&io->in_buffer[src],io->in_size);
+
+   // return
+
+   my_log("%s->Adapter: %s\n",io->name,string);
+
+   return TRUE;
+}
+
+// io_send()
+
+void io_send(io_t * io, const char format[], ...) {
+
+   va_list arg_list;
+   char string[StringSize];
+   int len;
+
+   ASSERT(io_is_ok(io));
+   ASSERT(format!=NULL);
+
+   ASSERT(io->out_fd>=0);
+
+   // format
+
+   va_start(arg_list,format);
+   vsprintf(string,format,arg_list);
+   va_end(arg_list);
+
+   // append string to buffer
+
+   len = strlen(string);
+   if (io->out_size + len > BufferSize-2) my_fatal("io_send(): buffer overflow\n");
+
+   memcpy(&io->out_buffer[io->out_size],string,len);
+   io->out_size += len;
+
+   ASSERT(io->out_size>=0&&io->out_size<=BufferSize-2);
+
+   // log
+
+   io->out_buffer[io->out_size] = '\0';
+   my_log("Adapter->%s: %s\n",io->name,io->out_buffer);
+    
+   // append EOL to buffer
+
+   if (UseCR) io->out_buffer[io->out_size++] = CR;
+   io->out_buffer[io->out_size++] = LF;
+
+   ASSERT(io->out_size>=0&&io->out_size<=BufferSize);
+
+   // flush buffer
+
+   if (UseDebug) my_log("POLYGLOT writing %d byte%s to %s\n",io->out_size,(io->out_size>1)?"s":"",io->name);
+   my_write(io->out_fd,io->out_buffer,io->out_size);
+
+   io->out_size = 0;
+}
+
+// io_send_queue()
+
+void io_send_queue(io_t * io, const char format[], ...) {
+
+   va_list arg_list;
+   char string[StringSize];
+   int len;
+
+   ASSERT(io_is_ok(io));
+   ASSERT(format!=NULL);
+
+   ASSERT(io->out_fd>=0);
+
+   // format
+
+   va_start(arg_list,format);
+   vsprintf(string,format,arg_list);
+   va_end(arg_list);
+
+   // append string to buffer
+
+   len = strlen(string);
+   if (io->out_size + len > BufferSize-2) my_fatal("io_send_queue(): buffer overflow\n");
+
+   memcpy(&io->out_buffer[io->out_size],string,len);
+   io->out_size += len;
+
+   ASSERT(io->out_size>=0&&io->out_size<=BufferSize-2);
+}
+
+// my_read()
+
+static int my_read(int fd, char string[], int size) {
+
+   int n;
+
+   ASSERT(fd>=0);
+   ASSERT(string!=NULL);
+   ASSERT(size>0);
+
+   do {
+      n = read(fd,string,size);
+   } while (n == -1 && errno == EINTR);
+
+   if (n == -1) my_fatal("my_read(): read(): %s\n",strerror(errno));
+
+   ASSERT(n>=0);
+
+   return n;
+}
+
+// my_write()
+
+static void my_write(int fd, const char string[], int size) {
+
+   int n;
+
+   ASSERT(fd>=0);
+   ASSERT(string!=NULL);
+   ASSERT(size>0);
+
+   do {
+
+      n = write(fd,string,size);
+
+      // if (n == -1 && errno != EINTR && errno != EPIPE) my_fatal("my_write(): write(): %s\n",strerror(errno));
+
+      if (n == -1) {
+         if (FALSE) {
+         } else if (errno == EINTR) {
+            n = 0; // nothing has been written
+         } else if (errno == EPIPE) {
+            n = size; // pretend everything has been written
+         } else {
+            my_fatal("my_write(): write(): %s\n",strerror(errno));
+         }
+      }
+
+      ASSERT(n>=0);
+
+      string += n;
+      size -= n;
+
+   } while (size > 0);
+
+   ASSERT(size==0);
+}
+
+// end of io.cpp
+
+#endif
diff --git a/io.h b/io.h
index ed470d6..7832262 100644 (file)
--- a/io.h
+++ b/io.h
@@ -8,13 +8,13 @@
 \r
 #include "util.h"\r
 \r
-// constants\r
+// defined\r
 \r
-const int BufferSize = 16384;\r
+#define BufferSize 16384\r
 \r
 // types\r
 \r
-struct io_t {\r
+typedef struct {\r
 \r
    int in_fd;\r
    int out_fd;\r
@@ -28,7 +28,7 @@ struct io_t {
 \r
    char in_buffer[BufferSize];\r
    char out_buffer[BufferSize];\r
-};\r
+} io_t;\r
 \r
 // functions\r
 \r
diff --git a/line.c b/line.c
new file mode 100644 (file)
index 0000000..de8c5bb
--- /dev/null
+++ b/line.c
@@ -0,0 +1,205 @@
+\r
+// line.c\r
+\r
+// includes\r
+\r
+#include <string.h>\r
+\r
+#include "board.h"\r
+#include "line.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_legal.h"\r
+#include "san.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const bool Strict = FALSE; // FALSE\r
+static const bool UseDebug = FALSE; // FALSE\r
+\r
+static const int StringSize = 1024;\r
+\r
+// functions\r
+\r
+// line_is_ok()\r
+\r
+bool line_is_ok(const move_t line[]) {\r
+\r
+   int move;\r
+\r
+   if (line == NULL) return FALSE;\r
+\r
+   while ((move = *line++) != MoveNone) {\r
+      if (!move_is_ok(move)) return FALSE;\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+// line_clear()\r
+\r
+void line_clear(move_t line[]) {\r
+\r
+   ASSERT(line!=NULL);\r
+\r
+   *line = MoveNone;\r
+}\r
+\r
+// line_copy()\r
+\r
+void line_copy(move_t dst[], const move_t src[]) {\r
+\r
+   ASSERT(dst!=NULL);\r
+   ASSERT(src!=NULL);\r
+\r
+   ASSERT(dst!=src);\r
+\r
+   while ((*dst++ = *src++) != MoveNone)\r
+      ;\r
+}\r
+\r
+// line_from_can()\r
+\r
+bool line_from_can (move_t line[], const board_t * board, const char string[], int size) {\r
+\r
+   int pos;\r
+   char new_string[StringSize], *p;\r
+   int move;\r
+   board_t new_board[1];\r
+\r
+   ASSERT(line!=NULL);\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=LineSize);\r
+\r
+   // init\r
+\r
+   pos = 0;\r
+   board_copy(new_board,board);\r
+\r
+   // loop\r
+\r
+   strcpy(new_string,string); // HACK\r
+\r
+   for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) {\r
+\r
+      move = move_from_can(p,new_board);\r
+\r
+      ASSERT(move!=MoveNone);\r
+      ASSERT(move_is_legal(move,new_board));\r
+\r
+      if (move == MoveNone || !move_is_legal(move,new_board)) break; // HACK: ignore illegal moves\r
+\r
+      if (pos >= size) return FALSE;\r
+      line[pos++] = move;\r
+\r
+      move_do(new_board,move);\r
+   }\r
+\r
+   if (pos >= size) return FALSE;\r
+   line[pos] = MoveNone;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// line_to_can()\r
+\r
+bool line_to_can(const move_t line[], const board_t * board, char string[], int size) {\r
+\r
+   board_t new_board[1];\r
+   int pos;\r
+   int move;\r
+\r
+   ASSERT(line_is_ok(line));\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=StringSize);\r
+\r
+   // init\r
+\r
+   if (size < StringSize) return FALSE;\r
+\r
+   board_copy(new_board,board);\r
+   pos = 0;\r
+\r
+   // loop\r
+\r
+   while ((move = *line++) != MoveNone) {\r
+\r
+      if (pos != 0) {\r
+         if (pos >= size) return FALSE;\r
+         string[pos++] = ' ';\r
+      }\r
+\r
+      if (!move_to_can(move,new_board,&string[pos],size-pos)) return FALSE;\r
+      pos += strlen(&string[pos]);\r
+\r
+      move_do(new_board,move);\r
+   }\r
+\r
+   if (pos >= size) return FALSE;\r
+   string[pos] = '\0';\r
+\r
+   return TRUE;\r
+}\r
+\r
+// line_to_san()\r
+\r
+bool line_to_san(const move_t line[], const board_t * board, char string[], int size) {\r
+\r
+   board_t new_board[1];\r
+   int pos;\r
+   int move;\r
+   char move_string[256];\r
+\r
+   ASSERT(line_is_ok(line));\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=StringSize);\r
+\r
+   // init\r
+\r
+   if (size < StringSize) return FALSE;\r
+\r
+   board_copy(new_board,board);\r
+   pos = 0;\r
+\r
+   // loop\r
+\r
+   while ((move = *line++) != MoveNone) {\r
+\r
+      if (pos != 0) {\r
+         if (pos >= size) return FALSE;\r
+         string[pos++] = ' ';\r
+      }\r
+\r
+      if (!move_is_legal(move,new_board)\r
+       || !move_to_san(move,new_board,&string[pos],size-pos)) {\r
+\r
+         if (Strict || UseDebug) {\r
+\r
+            move_to_can(move,new_board,move_string,256);\r
+            my_log("POLYGLOT ILLEGAL MOVE IN LINE %s\n",move_string);\r
+\r
+            board_disp(new_board);\r
+         }\r
+\r
+         if (Strict) my_fatal("line_to_san(): illegal move\n");\r
+\r
+         break;\r
+      }\r
+\r
+      pos += strlen(&string[pos]);\r
+\r
+      move_do(new_board,move);\r
+   }\r
+\r
+   if (pos >= size) return FALSE;\r
+   string[pos] = '\0';\r
+\r
+   return TRUE;\r
+}\r
+\r
+// end of line.cpp\r
+\r
diff --git a/line.h b/line.h
index b41eed8..6460edf 100644 (file)
--- a/line.h
+++ b/line.h
@@ -12,7 +12,7 @@
 \r
 // constants\r
 \r
-const int LineSize = 256;\r
+#define LineSize 256\r
 \r
 // functions\r
 \r
diff --git a/list.c b/list.c
new file mode 100644 (file)
index 0000000..4c2b08f
--- /dev/null
+++ b/list.c
@@ -0,0 +1,275 @@
+\r
+// list.c\r
+\r
+// includes\r
+\r
+#include "board.h"\r
+#include "list.h"\r
+#include "move.h"\r
+#include "util.h"\r
+\r
+// functions\r
+\r
+// list_is_ok()\r
+\r
+bool list_is_ok(const list_t * list) {\r
+\r
+   if (list == NULL) return FALSE;\r
+\r
+   if (list->size >= ListSize) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// list_clear()\r
+\r
+void list_clear(list_t * list) {\r
+\r
+   ASSERT(list!=NULL);\r
+\r
+   list->size = 0;\r
+}\r
+\r
+// list_add\r
+\r
+void list_add(list_t * list, int move){\r
+    list_add_ex(list, move, 0);\r
+}\r
+\r
+// list_add_ex()\r
+\r
+void list_add_ex(list_t * list, int move, int value) {\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(value>=-32767&&value<=+32767);\r
+\r
+   ASSERT(list->size<ListSize-1);\r
+\r
+   list->move[list->size] = move;\r
+   list->value[list->size] = value;\r
+   list->size++;\r
+}\r
+\r
+// list_remove()\r
+\r
+void list_remove(list_t * list, int index) {\r
+\r
+   int i;\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(index>=0&&index<list->size);\r
+\r
+   for (i = index; i < list->size-1; i++) {\r
+      list->move[i] = list->move[i+1];\r
+      list->value[i] = list->value[i+1];\r
+   }\r
+\r
+   list->size--;\r
+}\r
+\r
+// list_is_empty()\r
+\r
+bool list_is_empty(const list_t * list) {\r
+\r
+   ASSERT(list_is_ok(list));\r
+\r
+   return list->size == 0;\r
+}\r
+\r
+// list_size()\r
+\r
+int list_size(const list_t * list) {\r
+\r
+   ASSERT(list_is_ok(list));\r
+\r
+   return list->size;\r
+}\r
+\r
+// list_move()\r
+\r
+int list_move(const list_t * list, int index) {\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(index>=0&&index<list->size);\r
+\r
+   return list->move[index];\r
+}\r
+\r
+// list_value()\r
+\r
+int list_value(const list_t * list, int index) {\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(index>=0&&index<list->size);\r
+\r
+   return list->value[index];\r
+}\r
+\r
+// list_copy()\r
+\r
+void list_copy(list_t * dst, const list_t * src) {\r
+\r
+   int i;\r
+\r
+   ASSERT(dst!=NULL);\r
+   ASSERT(list_is_ok(src));\r
+\r
+   dst->size = src->size;\r
+\r
+   for (i = 0; i < src->size; i++) {\r
+      dst->move[i] = src->move[i];\r
+      dst->value[i] = src->value[i];\r
+   }\r
+}\r
+\r
+// list_move_to_front()\r
+\r
+void list_move_to_front(list_t * list, int index) {\r
+\r
+   int i;\r
+   int move, value;\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(index>=0&&index<list->size);\r
+\r
+   if (index != 0) {\r
+\r
+      move = list->move[index];\r
+      value = list->value[index];\r
+\r
+      for (i = index; i > 0; i--) {\r
+         list->move[i] = list->move[i-1];\r
+         list->value[i] = list->value[i-1];\r
+      }\r
+\r
+      list->move[0] = move;\r
+      list->value[0] = value;\r
+   }\r
+}\r
+\r
+// list_note()\r
+\r
+void list_note(list_t * list) {\r
+\r
+   int i, move;\r
+\r
+   ASSERT(list_is_ok(list));\r
+\r
+   for (i = 0; i < list->size; i++) {\r
+      move = list->move[i];\r
+      ASSERT(move_is_ok(move));\r
+      list->value[i] = -move_order(move);\r
+   }\r
+}\r
+\r
+// list_sort()\r
+\r
+void list_sort(list_t * list) {\r
+\r
+   int i, j;\r
+   int best_index, best_move, best_value;\r
+\r
+   ASSERT(list_is_ok(list));\r
+\r
+   for (i = 0; i < list->size-1; i++) {\r
+\r
+      best_index = i;\r
+      best_value = list->value[i];\r
+\r
+      for (j = i+1; j < list->size; j++) {\r
+         if (list->value[j] > best_value) {\r
+            best_index = j;\r
+            best_value = list->value[j];\r
+         }\r
+      }\r
+\r
+      if (best_index != i) {\r
+\r
+         best_move = list->move[best_index];\r
+         ASSERT(best_value==list->value[best_index]);\r
+\r
+         for (j = best_index; j > i; j--) {\r
+            list->move[j] = list->move[j-1];\r
+            list->value[j] = list->value[j-1];\r
+         }\r
+\r
+         list->move[i] = best_move;\r
+         list->value[i] = best_value;\r
+      }\r
+   }\r
+\r
+   if (DEBUG) {\r
+      for (i = 0; i < list->size-1; i++) {\r
+         ASSERT(list->value[i]>=list->value[i+1]);\r
+      }\r
+   }\r
+}\r
+\r
+// list_contain()\r
+\r
+bool list_contain(const list_t * list, int move) {\r
+\r
+   int i;\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(move_is_ok(move));\r
+\r
+   for (i = 0; i < list->size; i++) {\r
+      if (list->move[i] == move) return TRUE;\r
+   }\r
+\r
+   return FALSE;\r
+}\r
+\r
+// list_equal()\r
+\r
+bool list_equal(list_t * list_1, list_t * list_2) {\r
+\r
+   list_t copy_1[1], copy_2[1];\r
+   int i;\r
+\r
+   ASSERT(list_is_ok(list_1));\r
+   ASSERT(list_is_ok(list_2));\r
+\r
+   if (list_1->size != list_2->size) return FALSE;\r
+\r
+   list_copy(copy_1,list_1);\r
+   list_note(copy_1);\r
+   list_sort(copy_1);\r
+\r
+   list_copy(copy_2,list_2);\r
+   list_note(copy_2);\r
+   list_sort(copy_2);\r
+\r
+   for (i = 0; i < copy_1->size; i++) {\r
+      if (copy_1->move[i] != copy_2->move[i]) return FALSE;\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+// list_disp()\r
+\r
+void list_disp(const list_t * list, const board_t * board) {\r
+\r
+   int i, move, value;\r
+   char string[256];\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   for (i = 0; i < list->size; i++) {\r
+\r
+      move = list->move[i];\r
+      value = list->value[i];\r
+\r
+      if (!move_to_can(move,board,string,256)) ASSERT(FALSE);\r
+      my_log("POLYGLOT %-5s %04X %+4d\n",string,move,value);\r
+   }\r
+\r
+   my_log("POLYGLOT\n");\r
+}\r
+\r
+// end of list.cpp\r
+\r
diff --git a/list.h b/list.h
index 9004602..d366896 100644 (file)
--- a/list.h
+++ b/list.h
 #include "move.h"\r
 #include "util.h"\r
 \r
-// constants\r
+// defines\r
 \r
-const int ListSize = 256;\r
+#define ListSize 256\r
 \r
 // types\r
 \r
-struct list_t {\r
+typedef struct {\r
    sint16 size;\r
    move_t move[ListSize];\r
    sint16 value[ListSize];\r
-};\r
+} list_t;\r
 \r
 // functions\r
 \r
 extern bool list_is_ok    (const list_t * list);\r
 \r
 extern void list_clear    (list_t * list);\r
-extern void list_add      (list_t * list, int move, int value = 0);\r
+extern void list_add      (list_t * list, int move);\r
+extern void list_add_ex   (list_t * list, int move, int value);\r
+\r
 extern void list_remove   (list_t * list, int index);\r
 \r
 extern bool list_is_empty (const list_t * list);\r
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..ad9ecca
--- /dev/null
+++ b/main.c
@@ -0,0 +1,384 @@
+\r
+// main.c\r
+\r
+// includes\r
+\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "attack.h"\r
+#include "board.h"\r
+#include "book.h"\r
+#include "book_make.h"\r
+#include "book_merge.h"\r
+#include "engine.h"\r
+#include "epd.h"\r
+#include "fen.h"\r
+#include "gui.h"\r
+#include "hash.h"\r
+#include "list.h"\r
+#include "main.h"\r
+#include "mainloop.h"\r
+#include "move.h"\r
+#include "move_gen.h"\r
+#include "option.h"\r
+#include "piece.h"\r
+#include "search.h"\r
+#include "square.h"\r
+#include "uci.h"\r
+#include "util.h"\r
+#include "xboard2uci.h"\r
+#include "uci2uci.h"\r
+\r
+// constants\r
+\r
+\r
+static const char * const Version = "1.4.30b";\r
+static const char * const HelpMessage = "\\r
+SYNTAX\n\\r
+* polyglot [configfile]\n\\r
+* polyglot -ec enginecommand\n\\r
+* polyglot make-book [-pgn inputfile] [-bin outputfile] [-max-ply ply] [-min-game games] [-min-score score] [-only-white] [-only-black] [-uniform]\n\\r
+* polyglot merge-book -in1 inputfile1 -in2 inputfile2 [-out outputfile]\n\\r
+* polyglot info-book [-bin inputfile] [-exact]\n\\r
+* polyglot dumb-book [-bin inputfile] -color color [-out outputfile]\n\\r
+* polyglot [configfile] epd-test [-epd inputfile] [-min-depth depth] [-max-depth depth] [-min-time time] [-max-time time] [-depth-delta delta]\n\\r
+* polyglot perft [-fen fen] [-max-depth depth]\\r
+";\r
+\r
+static const int SearchDepth = 63;\r
+static const double SearchTime = 3600.0;\r
+static const int StringSize = 4096;\r
+\r
+// variables\r
+\r
+static bool Init;\r
+\r
+// prototypes\r
+\r
+static void parse_option ();\r
+static void init_book ();\r
+static bool parse_line   (char line[], char * * name_ptr, char * * value_ptr);\r
+static void stop_search  ();\r
+\r
+// functions\r
+\r
+// main()\r
+\r
+int main(int argc, char * argv[]) {\r
+\r
+    if(!DEBUG){\r
+        printf("PolyGlot %s by Fabien Letouzey.\n",Version);\r
+    }else{\r
+        printf("PolyGlot %s by Fabien Letouzey (debug build).\n",Version);\r
+    }\r
+\r
+    if(argc>=2 && ((my_string_case_equal(argv[1],"help")) || (my_string_case_equal(argv[1],"-help")) || (my_string_case_equal(argv[1],"--help")) ||  (my_string_case_equal(argv[1],"-h")) ||  my_string_case_equal(argv[1],"/?"))){\r
+        printf("%s\n",HelpMessage);\r
+        return EXIT_SUCCESS;\r
+    }\r
+\r
+   // init\r
+\r
+    Init = FALSE;\r
+\r
+    util_init();\r
+    option_init();\r
+    \r
+    square_init();\r
+    piece_init();\r
+    attack_init();\r
+    \r
+    hash_init();\r
+    \r
+    my_random_init();\r
+\r
+        // build book\r
+    \r
+    if (argc >= 2 && my_string_equal(argv[1],"make-book")) {\r
+        book_make(argc,argv);\r
+        return EXIT_SUCCESS;\r
+    }\r
+    \r
+    if (argc >= 2 && my_string_equal(argv[1],"merge-book")) {\r
+        book_merge(argc,argv);\r
+        return EXIT_SUCCESS;\r
+    }\r
+\r
+       if (argc >= 2 && my_string_equal(argv[1],"merge-book")) {\r
+      book_merge(argc,argv);\r
+      return EXIT_SUCCESS;\r
+   }\r
+\r
+   if (argc >= 2 && my_string_equal(argv[1],"dump-book")) {\r
+      book_dump(argc,argv);\r
+      return EXIT_SUCCESS;\r
+   }\r
+\r
+   if (argc >= 2 && my_string_equal(argv[1],"info-book")) {\r
+      book_info(argc,argv);\r
+      return EXIT_SUCCESS;\r
+   }\r
+    \r
+    if (argc >= 2 && my_string_equal(argv[1],"perft")) {\r
+        do_perft(argc,argv);\r
+        return EXIT_SUCCESS;\r
+    }\r
+    \r
+    if (argc >= 3 && my_string_equal(argv[1],"-ec")) {\r
+        option_set("EngineCommand",argv[2]);\r
+        engine_open(Engine);\r
+        if(!engine_active(Engine)){\r
+            my_fatal("Could not start \"%s\"\n",option_get("EngineCommand"));\r
+        }\r
+        Init=TRUE;\r
+        gui_init(GUI);\r
+        uci_open(Uci,Engine);\r
+        if (my_string_equal(option_get_string("EngineName"),"<empty>")) {\r
+            option_set("EngineName",Uci->name);\r
+        }\r
+        mainloop();\r
+        return EXIT_SUCCESS; \r
+    }\r
+    \r
+        // read options\r
+    \r
+    if (argc == 2) option_set("OptionFile",argv[1]); // HACK for compatibility\r
+\r
+    parse_option(); // HACK: also launches the engine\r
+    \r
+        // EPD test\r
+    \r
+    if (argc >= 2 && my_string_equal(argv[1],"epd-test")){\r
+        epd_test(argc,argv);\r
+        return EXIT_SUCCESS;\r
+    }else if(argc >= 3 && my_string_equal(argv[2],"epd-test")){\r
+        epd_test(argc-1,argv+1);\r
+        return EXIT_SUCCESS;\r
+    }\r
+    \r
+    if (argc >= 3) my_fatal("Too many arguments\n");\r
+\r
+\r
+    init_book();\r
+    gui_init(GUI);\r
+    mainloop();\r
+    return EXIT_SUCCESS; \r
+}\r
+\r
+// polyglot_set_option\r
+\r
+void polyglot_set_option(char *name, char *value){ // this must be cleaned up!\r
+    option_set(name,value);\r
+    if(option_get_bool("Book")&&(my_string_case_equal(name,"BookFile")||my_string_case_equal(name,"Book"))){\r
+        my_log("POLYGLOT *** SETTING BOOK ***\n");\r
+        my_log("POLYGLOT BOOK \"%s\"\n",option_get_string("BookFile"));\r
+        book_close();\r
+        book_clear();\r
+        book_open(option_get_string("BookFile"));\r
+        if(!book_is_open()){\r
+            my_log("POLYGLOT Unable to open book \"%s\"\n",option_get_string("BookFile"));\r
+        }\r
+    }else if(option_get_bool("Log")&&(my_string_case_equal(name,"LogFile") ||my_string_case_equal(name,"Log"))){\r
+        my_log("POLYGLOT *** SETTING LOGFILE ***\n");\r
+        my_log("POLYGLOT LOGFILE \"%s\"\n",option_get_string("LogFile"));\r
+        my_log_close();\r
+        my_log_open(option_get_string("LogFile"));\r
+    }else if(option_get_bool("UseNice") &&(my_string_case_equal(name,"NiceValue")||my_string_case_equal(name,"UseNice"))){\r
+        my_log("POLYGLOT Adjust Engine Piority\n");\r
+        engine_set_nice_value(Engine,atoi(option_get_string("NiceValue")));\r
+    }else if(my_string_case_equal(name,"Book") && !option_get_bool("Book")){\r
+        book_close();\r
+        book_clear();\r
+    }else if(my_string_case_equal(name,"UseNice") && !option_get_bool("UseNice")){\r
+        my_log("POLYGLOT Adjust Engine Piority\n");\r
+        engine_set_nice_value(Engine,0);\r
+    }else if(my_string_case_equal(name,"Log") && !option_get_bool("Log")){\r
+        my_log("POLYGLOT QUIT LOGGING\n");\r
+        my_log_close();\r
+    }\r
+}\r
+\r
+\r
+// init_book()\r
+\r
+static void init_book(){\r
+    book_clear();\r
+    if (option_get_bool("Book")){\r
+        my_log("POLYGLOT *** SETTING BOOK ***\n");\r
+        my_log("POLYGLOT BOOK \"%s\"\n",option_get_string("BookFile"));\r
+        book_open(option_get_string("BookFile"));\r
+        if(!book_is_open()){\r
+            my_log("POLYGLOT Unable to open book \"%s\"\n",\r
+                   option_get_string("BookFile"));\r
+        }\r
+    }\r
+}\r
+\r
+// parse_option()\r
+\r
+static void parse_option() {\r
+\r
+    const char * file_name;\r
+    FILE * file;\r
+    char line[256];\r
+    char * name, * value;\r
+    file_name = option_get_string("OptionFile");\r
+    \r
+    file = fopen(file_name,"r");\r
+    if (file == NULL) {\r
+        my_fatal("Can't open file \"%s\": %s\n",file_name,strerror(errno));\r
+    }\r
+    \r
+        // PolyGlot options (assumed first)\r
+    \r
+   while (TRUE) {\r
+       \r
+       if (!my_file_read_line(file,line,256)) {\r
+           my_fatal("parse_option(): missing [Engine] section\n");\r
+       }\r
+       \r
+       if (my_string_case_equal(line,"[engine]")) break;\r
+       \r
+       if (parse_line(line,&name,&value)) {\r
+           option_set(name,value);\r
+           option_set_default(name,value);\r
+       }\r
+   }\r
+   \r
+   if (option_get_bool("Log")) {\r
+       my_log_open(option_get_string("LogFile"));\r
+   }\r
+   \r
+   if(!DEBUG){\r
+       my_log("PolyGlot %s by Fabien Letouzey\n",Version);\r
+   }else{\r
+       my_log("PolyGlot %s by Fabien Letouzey (debug build)\n",Version);\r
+   }\r
+\r
+   my_log("POLYGLOT *** START ***\n");\r
+   my_log("POLYGLOT INI file \"%s\"\n",file_name);\r
+   engine_open(Engine);\r
+   if(!engine_active(Engine)){\r
+       my_fatal("Could not start \"%s\"\n",option_get("EngineCommand"));\r
+   }\r
+\r
+   if (option_get_bool("UCI")) {\r
+       my_log("POLYGLOT *** Switching to UCI mode ***\n");\r
+   }\r
+   uci_open(Uci,Engine);\r
+   Init = TRUE;\r
+   while (my_file_read_line(file,line,256)) {\r
+       if (line[0] == '[') my_fatal("parse_option(): unknown section %s\n",line);\r
+       if (parse_line(line,&name,&value)) {\r
+           uci_send_option(Uci,name,"%s",value);\r
+               //to get a decent display in winboard_x we need to now if an engine really is doing multipv analysis\r
+               // "multipv 1" in the pv is meaningless,f.i. toga sends that all the time\r
+               //therefore check if MultiPV is set to a decent value in the polyglot ini file\r
+           if(my_string_case_equal(name,"MultiPV") && atoi(value)>1)  Uci->multipv_mode=TRUE;\r
+       }\r
+   }\r
+   if (my_string_equal(option_get_string("EngineName"),"<empty>")) {\r
+       option_set("EngineName",Uci->name);\r
+   }\r
+   \r
+   fclose(file);\r
+}\r
+\r
+// parse_line()\r
+\r
+static bool parse_line(char line[], char * * name_ptr, char * * value_ptr) {\r
+    \r
+    char * ptr;\r
+    char * name, * value;\r
+    \r
+    ASSERT(line!=NULL);\r
+    ASSERT(name_ptr!=NULL);\r
+    ASSERT(value_ptr!=NULL);\r
+    \r
+        // remove comments\r
+    \r
+    ptr = strchr(line,';');\r
+    if (ptr != NULL) *ptr = '\0';\r
+    \r
+    ptr = strchr(line,'#');\r
+    if (ptr != NULL) *ptr = '\0';\r
+    \r
+        // split at '='\r
+    \r
+    ptr = strchr(line,'=');\r
+    if (ptr == NULL) return FALSE;\r
+    \r
+    name = line;\r
+    value = ptr+1;\r
+   \r
+        // cleanup name\r
+    \r
+    while (*name == ' ') name++; // remove leading spaces\r
+    \r
+    while (ptr > name && ptr[-1] == ' ') ptr--; // remove trailing spaces\r
+    *ptr = '\0';\r
+    \r
+    if (*name == '\0') return FALSE;\r
+    \r
+        // cleanup value\r
+    \r
+    ptr = &value[strlen(value)]; // pointer to string terminator\r
+    \r
+    while (*value == ' ') value++; // remove leading spaces\r
+    \r
+    while (ptr > value && ptr[-1] == ' ') ptr--; // remove trailing spaces\r
+    *ptr = '\0';\r
+    \r
+    if (*value == '\0') return FALSE;\r
+   \r
+        // end\r
+    \r
+    *name_ptr = name;\r
+    *value_ptr = value;\r
+    \r
+    return TRUE;\r
+}\r
+\r
+// quit()\r
+\r
+void quit() {\r
+\r
+    my_log("POLYGLOT *** QUIT ***\n");\r
+    \r
+    if (Init) {\r
+        \r
+        stop_search();\r
+        engine_send(Engine,"quit");\r
+        my_log("POLYGLOT Closing engine\n");\r
+        engine_close(Engine);\r
+        \r
+    }\r
+    my_log("POLYGLOT Calling exit\n");\r
+    exit(EXIT_SUCCESS);\r
+}\r
+\r
+// stop_search()\r
+\r
+static void stop_search() {\r
+    \r
+    if (Init && Uci->searching) {\r
+        \r
+        ASSERT(Uci->searching);\r
+        ASSERT(Uci->pending_nb>=1);\r
+        \r
+        my_log("POLYGLOT STOP SEARCH\n");\r
+        \r
+        if (option_get_bool("SyncStop")) {\r
+            uci_send_stop_sync(Uci);\r
+        } else {\r
+            uci_send_stop(Uci);\r
+        }\r
+    }\r
+}\r
+\r
+\r
+// end of main.cpp\r
+\r
diff --git a/mainloop.c b/mainloop.c
new file mode 100644 (file)
index 0000000..d41e713
--- /dev/null
@@ -0,0 +1,103 @@
+// mainloop.c\r
+\r
+// constants\r
+\r
+static const int StringSize = 4096;\r
+\r
+// includes\r
+\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "main.h"\r
+#include "engine.h"\r
+#include "gui.h"\r
+#include "option.h"\r
+#include "xboard2uci.h"\r
+#include "uci2uci.h"\r
+\r
+// prototypes\r
+\r
+static void mainloop_init            ();\r
+static void mainloop_wait_for_event  ();\r
+static void mainloop_engine_step(char * string);\r
+static void mainloop_gui_step(char * string);\r
+\r
+// functions\r
+\r
+// mainloop_init()\r
+    \r
+static void mainloop_init(){\r
+    if(!option_get_bool("UCI")){\r
+        xboard2uci_init();  // the default\r
+    }\r
+}\r
+\r
+// mainloop_engine_step()\r
+\r
+static void mainloop_engine_step(char * string){\r
+    if(option_get_bool("UCI")){\r
+        uci2uci_engine_step(string); \r
+    }else{\r
+        xboard2uci_engine_step(string);\r
+    }\r
+}\r
+\r
+// mainloop_gui_step()\r
+\r
+static void mainloop_gui_step(char * string){\r
+    if(option_get_bool("UCI")){\r
+        uci2uci_gui_step(string); \r
+    }else if(my_string_equal(string,"uci")){ // mode auto detection\r
+        my_log("POLYGLOT *** Switching to UCI mode ***\n");\r
+        option_set("UCI","TRUE");\r
+        uci2uci_gui_step(string);\r
+    }else{\r
+        xboard2uci_gui_step(string);\r
+    }\r
+}\r
+\r
+// mainloop()\r
+\r
+void mainloop() {\r
+    char string[StringSize];\r
+    mainloop_init();\r
+    while (!engine_eof(Engine)) {\r
+            // process buffered lines\r
+        while(TRUE){\r
+            if(gui_get_non_blocking(GUI,string)){\r
+                mainloop_gui_step(string);\r
+            }else if(!engine_eof(Engine) &&\r
+                     engine_get_non_blocking(Engine,string) ){\r
+                mainloop_engine_step(string);\r
+            }else{\r
+                break;\r
+            }\r
+        }\r
+        mainloop_wait_for_event();\r
+    }\r
+    my_log("POLYGLOT *** Mainloop has ended ***\n");\r
+    // This should be handled better.\r
+    engine_close(Engine);\r
+    my_log("POLYGLOT Calling exit\n");\r
+    exit(EXIT_SUCCESS);\r
+\r
+}\r
+\r
+\r
+\r
+\r
+// mainloop_wait_for_event()\r
+\r
+static void mainloop_wait_for_event(){\r
+    pipex_t *pipex[3];\r
+    pipex[0]=GUI->pipex;\r
+    pipex[1]=Engine->pipex;\r
+    pipex[2]=NULL;\r
+    pipex_wait_event(pipex);\r
+}\r
+\r
+\r
+\r
index d432b9c..8890ee9 100644 (file)
@@ -2,15 +2,15 @@ EXE = polyglot.exe
 
 OBJS = attack.o board.o book.o book_make.o book_merge.o colour.o engine.o\
  epd.o fen.o game.o gui.o hash.o io.o line.o list.o main.o mainloop.o\
- move.o move_do.o move_gen.o move_legal.o option.o parse.o pgn.o piece.o\
- pipe.o posix.o random.o san.o search.o square.o uci.o uci2uci.o util.o\
- xboard2uci.o
+ move.o move_do.o move_gen.o move_legal.o option.o parse.o pipex_win32.o\
+ pipex_posix.o pgn.o piece.o random.o san.o search.o square.o\
+ uci.o uci2uci.o util.o xboard2uci.o
 
 # set up for NO cygwin
 CYGF = -mno-cygwin
 CYGL = -lmsvcrt
 
-CC = g++
+CC = gcc
 DEFS = -DNDEBUG
 OPTS = -Os -frename-registers -funit-at-a-time -fstrict-aliasing -fstrength-reduce -fomit-frame-pointer
 CFLAGS = -Wall -pipe $(DEFS) $(OPTS) $(CYGF)
@@ -25,5 +25,5 @@ clean:
 $(EXE): $(OBJS)
        $(CC) $(LFLAGS) $(LIBS) $(OBJS) -o $(EXE)
 
-%.o: %.cpp
+%.o: %.c
        $(CC) $(CFLAGS) -c $<
diff --git a/move.c b/move.c
new file mode 100644 (file)
index 0000000..8d5699f
--- /dev/null
+++ b/move.c
@@ -0,0 +1,376 @@
+\r
+// move.c\r
+\r
+// includes\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "attack.h"\r
+#include "colour.h"\r
+#include "list.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_gen.h"\r
+#include "move_legal.h"\r
+#include "option.h"\r
+#include "piece.h"\r
+#include "square.h"\r
+#include "util.h"\r
+\r
+// "constants"\r
+\r
+static const uint8 PromotePiece[5] = { PieceNone64, Knight64, Bishop64, Rook64, Queen64 };\r
+\r
+// functions\r
+\r
+// move_is_ok()\r
+\r
+bool move_is_ok(int move) {\r
+\r
+   if (move < 0 || move >= 65536) return FALSE;\r
+\r
+   if (move == MoveNone) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// move_make()\r
+\r
+int move_make(int from, int to) {\r
+\r
+   ASSERT(square_is_ok(from));\r
+   ASSERT(square_is_ok(to));\r
+\r
+   return (square_to_64(from) << 6) | square_to_64(to);\r
+}\r
+\r
+// move_make_flags()\r
+\r
+int move_make_flags(int from, int to, int flags) {\r
+\r
+   ASSERT(square_is_ok(from));\r
+   ASSERT(square_is_ok(to));\r
+   ASSERT((flags&~0xF000)==0);\r
+\r
+   ASSERT(to!=from);\r
+\r
+   return (square_to_64(from) << 6) | square_to_64(to) | flags;\r
+}\r
+\r
+// move_from()\r
+\r
+int move_from(int move) {\r
+\r
+   int from_64;\r
+\r
+   ASSERT(move_is_ok(move));\r
+\r
+   from_64 = (move >> 6) & 077;\r
+\r
+   return square_from_64(from_64);\r
+}\r
+\r
+// move_to()\r
+\r
+int move_to(int move) {\r
+\r
+   int to_64;\r
+\r
+   ASSERT(move_is_ok(move));\r
+\r
+   to_64 = move & 077;\r
+\r
+   return square_from_64(to_64);\r
+}\r
+\r
+// move_promote_hack()\r
+\r
+int move_promote_hack(int move) {\r
+\r
+   int code;\r
+\r
+   ASSERT(move_is_ok(move));\r
+\r
+   ASSERT(move_is_promote(move));\r
+\r
+   code = move >> 12;\r
+   ASSERT(code>=1&&code<=4);\r
+\r
+   return PromotePiece[code];\r
+}\r
+\r
+// move_is_capture()\r
+\r
+bool move_is_capture(int move, const board_t * board) {\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   if (move_is_en_passant(move,board)) return TRUE;\r
+   if (board->square[move_to(move)] != Empty) return TRUE;\r
+\r
+   return FALSE;\r
+}\r
+\r
+// move_is_promote()\r
+\r
+bool move_is_promote(int move) {\r
+\r
+   ASSERT(move_is_ok(move));\r
+\r
+   return (move & MoveFlags) != 0;\r
+}\r
+\r
+// move_is_en_passant()\r
+\r
+bool move_is_en_passant(int move, const board_t * board) {\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   return piece_is_pawn(move_piece(move,board))\r
+       && move_to(move) == board->ep_square;\r
+}\r
+\r
+// move_is_castle()\r
+\r
+bool move_is_castle(int move, const board_t * board) {\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   return colour_equal(board->square[move_to(move)],board->turn);\r
+}\r
+\r
+// move_piece()\r
+\r
+int move_piece(int move, const board_t * board) {\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   return board->square[move_from(move)];\r
+}\r
+\r
+// move_capture()\r
+\r
+int move_capture(int move, const board_t * board) {\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   if (move_is_en_passant(move,board)) {\r
+      return piece_pawn_opp(move_piece(move,board));\r
+   }\r
+\r
+   return board->square[move_to(move)];\r
+}\r
+\r
+// move_promote()\r
+\r
+int move_promote(int move, const board_t * board) {\r
+\r
+   int code;\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   if (move_is_promote(move)) {\r
+      code = move >> 12;\r
+      ASSERT(code>=1&&code<=4);\r
+      return PromotePiece[code] | board->turn;\r
+   }\r
+\r
+   return Empty;\r
+}\r
+\r
+// move_is_check()\r
+\r
+bool move_is_check(int move, const board_t * board) {\r
+\r
+   board_t new_board[1];\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   board_copy(new_board,board);\r
+   move_do(new_board,move);\r
+   ASSERT(!is_in_check(new_board,colour_opp(new_board->turn)));\r
+\r
+   return board_is_check(new_board);\r
+}\r
+\r
+// move_is_mate()\r
+\r
+bool move_is_mate(int move, const board_t * board) {\r
+\r
+   board_t new_board[1];\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   board_copy(new_board,board);\r
+   move_do(new_board,move);\r
+   ASSERT(!is_in_check(new_board,colour_opp(new_board->turn)));\r
+\r
+   return board_is_mate(new_board);\r
+}\r
+\r
+// move_to_can()\r
+\r
+bool move_to_can(int move, const board_t * board, char string[], int size) {\r
+\r
+   int from, to;\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=6);\r
+\r
+   ASSERT(move_is_legal(move,board));\r
+\r
+   if (size < 6) return FALSE;\r
+\r
+   // init\r
+\r
+   from = move_from(move);\r
+   to = move_to(move);\r
+\r
+   // king-slide castling\r
+\r
+   if (move_is_castle(move,board) && !option_get_bool("Chess960")) {\r
+      if (FALSE) {\r
+      } else if (from == E1 && to == H1) {\r
+         to = G1;\r
+      } else if (from == E1 && to == A1) {\r
+         to = C1;\r
+      } else if (from == E8 && to == H8) {\r
+         to = G8;\r
+      } else if (from == E8 && to == A8) {\r
+         to = C8;\r
+      }\r
+   }\r
+\r
+   // normal moves\r
+\r
+   if (!square_to_string(from,&string[0],3)) ASSERT(FALSE);\r
+   if (!square_to_string(to,&string[2],3)) ASSERT(FALSE);\r
+   ASSERT(strlen(string)==4);\r
+\r
+   // promotes\r
+\r
+   if (move_is_promote(move)) {\r
+      string[4] = piece_to_char(move_promote_hack(move)|Black); // HACK: black => lower-case\r
+      string[5] = '\0';\r
+   }\r
+\r
+   // debug\r
+\r
+   ASSERT(move_from_can(string,board)==move);\r
+\r
+   return TRUE;\r
+}\r
+\r
+// move_from_can()\r
+\r
+int move_from_can(const char string[], const board_t * board) {\r
+\r
+   char tmp_string[256];\r
+   int from, to;\r
+   int side;\r
+   int move;\r
+\r
+   ASSERT(string!=NULL);\r
+   ASSERT(board_is_ok(board));\r
+\r
+   // from\r
+\r
+   tmp_string[0] = string[0];\r
+   tmp_string[1] = string[1];\r
+   tmp_string[2] = '\0';\r
+\r
+   from = square_from_string(tmp_string);\r
+   if (from == SquareNone) return MoveNone;\r
+\r
+   // to\r
+\r
+   tmp_string[0] = string[2];\r
+   tmp_string[1] = string[3];\r
+   tmp_string[2] = '\0';\r
+\r
+   to = square_from_string(tmp_string);\r
+   if (to == SquareNone) return MoveNone;\r
+\r
+   // convert "king slide" castling to KxR\r
+\r
+   if (piece_is_king(board->square[from])\r
+    && square_rank(to) == square_rank(from)\r
+    && abs(to-from) > 1) {\r
+      side = (to > from) ? SideH : SideA;\r
+      to = board->castle[board->turn][side];\r
+      if (to == SquareNone) return MoveNone;\r
+   }\r
+   // move\r
+\r
+   move = move_make(from,to);\r
+\r
+   // promote\r
+   switch (string[4]) {\r
+   case '\0': // not a promotion\r
+      if (piece_is_pawn(board->square[from])\r
+       && square_side_rank(to,board->turn) == Rank8\r
+       && option_get_bool("PromoteWorkAround")) {\r
+         move |= MovePromoteQueen;\r
+      }\r
+      break;\r
+   case 'N':\r
+   case 'n':\r
+      move |= MovePromoteKnight;\r
+      break;\r
+   case 'B':\r
+   case 'b':\r
+      move |= MovePromoteBishop;\r
+      break;\r
+   case 'R':\r
+   case 'r':\r
+      move |= MovePromoteRook;\r
+      break;\r
+   case 'Q':\r
+   case 'q':\r
+      move |= MovePromoteQueen;\r
+      break;\r
+   default:\r
+      return MoveNone;\r
+      break;\r
+   }\r
+   // debug\r
+\r
+   ASSERT(move_is_legal(move,board));\r
+   return move;\r
+}\r
+\r
+// move_order()\r
+\r
+int move_order(int move) {\r
+\r
+   ASSERT(move_is_ok(move));\r
+\r
+   return ((move & 07777) << 3) | (move >> 12); // from, to, promote\r
+}\r
+\r
+// move_disp()\r
+\r
+void move_disp(int move, const board_t * board) {\r
+\r
+   char string[256];\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   if (!move_to_can(move,board,string,256)) ASSERT(FALSE);\r
+   my_log("POLYGLOT %s\n",string);\r
+}\r
+\r
+// end of move.cpp\r
+\r
diff --git a/move.h b/move.h
index b6e7081..c83f155 100644 (file)
--- a/move.h
+++ b/move.h
@@ -9,15 +9,16 @@
 #include "board.h"\r
 #include "util.h"\r
 \r
-// constants\r
+// defined\r
 \r
-const int MoveNone = 0; // HACK: a1a1 cannot be a legal move\r
+// HACK: a1a1 cannot be a legal move\r
+#define MoveNone (0) \r
 \r
-const int MovePromoteKnight = 1 << 12;\r
-const int MovePromoteBishop = 2 << 12;\r
-const int MovePromoteRook   = 3 << 12;\r
-const int MovePromoteQueen  = 4 << 12;\r
-const int MoveFlags         = 7 << 12;\r
+#define MovePromoteKnight  (1 << 12)\r
+#define MovePromoteBishop  (2 << 12)\r
+#define MovePromoteRook    (3 << 12)\r
+#define MovePromoteQueen   (4 << 12)\r
+#define MoveFlags          (7 << 12)\r
 \r
 // types\r
 \r
diff --git a/move_do.c b/move_do.c
new file mode 100644 (file)
index 0000000..8c00687
--- /dev/null
+++ b/move_do.c
@@ -0,0 +1,363 @@
+\r
+// move_do.c\r
+\r
+// includes\r
+\r
+#include <stdlib.h>\r
+\r
+#include "board.h"\r
+#include "colour.h"\r
+#include "hash.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_legal.h"\r
+#include "piece.h"\r
+#include "random.h"\r
+#include "util.h"\r
+\r
+// prototypes\r
+\r
+static void square_clear (board_t * board, int square, int piece);\r
+static void square_set   (board_t * board, int square, int piece, int pos);\r
+static void square_move  (board_t * board, int from, int to, int piece);\r
+\r
+// functions\r
+\r
+// move_do()\r
+\r
+void move_do(board_t * board, int move) {\r
+\r
+   int me, opp;\r
+   int from, to;\r
+   int piece, pos, capture;\r
+   int old_flags, new_flags;\r
+   int sq, ep_square;\r
+   int pawn;\r
+\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(move_is_ok(move));\r
+\r
+   ASSERT(move_is_pseudo(move,board));\r
+\r
+   // init\r
+\r
+   me = board->turn;\r
+   opp = colour_opp(me);\r
+\r
+   from = move_from(move);\r
+   to = move_to(move);\r
+\r
+   piece = board->square[from];\r
+   ASSERT(colour_equal(piece,me));\r
+\r
+   pos = board->pos[from];\r
+   ASSERT(pos>=0);\r
+\r
+   // update turn\r
+\r
+   board->turn = opp;\r
+   board->key ^= random_64(RandomTurn);\r
+\r
+   // update castling rights\r
+\r
+   old_flags = board_flags(board);\r
+\r
+   if (piece_is_king(piece)) {\r
+      board->castle[me][SideH] = SquareNone;\r
+      board->castle[me][SideA] = SquareNone;\r
+   }\r
+\r
+   if (board->castle[me][SideH] == from) board->castle[me][SideH] = SquareNone;\r
+   if (board->castle[me][SideA] == from) board->castle[me][SideA] = SquareNone;\r
+\r
+   if (board->castle[opp][SideH] == to) board->castle[opp][SideH] = SquareNone;\r
+   if (board->castle[opp][SideA] == to) board->castle[opp][SideA] = SquareNone;\r
+\r
+   new_flags = board_flags(board);\r
+\r
+   board->key ^= hash_castle_key(new_flags^old_flags); // HACK\r
+\r
+   // update en-passant square\r
+\r
+   ep_square = sq = board->ep_square;\r
+   if (sq != SquareNone) {\r
+      board->key ^= random_64(RandomEnPassant+square_file(sq));\r
+      board->ep_square = SquareNone;\r
+   }\r
+\r
+   if (piece_is_pawn(piece) && abs(to-from) == 32) {\r
+      pawn = piece_make_pawn(opp);\r
+      if (board->square[to-1] == pawn || board->square[to+1] == pawn) {\r
+         board->ep_square = sq = (from + to) / 2;\r
+         board->key ^= random_64(RandomEnPassant+square_file(sq));\r
+      }\r
+   }\r
+\r
+   // update ply number (captures are handled later)\r
+\r
+   board->ply_nb++;\r
+   if (piece_is_pawn(piece)) board->ply_nb = 0; // conversion\r
+\r
+   // update move number\r
+\r
+   if (me == Black) board->move_nb++;\r
+\r
+   // castle\r
+\r
+   if (colour_equal(board->square[to],me)) {\r
+\r
+      int rank;\r
+      int king_from, king_to;\r
+      int rook_from, rook_to;\r
+      int rook;\r
+\r
+      rank = colour_is_white(me) ? Rank1 : Rank8;\r
+\r
+      king_from = from;\r
+      rook_from = to;\r
+\r
+      if (to > from) { // h side\r
+         king_to = square_make(FileG,rank);\r
+         rook_to = square_make(FileF,rank);\r
+      } else { // a side\r
+         king_to = square_make(FileC,rank);\r
+         rook_to = square_make(FileD,rank);\r
+      }\r
+\r
+      // remove the rook\r
+\r
+      pos = board->pos[rook_from];\r
+      ASSERT(pos>=0);\r
+\r
+      rook = Rook64 | me; // HACK\r
+\r
+      square_clear(board,rook_from,rook);\r
+\r
+      // move the king\r
+\r
+      square_move(board,king_from,king_to,piece);\r
+\r
+      // put the rook back\r
+\r
+      square_set(board,rook_to,rook,pos);\r
+\r
+      ASSERT(board->key==hash_key(board));\r
+\r
+      return;\r
+   }\r
+\r
+   // remove the captured piece\r
+\r
+   if (piece_is_pawn(piece) && to == ep_square) {\r
+\r
+      // en-passant capture\r
+\r
+      sq = square_ep_dual(to);\r
+      capture = board->square[sq];\r
+      ASSERT(capture==piece_make_pawn(opp));\r
+\r
+      square_clear(board,sq,capture);\r
+\r
+      board->ply_nb = 0; // conversion\r
+\r
+   } else {\r
+\r
+      capture = board->square[to];\r
+\r
+      if (capture != Empty) {\r
+\r
+         // normal capture\r
+\r
+         ASSERT(colour_equal(capture,opp));\r
+         ASSERT(!piece_is_king(capture));\r
+\r
+         square_clear(board,to,capture);\r
+\r
+         board->ply_nb = 0; // conversion\r
+      }\r
+   }\r
+\r
+   // move the piece\r
+\r
+   if (move_is_promote(move)) {\r
+\r
+      // promote\r
+\r
+      square_clear(board,from,piece);\r
+      piece = move_promote_hack(move) | me; // HACK\r
+      square_set(board,to,piece,pos);\r
+\r
+   } else {\r
+\r
+      // normal move\r
+\r
+      square_move(board,from,to,piece);\r
+   }\r
+\r
+   ASSERT(board->key==hash_key(board));\r
+}\r
+\r
+// square_clear()\r
+\r
+static void square_clear(board_t * board, int square, int piece) {\r
+\r
+   int pos, piece_12, colour;\r
+   int sq, size;\r
+\r
+   ASSERT(board!=NULL);\r
+   ASSERT(square_is_ok(square));\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   // init\r
+\r
+   pos = board->pos[square];\r
+   ASSERT(pos>=0);\r
+\r
+   colour = piece_colour(piece);\r
+   piece_12 = piece_to_12(piece);\r
+\r
+   // square\r
+\r
+   ASSERT(board->square[square]==piece);\r
+   board->square[square] = Empty;\r
+\r
+   ASSERT(board->pos[square]==pos);\r
+   board->pos[square] = -1; // not needed\r
+\r
+   // piece list\r
+\r
+   ASSERT(board->list_size[colour]>=2);\r
+   size = --board->list_size[colour];\r
+   ASSERT(pos<=size);\r
+\r
+   if (pos != size) {\r
+\r
+      sq = board->list[colour][size];\r
+      ASSERT(square_is_ok(sq));\r
+      ASSERT(sq!=square);\r
+\r
+      ASSERT(board->pos[sq]==size);\r
+      board->pos[sq] = pos;\r
+\r
+      ASSERT(board->list[colour][pos]==square);\r
+      board->list[colour][pos] = sq;\r
+   }\r
+\r
+   board->list[colour][size] = SquareNone;\r
+\r
+   // material\r
+\r
+   ASSERT(board->number[piece_12]>=1);\r
+   board->number[piece_12]--;\r
+\r
+   // hash key\r
+\r
+   board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square));\r
+}\r
+\r
+// square_set()\r
+\r
+static void square_set(board_t * board, int square, int piece, int pos) {\r
+\r
+   int piece_12, colour;\r
+   int sq, size;\r
+\r
+   ASSERT(board!=NULL);\r
+   ASSERT(square_is_ok(square));\r
+   ASSERT(piece_is_ok(piece));\r
+   ASSERT(pos>=0);\r
+\r
+   // init\r
+\r
+   colour = piece_colour(piece);\r
+   piece_12 = piece_to_12(piece);\r
+\r
+   // square\r
+\r
+   ASSERT(board->square[square]==Empty);\r
+   board->square[square] = piece;\r
+\r
+   ASSERT(board->pos[square]==-1);\r
+   board->pos[square] = pos;\r
+\r
+   // piece list\r
+\r
+   size = board->list_size[colour]++;\r
+   ASSERT(board->list[colour][size]==SquareNone);\r
+   ASSERT(pos<=size);\r
+\r
+   if (pos != size) {\r
+\r
+      sq = board->list[colour][pos];\r
+      ASSERT(square_is_ok(sq));\r
+      ASSERT(sq!=square);\r
+\r
+      ASSERT(board->pos[sq]==pos);\r
+      board->pos[sq] = size;\r
+\r
+      ASSERT(board->list[colour][size]==SquareNone);\r
+      board->list[colour][size] = sq;\r
+   }\r
+\r
+   board->list[colour][pos] = square;\r
+\r
+   // material\r
+\r
+   ASSERT(board->number[piece_12]<=8);\r
+   board->number[piece_12]++;\r
+\r
+   // hash key\r
+\r
+   board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square));\r
+}\r
+\r
+// square_move()\r
+\r
+static void square_move(board_t * board, int from, int to, int piece) {\r
+\r
+   int colour, pos;\r
+   int piece_index;\r
+\r
+   ASSERT(board!=NULL);\r
+   ASSERT(square_is_ok(from));\r
+   ASSERT(square_is_ok(to));\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   // init\r
+\r
+   colour = piece_colour(piece);\r
+\r
+   pos = board->pos[from];\r
+   ASSERT(pos>=0);\r
+\r
+   // from\r
+\r
+   ASSERT(board->square[from]==piece);\r
+   board->square[from] = Empty;\r
+\r
+   ASSERT(board->pos[from]==pos);\r
+   board->pos[from] = -1; // not needed\r
+\r
+   // to\r
+\r
+   ASSERT(board->square[to]==Empty);\r
+   board->square[to] = piece;\r
+\r
+   ASSERT(board->pos[to]==-1);\r
+   board->pos[to] = pos;\r
+\r
+   // piece list\r
+\r
+   ASSERT(board->list[colour][pos]==from);\r
+   board->list[colour][pos] = to;\r
+\r
+   // hash key\r
+\r
+   piece_index = RandomPiece + piece_to_12(piece) * 64;\r
+\r
+   board->key ^= random_64(piece_index+square_to_64(from))\r
+               ^ random_64(piece_index+square_to_64(to));\r
+}\r
+\r
+// end of move_do.cpp\r
+\r
diff --git a/move_gen.c b/move_gen.c
new file mode 100644 (file)
index 0000000..2d45564
--- /dev/null
@@ -0,0 +1,328 @@
+\r
+// move_gen.c\r
+\r
+// includes\r
+\r
+#include "attack.h"\r
+#include "board.h"\r
+#include "colour.h"\r
+#include "list.h"\r
+#include "move.h"\r
+#include "move_gen.h"\r
+#include "move_legal.h"\r
+#include "piece.h"\r
+#include "util.h"\r
+\r
+// prototypes\r
+\r
+static void add_all_moves    (list_t * list, const board_t * board);\r
+static void add_castle_moves (list_t * list, const board_t * board);\r
+\r
+static void add_pawn_move    (list_t * list, int from, int to);\r
+\r
+// functions\r
+\r
+// gen_legal_moves()\r
+\r
+void gen_legal_moves(list_t * list, const board_t * board) {\r
+\r
+   ASSERT(list!=NULL);\r
+   ASSERT(board_is_ok(board));\r
+\r
+   gen_moves(list,board);\r
+   filter_legal(list,board);\r
+}\r
+\r
+// gen_moves()\r
+\r
+void gen_moves(list_t * list, const board_t * board) {\r
+\r
+   ASSERT(list!=NULL);\r
+   ASSERT(board_is_ok(board));\r
+\r
+   list_clear(list);\r
+\r
+   add_all_moves(list,board);\r
+   if (!is_in_check(board,board->turn)) add_castle_moves(list,board);\r
+}\r
+\r
+// add_all_moves()\r
+\r
+static void add_all_moves(list_t * list, const board_t * board) {\r
+\r
+   int me, opp;\r
+   const uint8 * ptr;\r
+   const sint8 * ptr_inc;\r
+   int from, to;\r
+   int inc;\r
+   int piece, capture;\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   me = board->turn;\r
+   opp = colour_opp(me);\r
+\r
+   for (ptr = board->list[me]; (from=*ptr) != SquareNone; ptr++) {\r
+\r
+      piece = board->square[from];\r
+      ASSERT(colour_equal(piece,me));\r
+\r
+      switch (piece_type(piece)) {\r
+\r
+      case WhitePawn64:\r
+\r
+         to = from + 15;\r
+         if (to == board->ep_square || colour_equal(board->square[to],opp)) {\r
+            add_pawn_move(list,from,to);\r
+         }\r
+\r
+         to = from + 17;\r
+         if (to == board->ep_square || colour_equal(board->square[to],opp)) {\r
+            add_pawn_move(list,from,to);\r
+         }\r
+\r
+         to = from + 16;\r
+         if (board->square[to] == Empty) {\r
+            add_pawn_move(list,from,to);\r
+            if (square_rank(from) == Rank2) {\r
+               to = from + 32;\r
+               if (board->square[to] == Empty) {\r
+                  ASSERT(!square_is_promote(to));\r
+                  list_add(list,move_make(from,to));\r
+               }\r
+            }\r
+         }\r
+\r
+         break;\r
+\r
+      case BlackPawn64:\r
+\r
+         to = from - 17;\r
+         if (to == board->ep_square || colour_equal(board->square[to],opp)) {\r
+            add_pawn_move(list,from,to);\r
+         }\r
+\r
+         to = from - 15;\r
+         if (to == board->ep_square || colour_equal(board->square[to],opp)) {\r
+            add_pawn_move(list,from,to);\r
+         }\r
+\r
+         to = from - 16;\r
+         if (board->square[to] == Empty) {\r
+            add_pawn_move(list,from,to);\r
+            if (square_rank(from) == Rank7) {\r
+               to = from - 32;\r
+               if (board->square[to] == Empty) {\r
+                  ASSERT(!square_is_promote(to));\r
+                  list_add(list,move_make(from,to));\r
+               }\r
+            }\r
+         }\r
+\r
+         break;\r
+\r
+      case Knight64:\r
+\r
+         for (ptr_inc = KnightInc; (inc=*ptr_inc) != IncNone; ptr_inc++) {\r
+            to = from + inc;\r
+            capture = board->square[to];\r
+            if (capture == Empty || colour_equal(capture,opp)) {\r
+               list_add(list,move_make(from,to));\r
+            }\r
+         }\r
+\r
+         break;\r
+\r
+      case Bishop64:\r
+\r
+         for (ptr_inc = BishopInc; (inc=*ptr_inc) != IncNone; ptr_inc++) {\r
+            for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) {\r
+               list_add(list,move_make(from,to));\r
+            }\r
+            if (colour_equal(capture,opp)) {\r
+               list_add(list,move_make(from,to));\r
+            }\r
+         }\r
+\r
+         break;\r
+\r
+      case Rook64:\r
+\r
+         for (ptr_inc = RookInc; (inc=*ptr_inc) != IncNone; ptr_inc++) {\r
+            for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) {\r
+               list_add(list,move_make(from,to));\r
+            }\r
+            if (colour_equal(capture,opp)) {\r
+               list_add(list,move_make(from,to));\r
+            }\r
+         }\r
+\r
+         break;\r
+\r
+      case Queen64:\r
+\r
+         for (ptr_inc = QueenInc; (inc=*ptr_inc) != IncNone; ptr_inc++) {\r
+            for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) {\r
+               list_add(list,move_make(from,to));\r
+            }\r
+            if (colour_equal(capture,opp)) {\r
+               list_add(list,move_make(from,to));\r
+            }\r
+         }\r
+\r
+         break;\r
+\r
+      case King64:\r
+\r
+         for (ptr_inc = KingInc; (inc=*ptr_inc) != IncNone; ptr_inc++) {\r
+            to = from + inc;\r
+            capture = board->square[to];\r
+            if (capture == Empty || colour_equal(capture,opp)) {\r
+               list_add(list,move_make(from,to));\r
+            }\r
+         }\r
+\r
+         break;\r
+\r
+      default:\r
+\r
+         ASSERT(FALSE);\r
+         break;\r
+      }\r
+   }\r
+}\r
+\r
+// add_castle_moves()\r
+\r
+static void add_castle_moves(list_t * list, const board_t * board) {\r
+\r
+   int me, opp;\r
+   int rank;\r
+   int king_from, king_to;\r
+   int rook_from, rook_to;\r
+   bool legal;\r
+   int inc;\r
+   int sq;\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   ASSERT(!is_in_check(board,board->turn));\r
+\r
+   me = board->turn;\r
+   opp = colour_opp(me);\r
+\r
+   rank = colour_is_white(me) ? Rank1 : Rank8;\r
+\r
+   // h-side castling\r
+\r
+   if (board->castle[me][SideH] != SquareNone) {\r
+\r
+      king_from = king_pos(board,me);\r
+      king_to = square_make(FileG,rank);\r
+      rook_from = board->castle[me][SideH];\r
+      rook_to = square_make(FileF,rank);\r
+\r
+      ASSERT(square_rank(king_from)==rank);\r
+      ASSERT(square_rank(rook_from)==rank);\r
+      ASSERT(board->square[king_from]==(King64|me)); // HACK\r
+      ASSERT(board->square[rook_from]==(Rook64|me)); // HACK\r
+      ASSERT(rook_from>king_from);\r
+\r
+      legal = TRUE;\r
+\r
+      if (king_to != king_from) {\r
+\r
+         inc = (king_to > king_from) ? +1 : -1;\r
+\r
+         for (sq = king_from+inc; TRUE; sq += inc) {\r
+\r
+            if (sq != rook_from && board->square[sq] != Empty) legal = FALSE;\r
+            if (is_attacked(board,sq,opp)) legal = FALSE;\r
+\r
+            if (sq == king_to) break;\r
+         }\r
+      }\r
+\r
+      if (rook_to != rook_from) {\r
+\r
+         inc = (rook_to > rook_from) ? +1 : -1;\r
+\r
+         for (sq = rook_from+inc; TRUE; sq += inc) {\r
+            if (sq != king_from && board->square[sq] != Empty) legal = FALSE;\r
+            if (sq == rook_to) break;\r
+         }\r
+      }\r
+\r
+      if (legal) list_add(list,move_make(king_from,rook_from));\r
+   }\r
+\r
+   // a-side castling\r
+\r
+   if (board->castle[me][SideA] != SquareNone) {\r
+\r
+      king_from = king_pos(board,me);\r
+      king_to = square_make(FileC,rank);\r
+      rook_from = board->castle[me][SideA];\r
+      rook_to = square_make(FileD,rank);\r
+\r
+      ASSERT(square_rank(king_from)==rank);\r
+      ASSERT(square_rank(rook_from)==rank);\r
+      ASSERT(board->square[king_from]==(King64|me)); // HACK\r
+      ASSERT(board->square[rook_from]==(Rook64|me)); // HACK\r
+      ASSERT(rook_from<king_from);\r
+\r
+      legal = TRUE;\r
+\r
+      if (king_to != king_from) {\r
+\r
+         inc = (king_to > king_from) ? +1 : -1;\r
+\r
+         for (sq = king_from+inc; TRUE; sq += inc) {\r
+\r
+            if (sq != rook_from && board->square[sq] != Empty) legal = FALSE;\r
+            if (is_attacked(board,sq,opp)) legal = FALSE;\r
+\r
+            if (sq == king_to) break;\r
+         }\r
+      }\r
+\r
+      if (rook_to != rook_from) {\r
+\r
+         inc = (rook_to > rook_from) ? +1 : -1;\r
+\r
+         for (sq = rook_from+inc; TRUE; sq += inc) {\r
+            if (sq != king_from && board->square[sq] != Empty) legal = FALSE;\r
+            if (sq == rook_to) break;\r
+         }\r
+      }\r
+\r
+      if (legal) list_add(list,move_make(king_from,rook_from));\r
+   }\r
+}\r
+\r
+// add_pawn_move()\r
+\r
+static void add_pawn_move(list_t * list, int from, int to) {\r
+\r
+   int move;\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(square_is_ok(from));\r
+   ASSERT(square_is_ok(to));\r
+\r
+   move = move_make(from,to);\r
+\r
+   if (square_is_promote(to)) {\r
+      list_add(list,move|MovePromoteKnight);\r
+      list_add(list,move|MovePromoteBishop);\r
+      list_add(list,move|MovePromoteRook);\r
+      list_add(list,move|MovePromoteQueen);\r
+   } else {\r
+      list_add(list,move);\r
+   }\r
+}\r
+\r
+// end of move_gen.cpp\r
+\r
diff --git a/move_legal.c b/move_legal.c
new file mode 100644 (file)
index 0000000..ecf3fd2
--- /dev/null
@@ -0,0 +1,115 @@
+\r
+// move_legal.c\r
+\r
+// includes\r
+\r
+#include "attack.h"\r
+#include "colour.h"\r
+#include "fen.h"\r
+#include "list.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_gen.h"\r
+#include "move_legal.h"\r
+#include "piece.h"\r
+#include "square.h"\r
+#include "util.h"\r
+\r
+// prototypes\r
+\r
+static bool move_is_legal_debug (int move, const board_t * board);\r
+\r
+// functions\r
+\r
+// move_is_pseudo()\r
+\r
+bool move_is_pseudo(int move, const board_t * board) {\r
+\r
+   list_t list[1];\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   gen_moves(list,board);\r
+\r
+   return list_contain(list,move);\r
+}\r
+\r
+// pseudo_is_legal()\r
+\r
+bool pseudo_is_legal(int move, const board_t * board) {\r
+\r
+   board_t new_board[1];\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   ASSERT(move_is_pseudo(move,board));\r
+\r
+   board_copy(new_board,board);\r
+   move_do(new_board,move);\r
+\r
+   return !is_in_check(new_board,colour_opp(new_board->turn));\r
+}\r
+\r
+// move_is_legal()\r
+\r
+bool move_is_legal(int move, const board_t * board) {\r
+\r
+   bool legal;\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   legal = move_is_pseudo(move,board) && pseudo_is_legal(move,board);\r
+   ASSERT(legal==move_is_legal_debug(move,board));\r
+\r
+   return legal;\r
+}\r
+\r
+// filter_legal()\r
+\r
+void filter_legal(list_t * list, const board_t * board) {\r
+\r
+   int pos;\r
+   int i, move, value;\r
+\r
+   ASSERT(list_is_ok(list));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   pos = 0;\r
+\r
+   for (i = 0; i < list_size(list); i++) {\r
+\r
+      ASSERT(pos>=0&&pos<=i);\r
+\r
+      move = list_move(list,i);\r
+      value = list_value(list,i);\r
+\r
+      if (pseudo_is_legal(move,board)) {\r
+         list->move[pos] = move;\r
+         list->value[pos] = value;\r
+         pos++;\r
+      }\r
+   }\r
+\r
+   ASSERT(pos>=0&&pos<=list_size(list));\r
+   list->size = pos;\r
+}\r
+\r
+// move_is_legal_debug()\r
+\r
+static bool move_is_legal_debug(int move, const board_t * board) {\r
+\r
+   list_t list[1];\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+\r
+   gen_legal_moves(list,board);\r
+\r
+   return list_contain(list,move);\r
+}\r
+\r
+// end of move_legal.cpp\r
+\r
diff --git a/option.c b/option.c
new file mode 100644 (file)
index 0000000..fbf71ef
--- /dev/null
+++ b/option.c
@@ -0,0 +1,230 @@
+\r
+// option.c\r
+\r
+// includes\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "option.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const bool UseDebug = FALSE;\r
+\r
+\r
+// variables\r
+\r
+#define NNB { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }\r
+option_t Option[] = {\r
+\r
+    { "OptionFile",       "string","0","0",     "polyglot.ini", NULL,0,NNB,  PG}, \r
+\r
+   // options\r
+\r
+    { "EngineName",       "string","0","0",     "<empty>"   , NULL,0,NNB,  PG}, \r
+    { "EngineDir",        "string","0","0",     "."         , NULL,0,NNB,  PG}, \r
+    { "EngineCommand",    "string","0","0",     "<empty>"   , NULL,0,NNB,  PG}, \r
+\r
+    { "Log",              "check","0","0",     "false"      , NULL,0,NNB,  PG|XBOARD|UCI}, \r
+    { "LogFile",          "string","0","0",     "polyglot.log", NULL,0,NNB,  PG|XBOARD|UCI}, \r
+\r
+    { "UCI",              "check","0","0",      "false"     , NULL,0,NNB,  PG}, \r
+\r
+    { "UseNice",          "check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD|UCI}, \r
+    { "NiceValue",        "spin", "0","20",     "5"         , NULL,0,NNB,  PG|XBOARD|UCI}, \r
+\r
+    { "Chess960",         "check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD}, \r
+\r
+    { "Resign",           "check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD}, \r
+    { "ResignMoves",      "spin","0","10000",    "3"        , NULL,0,NNB,  PG|XBOARD}, \r
+    { "ResignScore",      "spin","0","10000",   "600"       , NULL,0,NNB,  PG|XBOARD}, \r
+\r
+    { "MateScore",        "spin","0","1000000", "10000"     , NULL,0,NNB,  PG|XBOARD}, \r
+\r
+    { "Book",             "check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD|UCI}, \r
+    { "BookFile",         "string","0","0",     "book.bin"  , NULL,0,NNB,  PG|XBOARD|UCI}, \r
+\r
+    { "BookRandom",       "check","0","0",      "true"      , NULL,0,NNB,  PG|XBOARD|UCI}, \r
+    { "BookLearn",        "check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD}, \r
+\r
+    { "KibitzMove",       "check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD}, \r
+    { "KibitzPV",         "check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD}, \r
+\r
+    { "KibitzCommand",    "string","0","0",     "tellall"   , NULL,0,NNB,  PG|XBOARD}, \r
+    { "KibitzDelay",      "spin","0","10000",  "5"         , NULL,0,NNB,  PG|XBOARD}, \r
+    { "KibitzInterval",   "spin","0","10000",  "0"         , NULL,0,NNB,  PG|XBOARD}, \r
+\r
+    { "ShowPonder",       "check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD}, \r
+    { "ScoreWhite",       "check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD}, \r
+\r
+   // work-arounds\r
+\r
+    { "UCIVersion",       "spin","1","2",       "2"         , NULL,0,NNB,  PG|XBOARD}, \r
+    { "CanPonder",        "check","1","2",      "false"     , NULL,0,NNB,  PG|XBOARD}, \r
+    { "SyncStop",         "check","1","2",      "false"     , NULL,0,NNB,  PG|XBOARD}, \r
+    { "Affinity",            "spin","-1","32",     "-1"        , NULL,0,NNB,  PG}, \r
+    { "RepeatPV",            "check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD},\r
+    { "PromoteWorkAround","check","0","0",      "false"     , NULL,0,NNB,  PG|XBOARD}, \r
+\r
+    { NULL,               NULL,"0","0",         NULL        , NULL,0,NNB,  0},\r
+};\r
+\r
+// prototypes\r
+\r
+static option_t * option_find (const char var[]);\r
+\r
+// functions\r
+\r
+// option_init()\r
+\r
+void option_init() {\r
+\r
+    option_t *p=Option;\r
+    const char * name;\r
+\r
+    while((name=(p++)->name)){\r
+        option_set(name,option_get_default(name));\r
+    }\r
+}\r
+\r
+\r
+// option_set()\r
+\r
+bool option_set(const char name[], const char value[]) {\r
+\r
+   option_t * opt;\r
+   ASSERT(name!=NULL);\r
+   ASSERT(value!=NULL);\r
+\r
+   opt = option_find(name);\r
+   if (opt == NULL) return FALSE;\r
+\r
+   my_string_set(&opt->value,value);\r
+\r
+   if (UseDebug) my_log("POLYGLOT OPTION SET \"%s\" -> \"%s\"\n",opt->name,opt->value);\r
+\r
+   return TRUE;\r
+}\r
+// option_set()\r
+\r
+bool option_set_default(const char name[], const char value[]) {\r
+\r
+   option_t * opt;\r
+   ASSERT(name!=NULL);\r
+   ASSERT(value!=NULL);\r
+\r
+   opt = option_find(name);\r
+   if (opt == NULL) return FALSE;\r
+\r
+   opt->default_=my_strdup(value);\r
+\r
+   if (UseDebug) my_log("POLYGLOT OPTION DEFAULT SET \"%s\" -> \"%s\"\n",opt->name,opt->default_);\r
+\r
+   return TRUE;\r
+}\r
+\r
+// option_get()\r
+\r
+const char * option_get(const char name[]) {\r
+\r
+   option_t * opt;\r
+\r
+   ASSERT(name!=NULL);\r
+\r
+   opt = option_find(name);\r
+   if (opt == NULL) my_fatal("option_get(): unknown option \"%s\"\n",name);\r
+\r
+   if (UseDebug) my_log("POLYGLOT OPTION GET \"%s\" -> \"%s\"\n",opt->name,opt->value);\r
+\r
+   return opt->value;\r
+}\r
+\r
+// option_get_default()\r
+\r
+const char * option_get_default(const char name[]) {\r
+\r
+   option_t * opt;\r
+\r
+   ASSERT(name!=NULL);\r
+\r
+   opt = option_find(name);\r
+   if (opt == NULL) my_fatal("option_get(): unknown option \"%s\"\n",name);\r
+\r
+   if (UseDebug) my_log("POLYGLOT OPTION GET \"%s\" -> \"%s\"\n",opt->name,opt->value);\r
+\r
+   return opt->default_;\r
+}\r
+\r
+// option_get_bool()\r
+\r
+bool option_get_bool(const char name[]) {\r
+\r
+   const char * value;\r
+\r
+   value = option_get(name);\r
+\r
+   if (FALSE) {\r
+   } else if (my_string_case_equal(value,"true") || my_string_case_equal(value,"yes") || my_string_equal(value,"1")) {\r
+      return TRUE;\r
+   } else if (my_string_case_equal(value,"false") || my_string_case_equal(value,"no") || my_string_equal(value,"0")) {\r
+      return FALSE;\r
+   }\r
+\r
+   ASSERT(FALSE);\r
+\r
+   return FALSE;\r
+}\r
+\r
+// option_get_double()\r
+\r
+double option_get_double(const char name[]) {\r
+\r
+   const char * value;\r
+\r
+   value = option_get(name);\r
+\r
+   return atof(value);\r
+}\r
+\r
+// option_get_int()\r
+\r
+int option_get_int(const char name[]) {\r
+\r
+   const char * value;\r
+\r
+   value = option_get(name);\r
+\r
+   return atoi(value);\r
+}\r
+\r
+// option_get_string()\r
+\r
+const char * option_get_string(const char name[]) {\r
+\r
+   const char * value;\r
+\r
+   value = option_get(name);\r
+\r
+   return value;\r
+}\r
+\r
+// option_find()\r
+\r
+static option_t * option_find(const char name[]) {\r
+\r
+   option_t * opt;\r
+\r
+   ASSERT(name!=NULL);\r
+\r
+\r
+   for (opt = &Option[0]; opt->name != NULL; opt++) {\r
+      if (my_string_case_equal(opt->name,name)) return opt;\r
+   }\r
+\r
+   return NULL;\r
+}\r
+\r
+// end of option.cpp\r
+\r
index c57438c..050ae0e 100644 (file)
--- a/option.h
+++ b/option.h
@@ -8,19 +8,16 @@
 \r
 #include "util.h"\r
 \r
-// constants\r
-\r
-const int VarNb = 16;\r
-\r
 // defines\r
 \r
-#define XBOARD 1\r
-#define UCI 2\r
-#define PG 4\r
+#define VarNb  16\r
+#define XBOARD (1<<0)\r
+#define UCI    (1<<1)\r
+#define PG     (1<<2)\r
 \r
 // types\r
 \r
-struct option_t {   // TODO: put back in more logical order\r
+typedef struct {   // TODO: put back in more logical order\r
     const char * name;\r
     const char * type;\r
     const char * min;\r
@@ -30,7 +27,7 @@ struct option_t {   // TODO: put back in more logical order
     int var_nb;\r
     const char * var[VarNb];\r
     int mode;\r
-};\r
+} option_t;\r
 \r
 // variables\r
 \r
diff --git a/parse.c b/parse.c
new file mode 100644 (file)
index 0000000..aaacae1
--- /dev/null
+++ b/parse.c
@@ -0,0 +1,264 @@
+\r
+// parse.c\r
+\r
+// includes\r
+\r
+#include <string.h>\r
+\r
+#include "parse.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const int StringSize = 256;\r
+\r
+// variables\r
+\r
+char * Star[STAR_NUMBER];\r
+\r
+// prototypes\r
+\r
+static bool match_rec (char string[], const char pattern[], char * star[]);\r
+\r
+// functions\r
+\r
+// match()\r
+\r
+bool match(char string[], const char pattern[]) {\r
+\r
+   ASSERT(string!=NULL);\r
+   ASSERT(pattern!=NULL);\r
+\r
+   ASSERT(strstr(pattern,"**")==NULL);\r
+\r
+   return match_rec(string,pattern,Star);\r
+}\r
+\r
+// match_rec()\r
+\r
+static bool match_rec(char string[], const char pattern[], char * star[]) {\r
+\r
+   int c;\r
+\r
+   ASSERT(string!=NULL);\r
+   ASSERT(pattern!=NULL);\r
+   ASSERT(star!=NULL);\r
+\r
+   // iterative matches\r
+\r
+   while ((c=*pattern++) != '*') {\r
+      if (FALSE) {\r
+      } else if (c == '\0') { // end of pattern\r
+         while (*string == ' ') string++; // skip trailing spaces\r
+         return *string == '\0';\r
+      } else if (c == ' ') { // spaces\r
+         if (*string++ != ' ') return FALSE; // mismatch\r
+         while (*string == ' ') string++; // skip trailing spaces\r
+      } else { // normal character\r
+         if (*string++ != c) return FALSE; // mismatch\r
+      }\r
+   }\r
+\r
+   // recursive wildcard match\r
+\r
+   ASSERT(c=='*');\r
+\r
+   while (*string == ' ') string++; // skip leading spaces\r
+   *star++ = string; // remember beginning of star\r
+\r
+   while ((c=*string++) != '\0') { // reject empty-string match\r
+      if (c != ' ' && match_rec(string,pattern,star)) { // shortest match\r
+         ASSERT(string>star[-1]);\r
+         *string = '\0'; // truncate star\r
+         return TRUE;\r
+      }\r
+   }\r
+\r
+   return FALSE;\r
+}\r
+\r
+// parse_is_ok()\r
+\r
+bool parse_is_ok(const parse_t * parse) {\r
+\r
+   if (parse == NULL) return FALSE;\r
+   if (parse->string == NULL) return FALSE;\r
+   if (parse->pos < 0 || parse->pos > (int) strlen(parse->string)) return FALSE;\r
+   if (parse->keyword_nb < 0 || parse->keyword_nb >= KEYWORD_NUMBER) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// parse_open()\r
+\r
+void parse_open(parse_t * parse, const char string[]) {\r
+\r
+   ASSERT(parse!=NULL);\r
+   ASSERT(string!=NULL);\r
+\r
+   parse->string = string;\r
+   parse->pos = 0;\r
+   parse->keyword_nb = 0;\r
+}\r
+\r
+// parse_close()\r
+\r
+void parse_close(parse_t * parse) {\r
+\r
+   int i;\r
+\r
+   ASSERT(parse_is_ok(parse));\r
+\r
+   parse->string = NULL;\r
+   parse->pos = 0;\r
+\r
+   for (i = 0; i < parse->keyword_nb; i++) {\r
+      my_string_clear(&parse->keyword[i]);\r
+   }\r
+\r
+   parse->keyword_nb = 0;\r
+}\r
+\r
+// parse_add_keyword()\r
+\r
+void parse_add_keyword(parse_t * parse, const char keyword[]) {\r
+\r
+   const char * * string;\r
+\r
+   ASSERT(parse_is_ok(parse));\r
+   ASSERT(keyword!=NULL);\r
+\r
+   if (parse->keyword_nb < KEYWORD_NUMBER) {\r
+\r
+      string = &parse->keyword[parse->keyword_nb];\r
+      parse->keyword_nb++;\r
+\r
+      *string = NULL;\r
+      my_string_set(string,keyword);\r
+   }\r
+}\r
+\r
+// parse_get_word()\r
+\r
+bool parse_get_word(parse_t * parse, char string[], int size) {\r
+\r
+   int pos;\r
+   int c;\r
+\r
+   ASSERT(parse!=NULL);\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=256);\r
+\r
+   // skip blanks\r
+\r
+   for (; parse->string[parse->pos] == ' '; parse->pos++)\r
+      ;\r
+\r
+   ASSERT(parse->string[parse->pos]!=' ');\r
+\r
+   // copy word\r
+\r
+   pos = 0;\r
+\r
+   while (TRUE) {\r
+\r
+      c = parse->string[parse->pos];\r
+      if (c == ' ' || pos >= size-1) c = '\0';\r
+\r
+      string[pos] = c;\r
+      if (c == '\0') break;\r
+\r
+      parse->pos++;\r
+      pos++;\r
+   }\r
+\r
+   ASSERT(strchr(string,' ')==NULL);\r
+\r
+   return pos > 0; // non-empty word?\r
+}\r
+\r
+// parse_get_string()\r
+\r
+bool parse_get_string(parse_t * parse, char string[], int size) {\r
+\r
+   int pos;\r
+   parse_t parse_2[1];\r
+   char word[StringSize];\r
+   int i;\r
+   int c;\r
+\r
+   ASSERT(parse!=NULL);\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=256);\r
+\r
+   // skip blanks\r
+\r
+   for (; parse->string[parse->pos] == ' '; parse->pos++)\r
+      ;\r
+\r
+   ASSERT(parse->string[parse->pos]!=' ');\r
+\r
+   // copy string\r
+\r
+   pos = 0;\r
+\r
+   while (TRUE) {\r
+\r
+      parse_open(parse_2,&parse->string[parse->pos]);\r
+\r
+      if (!parse_get_word(parse_2,word,StringSize)) {\r
+         string[pos] = '\0';\r
+         parse_close(parse_2);\r
+         goto finished;\r
+      }\r
+\r
+      for (i = 0; i < parse->keyword_nb; i++) {\r
+         if (my_string_equal(parse->keyword[i],word)) {\r
+            string[pos] = '\0';\r
+            parse_close(parse_2);\r
+            goto finished;\r
+         }\r
+      }\r
+\r
+      parse_close(parse_2);\r
+\r
+      // copy spaces\r
+\r
+      while (TRUE) {\r
+\r
+         c = parse->string[parse->pos];\r
+         if (c != ' ') break;\r
+\r
+         if (pos >= size-1) c = '\0';\r
+\r
+         string[pos] = c;\r
+         if (c == '\0') break;\r
+\r
+         parse->pos++;\r
+         pos++;\r
+      }\r
+\r
+      // copy non spaces\r
+\r
+      while (TRUE) {\r
+\r
+         c = parse->string[parse->pos];\r
+         if (c == ' ' || pos >= size-1) c = '\0';\r
+\r
+         string[pos] = c;\r
+         if (c == '\0') break;\r
+\r
+         parse->pos++;\r
+         pos++;\r
+      }\r
+\r
+      string[pos] = '\0';\r
+   }\r
+\r
+finished: ;\r
+\r
+   return pos > 0; // non-empty string?\r
+}\r
+\r
+// end of parse.cpp\r
+\r
diff --git a/parse.h b/parse.h
index dbd1f4f..5c35b32 100644 (file)
--- a/parse.h
+++ b/parse.h
@@ -8,19 +8,19 @@
 \r
 #include "util.h"\r
 \r
-// constants\r
+// defined\r
 \r
-const int STAR_NUMBER = 16;\r
-const int KEYWORD_NUMBER = 256;\r
+#define STAR_NUMBER         16\r
+#define KEYWORD_NUMBER     256\r
 \r
 // types\r
 \r
-struct parse_t {\r
+typedef struct {\r
    const char * string;\r
    int pos;\r
    int keyword_nb;\r
    const char * keyword[KEYWORD_NUMBER];\r
-};\r
+} parse_t;\r
 \r
 // variables\r
 \r
diff --git a/pgn.c b/pgn.c
new file mode 100644 (file)
index 0000000..3de7483
--- /dev/null
+++ b/pgn.c
@@ -0,0 +1,641 @@
+\r
+// pgn.c\r
+\r
+// includes\r
+\r
+#include <ctype.h>\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#include "pgn.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const bool DispMove = FALSE;\r
+static const bool DispToken = FALSE;\r
+static const bool DispChar = FALSE;\r
+\r
+static const int TAB_SIZE = 8;\r
+\r
+static const int CHAR_EOF = 256;\r
+\r
+// types\r
+\r
+enum token_t {\r
+   TOKEN_ERROR   = -1,\r
+   TOKEN_EOF     = 256,\r
+   TOKEN_SYMBOL  = 257,\r
+   TOKEN_STRING  = 258,\r
+   TOKEN_INTEGER = 259,\r
+   TOKEN_NAG     = 260,\r
+   TOKEN_RESULT  = 261\r
+};\r
+\r
+// prototypes\r
+\r
+static void pgn_token_read   (pgn_t * pgn);\r
+static void pgn_token_unread (pgn_t * pgn);\r
+\r
+static void pgn_read_token   (pgn_t * pgn);\r
+\r
+static bool is_symbol_start  (int c);\r
+static bool is_symbol_next   (int c);\r
+\r
+static void pgn_skip_blanks  (pgn_t * pgn);\r
+\r
+static void pgn_char_read    (pgn_t * pgn);\r
+static void pgn_char_unread  (pgn_t * pgn);\r
+\r
+// functions\r
+\r
+// pgn_open()\r
+\r
+void pgn_open(pgn_t * pgn, const char file_name[]) {\r
+\r
+   ASSERT(pgn!=NULL);\r
+   ASSERT(file_name!=NULL);\r
+\r
+   pgn->file = fopen(file_name,"r");\r
+   if (pgn->file == NULL) my_fatal("pgn_open(): can't open file \"%s\": %s\n",file_name,strerror(errno));\r
+\r
+   pgn->char_hack = CHAR_EOF; // DEBUG\r
+   pgn->char_line = 1;\r
+   pgn->char_column = 0;\r
+   pgn->char_unread = FALSE;\r
+   pgn->char_first = TRUE;\r
+\r
+   pgn->token_type = TOKEN_ERROR; // DEBUG\r
+   strcpy(pgn->token_string,"?"); // DEBUG\r
+   pgn->token_length = -1; // DEBUG\r
+   pgn->token_line = -1; // DEBUG\r
+   pgn->token_column = -1; // DEBUG\r
+   pgn->token_unread = FALSE;\r
+   pgn->token_first = TRUE;\r
+\r
+   strcpy(pgn->result,"?"); // DEBUG\r
+   strcpy(pgn->fen,"?"); // DEBUG\r
+\r
+   pgn->move_line = -1; // DEBUG\r
+   pgn->move_column = -1; // DEBUG\r
+}\r
+\r
+// pgn_close()\r
+\r
+void pgn_close(pgn_t * pgn) {\r
+\r
+   ASSERT(pgn!=NULL);\r
+\r
+   fclose(pgn->file);\r
+}\r
+\r
+// pgn_next_game()\r
+\r
+bool pgn_next_game(pgn_t * pgn) {\r
+\r
+   char name[PGN_STRING_SIZE];\r
+   char value[PGN_STRING_SIZE];\r
+\r
+   ASSERT(pgn!=NULL);\r
+\r
+   // init\r
+\r
+   strcpy(pgn->result,"*");\r
+   strcpy(pgn->fen,"");\r
+\r
+   // loop\r
+\r
+   while (TRUE) {\r
+\r
+      pgn_token_read(pgn);\r
+\r
+      if (pgn->token_type != '[') break;\r
+\r
+      // tag\r
+\r
+      pgn_token_read(pgn);\r
+      if (pgn->token_type != TOKEN_SYMBOL) {\r
+         my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb);\r
+      }\r
+      strcpy(name,pgn->token_string);\r
+\r
+      pgn_token_read(pgn);\r
+      if (pgn->token_type != TOKEN_STRING) {\r
+         my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb);\r
+      }\r
+      strcpy(value,pgn->token_string);\r
+\r
+      pgn_token_read(pgn);\r
+      if (pgn->token_type != ']') {\r
+         my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb);\r
+      }\r
+\r
+      // special tag?\r
+\r
+      if (FALSE) {\r
+      } else if (my_string_equal(name,"Result")) {\r
+         strcpy(pgn->result,value);\r
+      } else if (my_string_equal(name,"FEN")) {\r
+         strcpy(pgn->fen,value);\r
+      }\r
+   }\r
+\r
+   if (pgn->token_type == TOKEN_EOF) return FALSE;\r
+\r
+   pgn_token_unread(pgn);\r
+\r
+   return TRUE;\r
+}\r
+\r
+// pgn_next_move()\r
+\r
+bool pgn_next_move(pgn_t * pgn, char string[], int size) {\r
+\r
+   int depth;\r
+\r
+   ASSERT(pgn!=NULL);\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=PGN_STRING_SIZE);\r
+\r
+   // init\r
+\r
+   pgn->move_line = -1; // DEBUG\r
+   pgn->move_column = -1; // DEBUG\r
+\r
+   // loop\r
+\r
+   depth = 0;\r
+\r
+   while (TRUE) {\r
+\r
+      pgn_token_read(pgn);\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (pgn->token_type == '(') {\r
+\r
+         // open RAV\r
+\r
+         depth++;\r
+\r
+      } else if (pgn->token_type == ')') {\r
+\r
+         // close RAV\r
+\r
+         if (depth == 0) {\r
+            my_fatal("pgn_next_move(): malformed variation at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb);\r
+         }\r
+\r
+         depth--;\r
+         ASSERT(depth>=0);\r
+\r
+      } else if (pgn->token_type == TOKEN_RESULT) {\r
+\r
+         // game finished\r
+\r
+         if (depth > 0) {\r
+            my_fatal("pgn_next_move(): malformed variation at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb);\r
+         }\r
+\r
+         return FALSE;\r
+\r
+      } else {\r
+\r
+         // skip optional move number\r
+\r
+         if (pgn->token_type == TOKEN_INTEGER) {\r
+            do pgn_token_read(pgn); while (pgn->token_type == '.');\r
+         }\r
+\r
+         // move must be a symbol\r
+\r
+         if (pgn->token_type != TOKEN_SYMBOL) {\r
+            my_fatal("pgn_next_move(): malformed move at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb);\r
+         }\r
+\r
+         // store move for later use\r
+\r
+         if (depth == 0) {\r
+\r
+            if (pgn->token_length >= size) {\r
+               my_fatal("pgn_next_move(): move too long at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb);\r
+            }\r
+\r
+            strcpy(string,pgn->token_string);\r
+            pgn->move_line = pgn->token_line;\r
+            pgn->move_column = pgn->token_column;\r
+         }\r
+\r
+         // skip optional NAGs\r
+\r
+         do pgn_token_read(pgn); while (pgn->token_type == TOKEN_NAG);\r
+         pgn_token_unread(pgn);\r
+\r
+         // return move\r
+\r
+         if (depth == 0) {\r
+            if (DispMove) printf("move=\"%s\"\n",string);\r
+            return TRUE;\r
+         }\r
+      }\r
+   }\r
+\r
+   ASSERT(FALSE);\r
+\r
+   return FALSE;\r
+}\r
+\r
+// pgn_token_read()\r
+\r
+static void pgn_token_read(pgn_t * pgn) {\r
+\r
+   ASSERT(pgn!=NULL);\r
+\r
+   // token "stack"\r
+\r
+   if (pgn->token_unread) {\r
+      pgn->token_unread = FALSE;\r
+      return;\r
+   }\r
+\r
+   // consume the current token\r
+\r
+   if (pgn->token_first) {\r
+      pgn->token_first = FALSE;\r
+   } else {\r
+      ASSERT(pgn->token_type!=TOKEN_ERROR);\r
+      ASSERT(pgn->token_type!=TOKEN_EOF);\r
+   }\r
+\r
+   // read a new token\r
+\r
+   pgn_read_token(pgn);\r
+   if (pgn->token_type == TOKEN_ERROR) my_fatal("pgn_token_read(): lexical error at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+\r
+   if (DispToken) printf("< L%d C%d \"%s\" (%03X)\n",pgn->token_line,pgn->token_column,pgn->token_string,pgn->token_type);\r
+}\r
+\r
+// pgn_token_unread()\r
+\r
+static void pgn_token_unread(pgn_t * pgn) {\r
+\r
+   ASSERT(pgn!=NULL);\r
+\r
+   ASSERT(!pgn->token_unread);\r
+   ASSERT(!pgn->token_first);\r
+\r
+   pgn->token_unread = TRUE;\r
+}\r
+\r
+// pgn_read_token()\r
+\r
+static void pgn_read_token(pgn_t * pgn) {\r
+\r
+   ASSERT(pgn!=NULL);\r
+\r
+   // skip white-space characters\r
+\r
+   pgn_skip_blanks(pgn);\r
+\r
+   // init\r
+\r
+   pgn->token_type = TOKEN_ERROR;\r
+   strcpy(pgn->token_string,"");\r
+   pgn->token_length = 0;\r
+   pgn->token_line = pgn->char_line;\r
+   pgn->token_column = pgn->char_column;\r
+\r
+   // determine token type\r
+\r
+   if (FALSE) {\r
+\r
+   } else if (pgn->char_hack == CHAR_EOF) {\r
+\r
+      pgn->token_type = TOKEN_EOF;\r
+\r
+   } else if (strchr(".[]()<>",pgn->char_hack) != NULL) {\r
+\r
+      // single-character token\r
+\r
+      pgn->token_type = pgn->char_hack;\r
+      sprintf(pgn->token_string,"%c",pgn->char_hack);\r
+      pgn->token_length = 1;\r
+\r
+   } else if (pgn->char_hack == '*') {\r
+\r
+      pgn->token_type = TOKEN_RESULT;\r
+      sprintf(pgn->token_string,"%c",pgn->char_hack);\r
+      pgn->token_length = 1;\r
+\r
+   } else if (pgn->char_hack == '!') {\r
+\r
+      pgn_char_read(pgn);\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (pgn->char_hack == '!') { // "!!"\r
+\r
+         pgn->token_type = TOKEN_NAG;\r
+         strcpy(pgn->token_string,"3");\r
+         pgn->token_length = 1;\r
+\r
+      } else if (pgn->char_hack == '?') { // "!?"\r
+\r
+         pgn->token_type = TOKEN_NAG;\r
+         strcpy(pgn->token_string,"5");\r
+         pgn->token_length = 1;\r
+\r
+      } else { // "!"\r
+\r
+         pgn_char_unread(pgn);\r
+\r
+         pgn->token_type = TOKEN_NAG;\r
+         strcpy(pgn->token_string,"1");\r
+         pgn->token_length = 1;\r
+      }\r
+\r
+   } else if (pgn->char_hack == '?') {\r
+\r
+      pgn_char_read(pgn);\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (pgn->char_hack == '?') { // "??"\r
+\r
+         pgn->token_type = TOKEN_NAG;\r
+         strcpy(pgn->token_string,"4");\r
+         pgn->token_length = 1;\r
+\r
+      } else if (pgn->char_hack == '!') { // "?!"\r
+\r
+         pgn->token_type = TOKEN_NAG;\r
+         strcpy(pgn->token_string,"6");\r
+         pgn->token_length = 1;\r
+\r
+      } else { // "?"\r
+\r
+         pgn_char_unread(pgn);\r
+\r
+         pgn->token_type = TOKEN_NAG;\r
+         strcpy(pgn->token_string,"2");\r
+         pgn->token_length = 1;\r
+      }\r
+\r
+   } else if (is_symbol_start(pgn->char_hack)) {\r
+\r
+      // symbol, integer, or result\r
+\r
+      pgn->token_type = TOKEN_INTEGER;\r
+      pgn->token_length = 0;\r
+\r
+      do {\r
+\r
+         if (pgn->token_length >= PGN_STRING_SIZE-1) {\r
+            my_fatal("pgn_read_token(): symbol too long at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+         }\r
+\r
+         if (!isdigit(pgn->char_hack)) pgn->token_type = TOKEN_SYMBOL;\r
+\r
+         pgn->token_string[pgn->token_length++] = pgn->char_hack;\r
+\r
+         pgn_char_read(pgn);\r
+\r
+      } while (is_symbol_next(pgn->char_hack));\r
+\r
+      pgn_char_unread(pgn);\r
+\r
+      ASSERT(pgn->token_length>0&&pgn->token_length<PGN_STRING_SIZE);\r
+      pgn->token_string[pgn->token_length] = '\0';\r
+\r
+      if (my_string_equal(pgn->token_string,"1-0")\r
+       || my_string_equal(pgn->token_string,"0-1")\r
+       || my_string_equal(pgn->token_string,"1/2-1/2")) {\r
+         pgn->token_type = TOKEN_RESULT;\r
+      }\r
+\r
+   } else if (pgn->char_hack == '"') {\r
+\r
+      // string\r
+\r
+      pgn->token_type = TOKEN_STRING;\r
+      pgn->token_length = 0;\r
+\r
+      while (TRUE) {\r
+\r
+         pgn_char_read(pgn);\r
+\r
+         if (pgn->char_hack == CHAR_EOF) {\r
+            my_fatal("pgn_read_token(): EOF in string at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+         }\r
+\r
+         if (pgn->char_hack == '"') break;\r
+\r
+         if (pgn->char_hack == '\\') {\r
+\r
+            pgn_char_read(pgn);\r
+\r
+            if (pgn->char_hack == CHAR_EOF) {\r
+               my_fatal("pgn_read_token(): EOF in string at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+            }\r
+\r
+            if (pgn->char_hack != '"' && pgn->char_hack != '\\') {\r
+\r
+               // bad escape, ignore\r
+\r
+               if (pgn->token_length >= PGN_STRING_SIZE-1) {\r
+                  my_fatal("pgn_read_token(): string too long at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+               }\r
+\r
+               pgn->token_string[pgn->token_length++] = '\\';\r
+            }\r
+         }\r
+\r
+         if (pgn->token_length >= PGN_STRING_SIZE-1) {\r
+            my_fatal("pgn_read_token(): string too long at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+         }\r
+\r
+         pgn->token_string[pgn->token_length++] = pgn->char_hack;\r
+      }\r
+\r
+      ASSERT(pgn->token_length>=0&&pgn->token_length<PGN_STRING_SIZE);\r
+      pgn->token_string[pgn->token_length] = '\0';\r
+\r
+   } else if (pgn->char_hack == '$') {\r
+\r
+      // NAG\r
+\r
+      pgn->token_type = TOKEN_NAG;\r
+      pgn->token_length = 0;\r
+\r
+      while (TRUE) {\r
+\r
+         pgn_char_read(pgn);\r
+\r
+         if (!isdigit(pgn->char_hack)) break;\r
+\r
+         if (pgn->token_length >= 3) {\r
+            my_fatal("pgn_read_token(): NAG too long at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+         }\r
+\r
+         pgn->token_string[pgn->token_length++] = pgn->char_hack;\r
+      }\r
+\r
+      pgn_char_unread(pgn);\r
+\r
+      if (pgn->token_length == 0) {\r
+         my_fatal("pgn_read_token(): malformed NAG at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+      }\r
+\r
+      ASSERT(pgn->token_length>0&&pgn->token_length<=3);\r
+      pgn->token_string[pgn->token_length] = '\0';\r
+\r
+   } else {\r
+\r
+      // unknown token\r
+\r
+       my_fatal("lexical error at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+   }\r
+}\r
+\r
+// pgn_skip_blanks()\r
+\r
+static void pgn_skip_blanks(pgn_t * pgn) {\r
+\r
+   ASSERT(pgn!=NULL);\r
+\r
+   while (TRUE) {\r
+\r
+      pgn_char_read(pgn);\r
+\r
+         if (FALSE) {\r
+         }else if(pgn->char_hack==CHAR_EOF){ break;\r
+      } else if (isspace(pgn->char_hack)) {\r
+\r
+         // skip white space\r
+\r
+      } else if (pgn->char_hack == ';') {\r
+\r
+         // skip comment to EOL\r
+\r
+         do {\r
+\r
+            pgn_char_read(pgn);\r
+\r
+            if (pgn->char_hack == CHAR_EOF) {\r
+               my_fatal("pgn_skip_blanks(): EOF in comment at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+            }\r
+\r
+         } while (pgn->char_hack != '\n');\r
+\r
+      } else if (pgn->char_hack == '%' && pgn->char_column == 0) {\r
+\r
+         // skip comment to EOL\r
+\r
+         do {\r
+\r
+            pgn_char_read(pgn);\r
+\r
+            if (pgn->char_hack == CHAR_EOF) {\r
+               my_fatal("pgn_skip_blanks(): EOF in comment at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+            }\r
+\r
+         } while (pgn->char_hack != '\n');\r
+\r
+      } else if (pgn->char_hack == '{') {\r
+\r
+         // skip comment to next '}'\r
+\r
+         do {\r
+\r
+            pgn_char_read(pgn);\r
+\r
+            if (pgn->char_hack == CHAR_EOF) {\r
+               my_fatal("pgn_skip_blanks(): EOF in comment at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb);\r
+            }\r
+\r
+         } while (pgn->char_hack != '}');\r
+\r
+      } else { // not a white space\r
+\r
+         break;\r
+      }\r
+   }\r
+}\r
+\r
+// is_symbol_start()\r
+\r
+static bool is_symbol_start(int c) {\r
+\r
+   return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",c) != NULL;\r
+}\r
+\r
+// is_symbol_next()\r
+\r
+static bool is_symbol_next(int c) {\r
+\r
+   return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+#=:-/",c) != NULL;\r
+}\r
+\r
+// pgn_char_read()\r
+\r
+static void pgn_char_read(pgn_t * pgn) {\r
+\r
+   ASSERT(pgn!=NULL);\r
+\r
+   // char "stack"\r
+\r
+   if (pgn->char_unread) {\r
+      pgn->char_unread = FALSE;\r
+      return;\r
+   }\r
+\r
+   // consume the current character\r
+\r
+   if (pgn->char_first) {\r
+\r
+      pgn->char_first = FALSE;\r
+\r
+   } else {\r
+\r
+      // update counters\r
+\r
+      ASSERT(pgn->char_hack!=CHAR_EOF);\r
+\r
+      if (FALSE) {\r
+      } else if (pgn->char_hack == '\n') {\r
+         pgn->char_line++;\r
+         pgn->char_column = 0;\r
+      } else if (pgn->char_hack == '\t') {\r
+         pgn->char_column += TAB_SIZE - (pgn->char_column % TAB_SIZE);\r
+      } else {\r
+         pgn->char_column++;\r
+      }\r
+   }\r
+\r
+   // read a new character\r
+\r
+   pgn->char_hack = fgetc(pgn->file);\r
+\r
+   if (pgn->char_hack == EOF) {\r
+      if (ferror(pgn->file)) my_fatal("pgn_char_read(): fgetc(): %s\n",strerror(errno));\r
+      pgn->char_hack = CHAR_EOF;\r
+   }\r
+\r
+   if (DispChar) printf("< L%d C%d '%c' (%02X)\n",pgn->char_line,pgn->char_column,pgn->char_hack,pgn->char_hack);\r
+}\r
+\r
+// pgn_char_unread()\r
+\r
+static void pgn_char_unread(pgn_t * pgn) {\r
+\r
+   ASSERT(pgn!=NULL);\r
+\r
+   ASSERT(!pgn->char_unread);\r
+   ASSERT(!pgn->char_first);\r
+\r
+   pgn->char_unread = TRUE;\r
+}\r
+\r
+// end of pgn.cpp\r
+\r
diff --git a/pgn.h b/pgn.h
index e79fc3f..0f51015 100644 (file)
--- a/pgn.h
+++ b/pgn.h
@@ -6,17 +6,17 @@
 \r
 // includes\r
 \r
-#include <cstdio>\r
+#include <stdio.h>\r
 \r
 #include "util.h"\r
 \r
-// constants\r
+// defines\r
 \r
-const int PGN_STRING_SIZE = 256;\r
+#define PGN_STRING_SIZE 256\r
 \r
 // types\r
 \r
-struct pgn_t {\r
+typedef struct {\r
 \r
    FILE * file;\r
 \r
@@ -40,7 +40,7 @@ struct pgn_t {
    int move_line;\r
    int move_column;\r
    int game_nb;\r
-};\r
+} pgn_t;\r
 \r
 // functions\r
 \r
diff --git a/piece.c b/piece.c
new file mode 100644 (file)
index 0000000..82ed76a
--- /dev/null
+++ b/piece.c
@@ -0,0 +1,203 @@
+\r
+// piece.c\r
+\r
+// includes\r
+\r
+#include <string.h>\r
+\r
+#include "colour.h"\r
+#include "piece.h"\r
+#include "util.h"\r
+\r
+// "constants"\r
+\r
+static const uint8 MakePawn[ColourNb] = { PieceNone256, BlackPawn256, WhitePawn256 }; // -BW\r
+\r
+static const uint8 PieceFrom12[12] = {\r
+   BlackPawn256,   WhitePawn256,\r
+   BlackKnight256, WhiteKnight256,\r
+   BlackBishop256, WhiteBishop256,\r
+   BlackRook256,   WhiteRook256,\r
+   BlackQueen256,  WhiteQueen256,\r
+   BlackKing256,   WhiteKing256,\r
+};\r
+\r
+static const char PieceString[12+1] = "pPnNbBrRqQkK";\r
+\r
+// variables\r
+\r
+static sint8 PieceTo12[256];\r
+\r
+// functions\r
+\r
+// piece_init()\r
+\r
+void piece_init() {\r
+\r
+   int piece;\r
+\r
+   for (piece = 0; piece < 256; piece++) PieceTo12[piece] = -1;\r
+\r
+   for (piece = 0; piece < 12; piece++) {\r
+      PieceTo12[PieceFrom12[piece]] = piece;\r
+   }\r
+}\r
+\r
+// piece_is_ok()\r
+\r
+bool piece_is_ok(int piece) {\r
+\r
+   if (piece < 0 || piece >= 256) return FALSE;\r
+\r
+   if (PieceTo12[piece] < 0) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// piece_make_pawn()\r
+\r
+int piece_make_pawn(int colour) {\r
+\r
+   ASSERT(colour_is_ok(colour));\r
+\r
+   return MakePawn[colour];\r
+}\r
+\r
+// piece_pawn_opp()\r
+\r
+int piece_pawn_opp(int piece) {\r
+\r
+   ASSERT(piece==BlackPawn256||piece==WhitePawn256);\r
+\r
+   return piece ^ 15;\r
+}\r
+\r
+// piece_colour()\r
+\r
+int piece_colour(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return piece & 3;\r
+}\r
+\r
+// piece_type()\r
+\r
+int piece_type(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return piece & ~3;\r
+}\r
+\r
+// piece_is_pawn()\r
+\r
+bool piece_is_pawn(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return (piece & PawnFlags) != 0;\r
+}\r
+\r
+// piece_is_knight()\r
+\r
+bool piece_is_knight(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return (piece & KnightFlag) != 0;\r
+}\r
+\r
+// piece_is_bishop()\r
+\r
+bool piece_is_bishop(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return (piece & QueenFlags) == BishopFlag;\r
+}\r
+\r
+// piece_is_rook()\r
+\r
+bool piece_is_rook(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return (piece & QueenFlags) == RookFlag;\r
+}\r
+\r
+// piece_is_queen()\r
+\r
+bool piece_is_queen(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return (piece & QueenFlags) == QueenFlags;\r
+}\r
+\r
+// piece_is_king()\r
+\r
+bool piece_is_king(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return (piece & KingFlag) != 0;\r
+}\r
+\r
+// piece_is_slider()\r
+\r
+bool piece_is_slider(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return (piece & QueenFlags) != 0;\r
+}\r
+\r
+// piece_to_12()\r
+\r
+int piece_to_12(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return PieceTo12[piece];\r
+}\r
+\r
+// piece_from_12()\r
+\r
+int piece_from_12(int piece) {\r
+\r
+   ASSERT(piece>=0&&piece<12);\r
+\r
+   return PieceFrom12[piece];\r
+}\r
+\r
+// piece_to_char()\r
+\r
+int piece_to_char(int piece) {\r
+\r
+   ASSERT(piece_is_ok(piece));\r
+\r
+   return PieceString[piece_to_12(piece)];\r
+}\r
+\r
+// piece_from_char()\r
+\r
+int piece_from_char(int c) {\r
+\r
+   const char * ptr;\r
+\r
+   ptr = strchr(PieceString,c);\r
+   if (ptr == NULL) return PieceNone256;\r
+\r
+   return piece_from_12(ptr-PieceString);\r
+}\r
+\r
+// char_is_piece()\r
+\r
+bool char_is_piece(int c) {\r
+\r
+   return strchr("PNBRQK",c) != NULL;\r
+}\r
+\r
+// end of piece.cpp\r
+\r
diff --git a/piece.h b/piece.h
index a0bbafb..f060cb6 100644 (file)
--- a/piece.h
+++ b/piece.h
@@ -9,53 +9,53 @@
 #include "colour.h"\r
 #include "util.h"\r
 \r
-// constants\r
-\r
-const int BlackPawnFlag = 1 << 2;\r
-const int WhitePawnFlag = 1 << 3;\r
-const int KnightFlag    = 1 << 4;\r
-const int BishopFlag    = 1 << 5;\r
-const int RookFlag      = 1 << 6;\r
-const int KingFlag      = 1 << 7;\r
-\r
-const int PawnFlags  = BlackPawnFlag | WhitePawnFlag;\r
-const int QueenFlags = BishopFlag | RookFlag;\r
-\r
-const int PieceNone64 = 0;\r
-const int BlackPawn64 = BlackPawnFlag;\r
-const int WhitePawn64 = WhitePawnFlag;\r
-const int Knight64    = KnightFlag;\r
-const int Bishop64    = BishopFlag;\r
-const int Rook64      = RookFlag;\r
-const int Queen64     = QueenFlags;\r
-const int King64      = KingFlag;\r
-\r
-const int PieceNone256   = 0;\r
-const int BlackPawn256   = BlackPawn64 | Black;\r
-const int WhitePawn256   = WhitePawn64 | White;\r
-const int BlackKnight256 = Knight64    | Black;\r
-const int WhiteKnight256 = Knight64    | White;\r
-const int BlackBishop256 = Bishop64    | Black;\r
-const int WhiteBishop256 = Bishop64    | White;\r
-const int BlackRook256   = Rook64      | Black;\r
-const int WhiteRook256   = Rook64      | White;\r
-const int BlackQueen256  = Queen64     | Black;\r
-const int WhiteQueen256  = Queen64     | White;\r
-const int BlackKing256   = King64      | Black;\r
-const int WhiteKing256   = King64      | White;\r
-\r
-const int BlackPawn12   =  0;\r
-const int WhitePawn12   =  1;\r
-const int BlackKnight12 =  2;\r
-const int WhiteKnight12 =  3;\r
-const int BlackBishop12 =  4;\r
-const int WhiteBishop12 =  5;\r
-const int BlackRook12   =  6;\r
-const int WhiteRook12   =  7;\r
-const int BlackQueen12  =  8;\r
-const int WhiteQueen12  =  9;\r
-const int BlackKing12   = 10;\r
-const int WhiteKing12   = 11;\r
+// defines\r
+\r
+#define BlackPawnFlag     (1 << 2)\r
+#define WhitePawnFlag     (1 << 3)\r
+#define KnightFlag        (1 << 4)\r
+#define BishopFlag        (1 << 5)\r
+#define RookFlag          (1 << 6)\r
+#define KingFlag          (1 << 7)\r
+\r
+#define PawnFlags   (BlackPawnFlag | WhitePawnFlag)\r
+#define QueenFlags  (BishopFlag | RookFlag)\r
+\r
+#define PieceNone64     (0)\r
+#define BlackPawn64     (BlackPawnFlag)\r
+#define WhitePawn64     (WhitePawnFlag)\r
+#define Knight64        (KnightFlag)\r
+#define Bishop64        (BishopFlag)\r
+#define Rook64          (RookFlag)\r
+#define Queen64         (QueenFlags)\r
+#define King64          (KingFlag)\r
+\r
+#define  PieceNone256      (0)\r
+#define  BlackPawn256      (BlackPawn64 | Black)\r
+#define  WhitePawn256      (WhitePawn64 | White)\r
+#define  BlackKnight256    (Knight64    | Black)\r
+#define  WhiteKnight256    (Knight64    | White)\r
+#define  BlackBishop256    (Bishop64    | Black)\r
+#define  WhiteBishop256    (Bishop64    | White)\r
+#define  BlackRook256      (Rook64      | Black)\r
+#define  WhiteRook256      (Rook64      | White)\r
+#define  BlackQueen256     (Queen64     | Black)\r
+#define  WhiteQueen256     (Queen64     | White)\r
+#define  BlackKing256      (King64      | Black)\r
+#define  WhiteKing256      (King64      | White)\r
+\r
+#define BlackPawn12        (0)\r
+#define WhitePawn12        (1)\r
+#define BlackKnight12      (2)\r
+#define WhiteKnight12      (3)\r
+#define BlackBishop12      (4)\r
+#define WhiteBishop12      (5)\r
+#define BlackRook12        (6)\r
+#define WhiteRook12        (7)\r
+#define BlackQueen12       (8)\r
+#define WhiteQueen12       (9)\r
+#define BlackKing12       (10)\r
+#define WhiteKing12       (11)\r
 \r
 // functions\r
 \r
diff --git a/pipex.h b/pipex.h
new file mode 100644 (file)
index 0000000..e96457f
--- /dev/null
+++ b/pipex.h
@@ -0,0 +1,93 @@
+#ifndef PIPEX_H
+#define PIPEX_H
+#ifdef _WIN32
+
+// WIN32 part
+
+// includes
+
+#include <windows.h>
+#include <stdio.h>
+#include "util.h"
+
+// defines
+
+#define PIPEX_EOF (1<<0)
+#define PIPEX_ACTIVE (1<<1)
+
+// This should be bigger than the maximum length of an engine output or GUI
+// input line.
+
+#define LINE_INPUT_MAX_CHAR 4096
+
+// types
+
+typedef struct {
+    HANDLE hProcess;
+    HANDLE hEvent;
+    HANDLE hInput, hOutput;
+    FILE *fpInput;
+    HANDLE hThread;
+    BOOL bConsole;
+    BOOL bPipe;
+    CRITICAL_SECTION CriticalSection;
+    volatile DWORD state;
+    volatile char * lpFeedEnd;
+    volatile int nReadEnd;
+    char lpBuffer[LINE_INPUT_MAX_CHAR];
+    char lpReadBuffer[LINE_INPUT_MAX_CHAR];
+    const char *name;
+
+} pipex_t;
+
+#else
+
+// POSIX part
+
+// includes
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+
+#include "io.h"
+#include "util.h"
+
+// defines
+
+#define PIPEX_EOF (1<<0)
+#define PIPEX_ACTIVE (1<<1)
+
+// types
+
+typedef struct {
+    io_t io[1];
+    pid_t pid;
+    int state;
+} pipex_t;
+
+#endif
+
+// part common to WIN32 and POSIX
+
+// functions 
+
+extern void pipex_open         (pipex_t *pipex, 
+                                const char *name,
+                                const char *command);
+extern bool pipex_active       (pipex_t *pipex);
+extern bool pipex_readln       (pipex_t *pipex, char *string);
+extern bool pipex_readln_nb    (pipex_t *pipex, char *string);
+extern void pipex_writeln      (pipex_t *pipex, const char *string);
+extern bool pipex_eof          (pipex_t *pipex);
+extern void pipex_send_eof     (pipex_t *pipex);
+extern void pipex_exit         (pipex_t *pipex);
+extern void pipex_set_priority (pipex_t *pipex, int value);
+extern void pipex_set_affinity (pipex_t *pipex, int value);
+extern void pipex_wait_event   (pipex_t *pipex[]);
+
+// pipex
+
+#endif
diff --git a/pipex_posix.c b/pipex_posix.c
new file mode 100644 (file)
index 0000000..5d2edfa
--- /dev/null
@@ -0,0 +1,255 @@
+#ifndef _WIN32
+
+// includes
+
+#include <string.h>
+#include <errno.h>
+#include "pipex.h"
+
+// constants
+
+static const unsigned int StringSize = 4096;
+
+// prototypes
+
+static void my_close(int fd);
+static void my_dup2(int old_fd, int new_fd) ;
+
+// functions
+
+// pipex_open()
+
+void pipex_open(pipex_t *pipex, const char *name, const char *command){
+    char string[StringSize];
+    int argc;
+    char * ptr;
+    char * argv[256];
+    int from_child[2], to_child[2];
+
+    pipex->pid=-1;
+    pipex->io->name=name;
+    
+    if(command==NULL){
+        pipex->io->in_fd = STDIN_FILENO;
+        pipex->io->out_fd = STDOUT_FILENO;
+
+            // attach standard error to standard output
+        
+        my_dup2(STDOUT_FILENO,STDERR_FILENO);
+        io_init(pipex->io);
+    }else{
+    
+        // parse the command line and create the argument list
+    
+        if (strlen(command) >= StringSize) my_fatal("pipex_open(): buffer overflow\n");
+        strcpy(string,command);
+        argc = 0;
+        
+        for (ptr = strtok(string," "); ptr != NULL; ptr = strtok(NULL," ")) {
+            argv[argc++] = ptr;
+        }
+
+        argv[argc] = NULL;
+        
+      // create the pipes
+        
+        if (pipe(from_child) == -1) {
+            my_fatal("pipex_open(): pipe(): %s\n",strerror(errno));
+        }
+        
+        if (pipe(to_child) == -1) {
+            my_fatal("pipex_open(): pipe(): %s\n",strerror(errno));
+        }
+        
+            // create the child process
+        
+        pipex->pid = fork();
+        
+        if (pipex->pid == -1) {
+            
+            my_fatal("pipex_open(): fork(): %s\n",strerror(errno));
+            
+        } else if (pipex->pid == 0) {
+            
+                // child 
+            
+                // close unused pipe descriptors to avoid deadlocks
+            
+            my_close(from_child[0]);
+            my_close(to_child[1]);
+            
+                // attach the pipe to standard input
+            
+            my_dup2(to_child[0],STDIN_FILENO);
+            my_close(to_child[0]);
+            
+                // attach the pipe to standard output
+            
+            my_dup2(from_child[1],STDOUT_FILENO);
+            my_close(from_child[1]);
+            
+                // attach standard error to standard output
+                // commenting this out gives error messages on the console
+            
+           /* my_dup2(STDOUT_FILENO,STDERR_FILENO); */
+            
+                // launch the new executable file
+            
+            execvp(argv[0],&argv[0]);
+            
+                // execvp() only returns when an error has occured
+            
+            my_fatal("engine_open(): execvp(): %s\n",strerror(errno));
+            
+        } else { // pid > 0
+            
+            ASSERT(pipex->pid>0);
+            
+                // parent 
+            
+                // close unused pipe descriptors to avoid deadlocks
+            
+            my_close(from_child[1]);
+            my_close(to_child[0]);
+            
+                // fill in the pipex struct
+            
+            pipex->io->in_fd = from_child[0];
+            pipex->io->out_fd = to_child[1];
+            pipex->state|=PIPEX_ACTIVE; // can we test if this really TRUE?
+            
+            io_init(pipex->io);
+        } 
+    }
+}
+
+void pipex_wait_event(pipex_t *pipex[]){
+
+    fd_set set[1];
+    pipex_t *p;
+    int fd_max;
+    int val;
+    pipex_t **q;
+
+    q=pipex;
+
+        // init
+
+   FD_ZERO(set);
+   fd_max = -1; // HACK
+   while((p=*(q++))!=NULL){
+       ASSERT(p->io->in_fd>=0);
+       FD_SET(p->io->in_fd,set);
+       if (p->io->in_fd > fd_max){
+           fd_max = p->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("pipex_wait_event(): select(): %s\n",strerror(errno));
+
+   q=pipex;
+   if (val > 0) {
+       while((p=*(q++))!=NULL){
+           if (FD_ISSET(p->io->in_fd,set)) io_get_update(p->io); 
+       }
+   }    
+}
+
+// pipex_active()
+
+bool pipex_active(pipex_t *pipex){
+    return (pipex->state&PIPEX_ACTIVE)!=0;
+}
+
+// pipex_eof()
+
+bool pipex_eof(pipex_t *pipex){
+    return (pipex->state&PIPEX_EOF)!=0;
+}
+
+
+// pipex_set_priority()
+
+void pipex_set_priority(pipex_t *pipex, int value){
+    if(pipex->pid!=-1){
+        setpriority(PRIO_PROCESS,pipex->pid,value);
+    }
+}
+
+// pipex_set_affinity()
+
+void pipex_set_affinity(pipex_t *pipex, int value){
+    my_log("POLYGLOT Setting affinity is not yet implemented on posix\n");
+}
+
+// pipex_send_eof()
+
+void pipex_send_eof(pipex_t *pipex){
+    io_close(pipex->io);
+}
+
+// pipex_exit()
+
+void pipex_exit(pipex_t *pipex){
+        // NOOP for now
+    return;
+}
+
+// pipex_readln()
+
+bool pipex_readln(pipex_t *pipex, char *string){
+    while (!io_line_ready(pipex->io)) {
+      io_get_update(pipex->io);
+   }
+   if (!io_get_line(pipex->io,string,StringSize)) { // EOF
+       string[0]='\0';
+       pipex->state|=PIPEX_EOF;
+       return FALSE;
+   }
+   
+
+   return TRUE;
+}
+
+// pipex_readln_nb()
+
+bool pipex_readln_nb(pipex_t *pipex, char *string){
+    if(io_line_ready(pipex->io)){
+        return pipex_readln(pipex,string);
+    }else{  
+        string[0]='\0';
+        return FALSE;
+    }
+}
+
+// pipex_writeln()
+
+void pipex_writeln(pipex_t *pipex, const char *string){
+       io_send(pipex->io,"%s",string);
+}
+
+// my_close()
+
+static void my_close(int fd) {
+
+   ASSERT(fd>=0);
+
+   if (close(fd) == -1) my_fatal("my_close(): close(): %s\n",strerror(errno));
+}
+
+// my_dup2()
+
+static void my_dup2(int old_fd, int new_fd) {
+
+   ASSERT(old_fd>=0);
+   ASSERT(new_fd>=0);
+
+   if (dup2(old_fd,new_fd) == -1) my_fatal("my_dup2(): dup2(): %s\n",strerror(errno));
+}
+
+
+#endif
diff --git a/pipex_win32.c b/pipex_win32.c
new file mode 100644 (file)
index 0000000..8d9e893
--- /dev/null
@@ -0,0 +1,446 @@
+// pipex_win32.c
+
+#ifdef _WIN32
+
+// includes
+
+#include <io.h>
+#include <fcntl.h>
+#include "pipex.h"
+#include "util.h"
+
+// defines
+
+#define ErrorBufferSize 4096
+#define dwMaxHandles      32
+
+// variables
+
+static char ErrorBuffer[ErrorBufferSize];
+
+// prototypes
+
+static bool pipex_eof_input(pipex_t *pipex);
+static void pipex_set_eof_input(pipex_t *pipex);
+static void pipex_set_active(pipex_t *pipex);
+static int  pipex_read_data(pipex_t *pipex);
+static void pipex_read_input(pipex_t *pipex);
+
+// functions
+
+// win32_error()
+
+static char * win32_error(){
+    FormatMessage(
+        FORMAT_MESSAGE_FROM_SYSTEM,
+        NULL,
+        GetLastError(),
+        LANG_USER_DEFAULT,
+        ErrorBuffer,
+        ErrorBufferSize,
+        NULL);
+    return ErrorBuffer;
+}
+
+// TreadProc()
+
+static DWORD WINAPI ThreadProc(LPVOID lpParam){ 
+    pipex_t *p=(pipex_t *) lpParam;
+    while(!pipex_eof_input(p)){
+        if(p->nReadEnd<LINE_INPUT_MAX_CHAR-1){
+            pipex_read_input(p);
+        }else{
+                // wait until there is room in buffer
+            Sleep(10);
+        }
+    }
+    return 0;
+}
+
+// pipex_open()
+
+void pipex_open(pipex_t *pipex, const char *szName, const char *szProcFile) {
+    DWORD dwMode, dwThreadId;
+    HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite, hThread;
+    SECURITY_ATTRIBUTES sa;
+    STARTUPINFO si;
+    PROCESS_INFORMATION pi;
+    int fdInput;
+    pipex->state=0;
+    pipex->name=szName;
+    pipex->hProcess=NULL;
+    if (szProcFile == NULL) {
+        pipex->hInput = GetStdHandle(STD_INPUT_HANDLE);
+        pipex->hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+        pipex->bConsole = GetConsoleMode(pipex->hInput, &dwMode);
+        pipex->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)){
+            pipex->hProcess=pi.hProcess;
+            CloseHandle(pi.hThread);
+            CloseHandle(hStdinRead);
+            CloseHandle(hStdoutWrite);
+            pipex->hInput = hStdoutRead;
+            pipex->hOutput = hStdinWrite;
+            pipex->bConsole = FALSE;
+            pipex->bPipe=TRUE;
+        }else{
+            my_fatal("pipex_open(): %s",win32_error());
+        }
+    }
+    if (pipex->bConsole) {
+        SetConsoleMode(pipex->hInput,
+                       dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
+        FlushConsoleInputBuffer(pipex->hInput);
+    } 
+    fdInput=_open_osfhandle((long) pipex->hInput,_O_RDONLY);
+    if(fdInput==-1){
+        my_fatal("pipex_open(): %s",strerror(errno));
+    }
+    pipex->fpInput=fdopen(fdInput,"r");
+    if(pipex->fpInput==NULL){
+        my_fatal("pipex_open(): %s",strerror(errno));
+    }
+    pipex->nReadEnd = 0;
+    pipex->lpFeedEnd = NULL;
+    InitializeCriticalSection(&(pipex->CriticalSection));
+    pipex->hEvent=CreateEvent(NULL,           // default security
+                       FALSE,          // auto reset
+                       FALSE,          // not signaled
+                       NULL            // nameless
+                       );
+    if(!(pipex->hEvent)){
+        my_fatal("pipex_open(): %s",win32_error());
+    }
+    hThread=CreateThread(NULL,         // default security
+                         0,            // default stacksize
+                         ThreadProc,   // worker function
+                         pipex,        // tell worker about ourselves
+                         0,            // run immediately
+                         &dwThreadId   // dropped, but needed for the call to work in Win9x
+                         );          
+    if(!hThread){
+        my_fatal("pipex_open(): %s",win32_error());
+    }
+    pipex_set_active(pipex);
+}
+
+// pipex_wait_event(pipex)
+
+void pipex_wait_event(pipex_t *pipex[]){
+    HANDLE hHandles[dwMaxHandles]; 
+    DWORD dwHandleCount=0;
+    pipex_t *p;
+    while((p=pipex[dwHandleCount])!=NULL){
+        ASSERT((p->hEvent)!=0);
+        if(dwHandleCount>=dwMaxHandles){
+            my_fatal("pipex_wait_event(): Too many objects to wait for");
+        }
+        hHandles[dwHandleCount++]=p->hEvent;
+    }
+    WaitForMultipleObjects(dwHandleCount,   // count
+                           hHandles,        //
+                           FALSE,           // return if one object is signaled
+                           INFINITE         // no timeout
+                           );
+}
+
+
+// pipex_send_eof()
+
+void pipex_send_eof(pipex_t *pipex)  {
+    my_log("Adapter->%s: EOF\n",pipex->name);
+    CloseHandle(pipex->hOutput);
+}
+
+// pipex_exit()
+
+void pipex_exit(pipex_t *pipex) {
+    CloseHandle(pipex->hInput);
+    CloseHandle(pipex->hOutput);
+    DWORD lpexit;
+    
+    if(GetExitCodeProcess(pipex->hProcess,&lpexit)){
+        if(lpexit==STILL_ACTIVE)
+                //must be java,hammer it down!
+            TerminateProcess(pipex->hProcess,lpexit);
+    }
+       CloseHandle(pipex->hProcess);
+}
+
+// pipex_eof_input()
+
+static bool pipex_eof_input(pipex_t *pipex){ 
+    int ret;
+    EnterCriticalSection(&(pipex->CriticalSection));
+    ret=(pipex->state)&PIPEX_EOF;
+    LeaveCriticalSection(&(pipex->CriticalSection));
+    return ret;
+}
+
+// pipex_set_eof_input()
+
+static void pipex_set_eof_input(pipex_t *pipex){
+    EnterCriticalSection(&(pipex->CriticalSection));
+    (pipex->state)|=PIPEX_EOF;
+    LeaveCriticalSection(&(pipex->CriticalSection));
+        // not quit the right place
+    my_log("%s->Adapter: EOF\n",pipex->name);
+
+}
+
+// pipex_active()
+
+/*
+ * This function returns TRUE if and only if the pipes have succesfully
+ * been created and the client has been started.
+ *
+ */
+
+bool pipex_active(pipex_t *pipex){
+    int ret;
+    EnterCriticalSection(&(pipex->CriticalSection));
+    ret=(pipex->state)&PIPEX_ACTIVE;
+    LeaveCriticalSection(&(pipex->CriticalSection));
+    return ret;
+}
+
+// pipex_set_active()
+
+static void pipex_set_active(pipex_t *pipex){
+    EnterCriticalSection(&(pipex->CriticalSection));
+    (pipex->state)|=PIPEX_ACTIVE;
+    LeaveCriticalSection(&(pipex->CriticalSection));
+}
+
+// pipex_read_data()
+
+static int pipex_read_data(pipex_t *pipex){
+    DWORD dwBytes;
+    char * ret;
+        // No protection. Access to nReadEnd is atomic.
+        // It is not a problem that nReadEnd becomes smaller after the call.
+        // This just means we have read less than we could have. 
+    ret=fgets(pipex->lpReadBuffer,
+              LINE_INPUT_MAX_CHAR-(pipex->nReadEnd),
+              pipex->fpInput);
+    if(!ret){
+        pipex_set_eof_input(pipex);
+        (pipex->lpReadBuffer)[0]='\0';
+        return 0;
+    }
+    dwBytes=strlen(pipex->lpReadBuffer);
+    (pipex->lpReadBuffer)[dwBytes]='\0';
+    return dwBytes;
+}
+
+// pipex_read_input()
+
+static void pipex_read_input(pipex_t *pipex) {
+  int ret;
+  BOOL bSetEvent=FALSE;
+      // ReadData is outside the critical section otherwise everything
+      // would block during the blocking read
+  ret=pipex_read_data(pipex);
+  EnterCriticalSection(&(pipex->CriticalSection));
+  if(!pipex_eof_input(pipex)){
+      if(ret+(pipex->nReadEnd)>=LINE_INPUT_MAX_CHAR){
+          my_fatal("pipex_read_input(): Internal error: buffer overflow\n");
+      }
+      memcpy((pipex->lpBuffer)+(pipex->nReadEnd),(pipex->lpReadBuffer),ret+1);
+      (pipex->nReadEnd) += ret;
+      if(!(pipex->lpFeedEnd)){
+          (pipex->lpFeedEnd) =
+              (char *) memchr(pipex->lpBuffer,'\n',pipex->nReadEnd);
+      }
+      if(pipex->lpFeedEnd){
+          bSetEvent=TRUE;
+      }else if((pipex->nReadEnd)>=LINE_INPUT_MAX_CHAR-1){
+          my_fatal("pipex_read_input(): LINE_INPUT_MAX_CHAR is equal to %d which is too small to contain a full line of engine output or GUI input.\n",LINE_INPUT_MAX_CHAR);
+      }
+  }
+  LeaveCriticalSection(&(pipex->CriticalSection));
+  if(pipex_eof_input(pipex) || bSetEvent){
+      SetEvent(pipex->hEvent);
+  }
+}
+
+// pipex_eof()
+
+/*
+ * This function returns TRUE if and only if the input buffer does not
+ * contain a full line of data and EOF was encountered by
+ * the working thread.
+ *
+ */
+
+bool pipex_eof(pipex_t *pipex){
+  int ret;
+  EnterCriticalSection(&(pipex->CriticalSection));
+  if((pipex->lpFeedEnd) != NULL){
+    ret=FALSE;
+  }else if(pipex_eof_input(pipex)){
+    ret=TRUE;
+  }else{
+    ret=FALSE;
+  }
+  LeaveCriticalSection(&(pipex->CriticalSection));
+  return ret;
+}
+
+// pipex_readln_nb()
+
+/*
+ * This function returns FALSE if and only if the asynchronously filled
+ * input buffer does not contain a full line of data.
+ * In other words it operates in non-blocking mode.
+ *
+ */
+
+bool pipex_readln_nb(pipex_t *pipex, char *szLineStr) {
+  int nFeedEnd;
+  int ret;
+  EnterCriticalSection(&(pipex->CriticalSection));
+  if ((pipex->lpFeedEnd) == NULL) {
+    ret=FALSE;
+  } else {
+    nFeedEnd = pipex->lpFeedEnd - pipex->lpBuffer;
+    memcpy(szLineStr, pipex->lpBuffer, nFeedEnd+1);
+    szLineStr[nFeedEnd] = '\0';
+        // temp hack: we use the fact that strtok modifies its first argument
+    strtok(szLineStr,"\r\n");
+    ASSERT(strchr(szLineStr,'\n')==NULL)
+    ASSERT(strchr(szLineStr,'\r')==NULL)
+    nFeedEnd ++;
+    pipex->nReadEnd -= nFeedEnd;
+    memcpy(pipex->lpBuffer, pipex->lpBuffer + nFeedEnd, pipex->nReadEnd+1);
+    pipex->lpFeedEnd =
+        (char *) memchr(pipex->lpBuffer, '\n', pipex->nReadEnd);
+    ret=TRUE;
+  }
+  LeaveCriticalSection(&(pipex->CriticalSection));
+  if(ret){
+      my_log("%s->Adapter: %s\n",pipex->name,szLineStr);
+  }
+  return ret;
+}
+
+// pipex_readln()
+
+/*
+ * This function returns FALSE if and only if EOF has been encountered by 
+ * the working thread and no full line of data is present in the input buffer.
+ *
+ * If there is a full line of data present in the input buffer it returns 
+ * TRUE. 
+ *
+ * If none of these conditions is satisfied it blocks.
+ *
+ * As the name say this function is strictly for line input. 
+ * An incomplete line of data (i.e. not ending with \n) is lost when EOF
+ * is encountered.
+ *
+ */
+
+bool pipex_readln(pipex_t *pipex, char *szLineStr) {
+  while(!pipex_eof(pipex)){
+      if (pipex_readln_nb(pipex,szLineStr)) {
+          return TRUE;
+      }else{
+          WaitForSingleObject(pipex->hEvent,INFINITE);
+      }
+  }
+  szLineStr[0]='\0';
+  return FALSE;
+}
+
+//  GetWin32Priority()
+
+static DWORD GetWin32Priority(int nice)
+{
+/*
+REALTIME_PRIORITY_CLASS     0x00000100
+HIGH_PRIORITY_CLASS         0x00000080
+ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
+NORMAL_PRIORITY_CLASS       0x00000020
+BELOW_NORMAL_PRIORITY_CLASS 0x00004000
+IDLE_PRIORITY_CLASS         0x00000040
+*/
+       if (nice < -15) return 0x00000080;
+       if (nice < 0)   return 0x00008000;
+       if (nice == 0)  return 0x00000020;
+       if (nice < 15)  return 0x00004000;
+       return 0x00000040;
+}
+
+// pipex_set_priority()
+
+void pipex_set_priority(pipex_t *pipex, int value){
+    if(pipex->hProcess){
+        if(!SetPriorityClass(pipex->hProcess,
+                             GetWin32Priority(value))){
+            my_log("POLYGLOT Unable to change priority\n");
+        }
+    }
+}
+
+// pipex_set_affinit()
+
+void pipex_set_affinity(pipex_t *pipex, int value){
+    if(pipex->hProcess) return;
+    if(value==-1) return;
+
+    typedef void (WINAPI *SPAM)(HANDLE, int);
+    SPAM pSPAM;
+    pSPAM = (SPAM) GetProcAddress(
+        GetModuleHandle(TEXT("kernel32.dll")), 
+        "SetProcessAffinityMask");
+    if(NULL != pSPAM){
+            // [HGM] avoid crash on Win95 by first checking if API call exists
+        pSPAM(pipex->hProcess,value);
+    }else{
+        my_log("POLYGLOT API call \"SetProcessAffinityMask\" not available\n");
+    }
+}
+
+// pipex_writeln()
+
+void pipex_writeln(pipex_t *pipex, const char *szLineStr) {
+  DWORD dwBytes;
+  int nStrLen;
+  char szWriteBuffer[LINE_INPUT_MAX_CHAR];
+  my_log("Adapter->%s: %s\n",pipex->name,szLineStr);
+  if(pipex->bPipe){
+      nStrLen = strlen(szLineStr);
+      memcpy(szWriteBuffer, szLineStr, nStrLen);
+      szWriteBuffer[nStrLen] = '\r';
+      szWriteBuffer[nStrLen + 1] = '\n';
+      WriteFile(pipex->hOutput, szWriteBuffer, nStrLen + 2, &dwBytes, NULL);
+  }else{
+      printf("%s\n",szLineStr);
+      fflush(stdout);
+  }
+}
+#endif
index 9d2a734..257e04c 100644 (file)
@@ -1,6 +1,6 @@
 Summary: A Winboard protocol to UCI protocol adapter
 Name: polyglot
-Version: 1.4b27
+Version: 1.4.30b
 Release: 1
 License: GPL
 Group: Amusement/Games
diff --git a/random.c b/random.c
new file mode 100644 (file)
index 0000000..b687231
--- /dev/null
+++ b/random.c
@@ -0,0 +1,231 @@
+\r
+// random.c\r
+\r
+// includes\r
+\r
+#include "random.h"\r
+#include "util.h"\r
+\r
+// "constants"\r
+\r
+const uint64 Random64[RandomNb] = {\r
+   U64(0x9D39247E33776D41), U64(0x2AF7398005AAA5C7), U64(0x44DB015024623547), U64(0x9C15F73E62A76AE2),\r
+   U64(0x75834465489C0C89), U64(0x3290AC3A203001BF), U64(0x0FBBAD1F61042279), U64(0xE83A908FF2FB60CA),\r
+   U64(0x0D7E765D58755C10), U64(0x1A083822CEAFE02D), U64(0x9605D5F0E25EC3B0), U64(0xD021FF5CD13A2ED5),\r
+   U64(0x40BDF15D4A672E32), U64(0x011355146FD56395), U64(0x5DB4832046F3D9E5), U64(0x239F8B2D7FF719CC),\r
+   U64(0x05D1A1AE85B49AA1), U64(0x679F848F6E8FC971), U64(0x7449BBFF801FED0B), U64(0x7D11CDB1C3B7ADF0),\r
+   U64(0x82C7709E781EB7CC), U64(0xF3218F1C9510786C), U64(0x331478F3AF51BBE6), U64(0x4BB38DE5E7219443),\r
+   U64(0xAA649C6EBCFD50FC), U64(0x8DBD98A352AFD40B), U64(0x87D2074B81D79217), U64(0x19F3C751D3E92AE1),\r
+   U64(0xB4AB30F062B19ABF), U64(0x7B0500AC42047AC4), U64(0xC9452CA81A09D85D), U64(0x24AA6C514DA27500),\r
+   U64(0x4C9F34427501B447), U64(0x14A68FD73C910841), U64(0xA71B9B83461CBD93), U64(0x03488B95B0F1850F),\r
+   U64(0x637B2B34FF93C040), U64(0x09D1BC9A3DD90A94), U64(0x3575668334A1DD3B), U64(0x735E2B97A4C45A23),\r
+   U64(0x18727070F1BD400B), U64(0x1FCBACD259BF02E7), U64(0xD310A7C2CE9B6555), U64(0xBF983FE0FE5D8244),\r
+   U64(0x9F74D14F7454A824), U64(0x51EBDC4AB9BA3035), U64(0x5C82C505DB9AB0FA), U64(0xFCF7FE8A3430B241),\r
+   U64(0x3253A729B9BA3DDE), U64(0x8C74C368081B3075), U64(0xB9BC6C87167C33E7), U64(0x7EF48F2B83024E20),\r
+   U64(0x11D505D4C351BD7F), U64(0x6568FCA92C76A243), U64(0x4DE0B0F40F32A7B8), U64(0x96D693460CC37E5D),\r
+   U64(0x42E240CB63689F2F), U64(0x6D2BDCDAE2919661), U64(0x42880B0236E4D951), U64(0x5F0F4A5898171BB6),\r
+   U64(0x39F890F579F92F88), U64(0x93C5B5F47356388B), U64(0x63DC359D8D231B78), U64(0xEC16CA8AEA98AD76),\r
+   U64(0x5355F900C2A82DC7), U64(0x07FB9F855A997142), U64(0x5093417AA8A7ED5E), U64(0x7BCBC38DA25A7F3C),\r
+   U64(0x19FC8A768CF4B6D4), U64(0x637A7780DECFC0D9), U64(0x8249A47AEE0E41F7), U64(0x79AD695501E7D1E8),\r
+   U64(0x14ACBAF4777D5776), U64(0xF145B6BECCDEA195), U64(0xDABF2AC8201752FC), U64(0x24C3C94DF9C8D3F6),\r
+   U64(0xBB6E2924F03912EA), U64(0x0CE26C0B95C980D9), U64(0xA49CD132BFBF7CC4), U64(0xE99D662AF4243939),\r
+   U64(0x27E6AD7891165C3F), U64(0x8535F040B9744FF1), U64(0x54B3F4FA5F40D873), U64(0x72B12C32127FED2B),\r
+   U64(0xEE954D3C7B411F47), U64(0x9A85AC909A24EAA1), U64(0x70AC4CD9F04F21F5), U64(0xF9B89D3E99A075C2),\r
+   U64(0x87B3E2B2B5C907B1), U64(0xA366E5B8C54F48B8), U64(0xAE4A9346CC3F7CF2), U64(0x1920C04D47267BBD),\r
+   U64(0x87BF02C6B49E2AE9), U64(0x092237AC237F3859), U64(0xFF07F64EF8ED14D0), U64(0x8DE8DCA9F03CC54E),\r
+   U64(0x9C1633264DB49C89), U64(0xB3F22C3D0B0B38ED), U64(0x390E5FB44D01144B), U64(0x5BFEA5B4712768E9),\r
+   U64(0x1E1032911FA78984), U64(0x9A74ACB964E78CB3), U64(0x4F80F7A035DAFB04), U64(0x6304D09A0B3738C4),\r
+   U64(0x2171E64683023A08), U64(0x5B9B63EB9CEFF80C), U64(0x506AACF489889342), U64(0x1881AFC9A3A701D6),\r
+   U64(0x6503080440750644), U64(0xDFD395339CDBF4A7), U64(0xEF927DBCF00C20F2), U64(0x7B32F7D1E03680EC),\r
+   U64(0xB9FD7620E7316243), U64(0x05A7E8A57DB91B77), U64(0xB5889C6E15630A75), U64(0x4A750A09CE9573F7),\r
+   U64(0xCF464CEC899A2F8A), U64(0xF538639CE705B824), U64(0x3C79A0FF5580EF7F), U64(0xEDE6C87F8477609D),\r
+   U64(0x799E81F05BC93F31), U64(0x86536B8CF3428A8C), U64(0x97D7374C60087B73), U64(0xA246637CFF328532),\r
+   U64(0x043FCAE60CC0EBA0), U64(0x920E449535DD359E), U64(0x70EB093B15B290CC), U64(0x73A1921916591CBD),\r
+   U64(0x56436C9FE1A1AA8D), U64(0xEFAC4B70633B8F81), U64(0xBB215798D45DF7AF), U64(0x45F20042F24F1768),\r
+   U64(0x930F80F4E8EB7462), U64(0xFF6712FFCFD75EA1), U64(0xAE623FD67468AA70), U64(0xDD2C5BC84BC8D8FC),\r
+   U64(0x7EED120D54CF2DD9), U64(0x22FE545401165F1C), U64(0xC91800E98FB99929), U64(0x808BD68E6AC10365),\r
+   U64(0xDEC468145B7605F6), U64(0x1BEDE3A3AEF53302), U64(0x43539603D6C55602), U64(0xAA969B5C691CCB7A),\r
+   U64(0xA87832D392EFEE56), U64(0x65942C7B3C7E11AE), U64(0xDED2D633CAD004F6), U64(0x21F08570F420E565),\r
+   U64(0xB415938D7DA94E3C), U64(0x91B859E59ECB6350), U64(0x10CFF333E0ED804A), U64(0x28AED140BE0BB7DD),\r
+   U64(0xC5CC1D89724FA456), U64(0x5648F680F11A2741), U64(0x2D255069F0B7DAB3), U64(0x9BC5A38EF729ABD4),\r
+   U64(0xEF2F054308F6A2BC), U64(0xAF2042F5CC5C2858), U64(0x480412BAB7F5BE2A), U64(0xAEF3AF4A563DFE43),\r
+   U64(0x19AFE59AE451497F), U64(0x52593803DFF1E840), U64(0xF4F076E65F2CE6F0), U64(0x11379625747D5AF3),\r
+   U64(0xBCE5D2248682C115), U64(0x9DA4243DE836994F), U64(0x066F70B33FE09017), U64(0x4DC4DE189B671A1C),\r
+   U64(0x51039AB7712457C3), U64(0xC07A3F80C31FB4B4), U64(0xB46EE9C5E64A6E7C), U64(0xB3819A42ABE61C87),\r
+   U64(0x21A007933A522A20), U64(0x2DF16F761598AA4F), U64(0x763C4A1371B368FD), U64(0xF793C46702E086A0),\r
+   U64(0xD7288E012AEB8D31), U64(0xDE336A2A4BC1C44B), U64(0x0BF692B38D079F23), U64(0x2C604A7A177326B3),\r
+   U64(0x4850E73E03EB6064), U64(0xCFC447F1E53C8E1B), U64(0xB05CA3F564268D99), U64(0x9AE182C8BC9474E8),\r
+   U64(0xA4FC4BD4FC5558CA), U64(0xE755178D58FC4E76), U64(0x69B97DB1A4C03DFE), U64(0xF9B5B7C4ACC67C96),\r
+   U64(0xFC6A82D64B8655FB), U64(0x9C684CB6C4D24417), U64(0x8EC97D2917456ED0), U64(0x6703DF9D2924E97E),\r
+   U64(0xC547F57E42A7444E), U64(0x78E37644E7CAD29E), U64(0xFE9A44E9362F05FA), U64(0x08BD35CC38336615),\r
+   U64(0x9315E5EB3A129ACE), U64(0x94061B871E04DF75), U64(0xDF1D9F9D784BA010), U64(0x3BBA57B68871B59D),\r
+   U64(0xD2B7ADEEDED1F73F), U64(0xF7A255D83BC373F8), U64(0xD7F4F2448C0CEB81), U64(0xD95BE88CD210FFA7),\r
+   U64(0x336F52F8FF4728E7), U64(0xA74049DAC312AC71), U64(0xA2F61BB6E437FDB5), U64(0x4F2A5CB07F6A35B3),\r
+   U64(0x87D380BDA5BF7859), U64(0x16B9F7E06C453A21), U64(0x7BA2484C8A0FD54E), U64(0xF3A678CAD9A2E38C),\r
+   U64(0x39B0BF7DDE437BA2), U64(0xFCAF55C1BF8A4424), U64(0x18FCF680573FA594), U64(0x4C0563B89F495AC3),\r
+   U64(0x40E087931A00930D), U64(0x8CFFA9412EB642C1), U64(0x68CA39053261169F), U64(0x7A1EE967D27579E2),\r
+   U64(0x9D1D60E5076F5B6F), U64(0x3810E399B6F65BA2), U64(0x32095B6D4AB5F9B1), U64(0x35CAB62109DD038A),\r
+   U64(0xA90B24499FCFAFB1), U64(0x77A225A07CC2C6BD), U64(0x513E5E634C70E331), U64(0x4361C0CA3F692F12),\r
+   U64(0xD941ACA44B20A45B), U64(0x528F7C8602C5807B), U64(0x52AB92BEB9613989), U64(0x9D1DFA2EFC557F73),\r
+   U64(0x722FF175F572C348), U64(0x1D1260A51107FE97), U64(0x7A249A57EC0C9BA2), U64(0x04208FE9E8F7F2D6),\r
+   U64(0x5A110C6058B920A0), U64(0x0CD9A497658A5698), U64(0x56FD23C8F9715A4C), U64(0x284C847B9D887AAE),\r
+   U64(0x04FEABFBBDB619CB), U64(0x742E1E651C60BA83), U64(0x9A9632E65904AD3C), U64(0x881B82A13B51B9E2),\r
+   U64(0x506E6744CD974924), U64(0xB0183DB56FFC6A79), U64(0x0ED9B915C66ED37E), U64(0x5E11E86D5873D484),\r
+   U64(0xF678647E3519AC6E), U64(0x1B85D488D0F20CC5), U64(0xDAB9FE6525D89021), U64(0x0D151D86ADB73615),\r
+   U64(0xA865A54EDCC0F019), U64(0x93C42566AEF98FFB), U64(0x99E7AFEABE000731), U64(0x48CBFF086DDF285A),\r
+   U64(0x7F9B6AF1EBF78BAF), U64(0x58627E1A149BBA21), U64(0x2CD16E2ABD791E33), U64(0xD363EFF5F0977996),\r
+   U64(0x0CE2A38C344A6EED), U64(0x1A804AADB9CFA741), U64(0x907F30421D78C5DE), U64(0x501F65EDB3034D07),\r
+   U64(0x37624AE5A48FA6E9), U64(0x957BAF61700CFF4E), U64(0x3A6C27934E31188A), U64(0xD49503536ABCA345),\r
+   U64(0x088E049589C432E0), U64(0xF943AEE7FEBF21B8), U64(0x6C3B8E3E336139D3), U64(0x364F6FFA464EE52E),\r
+   U64(0xD60F6DCEDC314222), U64(0x56963B0DCA418FC0), U64(0x16F50EDF91E513AF), U64(0xEF1955914B609F93),\r
+   U64(0x565601C0364E3228), U64(0xECB53939887E8175), U64(0xBAC7A9A18531294B), U64(0xB344C470397BBA52),\r
+   U64(0x65D34954DAF3CEBD), U64(0xB4B81B3FA97511E2), U64(0xB422061193D6F6A7), U64(0x071582401C38434D),\r
+   U64(0x7A13F18BBEDC4FF5), U64(0xBC4097B116C524D2), U64(0x59B97885E2F2EA28), U64(0x99170A5DC3115544),\r
+   U64(0x6F423357E7C6A9F9), U64(0x325928EE6E6F8794), U64(0xD0E4366228B03343), U64(0x565C31F7DE89EA27),\r
+   U64(0x30F5611484119414), U64(0xD873DB391292ED4F), U64(0x7BD94E1D8E17DEBC), U64(0xC7D9F16864A76E94),\r
+   U64(0x947AE053EE56E63C), U64(0xC8C93882F9475F5F), U64(0x3A9BF55BA91F81CA), U64(0xD9A11FBB3D9808E4),\r
+   U64(0x0FD22063EDC29FCA), U64(0xB3F256D8ACA0B0B9), U64(0xB03031A8B4516E84), U64(0x35DD37D5871448AF),\r
+   U64(0xE9F6082B05542E4E), U64(0xEBFAFA33D7254B59), U64(0x9255ABB50D532280), U64(0xB9AB4CE57F2D34F3),\r
+   U64(0x693501D628297551), U64(0xC62C58F97DD949BF), U64(0xCD454F8F19C5126A), U64(0xBBE83F4ECC2BDECB),\r
+   U64(0xDC842B7E2819E230), U64(0xBA89142E007503B8), U64(0xA3BC941D0A5061CB), U64(0xE9F6760E32CD8021),\r
+   U64(0x09C7E552BC76492F), U64(0x852F54934DA55CC9), U64(0x8107FCCF064FCF56), U64(0x098954D51FFF6580),\r
+   U64(0x23B70EDB1955C4BF), U64(0xC330DE426430F69D), U64(0x4715ED43E8A45C0A), U64(0xA8D7E4DAB780A08D),\r
+   U64(0x0572B974F03CE0BB), U64(0xB57D2E985E1419C7), U64(0xE8D9ECBE2CF3D73F), U64(0x2FE4B17170E59750),\r
+   U64(0x11317BA87905E790), U64(0x7FBF21EC8A1F45EC), U64(0x1725CABFCB045B00), U64(0x964E915CD5E2B207),\r
+   U64(0x3E2B8BCBF016D66D), U64(0xBE7444E39328A0AC), U64(0xF85B2B4FBCDE44B7), U64(0x49353FEA39BA63B1),\r
+   U64(0x1DD01AAFCD53486A), U64(0x1FCA8A92FD719F85), U64(0xFC7C95D827357AFA), U64(0x18A6A990C8B35EBD),\r
+   U64(0xCCCB7005C6B9C28D), U64(0x3BDBB92C43B17F26), U64(0xAA70B5B4F89695A2), U64(0xE94C39A54A98307F),\r
+   U64(0xB7A0B174CFF6F36E), U64(0xD4DBA84729AF48AD), U64(0x2E18BC1AD9704A68), U64(0x2DE0966DAF2F8B1C),\r
+   U64(0xB9C11D5B1E43A07E), U64(0x64972D68DEE33360), U64(0x94628D38D0C20584), U64(0xDBC0D2B6AB90A559),\r
+   U64(0xD2733C4335C6A72F), U64(0x7E75D99D94A70F4D), U64(0x6CED1983376FA72B), U64(0x97FCAACBF030BC24),\r
+   U64(0x7B77497B32503B12), U64(0x8547EDDFB81CCB94), U64(0x79999CDFF70902CB), U64(0xCFFE1939438E9B24),\r
+   U64(0x829626E3892D95D7), U64(0x92FAE24291F2B3F1), U64(0x63E22C147B9C3403), U64(0xC678B6D860284A1C),\r
+   U64(0x5873888850659AE7), U64(0x0981DCD296A8736D), U64(0x9F65789A6509A440), U64(0x9FF38FED72E9052F),\r
+   U64(0xE479EE5B9930578C), U64(0xE7F28ECD2D49EECD), U64(0x56C074A581EA17FE), U64(0x5544F7D774B14AEF),\r
+   U64(0x7B3F0195FC6F290F), U64(0x12153635B2C0CF57), U64(0x7F5126DBBA5E0CA7), U64(0x7A76956C3EAFB413),\r
+   U64(0x3D5774A11D31AB39), U64(0x8A1B083821F40CB4), U64(0x7B4A38E32537DF62), U64(0x950113646D1D6E03),\r
+   U64(0x4DA8979A0041E8A9), U64(0x3BC36E078F7515D7), U64(0x5D0A12F27AD310D1), U64(0x7F9D1A2E1EBE1327),\r
+   U64(0xDA3A361B1C5157B1), U64(0xDCDD7D20903D0C25), U64(0x36833336D068F707), U64(0xCE68341F79893389),\r
+   U64(0xAB9090168DD05F34), U64(0x43954B3252DC25E5), U64(0xB438C2B67F98E5E9), U64(0x10DCD78E3851A492),\r
+   U64(0xDBC27AB5447822BF), U64(0x9B3CDB65F82CA382), U64(0xB67B7896167B4C84), U64(0xBFCED1B0048EAC50),\r
+   U64(0xA9119B60369FFEBD), U64(0x1FFF7AC80904BF45), U64(0xAC12FB171817EEE7), U64(0xAF08DA9177DDA93D),\r
+   U64(0x1B0CAB936E65C744), U64(0xB559EB1D04E5E932), U64(0xC37B45B3F8D6F2BA), U64(0xC3A9DC228CAAC9E9),\r
+   U64(0xF3B8B6675A6507FF), U64(0x9FC477DE4ED681DA), U64(0x67378D8ECCEF96CB), U64(0x6DD856D94D259236),\r
+   U64(0xA319CE15B0B4DB31), U64(0x073973751F12DD5E), U64(0x8A8E849EB32781A5), U64(0xE1925C71285279F5),\r
+   U64(0x74C04BF1790C0EFE), U64(0x4DDA48153C94938A), U64(0x9D266D6A1CC0542C), U64(0x7440FB816508C4FE),\r
+   U64(0x13328503DF48229F), U64(0xD6BF7BAEE43CAC40), U64(0x4838D65F6EF6748F), U64(0x1E152328F3318DEA),\r
+   U64(0x8F8419A348F296BF), U64(0x72C8834A5957B511), U64(0xD7A023A73260B45C), U64(0x94EBC8ABCFB56DAE),\r
+   U64(0x9FC10D0F989993E0), U64(0xDE68A2355B93CAE6), U64(0xA44CFE79AE538BBE), U64(0x9D1D84FCCE371425),\r
+   U64(0x51D2B1AB2DDFB636), U64(0x2FD7E4B9E72CD38C), U64(0x65CA5B96B7552210), U64(0xDD69A0D8AB3B546D),\r
+   U64(0x604D51B25FBF70E2), U64(0x73AA8A564FB7AC9E), U64(0x1A8C1E992B941148), U64(0xAAC40A2703D9BEA0),\r
+   U64(0x764DBEAE7FA4F3A6), U64(0x1E99B96E70A9BE8B), U64(0x2C5E9DEB57EF4743), U64(0x3A938FEE32D29981),\r
+   U64(0x26E6DB8FFDF5ADFE), U64(0x469356C504EC9F9D), U64(0xC8763C5B08D1908C), U64(0x3F6C6AF859D80055),\r
+   U64(0x7F7CC39420A3A545), U64(0x9BFB227EBDF4C5CE), U64(0x89039D79D6FC5C5C), U64(0x8FE88B57305E2AB6),\r
+   U64(0xA09E8C8C35AB96DE), U64(0xFA7E393983325753), U64(0xD6B6D0ECC617C699), U64(0xDFEA21EA9E7557E3),\r
+   U64(0xB67C1FA481680AF8), U64(0xCA1E3785A9E724E5), U64(0x1CFC8BED0D681639), U64(0xD18D8549D140CAEA),\r
+   U64(0x4ED0FE7E9DC91335), U64(0xE4DBF0634473F5D2), U64(0x1761F93A44D5AEFE), U64(0x53898E4C3910DA55),\r
+   U64(0x734DE8181F6EC39A), U64(0x2680B122BAA28D97), U64(0x298AF231C85BAFAB), U64(0x7983EED3740847D5),\r
+   U64(0x66C1A2A1A60CD889), U64(0x9E17E49642A3E4C1), U64(0xEDB454E7BADC0805), U64(0x50B704CAB602C329),\r
+   U64(0x4CC317FB9CDDD023), U64(0x66B4835D9EAFEA22), U64(0x219B97E26FFC81BD), U64(0x261E4E4C0A333A9D),\r
+   U64(0x1FE2CCA76517DB90), U64(0xD7504DFA8816EDBB), U64(0xB9571FA04DC089C8), U64(0x1DDC0325259B27DE),\r
+   U64(0xCF3F4688801EB9AA), U64(0xF4F5D05C10CAB243), U64(0x38B6525C21A42B0E), U64(0x36F60E2BA4FA6800),\r
+   U64(0xEB3593803173E0CE), U64(0x9C4CD6257C5A3603), U64(0xAF0C317D32ADAA8A), U64(0x258E5A80C7204C4B),\r
+   U64(0x8B889D624D44885D), U64(0xF4D14597E660F855), U64(0xD4347F66EC8941C3), U64(0xE699ED85B0DFB40D),\r
+   U64(0x2472F6207C2D0484), U64(0xC2A1E7B5B459AEB5), U64(0xAB4F6451CC1D45EC), U64(0x63767572AE3D6174),\r
+   U64(0xA59E0BD101731A28), U64(0x116D0016CB948F09), U64(0x2CF9C8CA052F6E9F), U64(0x0B090A7560A968E3),\r
+   U64(0xABEEDDB2DDE06FF1), U64(0x58EFC10B06A2068D), U64(0xC6E57A78FBD986E0), U64(0x2EAB8CA63CE802D7),\r
+   U64(0x14A195640116F336), U64(0x7C0828DD624EC390), U64(0xD74BBE77E6116AC7), U64(0x804456AF10F5FB53),\r
+   U64(0xEBE9EA2ADF4321C7), U64(0x03219A39EE587A30), U64(0x49787FEF17AF9924), U64(0xA1E9300CD8520548),\r
+   U64(0x5B45E522E4B1B4EF), U64(0xB49C3B3995091A36), U64(0xD4490AD526F14431), U64(0x12A8F216AF9418C2),\r
+   U64(0x001F837CC7350524), U64(0x1877B51E57A764D5), U64(0xA2853B80F17F58EE), U64(0x993E1DE72D36D310),\r
+   U64(0xB3598080CE64A656), U64(0x252F59CF0D9F04BB), U64(0xD23C8E176D113600), U64(0x1BDA0492E7E4586E),\r
+   U64(0x21E0BD5026C619BF), U64(0x3B097ADAF088F94E), U64(0x8D14DEDB30BE846E), U64(0xF95CFFA23AF5F6F4),\r
+   U64(0x3871700761B3F743), U64(0xCA672B91E9E4FA16), U64(0x64C8E531BFF53B55), U64(0x241260ED4AD1E87D),\r
+   U64(0x106C09B972D2E822), U64(0x7FBA195410E5CA30), U64(0x7884D9BC6CB569D8), U64(0x0647DFEDCD894A29),\r
+   U64(0x63573FF03E224774), U64(0x4FC8E9560F91B123), U64(0x1DB956E450275779), U64(0xB8D91274B9E9D4FB),\r
+   U64(0xA2EBEE47E2FBFCE1), U64(0xD9F1F30CCD97FB09), U64(0xEFED53D75FD64E6B), U64(0x2E6D02C36017F67F),\r
+   U64(0xA9AA4D20DB084E9B), U64(0xB64BE8D8B25396C1), U64(0x70CB6AF7C2D5BCF0), U64(0x98F076A4F7A2322E),\r
+   U64(0xBF84470805E69B5F), U64(0x94C3251F06F90CF3), U64(0x3E003E616A6591E9), U64(0xB925A6CD0421AFF3),\r
+   U64(0x61BDD1307C66E300), U64(0xBF8D5108E27E0D48), U64(0x240AB57A8B888B20), U64(0xFC87614BAF287E07),\r
+   U64(0xEF02CDD06FFDB432), U64(0xA1082C0466DF6C0A), U64(0x8215E577001332C8), U64(0xD39BB9C3A48DB6CF),\r
+   U64(0x2738259634305C14), U64(0x61CF4F94C97DF93D), U64(0x1B6BACA2AE4E125B), U64(0x758F450C88572E0B),\r
+   U64(0x959F587D507A8359), U64(0xB063E962E045F54D), U64(0x60E8ED72C0DFF5D1), U64(0x7B64978555326F9F),\r
+   U64(0xFD080D236DA814BA), U64(0x8C90FD9B083F4558), U64(0x106F72FE81E2C590), U64(0x7976033A39F7D952),\r
+   U64(0xA4EC0132764CA04B), U64(0x733EA705FAE4FA77), U64(0xB4D8F77BC3E56167), U64(0x9E21F4F903B33FD9),\r
+   U64(0x9D765E419FB69F6D), U64(0xD30C088BA61EA5EF), U64(0x5D94337FBFAF7F5B), U64(0x1A4E4822EB4D7A59),\r
+   U64(0x6FFE73E81B637FB3), U64(0xDDF957BC36D8B9CA), U64(0x64D0E29EEA8838B3), U64(0x08DD9BDFD96B9F63),\r
+   U64(0x087E79E5A57D1D13), U64(0xE328E230E3E2B3FB), U64(0x1C2559E30F0946BE), U64(0x720BF5F26F4D2EAA),\r
+   U64(0xB0774D261CC609DB), U64(0x443F64EC5A371195), U64(0x4112CF68649A260E), U64(0xD813F2FAB7F5C5CA),\r
+   U64(0x660D3257380841EE), U64(0x59AC2C7873F910A3), U64(0xE846963877671A17), U64(0x93B633ABFA3469F8),\r
+   U64(0xC0C0F5A60EF4CDCF), U64(0xCAF21ECD4377B28C), U64(0x57277707199B8175), U64(0x506C11B9D90E8B1D),\r
+   U64(0xD83CC2687A19255F), U64(0x4A29C6465A314CD1), U64(0xED2DF21216235097), U64(0xB5635C95FF7296E2),\r
+   U64(0x22AF003AB672E811), U64(0x52E762596BF68235), U64(0x9AEBA33AC6ECC6B0), U64(0x944F6DE09134DFB6),\r
+   U64(0x6C47BEC883A7DE39), U64(0x6AD047C430A12104), U64(0xA5B1CFDBA0AB4067), U64(0x7C45D833AFF07862),\r
+   U64(0x5092EF950A16DA0B), U64(0x9338E69C052B8E7B), U64(0x455A4B4CFE30E3F5), U64(0x6B02E63195AD0CF8),\r
+   U64(0x6B17B224BAD6BF27), U64(0xD1E0CCD25BB9C169), U64(0xDE0C89A556B9AE70), U64(0x50065E535A213CF6),\r
+   U64(0x9C1169FA2777B874), U64(0x78EDEFD694AF1EED), U64(0x6DC93D9526A50E68), U64(0xEE97F453F06791ED),\r
+   U64(0x32AB0EDB696703D3), U64(0x3A6853C7E70757A7), U64(0x31865CED6120F37D), U64(0x67FEF95D92607890),\r
+   U64(0x1F2B1D1F15F6DC9C), U64(0xB69E38A8965C6B65), U64(0xAA9119FF184CCCF4), U64(0xF43C732873F24C13),\r
+   U64(0xFB4A3D794A9A80D2), U64(0x3550C2321FD6109C), U64(0x371F77E76BB8417E), U64(0x6BFA9AAE5EC05779),\r
+   U64(0xCD04F3FF001A4778), U64(0xE3273522064480CA), U64(0x9F91508BFFCFC14A), U64(0x049A7F41061A9E60),\r
+   U64(0xFCB6BE43A9F2FE9B), U64(0x08DE8A1C7797DA9B), U64(0x8F9887E6078735A1), U64(0xB5B4071DBFC73A66),\r
+   U64(0x230E343DFBA08D33), U64(0x43ED7F5A0FAE657D), U64(0x3A88A0FBBCB05C63), U64(0x21874B8B4D2DBC4F),\r
+   U64(0x1BDEA12E35F6A8C9), U64(0x53C065C6C8E63528), U64(0xE34A1D250E7A8D6B), U64(0xD6B04D3B7651DD7E),\r
+   U64(0x5E90277E7CB39E2D), U64(0x2C046F22062DC67D), U64(0xB10BB459132D0A26), U64(0x3FA9DDFB67E2F199),\r
+   U64(0x0E09B88E1914F7AF), U64(0x10E8B35AF3EEAB37), U64(0x9EEDECA8E272B933), U64(0xD4C718BC4AE8AE5F),\r
+   U64(0x81536D601170FC20), U64(0x91B534F885818A06), U64(0xEC8177F83F900978), U64(0x190E714FADA5156E),\r
+   U64(0xB592BF39B0364963), U64(0x89C350C893AE7DC1), U64(0xAC042E70F8B383F2), U64(0xB49B52E587A1EE60),\r
+   U64(0xFB152FE3FF26DA89), U64(0x3E666E6F69AE2C15), U64(0x3B544EBE544C19F9), U64(0xE805A1E290CF2456),\r
+   U64(0x24B33C9D7ED25117), U64(0xE74733427B72F0C1), U64(0x0A804D18B7097475), U64(0x57E3306D881EDB4F),\r
+   U64(0x4AE7D6A36EB5DBCB), U64(0x2D8D5432157064C8), U64(0xD1E649DE1E7F268B), U64(0x8A328A1CEDFE552C),\r
+   U64(0x07A3AEC79624C7DA), U64(0x84547DDC3E203C94), U64(0x990A98FD5071D263), U64(0x1A4FF12616EEFC89),\r
+   U64(0xF6F7FD1431714200), U64(0x30C05B1BA332F41C), U64(0x8D2636B81555A786), U64(0x46C9FEB55D120902),\r
+   U64(0xCCEC0A73B49C9921), U64(0x4E9D2827355FC492), U64(0x19EBB029435DCB0F), U64(0x4659D2B743848A2C),\r
+   U64(0x963EF2C96B33BE31), U64(0x74F85198B05A2E7D), U64(0x5A0F544DD2B1FB18), U64(0x03727073C2E134B1),\r
+   U64(0xC7F6AA2DE59AEA61), U64(0x352787BAA0D7C22F), U64(0x9853EAB63B5E0B35), U64(0xABBDCDD7ED5C0860),\r
+   U64(0xCF05DAF5AC8D77B0), U64(0x49CAD48CEBF4A71E), U64(0x7A4C10EC2158C4A6), U64(0xD9E92AA246BF719E),\r
+   U64(0x13AE978D09FE5557), U64(0x730499AF921549FF), U64(0x4E4B705B92903BA4), U64(0xFF577222C14F0A3A),\r
+   U64(0x55B6344CF97AAFAE), U64(0xB862225B055B6960), U64(0xCAC09AFBDDD2CDB4), U64(0xDAF8E9829FE96B5F),\r
+   U64(0xB5FDFC5D3132C498), U64(0x310CB380DB6F7503), U64(0xE87FBB46217A360E), U64(0x2102AE466EBB1148),\r
+   U64(0xF8549E1A3AA5E00D), U64(0x07A69AFDCC42261A), U64(0xC4C118BFE78FEAAE), U64(0xF9F4892ED96BD438),\r
+   U64(0x1AF3DBE25D8F45DA), U64(0xF5B4B0B0D2DEEEB4), U64(0x962ACEEFA82E1C84), U64(0x046E3ECAAF453CE9),\r
+   U64(0xF05D129681949A4C), U64(0x964781CE734B3C84), U64(0x9C2ED44081CE5FBD), U64(0x522E23F3925E319E),\r
+   U64(0x177E00F9FC32F791), U64(0x2BC60A63A6F3B3F2), U64(0x222BBFAE61725606), U64(0x486289DDCC3D6780),\r
+   U64(0x7DC7785B8EFDFC80), U64(0x8AF38731C02BA980), U64(0x1FAB64EA29A2DDF7), U64(0xE4D9429322CD065A),\r
+   U64(0x9DA058C67844F20C), U64(0x24C0E332B70019B0), U64(0x233003B5A6CFE6AD), U64(0xD586BD01C5C217F6),\r
+   U64(0x5E5637885F29BC2B), U64(0x7EBA726D8C94094B), U64(0x0A56A5F0BFE39272), U64(0xD79476A84EE20D06),\r
+   U64(0x9E4C1269BAA4BF37), U64(0x17EFEE45B0DEE640), U64(0x1D95B0A5FCF90BC6), U64(0x93CBE0B699C2585D),\r
+   U64(0x65FA4F227A2B6D79), U64(0xD5F9E858292504D5), U64(0xC2B5A03F71471A6F), U64(0x59300222B4561E00),\r
+   U64(0xCE2F8642CA0712DC), U64(0x7CA9723FBB2E8988), U64(0x2785338347F2BA08), U64(0xC61BB3A141E50E8C),\r
+   U64(0x150F361DAB9DEC26), U64(0x9F6A419D382595F4), U64(0x64A53DC924FE7AC9), U64(0x142DE49FFF7A7C3D),\r
+   U64(0x0C335248857FA9E7), U64(0x0A9C32D5EAE45305), U64(0xE6C42178C4BBB92E), U64(0x71F1CE2490D20B07),\r
+   U64(0xF1BCC3D275AFE51A), U64(0xE728E8C83C334074), U64(0x96FBF83A12884624), U64(0x81A1549FD6573DA5),\r
+   U64(0x5FA7867CAF35E149), U64(0x56986E2EF3ED091B), U64(0x917F1DD5F8886C61), U64(0xD20D8C88C8FFE65F),\r
+   U64(0x31D71DCE64B2C310), U64(0xF165B587DF898190), U64(0xA57E6339DD2CF3A0), U64(0x1EF6E6DBB1961EC9),\r
+   U64(0x70CC73D90BC26E24), U64(0xE21A6B35DF0C3AD7), U64(0x003A93D8B2806962), U64(0x1C99DED33CB890A1),\r
+   U64(0xCF3145DE0ADD4289), U64(0xD0E4427A5514FB72), U64(0x77C621CC9FB3A483), U64(0x67A34DAC4356550B),\r
+   U64(0xF8D626AAAF278509),\r
+};\r
+\r
+// functions\r
+\r
+// random_init()\r
+\r
+void random_init() {\r
+\r
+   if ((Random64[RandomNb-1] >> 32) != 0xF8D626AA) { // upper half of the last element of the array\r
+      my_fatal("random_init(): broken 64-bit types\n");\r
+   }\r
+}\r
+\r
+// random_64()\r
+\r
+uint64 random_64(int n) {\r
+\r
+   ASSERT(n>=0&&n<RandomNb);\r
+\r
+   return Random64[n];\r
+}\r
+\r
+// end of random.cpp\r
+\r
index 3e2dcdc..18c6b1c 100644 (file)
--- a/random.h
+++ b/random.h
@@ -8,9 +8,9 @@
 \r
 #include "util.h"\r
 \r
-// constants\r
+// defines\r
 \r
-const int RandomNb = 781;\r
+#define RandomNb  781\r
 \r
 // macros\r
 \r
diff --git a/san.c b/san.c
new file mode 100644 (file)
index 0000000..2756550
--- /dev/null
+++ b/san.c
@@ -0,0 +1,567 @@
+\r
+// san.c\r
+\r
+// includes\r
+\r
+#include <ctype.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "attack.h"\r
+#include "board.h"\r
+#include "list.h"\r
+#include "move.h"\r
+#include "move_gen.h"\r
+#include "move_legal.h"\r
+#include "piece.h"\r
+#include "san.h"\r
+#include "square.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const bool UseSlowDebug = FALSE;\r
+\r
+enum ambiguity_t {\r
+   AMBIGUITY_NONE,\r
+   AMBIGUITY_FILE,\r
+   AMBIGUITY_RANK,\r
+   AMBIGUITY_SQUARE\r
+};\r
+\r
+// functions\r
+\r
+static bool san_to_lan    (const char san[], const board_t * board, char string[], int size);\r
+static int  move_from_lan (const char string[], const board_t * board);\r
+\r
+static int  ambiguity     (int move, const board_t * board);\r
+\r
+// move_to_san()\r
+\r
+bool move_to_san(int move, const board_t * board, char string[], int size) {\r
+\r
+   int from, to, piece;\r
+   char tmp_string[256];\r
+\r
+   ASSERT(move_is_ok(move));\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=8);\r
+\r
+   ASSERT(move_is_legal(move,board));\r
+\r
+   if (size < 8) return FALSE;\r
+\r
+   // init\r
+\r
+   from = move_from(move);\r
+   to = move_to(move);\r
+\r
+   string[0] = '\0';\r
+\r
+   // castle\r
+\r
+   if (move_is_castle(move,board)) {\r
+\r
+      if (to > from) {\r
+         strcat(string,"O-O");\r
+      } else {\r
+         strcat(string,"O-O-O");\r
+      }\r
+\r
+      goto check;\r
+   }\r
+\r
+   // from\r
+\r
+   piece = board->square[from];\r
+\r
+   if (piece_is_pawn(piece)) {\r
+\r
+      // pawn\r
+\r
+      if (move_is_capture(move,board)) {\r
+         sprintf(tmp_string,"%c",file_to_char(square_file(from)));\r
+         strcat(string,tmp_string);\r
+      }\r
+\r
+   } else {\r
+\r
+      // piece\r
+\r
+      sprintf(tmp_string,"%c",toupper(piece_to_char(piece)));\r
+      strcat(string,tmp_string);\r
+\r
+      // ambiguity\r
+\r
+      switch (ambiguity(move,board)) {\r
+      case AMBIGUITY_NONE:\r
+         break;\r
+      case AMBIGUITY_FILE:\r
+         sprintf(tmp_string,"%c",file_to_char(square_file(from)));\r
+         strcat(string,tmp_string);\r
+         break;\r
+      case AMBIGUITY_RANK:\r
+         sprintf(tmp_string,"%c",rank_to_char(square_rank(from)));\r
+         strcat(string,tmp_string);\r
+         break;\r
+      case AMBIGUITY_SQUARE:\r
+         if (!square_to_string(from,tmp_string,256)) return FALSE;\r
+         strcat(string,tmp_string);\r
+         break;\r
+      default:\r
+         ASSERT(FALSE);\r
+         break;\r
+      }\r
+   }\r
+\r
+   // capture\r
+\r
+   if (move_is_capture(move,board)) strcat(string,"x");\r
+\r
+   // to\r
+\r
+   if (!square_to_string(to,tmp_string,256)) return FALSE;\r
+   strcat(string,tmp_string);\r
+\r
+   // promote\r
+\r
+   if (move_is_promote(move)) {\r
+      sprintf(tmp_string,"=%c",toupper(piece_to_char(move_promote(move,board))));\r
+      strcat(string,tmp_string);\r
+   }\r
+\r
+   // check\r
+\r
+check:\r
+\r
+   if (move_is_mate(move,board)) {\r
+      strcat(string,"#");\r
+   } else if (move_is_check(move,board)) {\r
+      strcat(string,"+");\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+// move_from_san()\r
+\r
+int move_from_san(const char string[], const board_t * board) {\r
+\r
+   char s[256];\r
+   int move;\r
+\r
+   ASSERT(string!=NULL);\r
+   ASSERT(board_is_ok(board));\r
+\r
+   san_to_lan(string,board,s,256);\r
+   move = move_from_lan(s,board);\r
+\r
+   ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board));\r
+\r
+   return move;\r
+}\r
+\r
+// move_from_san_debug()\r
+\r
+int move_from_san_debug(const char string[], const board_t * board) {\r
+\r
+   list_t list[1];\r
+   int i, move;\r
+   char move_string[256];\r
+\r
+   ASSERT(string!=NULL);\r
+   ASSERT(board_is_ok(board));\r
+\r
+   gen_legal_moves(list,board);\r
+\r
+   for (i = 0; i < list_size(list); i++) {\r
+      move = list_move(list,i);\r
+      if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE);\r
+      if (my_string_equal(move_string,string)) return move;\r
+   }\r
+\r
+   return MoveNone;\r
+}\r
+\r
+// san_to_lan()\r
+\r
+static bool san_to_lan(const char san[], const board_t * board, char string[], int size) {\r
+\r
+   int len;\r
+   int left, right;\r
+   int c;\r
+   int king, rook;\r
+   char king_string[3], rook_string[3];\r
+\r
+   ASSERT(san!=NULL);\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=8);\r
+\r
+   // init\r
+\r
+   if (size < 8) return FALSE;\r
+   strcpy(string,"???????");\r
+\r
+   len = strlen(san);\r
+\r
+   left = 0;\r
+   right = len;\r
+\r
+   // skip trailing '+' or '#'\r
+\r
+   if (left < right) {\r
+      c = san[right-1];\r
+      if (c == '+' || c == '#') right--;\r
+   }\r
+\r
+   // castling\r
+\r
+   ASSERT(left==0);\r
+\r
+   if (FALSE) {\r
+\r
+   } else if (right == 3 && strncmp(san,"O-O",3) == 0) {\r
+\r
+      if (board->castle[board->turn][SideH] == SquareNone) return FALSE;\r
+\r
+      king = king_pos(board,board->turn);\r
+      rook = board->castle[board->turn][SideH];\r
+\r
+      square_to_string(king,king_string,3);\r
+      square_to_string(rook,rook_string,3);\r
+\r
+      sprintf(string,"K%s?%s?",king_string,rook_string);\r
+\r
+   } else if (right == 5 && strncmp(san,"O-O-O",5) == 0) {\r
+\r
+      if (board->castle[board->turn][SideA] == SquareNone) return FALSE;\r
+\r
+      king = king_pos(board,board->turn);\r
+      rook = board->castle[board->turn][SideA];\r
+\r
+      square_to_string(king,king_string,3);\r
+      square_to_string(rook,rook_string,3);\r
+\r
+      sprintf(string,"K%s?%s?",king_string,rook_string);\r
+\r
+   } else {\r
+\r
+      // moved piece\r
+\r
+      if (left < right) {\r
+\r
+         c = san[left];\r
+\r
+         if (char_is_piece(c)) {\r
+            string[0] = c;\r
+            left++;\r
+         }\r
+      }\r
+\r
+      // promotion\r
+\r
+      if (left < right) {\r
+\r
+         c = toupper(san[right-1]);\r
+\r
+         if (char_is_piece(c)) {\r
+\r
+            string[6] = c;\r
+            right--;\r
+\r
+            // skip '='\r
+\r
+            if (left < right && san[right-1] == '=') right--;\r
+         }\r
+      }\r
+\r
+      // to-square rank\r
+\r
+      if (left < right) {\r
+\r
+         c = san[right-1];\r
+\r
+         if (char_is_rank(c)) {\r
+            string[5] = c;\r
+            right--;\r
+         }\r
+      }\r
+\r
+      // to-square file\r
+\r
+      if (left < right) {\r
+\r
+         c = san[right-1];\r
+\r
+         if (char_is_file(c)) {\r
+            string[4] = c;\r
+            right--;\r
+         }\r
+      }\r
+\r
+      // captured piece\r
+\r
+      if (left < right) {\r
+\r
+         c = san[right-1];\r
+\r
+         if (char_is_piece(c)) {\r
+            string[3] = c;\r
+            right--;\r
+         }\r
+      }\r
+\r
+      // skip middle '-' or 'x'\r
+\r
+      if (left < right) {\r
+         c = san[right-1];\r
+         if (c == '-' || c == 'x') right--;\r
+      }\r
+\r
+      // from-square file\r
+\r
+      if (left < right) {\r
+\r
+         c = san[left];\r
+\r
+         if (char_is_file(c)) {\r
+            string[1] = c;\r
+            left++;\r
+         }\r
+      }\r
+\r
+      // from-square rank\r
+\r
+      if (left < right) {\r
+\r
+         c = san[left];\r
+\r
+         if (char_is_rank(c)) {\r
+            string[2] = c;\r
+            left++;\r
+         }\r
+      }\r
+\r
+      if (left != right) return FALSE;\r
+   }\r
+\r
+   // end\r
+\r
+   return TRUE;\r
+}\r
+\r
+// move_from_lan()\r
+\r
+static int move_from_lan(const char string[], const board_t * board) {\r
+\r
+   int len;\r
+   int move;\r
+   int promote;\r
+   char s[256];\r
+   int from, to;\r
+   int colour;\r
+   int inc;\r
+   int piece_char;\r
+   int n;\r
+   const uint8 * ptr;\r
+   int piece;\r
+   int side;\r
+\r
+   ASSERT(string!=NULL);\r
+   ASSERT(board_is_ok(board));\r
+\r
+   // init\r
+\r
+   len = strlen(string);\r
+   if (len != 7) return MoveNone;\r
+\r
+   move = MoveNone;\r
+   colour = board->turn;\r
+\r
+   // promote\r
+\r
+   promote = 0;\r
+\r
+   switch (string[6]) {\r
+   case '?': // not a promotion\r
+      break;\r
+   case 'N':\r
+      promote = MovePromoteKnight;\r
+      break;\r
+   case 'B':\r
+      promote = MovePromoteBishop;\r
+      break;\r
+   case 'R':\r
+      promote = MovePromoteRook;\r
+      break;\r
+   case 'Q':\r
+      promote = MovePromoteQueen;\r
+      break;\r
+   default:\r
+      return MoveNone;\r
+      break;\r
+   }\r
+\r
+   // to square\r
+\r
+   s[0] = string[4];\r
+   s[1] = string[5];\r
+   s[2] = '\0';\r
+\r
+   to = square_from_string(s);\r
+   if (to == SquareNone) return MoveNone;\r
+\r
+   // known from square?\r
+\r
+   if (string[1] != '?' && string[2] != '?') {\r
+\r
+      // from square\r
+\r
+      s[0] = string[1];\r
+      s[1] = string[2];\r
+      s[2] = '\0';\r
+\r
+      from = square_from_string(s);\r
+      if (from == SquareNone) return MoveNone;\r
+\r
+      // convert "king slide" castling to KxR\r
+\r
+      if (piece_is_king(board->square[from])\r
+       && square_rank(to) == square_rank(from)\r
+       && abs(to-from) > 1) {\r
+         side = (to > from) ? SideH : SideA;\r
+         to = board->castle[colour][side];\r
+         if (to == SquareNone) return MoveNone;\r
+      }\r
+\r
+      // move\r
+\r
+      move = move_make(from,to) | promote;\r
+\r
+      return move;\r
+   }\r
+\r
+   // pawn non-capture?\r
+\r
+   if (string[0] == '?' && string[1] == '?') {\r
+\r
+      if (board->square[to] != Empty) return MoveNone; // useful?\r
+\r
+      inc = (colour_is_white(colour)) ? +16 : -16;\r
+\r
+      from = to - inc;\r
+      if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) {\r
+         from -= inc;\r
+      }\r
+\r
+      if (board->square[from] != piece_make_pawn(colour)) { // useful?\r
+         return MoveNone;\r
+      }\r
+\r
+      // move\r
+\r
+      move = move_make(from,to) | promote;\r
+\r
+      return move;\r
+   }\r
+\r
+   // pawn capture?\r
+\r
+   piece_char = string[0];\r
+\r
+   if (piece_char == '?' && string[1] != '?') {\r
+      piece_char = 'P';\r
+   }\r
+\r
+   // attack loop\r
+\r
+   n = 0;\r
+\r
+   for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) {\r
+\r
+      piece = board->square[from];\r
+\r
+      if (toupper(piece_to_char(piece)) == piece_char) {\r
+         if (piece_attack(board,piece,from,to)) {\r
+            if (TRUE\r
+             && (string[1] == '?' || file_to_char(square_file(from)) == string[1])\r
+             && (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) {\r
+               if (!is_pinned(board,from,to,colour)) {\r
+                  move = move_make(from,to) | promote;\r
+                  n++;\r
+               }\r
+            }\r
+         }\r
+      }\r
+   }\r
+\r
+   if (n != 1) move = MoveNone;\r
+\r
+   return move;\r
+}\r
+\r
+// ambiguity()\r
+\r
+static int ambiguity(int move, const board_t * board) {\r
+\r
+   int from, to, piece;\r
+   list_t list[1];\r
+   int i, n, m;\r
+\r
+   // init\r
+\r
+   from = move_from(move);\r
+   to = move_to(move);\r
+   piece = move_piece(move,board);\r
+\r
+   gen_legal_moves(list,board);\r
+\r
+   // no ambiguity?\r
+\r
+   n = 0;\r
+\r
+   for (i = 0; i < list_size(list); i++) {\r
+      m = list_move(list,i);\r
+      if (move_piece(m,board) == piece && move_to(m) == to) {\r
+         n++;\r
+      }\r
+   }\r
+\r
+   if (n == 1) return AMBIGUITY_NONE;\r
+\r
+   // file ambiguity?\r
+\r
+   n = 0;\r
+\r
+   for (i = 0; i < list_size(list); i++) {\r
+      m = list_move(list,i);\r
+      if (move_piece(m,board) == piece && move_to(m) == to) {\r
+         if (square_file(move_from(m)) == square_file(from)) n++;\r
+      }\r
+   }\r
+\r
+   if (n == 1) return AMBIGUITY_FILE;\r
+\r
+   // rank ambiguity?\r
+\r
+   n = 0;\r
+\r
+   for (i = 0; i < list_size(list); i++) {\r
+      m = list_move(list,i);\r
+      if (move_piece(m,board) == piece && move_to(m) == to) {\r
+         if (square_rank(move_from(m)) == square_rank(from)) n++;\r
+      }\r
+   }\r
+\r
+   if (n == 1) return AMBIGUITY_RANK;\r
+\r
+   // square ambiguity\r
+\r
+   return AMBIGUITY_SQUARE;\r
+}\r
+\r
+// end of san.cpp\r
+\r
diff --git a/search.c b/search.c
new file mode 100644 (file)
index 0000000..524a874
--- /dev/null
+++ b/search.c
@@ -0,0 +1,252 @@
+// search.c\r
+\r
+// includes\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "attack.h"\r
+#include "board.h"\r
+#include "colour.h"\r
+#include "engine.h"\r
+#include "fen.h"\r
+#include "line.h"\r
+#include "list.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_gen.h"\r
+#include "move_legal.h"\r
+#include "option.h"\r
+#include "parse.h"\r
+#include "san.h"\r
+#include "search.h"\r
+#include "uci.h"\r
+#include "util.h"\r
+\r
+// constants\r
+\r
+static const int StringSize = 4096;\r
+\r
+// variables\r
+\r
+static int Depth;\r
+\r
+static int BestMove;\r
+static int BestValue;\r
+static move_t BestPV[LineSize];\r
+\r
+static sint64 NodeNb;\r
+static sint64 LeafNb;\r
+static double Time;\r
+\r
+static int Move;\r
+static int MovePos;\r
+static int MoveNb;\r
+\r
+// prototypes\r
+\r
+static bool depth_is_ok (int depth);\r
+static void perft       (const board_t * board, int depth);\r
+\r
+// functions\r
+\r
+// depth_is_ok()\r
+\r
+static bool depth_is_ok(int depth) {\r
+\r
+   return depth >= 0 && depth < DepthMax;\r
+}\r
+\r
+// search()\r
+\r
+void search(const board_t * board, int depth_max, double time_max) {\r
+\r
+   char string[256];\r
+\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(depth_max>=1&&depth_max<DepthMax);\r
+   ASSERT(time_max>=0.0);\r
+\r
+   // engine\r
+\r
+   Depth = 0;\r
+\r
+   BestMove = MoveNone;\r
+   BestValue = 0;\r
+   line_clear(BestPV);\r
+\r
+   NodeNb = 0;\r
+   LeafNb = 0;\r
+   Time = 0.0;\r
+\r
+   Move = MoveNone;\r
+   MovePos = 0;\r
+   MoveNb = 0;\r
+\r
+   // init\r
+\r
+   uci_send_ucinewgame(Uci);\r
+   uci_send_isready_sync(Uci);\r
+\r
+   // position\r
+\r
+   if (!board_to_fen(board,string,256)) ASSERT(FALSE);\r
+   engine_send(Engine,"position fen %s",string);\r
+\r
+   // search\r
+\r
+   engine_send_queue(Engine,"go");\r
+\r
+   engine_send_queue(Engine," movetime %.0f",time_max*1000.0);\r
+   engine_send_queue(Engine," depth %d",depth_max);\r
+\r
+   engine_send(Engine,""); // newline\r
+\r
+   // wait for feed-back\r
+\r
+   while (!engine_eof(Engine)) {\r
+\r
+      engine_get(Engine,string);\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (match(string,"bestmove * ponder *")) {\r
+\r
+         BestMove = move_from_can(Star[0],board);\r
+         ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board));\r
+\r
+         break;\r
+\r
+      } else if (match(string,"bestmove *")) {\r
+\r
+         BestMove = move_from_can(Star[0],board);\r
+         ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board));\r
+\r
+         break;\r
+      }\r
+   }\r
+\r
+   printf("\n");\r
+}\r
+\r
+// do_perft()\r
+\r
+void do_perft(int argc,char * argv[]){\r
+    const char * fen=NULL;\r
+    int depth=1;\r
+    board_t board[1];\r
+    int i;\r
+    for (i = 1; i < argc; i++) {\r
+        if (FALSE) {\r
+        } else if (my_string_equal(argv[i],"perft")) {\r
+                // skip\r
+        } else if (my_string_equal(argv[i],"-fen")) {\r
+            i++;\r
+            if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n");\r
+            my_string_set(&fen,argv[i]);\r
+        } else if (my_string_equal(argv[i],"-max-depth")){\r
+            i++;\r
+            if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n");\r
+            depth=atoi(argv[i]);\r
+            if(depth<1) my_fatal("do_perft(): illegal depth %d\n",depth);\r
+        } else {\r
+            my_fatal("do_perft(): unknown option \"%s\"\n",argv[i]);\r
+        }\r
+    }\r
+    if(fen==NULL){\r
+        my_string_set(&fen,StartFen);\r
+    }\r
+    board_from_fen(board,fen);\r
+    search_perft(board,depth);\r
+}\r
+\r
+// search_perft()\r
+\r
+void search_perft(const board_t * board, int depth_max) {\r
+\r
+   int depth;\r
+   my_timer_t timer[1];\r
+   double time, speed;\r
+   char node_string[StringSize];\r
+   char leafnode_string[StringSize];\r
+\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(depth_max>=1&&depth_max<DepthMax);\r
+\r
+   // init\r
+\r
+   board_disp(board);\r
+\r
+   // iterative deepening\r
+\r
+   for (depth = 1; depth <= depth_max; depth++) {\r
+\r
+      // init\r
+\r
+      NodeNb = 0;\r
+      LeafNb = 0;\r
+\r
+      my_timer_reset(timer);\r
+\r
+      my_timer_start(timer);\r
+      perft(board,depth);\r
+      my_timer_stop(timer);\r
+\r
+      time = my_timer_elapsed_real(timer);//my_timer_elapsed_cpu(timer);\r
+      speed = (time < 0.01) ? 0.0 : ((double)NodeNb) / time;\r
+\r
+      snprintf(node_string,StringSize,S64_FORMAT,NodeNb);\r
+      snprintf(leafnode_string,StringSize,S64_FORMAT,LeafNb);\r
+\r
+      printf("depth=%2d nodes=%12s leafnodes=%12s time=%7.2fs nps=%8.0f\n",depth,node_string,leafnode_string,time,speed);\r
+   }\r
+\r
+}\r
+\r
+// perft()\r
+\r
+static void perft(const board_t * board, int depth) {\r
+\r
+   int me;\r
+   list_t list[1];\r
+   int i, move;\r
+   board_t new_board[1];\r
+\r
+   ASSERT(board_is_ok(board));\r
+   ASSERT(depth_is_ok(depth));\r
+\r
+   ASSERT(!is_in_check(board,colour_opp(board->turn)));\r
+\r
+   // init\r
+\r
+   NodeNb++;\r
+\r
+   // leaf\r
+\r
+   if (depth == 0) {\r
+      LeafNb++;\r
+      return;\r
+   }\r
+\r
+   // more init\r
+\r
+   me = board->turn;\r
+\r
+   // move loop\r
+\r
+   gen_moves(list,board);\r
+\r
+   for (i = 0; i < list_size(list); i++) {\r
+\r
+      move = list_move(list,i);\r
+\r
+      board_copy(new_board,board);\r
+      move_do(new_board,move);\r
+\r
+      if (!is_in_check(new_board,me)) perft(new_board,depth-1);\r
+   }\r
+}\r
+\r
+// end of search.cpp\r
+\r
index 9e55568..b537297 100644 (file)
--- a/search.h
+++ b/search.h
@@ -8,9 +8,9 @@
 #include "board.h"\r
 #include "util.h"\r
 \r
-// constants\r
+// defines\r
 \r
-const int DepthMax = 63;\r
+#define DepthMax 63\r
 \r
 // functions\r
 \r
diff --git a/square.c b/square.c
new file mode 100644 (file)
index 0000000..f5a0fe9
--- /dev/null
+++ b/square.c
@@ -0,0 +1,246 @@
+\r
+// square.c\r
+\r
+// includes\r
+\r
+#include "colour.h"\r
+#include "square.h"\r
+#include "util.h"\r
+\r
+// "constants"\r
+\r
+static const uint8 SquareFrom64[64] = {\r
+   A1, B1, C1, D1, E1, F1, G1, H1,\r
+   A2, B2, C2, D2, E2, F2, G2, H2,\r
+   A3, B3, C3, D3, E3, F3, G3, H3,\r
+   A4, B4, C4, D4, E4, F4, G4, H4,\r
+   A5, B5, C5, D5, E5, F5, G5, H5,\r
+   A6, B6, C6, D6, E6, F6, G6, H6,\r
+   A7, B7, C7, D7, E7, F7, G7, H7,\r
+   A8, B8, C8, D8, E8, F8, G8, H8,\r
+};\r
+\r
+// variables\r
+\r
+static sint8 SquareTo64[SquareNb];\r
+\r
+// functions\r
+\r
+// square_init()\r
+\r
+void square_init() {\r
+\r
+   int sq;\r
+\r
+   for (sq = 0; sq < SquareNb; sq++) SquareTo64[sq] = -1;\r
+\r
+   for (sq = 0; sq < 64; sq++) {\r
+      SquareTo64[SquareFrom64[sq]] = sq;\r
+   }\r
+}\r
+\r
+// square_is_ok()\r
+\r
+bool square_is_ok(int square) {\r
+\r
+   if (square < 0 || square >= SquareNb) return FALSE;\r
+\r
+   if (SquareTo64[square] < 0) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// square_make()\r
+\r
+int square_make(int file, int rank) {\r
+\r
+   int sq_64;\r
+\r
+   ASSERT(file>=0&&file<8);\r
+   ASSERT(rank>=0&&rank<8);\r
+\r
+   sq_64 = (rank << 3) | file;\r
+\r
+   return square_from_64(sq_64);\r
+}\r
+\r
+// square_file()\r
+\r
+int square_file(int square) {\r
+\r
+   int file;\r
+\r
+   ASSERT(square_is_ok(square));\r
+\r
+   file = (square - 4) & 7;\r
+   ASSERT(file==(square_to_64(square)&7));\r
+\r
+   return file;\r
+}\r
+\r
+// square_rank()\r
+\r
+int square_rank(int square) {\r
+\r
+   int rank;\r
+\r
+   ASSERT(square_is_ok(square));\r
+\r
+   rank = (square >> 4) - 2;\r
+   ASSERT(rank==square_to_64(square)>>3);\r
+\r
+   return rank;\r
+}\r
+\r
+// square_side_rank()\r
+\r
+int square_side_rank(int square, int colour) {\r
+\r
+   int rank;\r
+\r
+   ASSERT(square_is_ok(square));\r
+   ASSERT(colour_is_ok(colour));\r
+\r
+   rank = square_rank(square);\r
+   if (colour_is_black(colour)) rank = 7-rank;\r
+\r
+   return rank;\r
+}\r
+\r
+// square_from_64()\r
+\r
+int square_from_64(int square) {\r
+\r
+   ASSERT(square>=0&&square<64);\r
+\r
+   return SquareFrom64[square];\r
+}\r
+\r
+// square_to_64()\r
+\r
+int square_to_64(int square) {\r
+\r
+   ASSERT(square_is_ok(square));\r
+\r
+   return SquareTo64[square];\r
+}\r
+\r
+// square_is_promote()\r
+\r
+bool square_is_promote(int square) {\r
+\r
+   int rank;\r
+\r
+   ASSERT(square_is_ok(square));\r
+\r
+   rank = square_rank(square);\r
+\r
+   return rank == Rank1 || rank == Rank8;\r
+}\r
+\r
+// square_ep_dual()\r
+\r
+int square_ep_dual(int square) {\r
+\r
+   ASSERT(square_is_ok(square));\r
+   ASSERT(square_rank(square)>=2&&square_rank(square)<=5);\r
+\r
+   return square ^ 16;\r
+}\r
+\r
+// square_colour()\r
+\r
+int square_colour(int square) {\r
+\r
+   ASSERT(square_is_ok(square));\r
+\r
+   return (square ^ (square >> 4)) & 1;\r
+}\r
+\r
+// file_from_char()\r
+\r
+int file_from_char(int c) {\r
+\r
+   ASSERT(c>='a'&&c<='h');\r
+\r
+   return c - 'a';\r
+}\r
+\r
+// rank_from_char()\r
+\r
+int rank_from_char(int c) {\r
+\r
+   ASSERT(c>='1'&&c<='8');\r
+\r
+   return c - '1';\r
+}\r
+\r
+// file_to_char()\r
+\r
+int file_to_char(int file) {\r
+\r
+   ASSERT(file>=0&&file<8);\r
+\r
+   return 'a' + file;\r
+}\r
+\r
+// rank_to_char()\r
+\r
+int rank_to_char(int rank) {\r
+\r
+   ASSERT(rank>=0&&rank<8);\r
+\r
+   return '1' + rank;\r
+}\r
+\r
+// char_is_file()\r
+\r
+bool char_is_file(int c) {\r
+\r
+   return c >= 'a' && c <= 'h';\r
+}\r
+\r
+// char_is_rank()\r
+\r
+bool char_is_rank(int c) {\r
+\r
+   return c >= '1' && c <= '8';\r
+}\r
+\r
+// square_to_string()\r
+\r
+bool square_to_string(int square, char string[], int size) {\r
+\r
+   ASSERT(square_is_ok(square));\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>=3);\r
+\r
+   if (size < 3) return FALSE;\r
+\r
+   string[0] = 'a' + square_file(square);\r
+   string[1] = '1' + square_rank(square);\r
+   string[2] = '\0';\r
+\r
+   return TRUE;\r
+}\r
+\r
+// square_from_string()\r
+\r
+int square_from_string(const char string[]) {\r
+\r
+   int file, rank;\r
+\r
+   ASSERT(string!=NULL);\r
+\r
+   if (string[0] < 'a' || string[0] > 'h') return SquareNone;\r
+   if (string[1] < '1' || string[1] > '8') return SquareNone;\r
+   if (string[2] != '\0') return SquareNone;\r
+\r
+   file = file_from_char(string[0]);\r
+   rank = rank_from_char(string[1]);\r
+\r
+   return square_make(file,rank);\r
+}\r
+\r
+// end of square.cpp\r
+\r
index 60ef4f9..b493597 100644 (file)
--- a/square.h
+++ b/square.h
@@ -8,41 +8,97 @@
 \r
 #include "util.h"\r
 \r
-// constants\r
-\r
-const int SquareNb = 16 * 12;\r
-\r
-const int FileA = 0;\r
-const int FileB = 1;\r
-const int FileC = 2;\r
-const int FileD = 3;\r
-const int FileE = 4;\r
-const int FileF = 5;\r
-const int FileG = 6;\r
-const int FileH = 7;\r
-\r
-const int Rank1 = 0;\r
-const int Rank2 = 1;\r
-const int Rank3 = 2;\r
-const int Rank4 = 3;\r
-const int Rank5 = 4;\r
-const int Rank6 = 5;\r
-const int Rank7 = 6;\r
-const int Rank8 = 7;\r
-\r
-const int SquareNone = 0;\r
-\r
-const int A1=0x24, B1=0x25, C1=0x26, D1=0x27, E1=0x28, F1=0x29, G1=0x2A, H1=0x2B;\r
-const int A2=0x34, B2=0x35, C2=0x36, D2=0x37, E2=0x38, F2=0x39, G2=0x3A, H2=0x3B;\r
-const int A3=0x44, B3=0x45, C3=0x46, D3=0x47, E3=0x48, F3=0x49, G3=0x4A, H3=0x4B;\r
-const int A4=0x54, B4=0x55, C4=0x56, D4=0x57, E4=0x58, F4=0x59, G4=0x5A, H4=0x5B;\r
-const int A5=0x64, B5=0x65, C5=0x66, D5=0x67, E5=0x68, F5=0x69, G5=0x6A, H5=0x6B;\r
-const int A6=0x74, B6=0x75, C6=0x76, D6=0x77, E6=0x78, F6=0x79, G6=0x7A, H6=0x7B;\r
-const int A7=0x84, B7=0x85, C7=0x86, D7=0x87, E7=0x88, F7=0x89, G7=0x8A, H7=0x8B;\r
-const int A8=0x94, B8=0x95, C8=0x96, D8=0x97, E8=0x98, F8=0x99, G8=0x9A, H8=0x9B;\r
-\r
-const int Dark  = 0;\r
-const int Light = 1;\r
+// defines\r
+\r
+#define SquareNb (16 * 12)\r
+\r
+#define FileA 0\r
+#define FileB 1\r
+#define FileC 2\r
+#define FileD 3\r
+#define FileE 4\r
+#define FileF 5\r
+#define FileG 6\r
+#define FileH 7\r
+\r
+#define Rank1 0\r
+#define Rank2 1\r
+#define Rank3 2\r
+#define Rank4 3\r
+#define Rank5 4\r
+#define Rank6 5\r
+#define Rank7 6\r
+#define Rank8 7\r
+\r
+#define SquareNone 0\r
+\r
+#define A1 0x24\r
+#define B1 0x25\r
+#define C1 0x26\r
+#define D1 0x27\r
+#define E1 0x28\r
+#define F1 0x29\r
+#define G1 0x2A\r
+#define H1 0x2B\r
+#define A2 0x34\r
+#define B2 0x35\r
+#define C2 0x36\r
+#define D2 0x37\r
+#define E2 0x38\r
+#define F2 0x39\r
+#define G2 0x3A\r
+#define H2 0x3B\r
+#define A3 0x44\r
+#define B3 0x45\r
+#define C3 0x46\r
+#define D3 0x47\r
+#define E3 0x48\r
+#define F3 0x49\r
+#define G3 0x4A\r
+#define H3 0x4B\r
+#define A4 0x54\r
+#define B4 0x55\r
+#define C4 0x56\r
+#define D4 0x57\r
+#define E4 0x58\r
+#define F4 0x59\r
+#define G4 0x5A\r
+#define H4 0x5B\r
+#define A5 0x64\r
+#define B5 0x65\r
+#define C5 0x66\r
+#define D5 0x67\r
+#define E5 0x68\r
+#define F5 0x69\r
+#define G5 0x6A\r
+#define H5 0x6B\r
+#define A6 0x74\r
+#define B6 0x75\r
+#define C6 0x76\r
+#define D6 0x77\r
+#define E6 0x78\r
+#define F6 0x79\r
+#define G6 0x7A\r
+#define H6 0x7B\r
+#define A7 0x84\r
+#define B7 0x85\r
+#define C7 0x86\r
+#define D7 0x87\r
+#define E7 0x88\r
+#define F7 0x89\r
+#define G7 0x8A\r
+#define H7 0x8B\r
+#define A8 0x94\r
+#define B8 0x95\r
+#define C8 0x96\r
+#define D8 0x97\r
+#define E8 0x98\r
+#define F8 0x99\r
+#define G8 0x9A\r
+#define H8 0x9B\r
+\r
+#define Dark  0\r
+#define Light 1\r
 \r
 // functions\r
 \r
diff --git a/uci.c b/uci.c
new file mode 100644 (file)
index 0000000..21c36e9
--- /dev/null
+++ b/uci.c
@@ -0,0 +1,978 @@
+\r
+// uci.c\r
+\r
+// includes\r
+\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "board.h"\r
+#include "engine.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_legal.h"\r
+#include "option.h"\r
+#include "parse.h"\r
+#include "line.h"\r
+#include "uci.h"\r
+\r
+// constants\r
+\r
+static const bool UseDebug = FALSE;\r
+\r
+static const int StringSize = 4096;\r
+\r
+// variables\r
+\r
+uci_t Uci[1];\r
+\r
+// Hopefully the following confusion is temporary\r
+// Normally we should check for the engine name but this is a hack anyway\r
+// Some of there where provided by Marc Lacrosse\r
+\r
+const char * thread_options[]={\r
+  "number of threads",        // toga\r
+  "number threads",           // Deep Learning Toga\r
+  "threads",                  // glaurung, zappa, cyclone, grapefruit,\r
+                              // Deep Shredder, Deep Junior\r
+  "core threads",             // HIARCS\r
+  "max cpus",                 // rybka\r
+  "cpus",                     // Deep Sjeng, Fruit2.3.5\r
+  "maxthreads",               // Naum \r
+  NULL\r
+};\r
+\r
+// prototypes\r
+\r
+static bool uci_is_ok      (const uci_t * uci);\r
+\r
+static int  parse_bestmove (uci_t * uci, const char string[]);\r
+static void parse_id       (uci_t * uci, const char string[]);\r
+static int  parse_info     (uci_t * uci, const char string[]);\r
+static void parse_option   (uci_t * uci, const char string[]);\r
+static void parse_score    (uci_t * uci, const char string[]);\r
+\r
+static int  mate_score     (int dist);\r
+\r
+// functions\r
+\r
+// uci_set_threads()\r
+\r
+void uci_set_threads(uci_t * uci, int n) {\r
+    const char **thread_options_copy = thread_options;\r
+    const char *thread_option;\r
+    ASSERT(n>=1);\r
+    while((thread_option = *(thread_options_copy++))){\r
+        uci_send_option(uci,thread_option,"%d",n); // checks also for existence\r
+    }\r
+}\r
+\r
+// uci_thread_option_exists()\r
+\r
+bool uci_thread_option_exist(uci_t * uci) {\r
+    const char **thread_options_copy = thread_options;\r
+    const char *thread_option;\r
+    while((thread_option = *(thread_options_copy++))){\r
+        if(uci_option_exist(uci,thread_option)) return TRUE;\r
+    }\r
+    return FALSE;\r
+}\r
+\r
+const char * uci_thread_option(uci_t * uci){\r
+    const char **thread_options_copy = thread_options;\r
+    const char *thread_option;\r
+    int i;\r
+    while((thread_option = *(thread_options_copy++))){\r
+        i=uci_get_option(uci,thread_option);\r
+        if(i>=0){\r
+            return Uci->option[i].name;\r
+            break;\r
+        }\r
+    }\r
+    return NULL;\r
+}\r
+\r
+// uci_is_ok()\r
+\r
+static bool uci_is_ok(const uci_t * uci) {\r
+\r
+   if (uci == NULL) return FALSE;\r
+   if (uci->engine == NULL) return FALSE;\r
+   if (uci->option_nb < 0 || uci->option_nb >= OptionNb) return FALSE;\r
+\r
+   return TRUE;\r
+}\r
+\r
+// uci_open()\r
+\r
+void uci_open(uci_t * uci, engine_t * engine) {\r
+\r
+   char string[StringSize];\r
+   int event;\r
+\r
+   ASSERT(uci!=NULL);\r
+   ASSERT(engine!=NULL);\r
+\r
+   // init\r
+\r
+   uci->engine = engine;\r
+\r
+   uci->name = NULL;\r
+   my_string_set(&uci->name,"<empty>");\r
+   uci->author = NULL;\r
+   my_string_set(&uci->author,"<empty>");\r
+   uci->option_nb = 0;\r
+\r
+   uci->ready_nb = 0;\r
+   uci->searching = 0;\r
+   uci->pending_nb = 0;\r
+   uci->multipv_mode = FALSE;\r
+   board_start(uci->board);\r
+   uci_clear(uci);\r
+\r
+   // send "uci" and wait for "uciok"\r
+\r
+   engine_send(uci->engine,"uci");\r
+\r
+   do {\r
+      engine_get(uci->engine,string);\r
+      event = uci_parse(uci,string);\r
+   } while (!engine_eof(Engine) && (event & EVENT_UCI) == 0);\r
+}\r
+\r
+// uci_close()\r
+\r
+void uci_close(uci_t * uci) {\r
+\r
+   int i;\r
+   option_t * opt;\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+   engine_close(uci->engine);\r
+   uci->engine = NULL;\r
+   my_string_clear(&uci->name);\r
+   my_string_clear(&uci->author);\r
+\r
+   for (i = 0; i < uci->option_nb; i++) {\r
+      opt = &uci->option[i];\r
+      my_string_clear(&opt->name);\r
+      my_string_clear(&opt->default_);\r
+   }\r
+\r
+   uci->option_nb = 0;\r
+}\r
+\r
+// uci_clear()\r
+\r
+void uci_clear(uci_t * uci) {\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+\r
+   ASSERT(!uci->searching);\r
+\r
+   uci->best_move = MoveNone;\r
+   uci->ponder_move = MoveNone;\r
+\r
+   uci->score = 0;\r
+   uci->depth = 0;\r
+   uci->sel_depth = 0;\r
+   line_clear(uci->pv);\r
+\r
+   uci->best_score = 0;\r
+   uci->best_depth = 0;\r
+   uci->best_sel_depth = 0;\r
+   line_clear(uci->best_pv);\r
+\r
+   uci->node_nb = 0;\r
+   uci->time = 0.0;\r
+   uci->speed = 0.0;\r
+   uci->cpu = 0.0;\r
+   uci->hash = 0.0;\r
+   line_clear(uci->current_line);\r
+\r
+   uci->root_move = MoveNone;\r
+   uci->root_move_pos = 0;\r
+   uci->root_move_nb = board_mobility(uci->board);\r
+}\r
+\r
+// uci_send_isready()\r
+\r
+void uci_send_isready(uci_t * uci) {\r
+\r
+   ASSERT(uci!=NULL);\r
+\r
+   engine_send(uci->engine,"isready");\r
+   uci->ready_nb++;\r
+}\r
+\r
+// uci_send_isready_sync()\r
+\r
+void uci_send_isready_sync(uci_t * uci) {\r
+\r
+   char string[StringSize];\r
+   int event;\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+\r
+   // send "isready" and wait for "readyok"\r
+\r
+   uci_send_isready(uci);\r
+\r
+   do {\r
+      engine_get(uci->engine,string);\r
+      event = uci_parse(uci,string);\r
+   } while (!engine_eof(Engine) && (event & EVENT_READY) == 0);\r
+}\r
+\r
+// uci_send_stop()\r
+\r
+void uci_send_stop(uci_t * uci) {\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+\r
+   ASSERT(uci->searching);\r
+   ASSERT(uci->pending_nb>=1);\r
+\r
+   engine_send(Engine,"stop");\r
+   uci->searching = FALSE;\r
+}\r
+\r
+// uci_send_stop_sync()\r
+\r
+void uci_send_stop_sync(uci_t * uci) {\r
+\r
+   char string[StringSize];\r
+   int event;\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+\r
+   ASSERT(uci->searching);\r
+   ASSERT(uci->pending_nb>=1);\r
+\r
+   // send "stop" and wait for "bestmove"\r
+\r
+   uci_send_stop(uci);\r
+\r
+   do {\r
+      engine_get(uci->engine,string);\r
+      event = uci_parse(uci,string);\r
+   } while (!engine_eof(Engine) && (event & EVENT_STOP) == 0);\r
+}\r
+\r
+// uci_send_ucinewgame()\r
+\r
+void uci_send_ucinewgame(uci_t * uci) {\r
+\r
+   ASSERT(uci!=NULL);\r
+\r
+   if (option_get_int("UCIVersion") >= 2) {\r
+      engine_send(uci->engine,"ucinewgame");\r
+   }\r
+}\r
+\r
+// uci_option_exist()\r
+\r
+bool uci_option_exist(uci_t * uci, const char option[]) {\r
+\r
+   int i;\r
+   option_t * opt;\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+   ASSERT(option!=NULL);\r
+\r
+   // scan options\r
+\r
+   for (i = 0; i < uci->option_nb; i++) {\r
+      opt = &uci->option[i];\r
+      if (my_string_case_equal(opt->name,option)) return TRUE;\r
+   }\r
+\r
+   return FALSE;\r
+}\r
+\r
+// uci_send_option()\r
+\r
+void uci_send_option(uci_t * uci, const char option[], const char format[], ...) {\r
+\r
+   va_list arg_list;\r
+   char value[StringSize];\r
+   int i;\r
+   option_t * opt;\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+   ASSERT(option!=NULL);\r
+   ASSERT(format!=NULL);\r
+\r
+   // format\r
+\r
+   va_start(arg_list,format);\r
+   vsprintf(value,format,arg_list);\r
+   va_end(arg_list);\r
+\r
+   if (UseDebug) my_log("POLYGLOT OPTION %s VALUE %s\n",option,value);\r
+\r
+   // scan options\r
+\r
+   for (i = 0; i < uci->option_nb; i++) {\r
+\r
+      opt = &uci->option[i];\r
+\r
+      if (my_string_case_equal(opt->name,option) && !my_string_equal(opt->default_,value)) {\r
+         engine_send(uci->engine,"setoption name %s value %s",opt->name,value);\r
+         my_string_set(&opt->default_,value);\r
+         break;\r
+      }\r
+   }\r
+}\r
+\r
+// uci_parse()\r
+\r
+int uci_parse(uci_t * uci, const char string[]) {\r
+\r
+   int event;\r
+   parse_t parse[1];\r
+   char command[StringSize];\r
+   char argument[StringSize];\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+   ASSERT(string!=NULL);\r
+\r
+   // init\r
+\r
+   event = EVENT_NONE;\r
+\r
+   // parse\r
+\r
+   parse_open(parse,string);\r
+\r
+   if (parse_get_word(parse,command,StringSize)) {\r
+\r
+      parse_get_string(parse,argument,StringSize);\r
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" ARGUMENT \"%s\"\n",command,argument);\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (my_string_equal(command,"bestmove")) {\r
+\r
+         // search end\r
+\r
+         ASSERT(uci->pending_nb>0);\r
+\r
+         if (uci->searching && uci->pending_nb == 1) {\r
+\r
+            // current search\r
+\r
+            uci->searching = FALSE;\r
+            uci->pending_nb--;\r
+\r
+            event = parse_bestmove(uci,argument); // updates uci->best_move and uci->ponder_move\r
+\r
+         } else {\r
+\r
+            // obsolete search\r
+\r
+            if (uci->pending_nb > 0) {\r
+               uci->pending_nb--;\r
+               if (uci->pending_nb == 0) event = EVENT_STOP;\r
+            }\r
+         }\r
+\r
+      } else if (my_string_equal(command,"id")) {\r
+\r
+         parse_id(uci,argument);\r
+\r
+      } else if (my_string_equal(command,"info")) {\r
+\r
+         // search information\r
+\r
+         if (uci->searching && uci->pending_nb == 1) { // current search\r
+            event = parse_info(uci,argument);\r
+         }\r
+\r
+      } else if (my_string_equal(command,"option")) {\r
+\r
+         parse_option(uci,argument);\r
+\r
+      } else if (my_string_equal(command,"readyok")) {\r
+\r
+         // engine is ready\r
+\r
+         ASSERT(uci->ready_nb>0);\r
+\r
+         if (uci->ready_nb > 0) {\r
+            uci->ready_nb--;\r
+            if (uci->ready_nb == 0) event = EVENT_READY;\r
+         }\r
+\r
+      } else if (my_string_equal(command,"uciok")) {\r
+\r
+         event = EVENT_UCI;\r
+\r
+      } else {\r
+\r
+         if (UseDebug) my_log("POLYGLOT unknown command \"%s\"\n",command);\r
+      }\r
+   }\r
+\r
+   parse_close(parse);\r
+\r
+   return event;\r
+}\r
+\r
+// parse_bestmove()\r
+\r
+static int parse_bestmove(uci_t * uci, const char string[]) {\r
+\r
+   parse_t parse[1];\r
+   char command[StringSize];\r
+   char option[StringSize];\r
+   char argument[StringSize];\r
+   board_t board[1];\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+   ASSERT(string!=NULL);\r
+\r
+   // init\r
+\r
+   strcpy(command,"bestmove");\r
+\r
+   parse_open(parse,string);\r
+   parse_add_keyword(parse,"ponder");\r
+\r
+   // bestmove\r
+\r
+   if (!parse_get_string(parse,argument,StringSize)) {\r
+      my_fatal("parse_bestmove(): missing argument\n");\r
+   }\r
+\r
+   uci->best_move = move_from_can(argument,uci->board);\r
+   if (uci->best_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);\r
+\r
+   ASSERT(uci->best_move!=MoveNone);\r
+   ASSERT(move_is_legal(uci->best_move,uci->board));\r
+\r
+   // loop\r
+\r
+   while (parse_get_word(parse,option,StringSize)) {\r
+\r
+      parse_get_string(parse,argument,StringSize);\r
+\r
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (my_string_equal(option,"ponder")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         board_copy(board,uci->board);\r
+         move_do(board,uci->best_move);\r
+\r
+         uci->ponder_move = move_from_can(argument,board);\r
+         // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument);\r
+\r
+         ASSERT(uci->ponder_move!=MoveNone);\r
+         ASSERT(move_is_legal(uci->ponder_move,board));\r
+\r
+      } else {\r
+\r
+         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
+      }\r
+   }\r
+\r
+   parse_close(parse);\r
+\r
+   return EVENT_MOVE;\r
+}\r
+\r
+// parse_id()\r
+\r
+static void parse_id(uci_t * uci, const char string[]) {\r
+\r
+   parse_t parse[1];\r
+   char command[StringSize];\r
+   char option[StringSize];\r
+   char argument[StringSize];\r
+\r
+   ASSERT(uci!=NULL);\r
+   ASSERT(string!=NULL);\r
+\r
+   // init\r
+\r
+   strcpy(command,"id");\r
+\r
+   parse_open(parse,string);\r
+   parse_add_keyword(parse,"author");\r
+   parse_add_keyword(parse,"name");\r
+\r
+   // loop\r
+\r
+   while (parse_get_word(parse,option,StringSize)) {\r
+\r
+      parse_get_string(parse,argument,StringSize);\r
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
+\r
+      if (FALSE) {\r
+      } else if (my_string_equal(option,"author")) {\r
+         ASSERT(!my_string_empty(argument));\r
+         my_string_set(&uci->author,argument);\r
+      } else if (my_string_equal(option,"name")) {\r
+         ASSERT(!my_string_empty(argument));\r
+         my_string_set(&uci->name,argument);\r
+      } else {\r
+         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
+      }\r
+   }\r
+\r
+   parse_close(parse);\r
+\r
+   if (UseDebug) my_log("POLYGLOT engine name \"%s\" author \"%s\"\n",uci->name,uci->author);\r
+}\r
+\r
+// parse_info()\r
+\r
+static int parse_info(uci_t * uci, const char string[]) {\r
+\r
+   int event;\r
+   parse_t parse[1];\r
+   char command[StringSize];\r
+   char option[StringSize];\r
+   char argument[StringSize];\r
+   int n;\r
+   int multipvline=0;\r
+   sint64 ln;\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+   ASSERT(string!=NULL);\r
+\r
+   // init\r
+\r
+   event = EVENT_NONE;\r
+\r
+   strcpy(command,"info");\r
+\r
+   parse_open(parse,string);\r
+   parse_add_keyword(parse,"cpuload");\r
+   parse_add_keyword(parse,"currline");\r
+   parse_add_keyword(parse,"currmove");\r
+   parse_add_keyword(parse,"currmovenumber");\r
+   parse_add_keyword(parse,"depth");\r
+   parse_add_keyword(parse,"hashfull");\r
+   parse_add_keyword(parse,"multipv");\r
+   parse_add_keyword(parse,"nodes");\r
+   parse_add_keyword(parse,"nps");\r
+   parse_add_keyword(parse,"pv");\r
+   parse_add_keyword(parse,"refutation");\r
+   parse_add_keyword(parse,"score");\r
+   parse_add_keyword(parse,"seldepth");\r
+   parse_add_keyword(parse,"string");\r
+   parse_add_keyword(parse,"tbhits");\r
+   parse_add_keyword(parse,"time");\r
+\r
+   // loop\r
+\r
+   while (parse_get_word(parse,option,StringSize)) {\r
+\r
+      parse_get_string(parse,argument,StringSize);\r
+\r
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (my_string_equal(option,"cpuload")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         n = atoi(argument);\r
+         ASSERT(n>=0);\r
+\r
+         if (n >= 0) uci->cpu = ((double)n) / 1000.0;\r
+\r
+      } else if (my_string_equal(option,"currline")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         line_from_can(uci->current_line,uci->board,argument,LineSize);\r
+\r
+      } else if (my_string_equal(option,"currmove")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         uci->root_move = move_from_can(argument,uci->board);\r
+         ASSERT(uci->root_move!=MoveNone);\r
+\r
+      } else if (my_string_equal(option,"currmovenumber")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         n = atoi(argument);\r
+         ASSERT(n>=1&&n<=uci->root_move_nb);\r
+\r
+         if (n >= 1 && n <= uci->root_move_nb) {\r
+            uci->root_move_pos = n - 1;\r
+            ASSERT(uci->root_move_pos>=0&&uci->root_move_pos<uci->root_move_nb);\r
+         }\r
+\r
+      } else if (my_string_equal(option,"depth")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         n = atoi(argument);\r
+         ASSERT(n>=1);\r
+\r
+         if (n >= 0) {\r
+            if (n > uci->depth) event |= EVENT_DEPTH;\r
+            uci->depth = n;\r
+         }\r
+\r
+      } else if (my_string_equal(option,"hashfull")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         n = atoi(argument);\r
+         ASSERT(n>=0);\r
+\r
+         if (n >= 0) uci->hash = ((double)n) / 1000.0;\r
+\r
+      } else if (my_string_equal(option,"multipv")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         n = atoi(argument);\r
+                if(Uci->multipv_mode) multipvline=n;\r
+        \r
+         ASSERT(n>=1);\r
+\r
+      } else if (my_string_equal(option,"nodes")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         ln = my_atoll(argument);\r
+         ASSERT(ln>=0);\r
+\r
+         if (ln >= 0) uci->node_nb = ln;\r
+\r
+      } else if (my_string_equal(option,"nps")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         n = atoi(argument);\r
+         ASSERT(n>=0);\r
+\r
+         if (n >= 0) uci->speed = ((double)n);\r
+\r
+      } else if (my_string_equal(option,"pv")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         line_from_can(uci->pv,uci->board,argument,LineSize);\r
+         event |= EVENT_PV;\r
+\r
+      } else if (my_string_equal(option,"refutation")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         line_from_can(uci->pv,uci->board,argument,LineSize);\r
+\r
+      } else if (my_string_equal(option,"score")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         parse_score(uci,argument);\r
+\r
+      } else if (my_string_equal(option,"seldepth")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         n = atoi(argument);\r
+         ASSERT(n>=0);\r
+\r
+         if (n >= 0) uci->sel_depth = n;\r
+\r
+      } else if (my_string_equal(option,"string")) {\r
+                 if(!strncmp(argument,"DrawOffer",9))\r
+                         event |= EVENT_DRAW;\r
+                 if(!strncmp(argument,"Resign",6))\r
+                         event |= EVENT_RESIGN;\r
+\r
+         // TODO: argument to EOS\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+      } else if (my_string_equal(option,"tbhits")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         ln = my_atoll(argument);\r
+         ASSERT(ln>=0);\r
+\r
+      } else if (my_string_equal(option,"time")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         n = atoi(argument);\r
+         ASSERT(n>=0);\r
+\r
+         if (n >= 0) uci->time = ((double)n) / 1000.0;\r
+\r
+      } else {\r
+\r
+         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
+      }\r
+   }\r
+\r
+   parse_close(parse);\r
+\r
+   // update display\r
+   //lousy uci,filter out lower depth multipv lines that have been repeated from the engine \r
+   if(multipvline>1 && uci->depth<uci->best_depth) event &= ~EVENT_PV;\r
+   if ((event & EVENT_PV) != 0) {\r
+      uci->best_score = uci->score; \r
+         uci->best_depth = uci->depth;\r
+         if(multipvline==1)uci->depth=-1; //HACK ,clears the engine outpout window,see send_pv in adapter.cpp \r
+      uci->best_sel_depth = uci->sel_depth;\r
+      line_copy(uci->best_pv,uci->pv);\r
+   }\r
+   return event;\r
+}\r
+\r
+int uci_get_option(uci_t * uci, const char * name){\r
+    int i;\r
+    for(i=0;i<Uci->option_nb;i++){\r
+        if(my_string_case_equal(Uci->option[i].name,name)){\r
+            return i;\r
+        }\r
+    }\r
+    return -1;\r
+}\r
+\r
+\r
+\r
+// uci_set_option()\r
+\r
+void uci_set_option(uci_t * uci,\r
+                    const char * name,\r
+                    const char * default_,\r
+                    const char * type,\r
+                    const char * max,\r
+                    const char * min,\r
+                    int var_nb,\r
+                    const char * var[]){\r
+    int i,j;\r
+    for(i=0;i<Uci->option_nb;i++){\r
+        if(my_string_equal(Uci->option[i].name,name)){\r
+            break;\r
+       }\r
+   }\r
+   if(i<OptionNb){\r
+       my_string_set(&(Uci->option[i].name),name);\r
+       my_string_set(&(Uci->option[i].default_),default_);\r
+       my_string_set(&(Uci->option[i].type),type);\r
+       my_string_set(&(Uci->option[i].min),min);\r
+       my_string_set(&(Uci->option[i].max),max);\r
+       Uci->option[i].var_nb=var_nb;\r
+       for(j=0;j<var_nb;j++){\r
+           my_string_set(&(Uci->option[i].var[j]),var[j]);\r
+       }\r
+       if(i==Uci->option_nb){\r
+           Uci->option_nb++;\r
+       }\r
+   }\r
+}\r
+\r
+// parse_option()\r
+\r
+static void parse_option(uci_t * uci, const char string[]) {\r
+\r
+   option_t * opt;\r
+   parse_t parse[1];\r
+   char command[StringSize];\r
+   char option[StringSize];\r
+   char argument[StringSize];\r
+\r
+   ASSERT(uci!=NULL);\r
+   ASSERT(string!=NULL);\r
+\r
+   // init\r
+\r
+   strcpy(command,"option");\r
+\r
+   if (uci->option_nb >= OptionNb) return;\r
+\r
+   opt = &uci->option[uci->option_nb];\r
+   uci->option_nb++;\r
+\r
+   opt->value=NULL;\r
+   my_string_set(&opt->value,"<empty>");\r
+   opt->mode=0;\r
+\r
+   opt->name = NULL;\r
+   my_string_set(&opt->name,"<empty>");\r
+\r
+   \r
+   opt->default_ = NULL;\r
+   my_string_set(&opt->default_,"<empty>");\r
+\r
+   opt->max = NULL;\r
+   my_string_set(&opt->max,"<empty>");\r
+\r
+   opt->min = NULL;\r
+   my_string_set(&opt->min,"<empty>");\r
+\r
+   opt->type = NULL;\r
+   my_string_set(&opt->type,"<empty>");\r
+\r
+   opt->var_nb=0;\r
+   \r
+   parse_open(parse,string);\r
+   parse_add_keyword(parse,"default");\r
+   parse_add_keyword(parse,"max");\r
+   parse_add_keyword(parse,"min");\r
+   parse_add_keyword(parse,"name");\r
+   parse_add_keyword(parse,"type");\r
+   parse_add_keyword(parse,"var");\r
+\r
+   // loop\r
+\r
+   while (parse_get_word(parse,option,StringSize)) {\r
+      parse_get_string(parse,argument,StringSize);\r
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (my_string_equal(option,"default")) {\r
+\r
+         // ASSERT(!my_string_empty(argument)); // HACK for Pepito\r
+\r
+         if (!my_string_empty(argument)) {\r
+            my_string_set(&opt->default_,argument);\r
+            my_string_set(&opt->value,argument);\r
+         }\r
+\r
+      } else if (my_string_equal(option,"max")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+         my_string_set(&opt->max,argument);\r
+\r
+      } else if (my_string_equal(option,"min")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+         my_string_set(&opt->min,argument);\r
+\r
+      } else if (my_string_equal(option,"name")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         if (!my_string_empty(argument)) {\r
+            my_string_set(&opt->name,argument);\r
+         }\r
+\r
+      } else if (my_string_equal(option,"type")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+         my_string_set(&opt->type,argument);\r
+\r
+      } else if (my_string_equal(option,"var")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+         my_string_set(&opt->var[opt->var_nb++],argument);\r
+         if(opt->var_nb==VarNb) break;\r
+\r
+      } else {\r
+\r
+         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
+      }\r
+   }\r
+\r
+   parse_close(parse);\r
+\r
+   if (UseDebug) my_log("POLYGLOT option name \"%s\" default \"%s\"\n",opt->name,opt->default_);\r
+}\r
+\r
+// parse_score()\r
+\r
+static void parse_score(uci_t * uci, const char string[]) {\r
+\r
+   parse_t parse[1];\r
+   char command[StringSize];\r
+   char option[StringSize];\r
+   char argument[StringSize];\r
+   int n;\r
+\r
+   ASSERT(uci_is_ok(uci));\r
+   ASSERT(string!=NULL);\r
+\r
+   // init\r
+\r
+   strcpy(command,"score");\r
+\r
+   parse_open(parse,string);\r
+   parse_add_keyword(parse,"cp");\r
+   parse_add_keyword(parse,"lowerbound");\r
+   parse_add_keyword(parse,"mate");\r
+   parse_add_keyword(parse,"upperbound");\r
+\r
+   // loop\r
+\r
+   while (parse_get_word(parse,option,StringSize)) {\r
+\r
+      parse_get_string(parse,argument,StringSize);\r
+\r
+      if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument);\r
+\r
+      if (FALSE) {\r
+\r
+      } else if (my_string_equal(option,"cp")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         n = atoi(argument);\r
+\r
+         uci->score = n;\r
+\r
+      } else if (my_string_equal(option,"lowerbound")) {\r
+\r
+         ASSERT(my_string_empty(argument));\r
+\r
+      } else if (my_string_equal(option,"mate")) {\r
+\r
+         ASSERT(!my_string_empty(argument));\r
+\r
+         n = atoi(argument);\r
+         ASSERT(n!=0);\r
+\r
+         uci->score = mate_score(n);\r
+\r
+      } else if (my_string_equal(option,"upperbound")) {\r
+\r
+         ASSERT(my_string_empty(argument));\r
+\r
+      } else {\r
+\r
+         my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command);\r
+      }\r
+   }\r
+\r
+   parse_close(parse);\r
+}\r
+\r
+// mate_score()\r
+\r
+static int mate_score(int dist) {\r
+\r
+   ASSERT(dist!=0);\r
+\r
+   if (FALSE) {\r
+   } else if (dist > 0) {\r
+      return +option_get_int("MateScore") - (+dist) * 2 + 1;\r
+   } else if (dist < 0) {\r
+      return -option_get_int("MateScore") + (-dist) * 2;\r
+   }\r
+\r
+   return 0;\r
+}\r
+\r
+// end of uci.cpp\r
+\r
diff --git a/uci.h b/uci.h
index 5d28aa5..0ac4f30 100644 (file)
--- a/uci.h
+++ b/uci.h
 #include "option.h"\r
 #include "util.h"\r
 \r
-// constants\r
+// defines\r
 \r
-const int OptionNb = 256;\r
+#define OptionNb 256\r
 \r
-struct uci_t {\r
+// types\r
+\r
+typedef struct {\r
 \r
    engine_t * engine;\r
 \r
@@ -59,9 +61,9 @@ struct uci_t {
    int root_move_pos;\r
    int root_move_nb;\r
    bool multipv_mode;\r
-};\r
+} uci_t;\r
 \r
-enum dummy_event_t {\r
+typedef enum {\r
    EVENT_NONE  = 0,\r
    EVENT_UCI   = 1 << 0,\r
    EVENT_READY = 1 << 1,\r
@@ -71,7 +73,7 @@ enum dummy_event_t {
    EVENT_DEPTH = 1 << 5,\r
    EVENT_DRAW  = 1 << 6,\r
    EVENT_RESIGN= 1 << 7\r
-};\r
+} dummy_event_t;\r
 \r
 // variables\r
 \r
diff --git a/uci2uci.c b/uci2uci.c
new file mode 100644 (file)
index 0000000..611697a
--- /dev/null
+++ b/uci2uci.c
@@ -0,0 +1,247 @@
+// uci2uci.c
+
+// includes
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "board.h"
+#include "engine.h"
+#include "fen.h"
+#include "gui.h"
+#include "move.h"
+#include "move_do.h"
+#include "move_legal.h"
+#include "parse.h"
+#include "option.h"
+#include "book.h"
+#include "main.h"
+#include "uci.h"
+
+// defines
+
+#define StringSize 4096
+
+// variables 
+
+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[]) {
+
+/* This is borrowed from Toga II. This code is quite hacky and will be
+   rewritten using the routines in parse.cpp.
+*/
+                                                   
+   const char * fen;
+   char * moves;
+   const char * ptr;
+   char move_string[256];
+   int move;
+   char * string_copy;
+
+   // init
+
+   string_copy=my_strdup(string);
+   
+   fen = strstr(string_copy,"fen ");
+   moves = strstr(string_copy,"moves ");
+
+   // start position
+
+   if (fen != NULL) { // "fen" present
+
+      if (moves != NULL) { // "moves" present
+         ASSERT(moves>fen);
+         moves[-1] = '\0'; // dirty, but so is UCI
+      }
+
+      board_from_fen(UCIboard,fen+4); // CHANGE ME
+
+   } else {
+
+      // HACK: assumes startpos
+
+      board_from_fen(UCIboard,StartFen);
+   }
+
+   // moves
+
+   if (moves != NULL) { // "moves" present
+
+      ptr = moves + 6;
+
+      while (*ptr != '\0') {
+
+         while (*ptr == ' ') ptr++;
+
+         move_string[0] = *ptr++;
+         move_string[1] = *ptr++;
+         move_string[2] = *ptr++;
+         move_string[3] = *ptr++;
+
+         if (*ptr == '\0' || *ptr == ' ') {
+            move_string[4] = '\0';
+         } else { // promote
+            move_string[4] = *ptr++;
+            move_string[5] = '\0';
+         }
+         move = move_from_can(move_string,UCIboard);
+
+         move_do(UCIboard,move);
+
+      }
+   }
+   free(string_copy);
+}
+
+
+// send_book_move()
+
+static void send_book_move(int move){
+    char move_string[256];
+    my_log("POLYGLOT *BOOK MOVE*\n");
+    move_to_can(move,UCIboard,move_string,256);
+        // bogus info lines
+    gui_send(GUI,"info depth 1 time 0 nodes 0 nps 0 cpuload 0");
+    gui_send(GUI,"bestmove %s",move_string);
+}
+
+// format_uci_option_line()
+
+static void format_uci_option_line(char * option_line,option_t *opt){
+    char option_string[StringSize];
+    int j;
+    strcpy(option_line,"");
+    strcat(option_line,"option name");
+    if(opt->mode&PG){
+        strcat(option_line," Polyglot");
+    }
+    sprintf(option_string," %s",opt->name);
+    strcat(option_line,option_string);
+    sprintf(option_string," type %s",opt->type);
+    strcat(option_line,option_string);
+    if(strcmp(opt->type,"button")){
+        sprintf(option_string," default %s",opt->default_);
+        strcat(option_line,option_string);
+    }
+    if(!strcmp(opt->type,"spin")){
+        sprintf(option_string," min %s",opt->min);
+        strcat(option_line,option_string);
+    }
+    if(!strcmp(opt->type,"spin")){
+        sprintf(option_string," max %s",opt->max);
+        strcat(option_line,option_string);
+    }
+    for(j=0;j<opt->var_nb;j++){
+        sprintf(option_string," var %s",opt->var[j]);
+        strcat(option_line,option_string);
+    }
+}
+
+// send_uci_options()
+
+static void send_uci_options() {
+    int i;
+    option_t *p=Option;
+    char option_line[StringSize]="";
+    gui_send(GUI,"id name %s", Uci->name);
+    gui_send(GUI,"id author %s", Uci->author);
+    for(i=0;i<Uci->option_nb;i++){
+        format_uci_option_line(option_line,Uci->option+i);
+         gui_send(GUI,"%s",option_line);
+    }
+    while(p->name){
+        if(p->mode &UCI){
+            format_uci_option_line(option_line,p);
+            gui_send(GUI,"%s",option_line);
+        }
+        p++;
+    }   
+    gui_send(GUI,"uciok");
+}
+
+// parse_setoption()
+
+
+
+static void parse_setoption(const char string[]) {
+    char *name;
+    char *pg_name;
+    char *value;
+    char * string_copy;
+    string_copy=my_strdup(string);
+    if(match(string_copy,"setoption name * value *")){
+        name=Star[0];
+        value=Star[1];
+        if(match(name, "Polyglot *")){
+            pg_name=Star[0];
+            polyglot_set_option(pg_name,value);
+        }else{
+            engine_send(Engine,"%s",string);
+        }
+    }else{
+        engine_send(Engine,"%s",string);
+    }
+    free(string_copy);
+}
+
+
+// uci2uci_gui_step()
+
+void uci2uci_gui_step(char string[]) {
+    int move;
+     if(FALSE){
+     }else if(match(string,"uci")){
+         send_uci_options();
+         return;
+     }else if(match(string,"setoption *")){
+         parse_setoption(string);
+         return;
+     }else if(match(string,"position *")){
+         parse_position(string);
+         Init=FALSE;
+     }else if(match(string,"go *")){
+         if(Init){
+             board_from_fen(UCIboard,StartFen);
+             Init=FALSE;
+         }
+         SavedMove=MoveNone;
+         if(!strstr(string,"infinite")){
+             move=book_move(UCIboard,option_get_bool("BookRandom"));
+             if (move != MoveNone && move_is_legal(move,UCIboard)) {
+                 if(strstr(string,"ponder")){
+                     SavedMove=move;
+                     return;
+                 }else{
+                     send_book_move(move);
+                     return;
+                 }
+             }
+         }
+     }else if(match(string,"ponderhit") || match(string,"stop")){
+         if(SavedMove!=MoveNone){
+               send_book_move(SavedMove);
+               SavedMove=MoveNone;
+               return;
+         }
+     }else if(match(string,"quit")){
+         my_log("POLYGLOT *** \"quit\" from GUI ***\n");
+         quit();
+     }
+     engine_send(Engine,"%s",string);
+}
+
+void uci2uci_engine_step(char string[]) {
+    gui_send(GUI,string);
+}
+
+// end of uci2uci.cpp
diff --git a/util.c b/util.c
new file mode 100644 (file)
index 0000000..8551aca
--- /dev/null
+++ b/util.c
@@ -0,0 +1,412 @@
+\r
+// util.c\r
+\r
+// includes\r
+\r
+#ifdef _WIN32\r
+#include <windows.h>\r
+#include <direct.h>\r
+#else\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <ctype.h>\r
+#include <errno.h>\r
+#include <math.h>\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <time.h>\r
+#include <sys/time.h>\r
+\r
+#include "main.h"\r
+#include "util.h"\r
+\r
+// variables\r
+\r
+static bool Error;\r
+\r
+FILE * LogFile=NULL;\r
+\r
+\r
+// functions\r
+\r
+// util_init()\r
+\r
+void util_init() {\r
+\r
+   Error = FALSE;\r
+\r
+   // init log file\r
+\r
+   LogFile = NULL;\r
+\r
+   // switch file buffering off\r
+\r
+   setbuf(stdin,NULL);\r
+   setbuf(stdout,NULL);\r
+}\r
+\r
+// my_random_init()\r
+\r
+void my_random_init() {\r
+   srand(time(NULL));\r
+}\r
+\r
+// my_random_int()\r
+\r
+int my_random_int(int n) {\r
+\r
+   int r;\r
+\r
+   ASSERT(n>0);\r
+\r
+   r = ((int)floor(my_random_double()*((double)n)));\r
+   ASSERT(r>=0&&r<n);\r
+\r
+   return r;\r
+}\r
+\r
+// my_random_double()\r
+\r
+double my_random_double() {\r
+\r
+   double r;\r
+\r
+   r = ((double)rand()) / (((double)RAND_MAX) + 1.0);\r
+   ASSERT(r>=0.0&&r<1.0);\r
+\r
+   return r;\r
+}\r
+\r
+// my_atoll()\r
+\r
+sint64 my_atoll(const char string[]) {\r
+\r
+   sint64 n;\r
+\r
+   sscanf(string,S64_FORMAT,&n);\r
+\r
+   return n;\r
+}\r
+\r
+// my_round()\r
+\r
+int my_round(double x) {\r
+\r
+    return ((int)floor(x+0.5));\r
+}\r
+\r
+// my_malloc()\r
+\r
+void * my_malloc(size_t size) {\r
+\r
+   void * address;\r
+\r
+   ASSERT(size>0);\r
+\r
+   address = malloc(size);\r
+   if (address == NULL) my_fatal("my_malloc(): malloc(): %s\n",strerror(errno));\r
+\r
+   return address;\r
+}\r
+\r
+// my_realloc()\r
+\r
+void * my_realloc(void * address, size_t size) {\r
+\r
+   ASSERT(address!=NULL);\r
+   ASSERT(size>0);\r
+\r
+   address = realloc(address,size);\r
+   if (address == NULL) my_fatal("my_realloc(): realloc(): %s\n",strerror(errno));\r
+\r
+   return address;\r
+}\r
+\r
+// my_free()\r
+\r
+void my_free(void * address) {\r
+\r
+   ASSERT(address!=NULL);\r
+\r
+   free(address);\r
+}\r
+\r
+// my_log_open()\r
+\r
+void my_log_open(const char file_name[]) {\r
+\r
+   ASSERT(file_name!=NULL);\r
+\r
+   LogFile = fopen(file_name,"a");\r
+#ifndef _WIN32\r
+//line buffering doesn't work too well in MSVC and/or windows \r
+   if (LogFile != NULL) setvbuf(LogFile,NULL,_IOLBF,0); // line buffering\r
+#endif\r
+}\r
+\r
+// my_log_close()\r
+\r
+void my_log_close() {\r
+\r
+   if (LogFile != NULL) fclose(LogFile);\r
+   LogFile=NULL;\r
+}\r
+\r
+// my_log()\r
+\r
+void my_log(const char format[], ...) {\r
+\r
+   va_list ap;\r
+\r
+   ASSERT(format!=NULL);\r
+\r
+   if (LogFile != NULL) {\r
+      fprintf(LogFile,"%.3f ",now_real());\r
+      va_start(ap,format);\r
+\r
+      vfprintf(LogFile,format,ap);\r
+      va_end(ap);\r
+#ifdef _WIN32\r
+      fflush(LogFile);\r
+#endif\r
+   }\r
+}\r
+\r
+// my_fatal()\r
+\r
+void my_fatal(const char format[], ...) {\r
+\r
+   va_list ap;\r
+\r
+   ASSERT(format!=NULL);\r
+\r
+   va_start(ap,format);\r
+\r
+   vfprintf(stderr,format,ap);\r
+   if (LogFile != NULL) vfprintf(LogFile,format,ap);\r
+\r
+   va_end(ap);\r
+   if (Error) { // recursive error\r
+      my_log("POLYGLOT *** RECURSIVE ERROR ***\n");\r
+      exit(EXIT_FAILURE);\r
+      // abort();\r
+   } else {\r
+      Error = TRUE;\r
+      quit();\r
+   }\r
+}\r
+\r
+// my_file_read_line()\r
+\r
+bool my_file_read_line(FILE * file, char string[], int size) {\r
+\r
+   int src, dst;\r
+   int c;\r
+\r
+   ASSERT(file!=NULL);\r
+   ASSERT(string!=NULL);\r
+   ASSERT(size>0);\r
+\r
+   if (fgets(string,size,file) == NULL) {\r
+      if (feof(file)) {\r
+         return FALSE;\r
+      } else { // error\r
+         my_fatal("my_file_read_line(): fgets(): %s\n",strerror(errno));\r
+      }\r
+   }\r
+\r
+   // remove CRs and LFs\r
+\r
+   src = 0;\r
+   dst = 0;\r
+   \r
+   while ((c=string[src++]) != '\0') {\r
+      if (c != '\r' && c != '\n') string[dst++] = c;\r
+   }\r
+\r
+   string[dst] = '\0';\r
+\r
+   return TRUE;\r
+}\r
+\r
+// my_string_empty()\r
+\r
+bool my_string_empty(const char string[]) {\r
+\r
+   return string == NULL || string[0] == '\0';\r
+}\r
+\r
+// my_string_whitespace()\r
+\r
+bool my_string_whitespace(const char string[]){\r
+    int pos=0;\r
+    while(string[pos]!='\0'){\r
+        if(string[pos]!=' ' && string[pos]!='\t'){\r
+            return FALSE;\r
+        }\r
+        pos++;\r
+    }\r
+    return TRUE;\r
+}\r
+\r
+// my_string_equal()\r
+\r
+bool my_string_equal(const char string_1[], const char string_2[]) {\r
+\r
+   ASSERT(string_1!=NULL);\r
+   ASSERT(string_2!=NULL);\r
+\r
+   return strcmp(string_1,string_2) == 0;\r
+}\r
+\r
+// my_string_case_equal()\r
+\r
+bool my_string_case_equal(const char string_1[], const char string_2[]) {\r
+\r
+   int c1, c2;\r
+\r
+   ASSERT(string_1!=NULL);\r
+   ASSERT(string_2!=NULL);\r
+\r
+   while (TRUE) {\r
+\r
+      c1 = *string_1++;\r
+      c2 = *string_2++;\r
+\r
+      if (tolower(c1) != tolower(c2)) return FALSE;\r
+      if (c1 == '\0') return TRUE;\r
+   }\r
+\r
+   return FALSE;\r
+}\r
+\r
+// my_strdup()\r
+\r
+char * my_strdup(const char string[]) {\r
+\r
+   char * address;\r
+\r
+   ASSERT(string!=NULL);\r
+\r
+   // strdup() is not ANSI C\r
+\r
+   address = (char *) my_malloc(strlen(string)+1);\r
+   strcpy(address,string);\r
+\r
+   return address;\r
+}\r
+\r
+// my_string_clear()\r
+\r
+void my_string_clear(const char * * variable) {\r
+\r
+   ASSERT(variable!=NULL);\r
+\r
+   if (*variable != NULL) {\r
+      my_free((void*)(*variable));\r
+      *variable = NULL;\r
+   }\r
+}\r
+\r
+// my_string_set()\r
+\r
+void my_string_set(const char * * variable, const char string[]) {\r
+\r
+   ASSERT(variable!=NULL);\r
+   ASSERT(string!=NULL);\r
+\r
+   if (*variable != NULL) my_free((void*)(*variable));\r
+   *variable = my_strdup(string);\r
+}\r
+\r
+double now_real() {\r
+#ifndef _WIN32\r
+   struct timeval tv[1];\r
+   struct timezone tz[1];\r
+\r
+   tz->tz_minuteswest = 0;\r
+   tz->tz_dsttime = 0; // DST_NONE not declared in linux\r
+\r
+   if (gettimeofday(tv,tz) == -1) {\r
+      my_fatal("now_real(): gettimeofday(): %s\n",strerror(errno));\r
+   }\r
+\r
+   return tv->tv_sec + tv->tv_usec * 1E-6;\r
+#else\r
+   return (double) GetTickCount() / 1000.0;  // we can do better here:-)\r
+#endif\r
+}\r
+\r
+\r
+// my_timer_reset()\r
+\r
+void my_timer_reset(my_timer_t * timer) {\r
+\r
+   ASSERT(timer!=NULL);\r
+\r
+   timer->start_real = 0.0;\r
+   timer->elapsed_real = 0.0;\r
+   timer->running = FALSE;\r
+}\r
+\r
+// my_timer_start()\r
+\r
+void my_timer_start(my_timer_t * timer) {\r
+// timer->start_real = 0.0;\r
+   timer->elapsed_real = 0.0;\r
+// timer->running = FALSE;\r
+   ASSERT(timer!=NULL);\r
+\r
+   timer->running = TRUE;\r
+   timer->start_real = now_real();\r
+}\r
+\r
+// my_timer_stop()\r
+\r
+void my_timer_stop(my_timer_t * timer) {\r
+\r
+   ASSERT(timer!=NULL);\r
+\r
+   ASSERT(timer->running);\r
+\r
+   timer->elapsed_real += now_real() - timer->start_real;\r
+   timer->start_real = 0.0;\r
+   timer->running = FALSE;\r
+}\r
+\r
+// my_timer_elapsed_real()\r
+\r
+double my_timer_elapsed_real(const my_timer_t * timer) {\r
+\r
+   double elapsed;\r
+\r
+   ASSERT(timer!=NULL);\r
+\r
+   elapsed = timer->elapsed_real;\r
+   if (timer->running) elapsed += now_real() - timer->start_real;\r
+\r
+   if (elapsed < 0.0) elapsed = 0.0;\r
+\r
+   return elapsed;\r
+}\r
+\r
+\r
+char * my_getcwd(char *buf, size_t size){\r
+#ifdef _WIN32\r
+    return _getcwd(buf,size);\r
+#else\r
+    return getcwd(buf,size);\r
+#endif\r
+}\r
+\r
+int my_chdir (const char *path){\r
+    ASSERT(path!=NULL);\r
+#ifdef _WIN32\r
+    return _chdir(path);\r
+#else\r
+    return chdir(path);\r
+#endif\r
+}\r
diff --git a/util.h b/util.h
index 1ce7e32..cf197fe 100644 (file)
--- a/util.h
+++ b/util.h
@@ -6,9 +6,22 @@
 \r
 // includes\r
 \r
-#include <cstdio>\r
+#include <stdio.h>\r
+\r
+// defines\r
+\r
+#ifndef EXIT_SUCCES\r
+#define EXIT_SUCCES 0\r
+#endif\r
+\r
+#ifndef STDIN_FILENO\r
+#define STDIN_FILENO 0\r
+#endif\r
+\r
+#ifndef STDOUT_FILENO\r
+#define STDOUT_FILENO 1\r
+#endif\r
 \r
-// constants\r
 \r
 #undef FALSE\r
 #define FALSE 0\r
@@ -63,6 +76,8 @@ typedef unsigned short uint16;
 typedef signed int sint32;\r
 typedef unsigned int uint32;\r
 \r
+typedef int bool;\r
+\r
 #ifdef _MSC_VER\r
   typedef signed __int64 sint64;\r
   typedef unsigned __int64 uint64;\r
@@ -71,28 +86,14 @@ typedef unsigned int uint32;
   typedef unsigned long long int uint64;\r
 #endif\r
 \r
-struct my_timer_t {\r
+typedef struct {\r
    double start_real;\r
    double elapsed_real;\r
    bool running;\r
-};\r
+} my_timer_t;\r
 \r
 // functions\r
 \r
-#ifdef _WIN32\r
-  #include <windows.h>\r
-  inline void Idle(void) {\r
-    Sleep(1);\r
-  }\r
-  inline void Idle500msecs(void){\r
-         Sleep(500);\r
-  }\r
-#else\r
-  #include <unistd.h>\r
-  inline void Idle(void) {\r
-    usleep(1000);\r
-  }\r
-#endif\r
 extern void   util_init             ();\r
 \r
 extern void   my_random_init        ();\r
@@ -124,6 +125,8 @@ extern char * my_strdup             (const char string[]);
 extern void   my_string_clear       (const char * * variable);\r
 extern void   my_string_set         (const char * * variable, const char string[]);\r
 \r
+extern double now_real              ();\r
+\r
 extern void   my_timer_reset        (my_timer_t * timer);\r
 extern void   my_timer_start        (my_timer_t * timer);\r
 extern void   my_timer_stop         (my_timer_t * timer);\r
@@ -132,6 +135,9 @@ extern double my_timer_elapsed_real (const my_timer_t * timer);
 \r
 extern char * my_error();\r
 \r
+extern char * my_getcwd             (char *buf, size_t size);\r
+extern int    my_chdir              (const char *path);\r
+\r
 #endif // !defined UTIL_H\r
 \r
 // end of util.h\r
diff --git a/xboard2uci.c b/xboard2uci.c
new file mode 100644 (file)
index 0000000..43bc63b
--- /dev/null
@@ -0,0 +1,1553 @@
+\r
+// xboard2uci.c\r
+\r
+// includes\r
+\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+#include "board.h"\r
+#include "book.h"\r
+#include "colour.h"\r
+#include "engine.h"\r
+#include "fen.h"\r
+#include "game.h"\r
+#include "gui.h"\r
+#include "line.h"\r
+#include "main.h"\r
+#include "move.h"\r
+#include "move_do.h"\r
+#include "move_legal.h"\r
+#include "option.h"\r
+#include "parse.h"\r
+#include "san.h"\r
+#include "uci.h"\r
+#include "uci2uci.h"\r
+#include "util.h"\r
+\r
+// defines\r
+\r
+#define StringSize 4096\r
+\r
+// constants\r
+\r
+static const bool UseDebug = FALSE;\r
+static const bool DelayPong = FALSE;\r
+\r
+// types\r
+\r
+typedef struct {\r
+   int state;\r
+   bool computer[ColourNb];\r
+   int exp_move;\r
+   int resign_nb;\r
+   my_timer_t timer[1];\r
+} state_t;\r
+\r
+typedef struct {\r
+    bool has_feature_memory;\r
+    bool has_feature_smp;\r
+    bool has_feature_egt;\r
+    bool analyse;\r
+    bool computer;\r
+    const char * name;\r
+    bool ics;\r
+    bool new_hack; // "new" is a C++ keyword\r
+    bool ponder;\r
+    int ping;\r
+    bool post;\r
+    int proto_ver;\r
+    bool result;\r
+\r
+    int mps;\r
+    double base;\r
+    double inc;\r
+    \r
+    bool time_limit;\r
+    double time_max;\r
+    \r
+    bool depth_limit;\r
+    int depth_max;\r
+    \r
+    double my_time;\r
+    double opp_time;\r
+} xb_t;\r
+\r
+typedef enum { WAIT, THINK, PONDER, ANALYSE } dummy_state_t;\r
+\r
+// variables\r
+\r
+static state_t State[1];\r
+static xb_t XB[1];\r
+\r
+// prototypes\r
+\r
+static void comp_move      (int move);\r
+static void move_step      (int move);\r
+static void board_update   ();\r
+\r
+static void mess           ();\r
+static void no_mess        (int move);\r
+\r
+static void search_update  ();\r
+static void search_clear   ();\r
+static void update_remaining_time();\r
+static int  report_best_score();\r
+static bool kibitz_throttle (bool searching);\r
+static void start_protected_command();\r
+static void end_protected_command();\r
+\r
+static bool active         ();\r
+static bool ponder         ();\r
+static bool ponder_ok      (int ponder_move);\r
+\r
+static void stop_search    ();\r
+\r
+static void send_board     (int extra_move);\r
+static void send_pv        ();\r
+\r
+static void send_xboard_options ();\r
+\r
+static void learn          (int result);\r
+\r
+\r
+// functions\r
+\r
+// xboard2uci_init()\r
+\r
+void xboard2uci_init() {\r
+   // init\r
+\r
+   game_clear(Game);\r
+\r
+   // state\r
+\r
+   State->state = WAIT;\r
+\r
+   State->computer[White] = FALSE;\r
+   State->computer[Black] = TRUE;\r
+\r
+   State->exp_move = MoveNone;\r
+   State->resign_nb = 0;\r
+   my_timer_reset(State->timer);\r
+\r
+   // yes there are engines that do not have the "Hash" option....\r
+   XB->has_feature_memory= uci_option_exist(Uci,"Hash");\r
+   XB->has_feature_smp = uci_thread_option_exist(Uci);\r
+   // TODO: support for other types of table bases\r
+   XB->has_feature_egt = uci_option_exist(Uci,"NalimovPath");\r
+   XB->analyse = FALSE;\r
+   XB->computer = FALSE;\r
+   XB->name = NULL;\r
+   my_string_set(&XB->name,"<empty>");\r
+   XB->ics = FALSE;\r
+   XB->new_hack = TRUE;\r
+   XB->ping = -1;\r
+   XB->ponder = FALSE;\r
+   XB->post = FALSE;\r
+   XB->proto_ver = 1;\r
+   XB->result = FALSE;\r
+\r
+   XB->mps = 0;\r
+   XB->base = 300.0;\r
+   XB->inc = 0.0;\r
+\r
+   XB->time_limit = FALSE;\r
+   XB->time_max = 5.0;\r
+\r
+   XB->depth_limit = FALSE;\r
+   XB->depth_max = 127;\r
+\r
+   XB->my_time = 300.0;\r
+   XB->opp_time = 300.0;\r
+}\r
+\r
+// xboard2uci_gui_step()\r
+\r
+void xboard2uci_gui_step(char string[]) {\r
+\r
+       int move;\r
+       char move_string[256];\r
+       board_t board[1];\r
+\r
+               if (FALSE) {\r
+         \r
+               } else if (match(string,"accepted *")) {\r
+\r
+                       // ignore\r
+\r
+               } else if (match(string,"analyze")) {\r
+\r
+                       State->computer[White] = FALSE;\r
+                       State->computer[Black] = FALSE;\r
+\r
+                       XB->analyse = TRUE;\r
+                       XB->new_hack = FALSE;\r
+                       ASSERT(!XB->result);\r
+                       XB->result = FALSE;\r
+\r
+                       mess();\r
+\r
+               } else if (match(string,"bk")) {\r
+\r
+                       if (option_get_bool("Book")) {\r
+                               game_get_board(Game,board);\r
+                               book_disp(board);\r
+                       }\r
+\r
+               } else if (match(string,"black")) {\r
+\r
+                       if (colour_is_black(game_turn(Game))) {\r
+\r
+                               State->computer[White] = TRUE;\r
+                               State->computer[Black] = FALSE;\r
+\r
+                               XB->new_hack = TRUE;\r
+                               XB->result = FALSE;\r
+\r
+                               mess();\r
+                       }\r
+\r
+               } else if (match(string,"computer")) {\r
+\r
+                       XB->computer = TRUE;\r
+\r
+               } else if (match(string,"draw")) {\r
+                       if(uci_option_exist(Uci,"UCI_DrawOffers")){\r
+                           my_log("POLYGLOT draw from XB received");\r
+                               uci_send_option(Uci,"DrawOffer","%s","draw");}\r
+               } else if (match(string,"easy")) {\r
+\r
+                       XB->ponder = FALSE;\r
+\r
+                       mess();\r
+\r
+               } else if (match(string,"edit")) {\r
+\r
+                       // refuse\r
+\r
+                       gui_send(GUI,"Error (unknown command): %s",string);\r
+\r
+               } else if (match(string,"exit")) {\r
+\r
+                       State->computer[White] = FALSE;\r
+                       State->computer[Black] = FALSE;\r
+\r
+                       XB->analyse = FALSE;\r
+\r
+                       mess();\r
+\r
+               } else if (match(string,"force")) {\r
+\r
+                       State->computer[White] = FALSE;\r
+                       State->computer[Black] = FALSE;\r
+\r
+                       mess();\r
+\r
+               } else if (match(string,"go")) {\r
+\r
+                       State->computer[game_turn(Game)] = TRUE;\r
+                       State->computer[colour_opp(game_turn(Game))] = FALSE;\r
+\r
+                       XB->new_hack = FALSE;\r
+                       ASSERT(!XB->result);\r
+                       XB->result = FALSE;\r
+\r
+                       mess();\r
+\r
+               } else if (match(string,"hard")) {\r
+\r
+                       XB->ponder = TRUE;\r
+\r
+                       mess();\r
+\r
+               } else if (match(string,"hint")) {\r
+\r
+                       if (option_get_bool("Book")) {\r
+\r
+                               game_get_board(Game,board);\r
+                               move = book_move(board,FALSE);\r
+\r
+                               if (move != MoveNone && move_is_legal(move,board)) {\r
+                                       move_to_san(move,board,move_string,256);\r
+                                       gui_send(GUI,"Hint: %s",move_string);\r
+                               }\r
+                       }\r
+\r
+               } else if (match(string,"ics *")) {\r
+\r
+                       XB->ics = TRUE;\r
+\r
+               } else if (match(string,"level * *:* *")) {\r
+\r
+                       XB->mps  = atoi(Star[0]);\r
+                       XB->base = ((double)atoi(Star[1])) * 60.0 + ((double)atoi(Star[2]));\r
+                       XB->inc  = ((double)atoi(Star[3]));\r
+\r
+               } else if (match(string,"level * * *")) {\r
+\r
+                       XB->mps  = atoi(Star[0]);\r
+                       XB->base = ((double)atoi(Star[1])) * 60.0;\r
+                       XB->inc  = ((double)atoi(Star[2]));\r
+\r
+               } else if (match(string,"name *")) {\r
+\r
+                       my_string_set(&XB->name,Star[0]);\r
+\r
+               } else if (match(string,"new")) {\r
+\r
+            uci_send_isready(Uci);\r
+                       my_log("POLYGLOT NEW GAME\n");\r
+\r
+                       option_set("Chess960","FALSE");\r
+\r
+                       game_clear(Game);\r
+\r
+                       if (XB->analyse) {\r
+                               State->computer[White] = FALSE;\r
+                               State->computer[Black] = FALSE;\r
+                       } else {\r
+                               State->computer[White] = FALSE;\r
+                               State->computer[Black] = TRUE;\r
+                       }\r
+\r
+                       XB->new_hack = TRUE;\r
+                       XB->result = FALSE;\r
+\r
+                       XB->depth_limit = FALSE;\r
+\r
+                       XB->computer = FALSE;\r
+                       my_string_set(&XB->name,"<empty>");\r
+\r
+                       board_update();\r
+                       mess();\r
+\r
+                       uci_send_ucinewgame(Uci);\r
+\r
+               } else if (match(string,"nopost")) {\r
+\r
+                       XB->post = FALSE;\r
+\r
+               } else if (match(string,"otim *")) {\r
+\r
+                       XB->opp_time = ((double)atoi(Star[0])) / 100.0;\r
+                       if (XB->opp_time < 0.0) XB->opp_time = 0.0;\r
+\r
+               } else if (match(string,"pause")) {\r
+\r
+                       // refuse\r
+\r
+                       gui_send(GUI,"Error (unknown command): %s",string);\r
+\r
+               } else if (match(string,"ping *")) {\r
+\r
+                       // HACK; TODO: answer only after an engine move\r
+\r
+                       if (DelayPong) {\r
+                               if (XB->ping >= 0) gui_send(GUI,"pong %d",XB->ping); // HACK: get rid of old ping\r
+                               XB->ping = atoi(Star[0]);\r
+                               uci_send_isready(Uci);\r
+                       } else {\r
+                               ASSERT(XB->ping==-1);\r
+                               gui_send(GUI,"pong %s",Star[0]);\r
+                       }\r
+\r
+               } else if (match(string,"playother")) {\r
+\r
+                       State->computer[game_turn(Game)] = FALSE;\r
+                       State->computer[colour_opp(game_turn(Game))] = TRUE;\r
+\r
+                       XB->new_hack = FALSE;\r
+                       ASSERT(!XB->result);\r
+                       XB->result = FALSE;\r
+\r
+                       mess();\r
+\r
+               } else if (match(string,"post")) {\r
+\r
+                       XB->post = TRUE;\r
+\r
+               } else if (match(string,"protover *")) {\r
+\r
+            send_xboard_options();\r
+\r
+               } else if (match(string,"quit")) {\r
+                       my_log("POLYGLOT *** \"quit\" from GUI ***\n");\r
+                       quit();\r
+               } else if (match(string,"random")) {\r
+\r
+                       // ignore\r
+\r
+               } else if (match(string,"rating * *")) {\r
+\r
+                       // ignore\r
+\r
+               } else if (match(string,"remove")) {\r
+\r
+                       if (game_pos(Game) >= 2) {\r
+\r
+                               game_goto(Game,game_pos(Game)-2);\r
+\r
+                               ASSERT(!XB->new_hack);\r
+                               XB->new_hack = FALSE; // HACK?\r
+                               XB->result = FALSE;\r
+\r
+                               board_update();\r
+                               mess();\r
+                       }\r
+\r
+               } else if (match(string,"rejected *")) {\r
+\r
+                       // ignore\r
+\r
+               } else if (match(string,"reset")) { // protover 3?\r
+\r
+                       // refuse\r
+\r
+                       gui_send(GUI,"Error (unknown command): %s",string);\r
+\r
+               } else if (FALSE\r
+                       || match(string,"result * {*}")\r
+                       || match(string,"result * {* }")\r
+                       || match(string,"result * { *}")\r
+                       || match(string,"result * { * }")) {\r
+\r
+                               my_log("POLYGLOT GAME END\n");\r
+\r
+                               XB->result = TRUE;\r
+\r
+                               mess();\r
+\r
+                               // book learning\r
+\r
+                               if (option_get_bool("Book") && option_get_bool("BookLearn")) {\r
+\r
+                                       if (FALSE) {\r
+                                       } else if (my_string_equal(Star[0],"1-0")) {\r
+                                               learn(+1);\r
+                                       } else if (my_string_equal(Star[0],"0-1")) {\r
+                                               learn(-1);\r
+                                       } else if (my_string_equal(Star[0],"1/2-1/2")) {\r
+                                               learn(0);\r
+                                       }\r
+                               }\r
+               } else if (match(string,"resume")) {\r
+\r
+                       // refuse\r
+\r
+                       gui_send(GUI,"Error (unknown command): %s",string);\r
+\r
+        } else if (match(string,"option *=*")){\r
+            char *name=Star[0];\r
+            char *value=Star[1];\r
+            if(match(name, "Polyglot *")){\r
+                char *pg_name=Star[0];\r
+                polyglot_set_option(pg_name,value);\r
+            }else{\r
+                start_protected_command();\r
+                engine_send(Engine,"setoption name %s value %s",name,value);\r
+                end_protected_command();\r
+            }\r
+        } else if (match(string,"option *")){\r
+            char *name=Star[0];\r
+            start_protected_command();\r
+            engine_send(Engine,"setoption name %s",name);\r
+            end_protected_command();\r
+        } else if (XB->has_feature_smp && match(string,"cores *")){\r
+                int cores=atoi(Star[0]);\r
+                if(cores>=1){\r
+                    // updating the number of cores\r
+                    my_log("POLYGLOT setting the number of cores to %d\n",cores);\r
+                    start_protected_command();\r
+                    uci_set_threads(Uci,cores); \r
+                    end_protected_command();\r
+                } else{\r
+                   // refuse\r
+                    gui_send(GUI,"Error (unknown command): %s",string);\r
+                }\r
+        } else if (XB->has_feature_egt && match(string,"egtpath * *")){\r
+                char *type=Star[0];\r
+                char *path=Star[1];\r
+                if(!my_string_case_equal(type,"nalimov")){\r
+                   // refuse\r
+                    gui_send(GUI,"Error (unsupported table base format): %s",string);\r
+                }else if(my_string_empty(path)){\r
+                    // refuse\r
+                    gui_send(GUI,"Error (unknown command): %s",string);\r
+                }else{\r
+                    // updating NalimovPath\r
+                    my_log("POLYGLOT setting the Nalimov path to %s\n",path);\r
+                    start_protected_command();\r
+                    uci_send_option(Uci,"NalimovPath","%s",path);\r
+                    end_protected_command();\r
+                }\r
+        } else if (XB->has_feature_memory && match(string,"memory *")){\r
+            int memory = atoi(Star[0]);\r
+            int nalimov_cache;\r
+            int real_memory;\r
+            if(memory>=1){\r
+                // updating the available memory\r
+                my_log("POLYGLOT setting the amount of memory to %dMb\n",memory);\r
+                if(uci_get_option(Uci,"NalimovCache")>=0){\r
+                    nalimov_cache=atoi(Uci->option[uci_get_option(Uci,"NalimovCache")].value);\r
+                }else{\r
+                    nalimov_cache=0;\r
+                }\r
+                my_log("POLYGLOT Nalimov Cache is %dMb\n",nalimov_cache);\r
+                real_memory=memory-nalimov_cache;\r
+                if(real_memory>0){\r
+                    start_protected_command();\r
+                    uci_send_option(Uci,"Hash", "%d", real_memory);\r
+                    end_protected_command();\r
+                }\r
+            }else{\r
+                // refuse\r
+                gui_send(GUI,"Error (unknown command): %s",string);\r
+            }\r
+\r
+               } else if (match(string,"sd *")) {\r
+\r
+                       XB->depth_limit = TRUE;\r
+                       XB->depth_max = atoi(Star[0]);\r
+\r
+               } else if (match(string,"setboard *")) {\r
+\r
+                       my_log("POLYGLOT FEN %s\n",Star[0]);\r
+\r
+                       if (!game_init(Game,Star[0])) my_fatal("xboard_step(): bad FEN \"%s\"\n",Star[0]);\r
+\r
+                       State->computer[White] = FALSE;\r
+                       State->computer[Black] = FALSE;\r
+\r
+                       XB->new_hack = TRUE; // HACK?\r
+                       XB->result = FALSE;\r
+\r
+                       board_update();\r
+                       mess();\r
+\r
+               } else if (match(string,"st *")) {\r
+\r
+                       XB->time_limit = TRUE;\r
+                       XB->time_max = ((double)atoi(Star[0]));\r
+\r
+               } else if (match(string,"time *")) {\r
+\r
+                       XB->my_time = ((double)atoi(Star[0])) / 100.0;\r
+                       if (XB->my_time < 0.0) XB->my_time = 0.0;\r
+\r
+               } else if (match(string,"undo")) {\r
+\r
+                       if (game_pos(Game) >= 1) {\r
+\r
+                               game_goto(Game,game_pos(Game)-1);\r
+\r
+                               ASSERT(!XB->new_hack);\r
+                               XB->new_hack = FALSE; // HACK?\r
+                               XB->result = FALSE;\r
+\r
+                               board_update();\r
+                               mess();\r
+                       }\r
+\r
+               } else if (match(string,"usermove *")) {\r
+\r
+                       game_get_board(Game,board);\r
+                       move = move_from_san(Star[0],board);\r
+\r
+                       if (move != MoveNone && move_is_legal(move,board)) {\r
+\r
+                               XB->new_hack = FALSE;\r
+                               ASSERT(!XB->result);\r
+                               XB->result = FALSE;\r
+\r
+                               move_step(move);\r
+                               no_mess(move);\r
+\r
+                       } else {\r
+\r
+                               gui_send(GUI,"Illegal move: %s",Star[0]);\r
+                       }\r
+\r
+               } else if (match(string,"variant *")) {\r
+\r
+                       if (my_string_equal(Star[0],"fischerandom")) {\r
+                               option_set("Chess960","TRUE");\r
+                       } else {\r
+                               option_set("Chess960","FALSE");\r
+                       }\r
+\r
+               } else if (match(string,"white")) {\r
+\r
+                       if (colour_is_white(game_turn(Game))) {\r
+\r
+                               State->computer[White] = FALSE;\r
+                               State->computer[Black] = TRUE;\r
+\r
+                               XB->new_hack = TRUE;\r
+                               XB->result = FALSE;\r
+\r
+                               mess();\r
+                       }\r
+\r
+               } else if (match(string,"xboard")) {\r
+\r
+                       // ignore\r
+\r
+               } else if (match(string,".")) { // analyse info\r
+\r
+                       if (State->state == ANALYSE) {\r
+                               int depth=Uci->best_depth;//HACK: don't clear engine-output window...\r
+\r
+                               ASSERT(Uci->searching);\r
+                               ASSERT(Uci->pending_nb>=1);\r
+\r
+                               if (Uci->root_move != MoveNone && move_is_legal(Uci->root_move,Uci->board)) {\r
+                                       move_to_san(Uci->root_move,Uci->board,move_string,256);\r
+                                       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);\r
+                               } else {\r
+                                       gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,0,0); // HACK\r
+                               }\r
+                       }\r
+\r
+               } else if (match(string,"?")) { // move now\r
+\r
+                       if (State->state == THINK) {\r
+\r
+                               ASSERT(Uci->searching);\r
+                               ASSERT(Uci->pending_nb>=1);\r
+\r
+                               // HACK: just send "stop" to the engine\r
+\r
+                               if (Uci->searching) {\r
+                                       my_log("POLYGLOT STOP SEARCH\n");\r
+                                       engine_send(Engine,"stop");\r
+                               }\r
+                       }\r
+\r
+               } else { // unknown command, maybe a move?\r
+\r
+                       game_get_board(Game,board);\r
+                       move = move_from_san(string,board);\r
+\r
+                       if (move != MoveNone && move_is_legal(move,board)) {\r
+\r
+                               XB->new_hack = FALSE;\r
+                               ASSERT(!XB->result);\r
+                               XB->result = FALSE;\r
+\r
+                               move_step(move);\r
+                               no_mess(move);\r
+\r
+                       } else if (move != MoveNone) {\r
+\r
+                               gui_send(GUI,"Illegal move: %s",string);\r
+\r
+                       } else {\r
+\r
+                               gui_send(GUI,"Error (unknown command): %s",string);\r
+                       }\r
+               }\r
+       return;\r
+}\r
+\r
+// xboard2uci_engine_step()\r
+\r
+void xboard2uci_engine_step(char string[]) {\r
+\r
+       int event;\r
+               event = uci_parse(Uci,string);\r
+\r
+               // react to events\r
+\r
+               if ((event & EVENT_READY) != 0) {\r
+\r
+                       // the engine is now ready\r
+\r
+                       if (!Uci->ready) {\r
+                               Uci->ready = TRUE;\r
+                    // if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1");\r
+                       }\r
+\r
+                       if (!DelayPong && XB->ping >= 0) {\r
+                               gui_send(GUI,"pong %d",XB->ping);\r
+                               XB->ping = -1;\r
+                       }\r
+               }\r
+\r
+               if ((event & EVENT_MOVE) != 0 && State->state == THINK) {\r
+\r
+                       // the engine is playing a move\r
+\r
+                       // MEGA HACK: estimate remaining time because XBoard won't send it!\r
+\r
+                       my_timer_stop(State->timer);\r
+\r
+                       XB->my_time -= my_timer_elapsed_real(State->timer);\r
+                       XB->my_time += XB->inc;\r
+                       if (XB->mps != 0 && (game_move_nb(Game) + 1) % XB->mps == 0) XB->my_time += XB->base;\r
+\r
+                       if (XB->my_time < 0.0) XB->my_time = 0.0;\r
+\r
+                       // play the engine move\r
+\r
+                       comp_move(Uci->best_move);\r
+               }\r
+\r
+               if ((event & EVENT_PV) != 0) {\r
+\r
+                       // the engine has sent a new PV\r
+\r
+                       send_pv();\r
+               }\r
+               if((event & (EVENT_DRAW|EVENT_RESIGN))!=0){\r
+                       my_log("POYGLOT draw offer/resign from engine\n");\r
+                       if(uci_option_exist(Uci,"UCI_DrawOffers")){\r
+                               if(event & EVENT_DRAW)\r
+                                       gui_send(GUI,"offer draw");\r
+                               else\r
+                                       gui_send(GUI,"resign");\r
+                       }\r
+               }\r
+}\r
+\r
+// format_xboard_option_line\r
+\r
+void format_xboard_option_line(char * option_line, option_t *opt){\r
+    int j;\r
+    char option_string[StringSize];\r
+    strcpy(option_line,"");\r
+    strcat(option_line,"feature option=\"");\r
+    if(opt->mode&PG){\r
+        strcat(option_line,"Polyglot ");\r
+    }\r
+    sprintf(option_string,"%s",opt->name);\r
+    strcat(option_line,option_string);\r
+    sprintf(option_string," -%s",opt->type);\r
+    strcat(option_line,option_string);\r
+    if(strcmp(opt->type,"button") && strcmp(opt->type,"combo")){\r
+        if(strcmp(opt->type,"check")){\r
+            sprintf(option_string," %s",opt->default_);\r
+        }else{\r
+            sprintf(option_string," %d",\r
+                    strcmp(opt->default_,"TRUE")?0:1);\r
+        }\r
+        strcat(option_line,option_string);\r
+    }\r
+    if(!strcmp(opt->type,"spin")){\r
+        sprintf(option_string," %s",opt->min);\r
+            strcat(option_line,option_string);\r
+    }\r
+    if(!strcmp(opt->type,"spin")){\r
+        sprintf(option_string," %s",opt->max);\r
+        strcat(option_line,option_string);\r
+    }\r
+    for(j=0;j<opt->var_nb;j++){\r
+        if(!strcmp(opt->var[j],opt->default_)){\r
+            sprintf(option_string," *%s",opt->var[j]);\r
+        }else{\r
+            sprintf(option_string," %s",opt->var[j]);\r
+        }\r
+        strcat(option_line,option_string);\r
+        if(j!=opt->var_nb-1){\r
+            strcat(option_line," ///");\r
+        }\r
+    }\r
+    strcat(option_line,"\"");\r
+}\r
+\r
+// send_xboard_options\r
+\r
+static void send_xboard_options(){\r
+    int i;\r
+    char option_line[StringSize]="";\r
+    option_t *p=Option;\r
+    const char * name;\r
+    XB->proto_ver = atoi(Star[0]);\r
+    ASSERT(XB->proto_ver>=2);\r
+    \r
+    gui_send(GUI,"feature done=0");\r
+    \r
+    gui_send(GUI,"feature analyze=1");\r
+    gui_send(GUI,"feature colors=0");\r
+    gui_send(GUI,"feature draw=1");\r
+    gui_send(GUI,"feature ics=1");\r
+    gui_send(GUI,"feature myname=\"%s\"",option_get_string("EngineName"));\r
+    gui_send(GUI,"feature name=1");\r
+    gui_send(GUI,"feature pause=0");\r
+    gui_send(GUI,"feature ping=1");\r
+    gui_send(GUI,"feature playother=1");\r
+    gui_send(GUI,"feature reuse=1");\r
+    gui_send(GUI,"feature san=0");\r
+    gui_send(GUI,"feature setboard=1");\r
+    gui_send(GUI,"feature sigint=0");\r
+    gui_send(GUI,"feature sigterm=0");\r
+    gui_send(GUI,"feature time=1");\r
+    gui_send(GUI,"feature usermove=1");\r
+    if (XB->has_feature_memory){\r
+        gui_send(GUI,"feature memory=1");\r
+    }else{\r
+        gui_send(GUI,"feature memory=0");\r
+    }\r
+    if (XB->has_feature_smp){\r
+        gui_send(GUI,"feature smp=1");\r
+    }else{\r
+        gui_send(GUI,"feature smp=0");\r
+    }\r
+    if (XB->has_feature_egt){\r
+            // TODO: support for other types of table bases\r
+        gui_send(GUI,"feature egt=\"nalimov\"");\r
+    }else{\r
+        gui_send(GUI,"feature egt=\"\"");\r
+    }\r
+    \r
+    if (uci_option_exist(Uci,"UCI_Chess960")) {\r
+        gui_send(GUI,"feature variants=\"normal,fischerandom\"");\r
+    } else {\r
+        gui_send(GUI,"feature variants=\"normal\"");\r
+    }\r
+    \r
+    for(i=0;i<Uci->option_nb;i++){\r
+        if(my_string_case_equal(Uci->option[i].name,"UCI_AnalyseMode")) continue;\r
+        if(my_string_case_equal(Uci->option[i].name,"Ponder")) continue;\r
+        if(my_string_case_equal(Uci->option[i].name,"Hash")) continue;\r
+        if(my_string_case_equal(Uci->option[i].name,"NalimovPath")) continue;\r
+        if((name=uci_thread_option(Uci))!=NULL && my_string_case_equal(Uci->option[i].name,name)) continue;\r
+        format_xboard_option_line(option_line,Uci->option+i);\r
+\r
+        gui_send(GUI,"%s",option_line);\r
+\r
+    }\r
+    while(p->name){\r
+        if(p->mode &XBOARD){\r
+            format_xboard_option_line(option_line,p);\r
+            gui_send(GUI,"%s",option_line);\r
+        }\r
+        p++;\r
+    }       \r
+    gui_send(GUI,"feature done=1"); \r
+    \r
+}\r
+\r
+// report_best_score()\r
+\r
+static int report_best_score(){\r
+    if(!option_get_bool("ScoreWhite") || colour_is_white(Uci->board->turn)){\r
+        return Uci->best_score;\r
+    }else{\r
+        return -Uci->best_score;\r
+    }\r
+}\r
+\r
+// comp_move()\r
+\r
+static void comp_move(int move) {\r
+\r
+   board_t board[1];\r
+   char string[256];\r
+\r
+   ASSERT(move_is_ok(move));\r
+\r
+   ASSERT(State->state==THINK);\r
+   ASSERT(!XB->analyse);\r
+\r
+   if(option_get_bool("RepeatPV"))\r
+          send_pv(); // to update time and nodes\r
+\r
+   // send the move\r
+\r
+   game_get_board(Game,board);\r
+\r
+   if (move_is_castle(move,board) && option_get_bool("Chess960")) {\r
+      if (!move_to_san(move,board,string,256)) my_fatal("comp_move(): move_to_san() failed\n"); // O-O/O-O-O\r
+   } else {\r
+      if (!move_to_can(move,board,string,256)) my_fatal("comp_move(): move_to_can() failed\n");\r
+   }\r
+\r
+   gui_send(GUI,"move %s",string);\r
+\r
+   // resign?\r
+\r
+   if (option_get_bool("Resign") && Uci->root_move_nb > 1) {\r
+\r
+      if (Uci->best_score <= -abs(option_get_int("ResignScore"))) {\r
+\r
+         State->resign_nb++;\r
+         my_log("POLYGLOT %d move%s with resign score\n",State->resign_nb,(State->resign_nb>1)?"s":"");\r
+\r
+         if (State->resign_nb >= option_get_int("ResignMoves")) {\r
+            my_log("POLYGLOT *** RESIGN ***\n");\r
+            gui_send(GUI,"resign");\r
+         }\r
+\r
+      } else {\r
+\r
+         if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb);\r
+         State->resign_nb = 0;\r
+      }\r
+   }\r
+\r
+   // play the move\r
+\r
+   move_step(move);\r
+   no_mess(move);\r
+}\r
+\r
+// move_step()\r
+\r
+static void move_step(int move) {\r
+\r
+   board_t board[1];\r
+   char move_string[256];\r
+\r
+   ASSERT(move_is_ok(move));\r
+\r
+   // log\r
+\r
+   game_get_board(Game,board);\r
+\r
+   if (move != MoveNone && move_is_legal(move,board)) {\r
+\r
+      move_to_san(move,board,move_string,256);\r
+      my_log("POLYGLOT MOVE %s\n",move_string);\r
+\r
+   } else {\r
+\r
+      move_to_can(move,board,move_string,256);\r
+      my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string);\r
+      board_disp(board);\r
+\r
+      my_fatal("move_step(): illegal move \"%s\"\n",move_string);\r
+   }\r
+\r
+   // play the move\r
+\r
+   game_add_move(Game,move);\r
+   board_update();\r
+}\r
+\r
+// board_update()\r
+\r
+static void board_update() {\r
+\r
+   // handle game end\r
+\r
+   ASSERT(!XB->result);\r
+\r
+   switch (game_status(Game)) {\r
+   case PLAYING:\r
+      break;\r
+   case WHITE_MATES:\r
+      gui_send(GUI,"1-0 {White mates}");\r
+      break;\r
+   case BLACK_MATES:\r
+      gui_send(GUI,"0-1 {Black mates}");\r
+      break;\r
+   case STALEMATE:\r
+      gui_send(GUI,"1/2-1/2 {Stalemate}");\r
+      break;\r
+   case DRAW_MATERIAL:\r
+      gui_send(GUI,"1/2-1/2 {Draw by insufficient material}");\r
+      break;\r
+   case DRAW_FIFTY:\r
+      gui_send(GUI,"1/2-1/2 {Draw by fifty-move rule}");\r
+      break;\r
+   case DRAW_REPETITION:\r
+      gui_send(GUI,"1/2-1/2 {Draw by repetition}");\r
+      break;\r
+   default:\r
+      ASSERT(FALSE);\r
+      break;\r
+   }\r
+}\r
+\r
+// mess()\r
+\r
+static void mess() {\r
+\r
+   // clear state variables\r
+\r
+   State->resign_nb = 0;\r
+   State->exp_move = MoveNone;\r
+   my_timer_reset(State->timer);\r
+\r
+   // abort a possible search\r
+\r
+   stop_search();\r
+\r
+   // calculate the new state\r
+\r
+   if (FALSE) {\r
+   } else if (!active()) {\r
+      State->state = WAIT;\r
+      my_log("POLYGLOT WAIT\n");\r
+   } else if (XB->analyse) {\r
+      State->state = ANALYSE;\r
+      my_log("POLYGLOT ANALYSE\n");\r
+   } else if (State->computer[game_turn(Game)]) {\r
+      State->state = THINK;\r
+      my_log("POLYGLOT THINK\n");\r
+   } else {\r
+      State->state = WAIT;\r
+      my_log("POLYGLOT WAIT\n");\r
+   }\r
+\r
+   search_update();\r
+}\r
+\r
+// no_mess()\r
+\r
+static void no_mess(int move) {\r
+\r
+   ASSERT(move_is_ok(move));\r
+\r
+   // just received a move, calculate the new state\r
+\r
+   if (FALSE) {\r
+\r
+   } else if (!active()) {\r
+\r
+      stop_search(); // abort a possible search\r
+\r
+      State->state = WAIT;\r
+      State->exp_move = MoveNone;\r
+\r
+      my_log("POLYGLOT WAIT\n");\r
+\r
+   } else if (State->state == WAIT) {\r
+\r
+      ASSERT(State->computer[game_turn(Game)]);\r
+      ASSERT(!State->computer[colour_opp(game_turn(Game))]);\r
+      ASSERT(!XB->analyse);\r
+\r
+      my_log("POLYGLOT WAIT -> THINK\n");\r
+\r
+      State->state = THINK;\r
+      State->exp_move = MoveNone;\r
+\r
+   } else if (State->state == THINK) {\r
+\r
+      ASSERT(!State->computer[game_turn(Game)]);\r
+      ASSERT(State->computer[colour_opp(game_turn(Game))]);\r
+      ASSERT(!XB->analyse);\r
+\r
+      if (ponder() && ponder_ok(Uci->ponder_move)) {\r
+\r
+         my_log("POLYGLOT THINK -> PONDER\n");\r
+\r
+         State->state = PONDER;\r
+         State->exp_move = Uci->ponder_move;\r
+\r
+      } else {\r
+\r
+         my_log("POLYGLOT THINK -> WAIT\n");\r
+\r
+         State->state = WAIT;\r
+         State->exp_move = MoveNone;\r
+      }\r
+\r
+   } else if (State->state == PONDER) {\r
+\r
+      ASSERT(State->computer[game_turn(Game)]);\r
+      ASSERT(!State->computer[colour_opp(game_turn(Game))]);\r
+      ASSERT(!XB->analyse);\r
+\r
+      if (move == State->exp_move && Uci->searching) {\r
+\r
+         ASSERT(Uci->searching);\r
+         ASSERT(Uci->pending_nb>=1);\r
+\r
+         my_timer_start(State->timer);//also resets\r
+\r
+         my_log("POLYGLOT PONDER -> THINK (*** HIT ***)\n");\r
+         engine_send(Engine,"ponderhit");\r
+\r
+         State->state = THINK;\r
+         State->exp_move = MoveNone;\r
+\r
+         send_pv(); // update display\r
+\r
+         return; // do not launch a new search\r
+\r
+      } else {\r
+\r
+         my_log("POLYGLOT PONDER -> THINK (miss)\n");\r
+\r
+         stop_search();\r
+\r
+         State->state = THINK;\r
+         State->exp_move = MoveNone;\r
+      }\r
+\r
+   } else if (State->state == ANALYSE) {\r
+\r
+      ASSERT(XB->analyse);\r
+\r
+      my_log("POLYGLOT ANALYSE -> ANALYSE\n");\r
+\r
+      stop_search();\r
+\r
+   } else {\r
+\r
+      ASSERT(FALSE);\r
+   }\r
+\r
+   search_update();\r
+}\r
+\r
+// start_protected_command()\r
+\r
+static void start_protected_command(){\r
+    stop_search();\r
+}\r
+\r
+static void end_protected_command(){\r
+    if(Uci->ready){ // not init faze\r
+        uci_send_isready_sync(Uci); // gobble up spurious "bestmove"\r
+    }\r
+    update_remaining_time();\r
+    search_update();   // relaunch search if necessary\r
+}\r
+\r
+// update_remaining_time()\r
+\r
+static void update_remaining_time(){\r
+   double reduce;\r
+   if(State->timer->running){\r
+       my_timer_stop(State->timer);\r
+       reduce = my_timer_elapsed_real(State->timer);\r
+       my_log("POLYGLOT reducing remaing time by %f seconds\n",reduce);\r
+       XB->my_time -= reduce;\r
+       if(XB->my_time<0.0){\r
+           XB->my_time=0.0;\r
+       }\r
+   }\r
+}\r
+\r
+\r
+// search_update()\r
+\r
+static void search_update() {\r
+\r
+   int move;\r
+   int move_nb;\r
+   board_t board[1];\r
+\r
+   ASSERT(!Uci->searching);\r
+\r
+\r
+\r
+   \r
+   // launch a new search if needed\r
+\r
+   \r
+\r
+   if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) {\r
+\r
+      // opening book\r
+\r
+      if (State->state == THINK && option_get_bool("Book")) {\r
+\r
+         game_get_board(Game,Uci->board);\r
+\r
+         move = book_move(Uci->board,option_get_bool("BookRandom"));\r
+\r
+         if (move != MoveNone && move_is_legal(move,Uci->board)) {\r
+\r
+            my_log("POLYGLOT *BOOK MOVE*\n");\r
+\r
+            search_clear(); // clears Uci->ponder_move\r
+            Uci->best_move = move;\r
+\r
+            board_copy(board,Uci->board);\r
+            move_do(board,move);\r
+            Uci->ponder_move = book_move(board,FALSE); // expected move = best book move\r
+\r
+            Uci->best_pv[0] = Uci->best_move;\r
+            Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone\r
+            Uci->best_pv[2] = MoveNone;\r
+\r
+            comp_move(Uci->best_move);\r
+\r
+            return;\r
+         }\r
+      }\r
+\r
+      // engine search\r
+\r
+      my_log("POLYGLOT START SEARCH\n");\r
+\r
+      // options\r
+\r
+      uci_send_option(Uci,"UCI_Chess960","%s",option_get_bool("Chess960")?"TRUE":"FALSE");\r
+\r
+      if (option_get_int("UCIVersion") >= 2) {\r
+         uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name);\r
+         uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"TRUE":"FALSE");\r
+      }\r
+\r
+      uci_send_option(Uci,"Ponder","%s",ponder()?"TRUE":"FALSE");\r
+\r
+      // position\r
+\r
+      move = (State->state == PONDER) ? State->exp_move : MoveNone;\r
+      send_board(move); // updates Uci->board global variable\r
+\r
+      // search\r
+\r
+      if (State->state == THINK || State->state == PONDER) {\r
+\r
+         engine_send_queue(Engine,"go");\r
+\r
+         if (XB->time_limit) {\r
+\r
+            // fixed time per move\r
+\r
+            engine_send_queue(Engine," movetime %.0f",XB->time_max*1000.0);\r
+\r
+         } else {\r
+\r
+            // time controls\r
+\r
+            if (colour_is_white(Uci->board->turn)) {\r
+               engine_send_queue(Engine," wtime %.0f btime %.0f",XB->my_time*1000.0,XB->opp_time*1000.0);\r
+            } else {\r
+               engine_send_queue(Engine," wtime %.0f btime %.0f",XB->opp_time*1000.0,XB->my_time*1000.0);\r
+            }\r
+\r
+            if (XB->inc != 0.0) engine_send_queue(Engine," winc %.0f binc %.0f",XB->inc*1000.0,XB->inc*1000.0);\r
+\r
+            if (XB->mps != 0) {\r
+\r
+               move_nb = XB->mps - (Uci->board->move_nb % XB->mps);\r
+               ASSERT(move_nb>=1&&move_nb<=XB->mps);\r
+\r
+               engine_send_queue(Engine," movestogo %d",move_nb);\r
+            }\r
+         }\r
+\r
+         if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max);\r
+\r
+         if (State->state == PONDER) engine_send_queue(Engine," ponder");\r
+\r
+         engine_send(Engine,""); // newline\r
+\r
+      } else if (State->state == ANALYSE) {\r
+\r
+         engine_send(Engine,"go infinite");\r
+\r
+      } else {\r
+\r
+         ASSERT(FALSE);\r
+      }\r
+\r
+      // init search info\r
+\r
+      ASSERT(!Uci->searching);\r
+\r
+      search_clear();\r
+\r
+      Uci->searching = TRUE;\r
+      Uci->pending_nb++;\r
+   }\r
+}\r
+\r
+// search_clear()\r
+\r
+static void search_clear() {\r
+\r
+   uci_clear(Uci);\r
+\r
+   // TODO: MOVE ME\r
+\r
+   my_timer_start(State->timer);//also resets\r
+}\r
+\r
+// active()\r
+\r
+static bool active() {\r
+\r
+   // position state\r
+\r
+   if (game_status(Game) != PLAYING) return FALSE; // game ended\r
+\r
+   // xboard state\r
+\r
+   if (XB->analyse) return TRUE; // analysing\r
+   if (!State->computer[White] && !State->computer[Black]) return FALSE; // force mode\r
+   if (XB->new_hack || XB->result) return FALSE; // unstarted or ended game\r
+\r
+   return TRUE; // playing\r
+}\r
+\r
+// ponder()\r
+\r
+static bool ponder() {\r
+\r
+   return XB->ponder && (option_get_bool("CanPonder") || uci_option_exist(Uci,"Ponder"));\r
+}\r
+// ponder_ok()\r
+\r
+static bool ponder_ok(int move) {\r
+   int status;\r
+   board_t board[1];\r
+\r
+   ASSERT(move==MoveNone||move_is_ok(move));\r
+\r
+   // legal ponder move?\r
+\r
+   if (move == MoveNone) return FALSE;\r
+\r
+   game_get_board(Game,board);\r
+   if (!move_is_legal(move,board)) return FALSE;\r
+\r
+   // UCI-legal resulting position?\r
+\r
+   game_add_move(Game,move);\r
+\r
+   game_get_board(Game,board);\r
+   status = game_status(Game);\r
+\r
+   game_rem_move(Game);\r
+\r
+   if (status != PLAYING) return FALSE; // game ended\r
+\r
+   if (option_get_bool("Book") && is_in_book(board)) {\r
+      return FALSE;\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+// stop_search()\r
+\r
+static void stop_search() {\r
+\r
+   if (Uci->searching) {\r
+\r
+      ASSERT(Uci->searching);\r
+      ASSERT(Uci->pending_nb>=1);\r
+\r
+      my_log("POLYGLOT STOP SEARCH\n");\r
+\r
+/*\r
+      engine_send(Engine,"stop");\r
+      Uci->searching = FALSE;\r
+*/\r
+\r
+      if (option_get_bool("SyncStop")) {\r
+         uci_send_stop_sync(Uci);\r
+      } else {\r
+         uci_send_stop(Uci);\r
+      }\r
+       }\r
+}\r
+\r
+// send_board()\r
+\r
+static void send_board(int extra_move) {\r
+\r
+   char fen[256];\r
+   int start, end;\r
+   board_t board[1];\r
+   int pos;\r
+   int move;\r
+   char string[256];\r
+\r
+   ASSERT(extra_move==MoveNone||move_is_ok(extra_move));\r
+\r
+   ASSERT(!Uci->searching);\r
+\r
+   // init\r
+\r
+   game_get_board(Game,Uci->board);\r
+   if (extra_move != MoveNone) move_do(Uci->board,extra_move);\r
+\r
+   board_to_fen(Uci->board,fen,256);\r
+   my_log("POLYGLOT FEN %s\n",fen);\r
+\r
+   ASSERT(board_can_play(Uci->board));\r
+\r
+   // more init\r
+\r
+   start = 0;\r
+   end = game_pos(Game);\r
+   ASSERT(end>=start);\r
+\r
+   // position\r
+\r
+   game_get_board_ex(Game,board,start);\r
+   board_to_fen(board,string,256);\r
+\r
+   engine_send_queue(Engine,"position");\r
+\r
+   if (my_string_equal(string,StartFen)) {\r
+      engine_send_queue(Engine," startpos");\r
+   } else {\r
+      engine_send_queue(Engine," fen %s",string);\r
+   }\r
+\r
+   // move list\r
+\r
+   if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves");\r
+\r
+   for (pos = start; pos < end; pos++) { // game moves\r
+\r
+      move = game_move(Game,pos);\r
+\r
+      move_to_can(move,board,string,256);\r
+      engine_send_queue(Engine," %s",string);\r
+\r
+      move_do(board,move);\r
+   }\r
+\r
+   if (extra_move != MoveNone) { // move to ponder on\r
+      move_to_can(extra_move,board,string,256);\r
+      engine_send_queue(Engine," %s",string);\r
+   }\r
+\r
+   // end\r
+\r
+   engine_send(Engine,""); // newline\r
+}\r
+\r
+// send_pv()\r
+\r
+static void send_pv() {\r
+\r
+   char pv_string[StringSize];\r
+   board_t board[1];\r
+   int move;\r
+   char move_string[StringSize];\r
+\r
+   ASSERT(State->state!=WAIT);\r
+\r
+   if (Uci->best_depth == 0) return;\r
+\r
+   // xboard search information\r
+\r
+   if (XB->post) {\r
+\r
+      if (State->state == THINK || State->state == ANALYSE) {\r
+\r
+         line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);\r
+\r
+                if(Uci->depth==-1) //hack to clear the engine output window\r
+             gui_send(GUI,"%d %+d %.0f "S64_FORMAT" ",0,report_best_score(),Uci->time*100.0,Uci->node_nb);\r
+\r
+                gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,pv_string);\r
+\r
+      } else if (State->state == PONDER && option_get_bool("ShowPonder")) {\r
+\r
+         game_get_board(Game,board);\r
+         move = State->exp_move;\r
+\r
+         if (move != MoveNone && move_is_legal(move,board)) {\r
+            move_to_san(move,board,move_string,256);\r
+            line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);\r
+            gui_send(GUI,"%d %+d %.0f "S64_FORMAT" (%s) %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,move_string,pv_string);\r
+         }\r
+      }\r
+   }\r
+\r
+   // kibitz\r
+\r
+   if ((Uci->searching && option_get_bool("KibitzPV") && Uci->time >= option_get_double("KibitzDelay"))\r
+    || (!Uci->searching && option_get_bool("KibitzMove"))) {\r
+\r
+      if (State->state == THINK || State->state == ANALYSE) {\r
+\r
+         line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);\r
+         if(kibitz_throttle(Uci->searching)){\r
+             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)report_best_score())/100.0,pv_string);\r
+         }\r
+      } else if (State->state == PONDER) {\r
+\r
+         game_get_board(Game,board);\r
+         move = State->exp_move;\r
+\r
+         if (move != MoveNone && move_is_legal(move,board)) {\r
+            move_to_san(move,board,move_string,256);\r
+            line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize);\r
+            if(kibitz_throttle(Uci->searching)){\r
+                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)report_best_score())/100.0,move_string,pv_string);\r
+            }\r
+         }\r
+      }\r
+   }\r
+}\r
+\r
+// kibitz_throttle()\r
+\r
+static bool kibitz_throttle(bool searching){\r
+    time_t curr_time;\r
+    static time_t lastKibitzMove=0;\r
+    static time_t lastKibitzPV=0;\r
+    curr_time = time(NULL);\r
+    if(searching){   // KibitzPV\r
+        if(curr_time >= (option_get_int("KibitzInterval") + lastKibitzPV)){\r
+            lastKibitzPV=curr_time;\r
+            return TRUE;\r
+        }\r
+    }else{       // KibitzMove\r
+        if(curr_time >= (option_get_int("KibitzInterval") + lastKibitzMove)){\r
+            lastKibitzPV=curr_time;\r
+            lastKibitzMove=curr_time;\r
+            return TRUE;\r
+        }        \r
+    }\r
+    return FALSE;\r
+}\r
+\r
+// learn()\r
+\r
+static void learn(int result) {\r
+\r
+   int pos;\r
+   board_t board[1];\r
+   int move;\r
+\r
+   ASSERT(result>=-1&&result<=+1);\r
+\r
+   ASSERT(XB->result);\r
+   ASSERT(State->computer[White]||State->computer[Black]);\r
+\r
+   // init\r
+\r
+   pos = 0;\r
+\r
+   if (FALSE) {\r
+   } else if (State->computer[White]) {\r
+      pos = 0;\r
+   } else if (State->computer[Black]) {\r
+      pos = 1;\r
+      result = -result;\r
+   } else {\r
+      my_fatal("learn(): unknown side\n");\r
+   }\r
+\r
+   if (FALSE) {\r
+   } else if (result > 0) {\r
+      my_log("POLYGLOT *LEARN WIN*\n");\r
+   } else if (result < 0) {\r
+      my_log("POLYGLOT *LEARN LOSS*\n");\r
+   } else {\r
+      my_log("POLYGLOT *LEARN DRAW*\n");\r
+   }\r
+\r
+   // loop\r
+\r
+   for (; pos < Game->size; pos += 2) {\r
+\r
+      game_get_board_ex(Game,board,pos);\r
+      move = game_move(Game,pos);\r
+\r
+      book_learn_move(board,move,result);\r
+   }\r
+\r
+   book_flush();\r
+}\r
+\r
+// end of adapter.cpp\r