From e15efca6667b2673b4c1a5879a6917eab6800e58 Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Thu, 9 Jun 2011 09:52:55 +0200 Subject: [PATCH] version 1.4.30b --- ChangeLog | 12 + Makefile.am | 2 +- Makefile.in | 49 +-- attack.c | 224 +++++++++ attack.h | 4 +- board.c | 492 ++++++++++++++++++ board.h | 15 +- book.c | 384 ++++++++++++++ book_make.c | 1084 ++++++++++++++++++++++++++++++++++++++++ book_merge.c | 304 +++++++++++ colour.c | 55 ++ colour.h | 17 +- config.h | 6 +- configure | 1174 +++++++++++++------------------------------- configure.ac | 9 +- engine.c | 120 +++++ engine.h | 23 +- epd.c | 444 ++++++++++++++++ fen.c | 392 +++++++++++++++ game.c | 361 +++++++++++++ game.h | 17 +- gui.c | 104 ++++ gui.h | 20 +- hash.c | 128 +++++ hash.h | 16 +- io.c | 334 +++++++++++++ io.h | 8 +- line.c | 205 ++++++++ line.h | 2 +- list.c | 275 ++++++++++ list.h | 12 +- main.c | 384 ++++++++++++++ mainloop.c | 103 ++++ makefile.gcc | 10 +- move.c | 376 ++++++++++++++ move.h | 15 +- move_do.c | 363 ++++++++++++++ move_gen.c | 328 ++++++++++++ move_legal.c | 115 +++++ option.c | 230 +++++++++ option.h | 15 +- parse.c | 264 ++++++++++ parse.h | 10 +- pgn.c | 641 ++++++++++++++++++++++++ pgn.h | 10 +- piece.c | 203 ++++++++ piece.h | 94 ++-- pipex.h | 93 ++++ pipex_posix.c | 255 ++++++++++ pipex_win32.c | 446 +++++++++++++++++ polyglot.spec | 2 +- random.c | 231 +++++++++ random.h | 4 +- san.c | 567 +++++++++++++++++++++ search.c | 252 ++++++++++ search.h | 4 +- square.c | 246 +++++++++ square.h | 126 ++++-- uci.c | 978 ++++++++++++++++++++++++++++++++++++ uci.h | 14 +- uci2uci.c | 247 +++++++++ util.c | 412 +++++++++++++++ util.h | 42 +- xboard2uci.c | 1553 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 64 files changed, 13837 insertions(+), 1088 deletions(-) create mode 100644 attack.c create mode 100644 board.c create mode 100644 book.c create mode 100644 book_make.c create mode 100644 book_merge.c create mode 100644 colour.c create mode 100644 engine.c create mode 100644 epd.c create mode 100644 fen.c create mode 100644 game.c create mode 100644 gui.c create mode 100644 hash.c create mode 100644 io.c create mode 100644 line.c create mode 100644 list.c create mode 100644 main.c create mode 100644 mainloop.c create mode 100644 move.c create mode 100644 move_do.c create mode 100644 move_gen.c create mode 100644 move_legal.c create mode 100644 option.c create mode 100644 parse.c create mode 100644 pgn.c create mode 100644 piece.c create mode 100644 pipex.h create mode 100644 pipex_posix.c create mode 100644 pipex_win32.c create mode 100644 random.c create mode 100644 san.c create mode 100644 search.c create mode 100644 square.c create mode 100644 uci.c create mode 100644 uci2uci.c create mode 100644 util.c create mode 100644 xboard2uci.c diff --git a/ChangeLog b/ChangeLog index 5198de5..ba23d6d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +=========1.4.30b================ +- Some more meaningful error messages added. +- Some buffer overflow checks added. +- Simplification of strange signal kludge in gui.c. +- 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 +- The format of the version number has changed once again. Debian was unhappy with the previous one. +=========1.4b29================ +- Conversion from C++ to C (suggested by E.M.) +- More refactoring. The win32 and posix I/O now have a uniform interface (see pipex.h). +=========1.4b28================ +- Some comments added to explain the exact behaviour of some of the public functions in pipe.cpp. +- LineInput now returns a bool which is FALSE in case of EOF. =========1.4b27================ - Option "ScoreWhite" : report score from white's point of view (suggested by E.M.). - Option "KibitzInterval" : try to wait this many seconds between kibitzes (suggested by E.M.) diff --git a/Makefile.am b/Makefile.am index 251418c..6fc2377 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/Makefile.in b/Makefile.in index 0db7deb..131f851 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 index 0000000..ecaa14a --- /dev/null +++ b/attack.c @@ -0,0 +1,224 @@ + +// attack.c + +// includes + +#include "board.h" +#include "colour.h" +#include "move.h" +#include "attack.h" +#include "piece.h" +#include "util.h" + +// macros + +#define DELTA_INC(delta) (DeltaInc[128+(delta)]) +#define DELTA_MASK(delta) (DeltaMask[128+(delta)]) + +// "constants" + +const sint8 KnightInc[8+1] = { + -33, -31, -18, -14, +14, +18, +31, +33, 0 +}; + +const sint8 BishopInc[4+1] = { + -17, -15, +15, +17, 0 +}; + +const sint8 RookInc[4+1] = { + -16, -1, +1, +16, 0 +}; + +const sint8 QueenInc[8+1] = { + -17, -16, -15, -1, +1, +15, +16, +17, 0 +}; + +const sint8 KingInc[8+1] = { + -17, -16, -15, -1, +1, +15, +16, +17, 0 +}; + +// variables + +static sint8 DeltaInc[256]; +static uint8 DeltaMask[256]; + +// prototypes + +static bool delta_is_ok (int delta); +static bool inc_is_ok (int inc); + +// functions + +// attack_init() + +void attack_init() { + + int delta; + int dir, inc, dist; + + for (delta = -128; delta < +128; delta++) { + DeltaInc[128+delta] = IncNone; + DeltaMask[128+delta] = 0; + } + + DeltaMask[128-17] |= BlackPawnFlag; + DeltaMask[128-15] |= BlackPawnFlag; + + DeltaMask[128+15] |= WhitePawnFlag; + DeltaMask[128+17] |= WhitePawnFlag; + + for (dir = 0; dir < 8; dir++) { + delta = KnightInc[dir]; + ASSERT(delta_is_ok(delta)); + DeltaMask[128+delta] |= KnightFlag; + } + + for (dir = 0; dir < 4; dir++) { + inc = BishopInc[dir]; + ASSERT(inc!=IncNone); + for (dist = 1; dist < 8; dist++) { + delta = inc*dist; + ASSERT(delta_is_ok(delta)); + ASSERT(DeltaInc[128+delta]==IncNone); + DeltaInc[128+delta] = inc; + DeltaMask[128+delta] |= BishopFlag; + } + } + + for (dir = 0; dir < 4; dir++) { + inc = RookInc[dir]; + ASSERT(inc!=IncNone); + for (dist = 1; dist < 8; dist++) { + delta = inc*dist; + ASSERT(delta_is_ok(delta)); + ASSERT(DeltaInc[128+delta]==IncNone); + DeltaInc[128+delta] = inc; + DeltaMask[128+delta] |= RookFlag; + } + } + + for (dir = 0; dir < 8; dir++) { + delta = KingInc[dir]; + ASSERT(delta_is_ok(delta)); + DeltaMask[128+delta] |= KingFlag; + } +} + +// delta_is_ok() + +static bool delta_is_ok(int delta) { + + if (delta < -119 || delta > +119) return FALSE; + + return TRUE; +} + +// inc_is_ok() + +static bool inc_is_ok(int inc) { + + int dir; + + for (dir = 0; dir < 8; dir++) { + if (KingInc[dir] == inc) return TRUE; + } + + return FALSE; +} + +// is_in_check() + +bool is_in_check(const board_t * board, int colour) { + + ASSERT(board_is_ok(board)); + ASSERT(colour_is_ok(colour)); + + return is_attacked(board,king_pos(board,colour),colour_opp(colour)); +} + +// is_attacked() + +bool is_attacked(const board_t * board, int to, int colour) { + + const uint8 * ptr; + int from, piece; + + ASSERT(board_is_ok(board)); + ASSERT(square_is_ok(to)); + ASSERT(colour_is_ok(colour)); + + for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { + + piece = board->square[from]; + ASSERT(colour_equal(piece,colour)); + + if (piece_attack(board,piece,from,to)) return TRUE; + } + + return FALSE; +} + +// piece_attack() + +bool piece_attack(const board_t * board, int piece, int from, int to) { + + int delta; + int inc, sq; + + ASSERT(board_is_ok(board)); + ASSERT(piece_is_ok(piece)); + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + + delta = to - from; + ASSERT(delta_is_ok(delta)); + + if ((piece & DELTA_MASK(delta)) == 0) return FALSE; // no pseudo-attack + + if (!piece_is_slider(piece)) return TRUE; + + inc = DELTA_INC(delta); + ASSERT(inc_is_ok(inc)); + + for (sq = from+inc; sq != to; sq += inc) { + ASSERT(square_is_ok(sq)); + if (board->square[sq] != Empty) return FALSE; // blocker + } + + return TRUE; +} + +// is_pinned() + +bool is_pinned(const board_t * board, int from, int to, int colour) { + + int king; + int inc; + int sq, piece; + + ASSERT(board!=NULL); + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + ASSERT(colour_is_ok(colour)); + + king = king_pos(board,colour); + + inc = DELTA_INC(king-from); + if (inc == IncNone) return FALSE; // not a line + + sq = from; + do sq += inc; while (board->square[sq] == Empty); + + if (sq != king) return FALSE; // blocker + + sq = from; + do sq -= inc; while ((piece=board->square[sq]) == Empty); + + return square_is_ok(sq) + && (piece & DELTA_MASK(king-sq)) != 0 + && piece_colour(piece) == colour_opp(colour) + && DELTA_INC(king-to) != inc; +} + +// end of attack.cpp + diff --git a/attack.h b/attack.h index 7e664a6..c111cdc 100644 --- a/attack.h +++ b/attack.h @@ -9,9 +9,9 @@ #include "board.h" #include "util.h" -// constants +// defines -const int IncNone = 0; +#define IncNone 0 // "constants" diff --git a/board.c b/board.c new file mode 100644 index 0000000..b17d354 --- /dev/null +++ b/board.c @@ -0,0 +1,492 @@ + +// board.c + +// includes + +#include + +#include "attack.h" +#include "board.h" +#include "colour.h" +#include "fen.h" +#include "hash.h" +#include "list.h" +#include "move.h" +#include "move_do.h" +#include "move_gen.h" +#include "move_legal.h" +#include "piece.h" +#include "util.h" + +// constants + +static const bool UseSlowDebug = FALSE; + +// functions + +// board_is_ok() + +bool board_is_ok(const board_t * board) { + + int sq, piece; + int colour, pos; + int king, rook; + + if (board == NULL) return FALSE; + + // optional heavy DEBUG mode + + if (!UseSlowDebug) return TRUE; + + // squares + + for (sq = 0; sq < SquareNb; sq++) { + piece = board->square[sq]; + if (square_is_ok(sq)) { + pos = board->pos[sq]; + if (piece == Empty) { + if (pos != -1) return FALSE; + } else { + if (pos < 0) return FALSE; + if (board->list[piece_colour(piece)][pos] != sq) return FALSE; + } + } else { + if (piece != Knight64) return FALSE; + } + } + + // white piece list + + colour = White; + pos = 0; + + if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return FALSE; + + sq = board->list[colour][pos]; + if (sq == SquareNone) return FALSE; + if (board->pos[sq] != pos) return FALSE; + piece = board->square[sq]; + if (!colour_equal(piece,colour) || !piece_is_king(piece)) return FALSE; + + for (pos++; pos < board->list_size[colour]; pos++) { + sq = board->list[colour][pos]; + if (sq == SquareNone) return FALSE; + if (board->pos[sq] != pos) return FALSE; + if (!colour_equal(board->square[sq],colour)) return FALSE; + } + + sq = board->list[colour][pos]; + if (sq != SquareNone) return FALSE; + + // black piece list + + colour = Black; + pos = 0; + + if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return FALSE; + + sq = board->list[colour][pos]; + if (sq == SquareNone) return FALSE; + if (board->pos[sq] != pos) return FALSE; + piece = board->square[sq]; + if (!colour_equal(piece,colour) || !piece_is_king(piece)) return FALSE; + + for (pos++; pos < board->list_size[colour]; pos++) { + sq = board->list[colour][pos]; + if (sq == SquareNone) return FALSE; + if (board->pos[sq] != pos) return FALSE; + if (!colour_equal(board->square[sq],colour)) return FALSE; + } + + sq = board->list[colour][pos]; + if (sq != SquareNone) return FALSE; + + // TODO: material + + if (board->number[WhiteKing12] != 1) return FALSE; + if (board->number[BlackKing12] != 1) return FALSE; + + if (!colour_is_ok(board->turn)) return FALSE; + + // castling status + + if (board->castle[White][SideH] != SquareNone) { + + king = board->list[White][0]; + if ((king < A1) || (king > H1)) return FALSE; + if (board->square[king] != WhiteKing256) return FALSE; + + rook = board->castle[White][SideH]; + if ((rook < A1) || (rook > H1)) return FALSE; + if (board->square[rook] != WhiteRook256) return FALSE; + + if (rook <= king) return FALSE; + } + + if (board->castle[White][SideA] != SquareNone) { + + king = board->list[White][0]; + if ((king < A1) || (king > H1)) return FALSE; + if (board->square[king] != WhiteKing256) return FALSE; + + rook = board->castle[White][SideA]; + if ((rook < A1) || (rook > H1)) return FALSE; + if (board->square[rook] != WhiteRook256) return FALSE; + + if (rook >= king) return FALSE; + } + + if (board->castle[Black][SideH] != SquareNone) { + + king = board->list[Black][0]; + if ((king < A8) || (king > H8)) return FALSE; + if (board->square[king] != BlackKing256) return FALSE; + + rook = board->castle[Black][SideH]; + if ((rook < A8) || (rook > H8)) return FALSE; + if (board->square[rook] != BlackRook256) return FALSE; + + if (rook <= king) return FALSE; + } + + if (board->castle[Black][SideA] != SquareNone) { + + king = board->list[Black][0]; + if (king < A8 || king > H8) return FALSE; + if (board->square[king] != BlackKing256) return FALSE; + + rook = board->castle[Black][SideA]; + if (rook < A8 || rook > H8) return FALSE; + if (board->square[rook] != BlackRook256) return FALSE; + + if (rook >= king) return FALSE; + } + + return TRUE; +} + +// board_clear() + +void board_clear(board_t * board) { + + int file, rank, sq; + int colour, pos; + int piece; + + ASSERT(board!=NULL); + + // edge squares + + for (sq = 0; sq < SquareNb; sq++) { + board->square[sq] = Knight64; // HACK: uncoloured knight + board->pos[sq] = -1; + } + + // empty squares + + for (rank = 0; rank < 8; rank++) { + for (file = 0; file < 8; file++) { + sq = square_make(file,rank); + board->square[sq] = Empty; + } + } + + // piece lists + + for (colour = 0; colour < 3; colour++) { + for (pos = 0; pos < 32; pos++) { // HACK + board->list[colour][pos] = SquareNone; + } + board->list_size[colour] = 0; + } + + // material + + for (piece = 0; piece < 12; piece++) { + board->number[piece] = 0; + } + + // rest + + board->turn = ColourNone; + board->castle[White][SideH] = SquareNone; + board->castle[White][SideA] = SquareNone; + board->castle[Black][SideH] = SquareNone; + board->castle[Black][SideA] = SquareNone; + board->ep_square = SquareNone; + + board->ply_nb = 0; + board->move_nb = 0; + + board->key = 0; +} + +// board_start() + +void board_start(board_t * board) { + + ASSERT(board!=NULL); + + if (!board_from_fen(board,StartFen)) ASSERT(FALSE); +} + +// board_copy() + +void board_copy(board_t * dst, const board_t * src) { + + ASSERT(dst!=NULL); + ASSERT(board_is_ok(src)); + + *dst = *src; +} + +// board_equal() + +bool board_equal(const board_t * board_1, const board_t * board_2) { + + int sq_64, sq; + + ASSERT(board_is_ok(board_1)); + ASSERT(board_is_ok(board_2)); + + // fast comparison + + if (board_1->key != board_2->key) return FALSE; + + // slow comparison + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + if (board_1->square[sq] != board_2->square[sq]) return FALSE; + } + + if (board_1->turn != board_2->turn) return FALSE; + if (board_1->castle[White][SideH] != board_2->castle[White][SideH]) return FALSE; + if (board_1->castle[White][SideA] != board_2->castle[White][SideA]) return FALSE; + if (board_1->castle[Black][SideH] != board_2->castle[Black][SideH]) return FALSE; + if (board_1->castle[Black][SideA] != board_2->castle[Black][SideA]) return FALSE; + if (board_1->ep_square != board_2->ep_square) return FALSE; + + return TRUE; +} + +// board_init_list() + +void board_init_list(board_t * board) { + + int sq_64, sq, piece; + int colour, pos; + + ASSERT(board!=NULL); + + // init + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + board->pos[sq] = -1; + } + + for (piece = 0; piece < 12; piece++) board->number[piece] = 0; + + // white piece list + + colour = White; + pos = 0; + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + piece = board->square[sq]; + ASSERT(pos>=0&&pos<=16); + if (colour_equal(piece,colour) && piece_is_king(piece)) { + board->pos[sq] = pos; + board->list[colour][pos] = sq; + pos++; + board->number[piece_to_12(piece)]++; + } + } + ASSERT(pos==1); + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + piece = board->square[sq]; + ASSERT(pos>=0&&pos<=16); + if (colour_equal(piece,colour) && !piece_is_king(piece)) { + board->pos[sq] = pos; + board->list[colour][pos] = sq; + pos++; + board->number[piece_to_12(piece)]++; + } + } + + ASSERT(pos>=1&&pos<=16); + board->list[colour][pos] = SquareNone; + board->list_size[colour] = pos; + + // black piece list + + colour = Black; + pos = 0; + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + piece = board->square[sq]; + ASSERT(pos>=0&&pos<=16); + if (colour_equal(piece,colour) && piece_is_king(piece)) { + board->pos[sq] = pos; + board->list[colour][pos] = sq; + pos++; + board->number[piece_to_12(piece)]++; + } + } + ASSERT(pos==1); + + for (sq_64 = 0; sq_64 < 64; sq_64++) { + sq = square_from_64(sq_64); + piece = board->square[sq]; + ASSERT(pos>=1&&pos<=16); + if (colour_equal(piece,colour) && !piece_is_king(piece)) { + board->pos[sq] = pos; + board->list[colour][pos] = sq; + pos++; + board->number[piece_to_12(piece)]++; + } + } + + ASSERT(pos>=1&&pos<=16); + board->list[colour][pos] = SquareNone; + board->list_size[colour] = pos; + + // hash key + + board->key = hash_key(board); +} + +// board_flags() + +int board_flags(const board_t * board) { + + int flags; + + flags = 0; + + if (board->castle[White][SideH] != SquareNone) flags |= 1 << 0; + if (board->castle[White][SideA] != SquareNone) flags |= 1 << 1; + if (board->castle[Black][SideH] != SquareNone) flags |= 1 << 2; + if (board->castle[Black][SideA] != SquareNone) flags |= 1 << 3; + + return flags; +} + +// board_can_play() + +bool board_can_play(const board_t * board) { + + list_t list[1]; + int i, move; + + ASSERT(board_is_ok(board)); + + gen_moves(list,board); + + for (i = 0; i < list_size(list); i++) { + move = list_move(list,i); + if (pseudo_is_legal(move,board)) return TRUE; + } + + return FALSE; // no legal move +} + +// board_mobility() + +int board_mobility(const board_t * board) { + + list_t list[1]; + + ASSERT(board_is_ok(board)); + + gen_legal_moves(list,board); + + return list_size(list); +} + +// board_is_check() + +bool board_is_check(const board_t * board) { + + ASSERT(board_is_ok(board)); + + return is_in_check(board,board->turn); +} + +// board_is_mate() + +bool board_is_mate(const board_t * board) { + + ASSERT(board_is_ok(board)); + + if (!board_is_check(board)) return FALSE; + if (board_can_play(board)) return FALSE; + + return TRUE; +} + +// board_is_stalemate() + +bool board_is_stalemate(const board_t * board) { + + ASSERT(board_is_ok(board)); + + if (board_is_check(board)) return FALSE; + if (board_can_play(board)) return FALSE; + + return TRUE; +} + +// king_pos() + +int king_pos(const board_t * board, int colour) { + + ASSERT(board_is_ok(board)); + ASSERT(colour_is_ok(colour)); + + return board->list[colour][0]; +} + +// board_disp() + +void board_disp(const board_t * board) { + + int file, rank, sq; + int piece, c; + char fen[256]; + + ASSERT(board!=NULL); + + if (!board_to_fen(board,fen,256)) ASSERT(FALSE); + my_log("POLYGLOT %s\n",fen); + my_log("POLYGLOT\n"); + + for (rank = 7; rank >= 0; rank--) { + + my_log("POLYGLOT "); + + for (file = 0; file < 8; file++) { + + sq = square_make(file,rank); + piece = board->square[sq]; + + c = (piece != Empty) ? piece_to_char(piece) : '-'; + my_log("%c ",c); + } + + my_log("\n"); + } + + my_log("POLYGLOT\n"); + + my_log("POLYGLOT %s to play\n",(colour_is_black(board->turn))?"black":"white"); + my_log("POLYGLOT\n"); +} + +// end of board.cpp + diff --git a/board.h b/board.h index 9a9a503..4223e83 100644 --- a/board.h +++ b/board.h @@ -10,17 +10,16 @@ #include "square.h" #include "util.h" -// constants +// defines -const int Empty = 0; - -const int SideH = 0; -const int SideA = 1; -const int SideNb = 2; +#define Empty 0 +#define SideH 0 +#define SideA 1 +#define SideNb 2 // types -struct board_t { +typedef struct { uint8 square[SquareNb]; sint8 pos[SquareNb]; @@ -38,7 +37,7 @@ struct board_t { sint16 move_nb; uint64 key; -}; +} board_t; // functions diff --git a/book.c b/book.c new file mode 100644 index 0000000..73fb2d2 --- /dev/null +++ b/book.c @@ -0,0 +1,384 @@ + +// book.c + +// includes + +#include +#include +#include +#include + +#include "board.h" +#include "book.h" +#include "move.h" +#include "move_legal.h" +#include "san.h" +#include "util.h" +#include "option.h" + +// types + +typedef struct { + uint64 key; + uint16 move; + uint16 count; + uint16 n; + uint16 sum; +} entry_t; + +// variables + +static FILE * BookFile; +static int BookSize; + +// prototypes + +static int find_pos (uint64 key); + +static void read_entry (entry_t * entry, int n); +static void write_entry (const entry_t * entry, int n); + +static uint64 read_integer (FILE * file, int size); +static void write_integer (FILE * file, int size, uint64 n); + +// functions + +// book_clear() + +void book_clear() { + + BookFile = NULL; + BookSize = 0; +} + +bool book_is_open(){ + return BookFile!=NULL; +} + +// book_open() + +void book_open(const char file_name[]) { + + ASSERT(file_name!=NULL); + if(option_get_bool("BookLearn")){ + BookFile = fopen(file_name,"rb+"); + }else{ + BookFile = fopen(file_name,"rb"); + } + +// if (BookFile == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); + if (BookFile == NULL) return; + + if (fseek(BookFile,0,SEEK_END) == -1) { + my_fatal("book_open(): fseek(): %s\n",strerror(errno)); + } + + BookSize = ftell(BookFile) / 16; +// if (BookSize == 0) my_fatal("book_open(): empty file\n"); + if (BookSize == 0) { + book_close(); + book_clear(); + }; +} + +// book_close() + +void book_close() { + + if(BookFile==NULL) return; + + if (fclose(BookFile) == EOF) { + my_fatal("book_close(): fclose(): %s\n",strerror(errno)); + } +} + +// is_in_book() + +bool is_in_book(const board_t * board) { + + int pos; + entry_t entry[1]; + + if(BookFile==NULL) return FALSE; + + ASSERT(board!=NULL); + + for (pos = find_pos(board->key); pos < BookSize; pos++) { + read_entry(entry,pos); + if (entry->key == board->key) return TRUE; + } + + return FALSE; +} + +// book_move() + +int book_move(const board_t * board, bool random) { + + int best_move; + int best_score; + int pos; + entry_t entry[1]; + int move; + int score; + + if(BookFile==NULL) return MoveNone; + + ASSERT(board!=NULL); + ASSERT(random==TRUE||random==FALSE); + + + best_move = MoveNone; + best_score = 0; + for (pos = find_pos(board->key); pos < BookSize; pos++) { + + read_entry(entry,pos); + if (entry->key != board->key) break; + + move = entry->move; + score = entry->count; + + if (move != MoveNone && move_is_legal(move,board)) { + + // pick this move? + + ASSERT(score>0); + + if (random) { + best_score += score; + if (my_random_int(best_score) < score) best_move = move; + } else { + if (score > best_score) { + best_move = move; + best_score = score; + } + } + + } else { + + ASSERT(FALSE); + } + } + + return best_move; +} + +// book_disp() + +void book_disp(const board_t * board) { + + int first_pos; + int sum; + int pos; + entry_t entry[1]; + int move; + int score; + char move_string[256]; + + ASSERT(board!=NULL); + + if(BookFile==NULL) return; + + first_pos = find_pos(board->key); + + // sum + + sum = 0; + + for (pos = first_pos; pos < BookSize; pos++) { + + read_entry(entry,pos); + if (entry->key != board->key) break; + + sum += entry->count; + } + + // disp + + for (pos = first_pos; pos < BookSize; pos++) { + + read_entry(entry,pos); + if (entry->key != board->key) break; + + move = entry->move; + score = entry->count; + + if (score > 0 && move != MoveNone && move_is_legal(move,board)) { + move_to_san(move,board,move_string,256); + printf(" %s (%.0f%%)\n",move_string,((double)score)/((double)sum)*100.0); + } + } + + printf("\n"); +} + +// book_learn_move() + +void book_learn_move(const board_t * board, int move, int result) { + + int pos; + entry_t entry[1]; + + if(BookFile==NULL) return; + + ASSERT(board!=NULL); + ASSERT(move_is_ok(move)); + ASSERT(result>=-1&&result<=+1); + + ASSERT(move_is_legal(move,board)); + + for (pos = find_pos(board->key); pos < BookSize; pos++) { + + read_entry(entry,pos); + if (entry->key != board->key) break; + + if (entry->move == move) { + + entry->n++; + entry->sum += result+1; + + write_entry(entry,pos); + + break; + } + } +} + +// book_flush() + +void book_flush() { + + if(BookFile==NULL) return; + + if (fflush(BookFile) == EOF) { + my_fatal("book_flush(): fflush(): %s\n",strerror(errno)); + } +} + +// find_pos() + +static int find_pos(uint64 key) { + + int left, right, mid; + entry_t entry[1]; + + // binary search (finds the leftmost entry) + + left = 0; + right = BookSize-1; + + ASSERT(left<=right); + + while (left < right) { + + mid = (left + right) / 2; + ASSERT(mid>=left&&midkey) { + right = mid; + } else { + left = mid+1; + } + } + + ASSERT(left==right); + + read_entry(entry,left); + + return (entry->key == key) ? left : BookSize; +} + +// read_entry() + +static void read_entry(entry_t * entry, int n) { + + ASSERT(entry!=NULL); + ASSERT(n>=0&&nkey = read_integer(BookFile,8); + entry->move = read_integer(BookFile,2); + entry->count = read_integer(BookFile,2); + entry->n = read_integer(BookFile,2); + entry->sum = read_integer(BookFile,2); +} + +// write_entry() + +static void write_entry(const entry_t * entry, int n) { + + ASSERT(entry!=NULL); + ASSERT(n>=0&&nkey); + write_integer(BookFile,2,entry->move); + write_integer(BookFile,2,entry->count); + write_integer(BookFile,2,entry->n); + write_integer(BookFile,2,entry->sum); +} + +// read_integer() + +static uint64 read_integer(FILE * file, int size) { + + uint64 n; + int i; + int b; + + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + + n = 0; + + for (i = 0; i < size; i++) { + + b = fgetc(file); + + if (b == EOF) { + if (feof(file)) { + my_fatal("read_integer(): fgetc(): EOF reached\n"); + } else { // error + my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); + } + } + + ASSERT(b>=0&&b<256); + n = (n << 8) | b; + } + + return n; +} + +// write_integer() + +static void write_integer(FILE * file, int size, uint64 n) { + + int i; + int b; + + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + ASSERT(size==8||n>>(size*8)==0); + + for (i = size-1; i >= 0; i--) { + + b = (n >> (i*8)) & 0xFF; + ASSERT(b>=0&&b<256); + + if (fputc(b,file) == EOF) { + my_fatal("write_integer(): fputc(): %s\n",strerror(errno)); + } + } +} + +// end of book.cpp + diff --git a/book_make.c b/book_make.c new file mode 100644 index 0000000..ac9a66c --- /dev/null +++ b/book_make.c @@ -0,0 +1,1084 @@ +// book_make.c + +// includes + +#include +#include +#include +#include +#include + +#include "board.h" +#include "book_make.h" +#include "move.h" +#include "move_do.h" +#include "move_gen.h" +#include "move_legal.h" +#include "pgn.h" +#include "san.h" +#include "util.h" + +// constants + +static const int COUNT_MAX = 16384; +static const int StringSize = 4096; + +static const int NIL = -1; + +// defines + +#define opp_search(s) ((s)==BOOK?ALL:BOOK) + +// types + +typedef struct { + uint64 key; + uint16 move; + uint16 count; +// Unfortunately the minggw32 cross compiler [4.2.1-sjlj (mingw32-2)] +// seems to have a bug with anon structs contained in unions when using -O2. +// See the ASSERT below in "read_entry_file"... +// To be fair this seems to be illegal in C++ +// although it is hard to understand why, and the compiler does not complain +// even with -Wall. +// union { +// struct { + uint16 n; + uint16 sum; +// }; +// struct { + uint8 height; + int line; +// }; +// }; + uint8 colour; +} entry_t; + +typedef struct { + int size; + int alloc; + uint32 mask; + entry_t * entry; + sint32 * hash; +} book_t; + +typedef enum { + BOOK, + ALL +} search_t; + +typedef struct { + int height; + int line; + int initial_color; + bool book_trans_only; + bool extended_search; + uint16 moves[1024]; + double probs[1024]; + uint64 keys[1024]; + FILE *output; +} info_t; + + +// variables + +static int MaxPly; +static int MinGame; +static double MinScore; +static bool RemoveWhite, RemoveBlack; +static bool Uniform; +static bool Quiet=FALSE; + +static book_t Book[1]; + +// prototypes + +static void book_clear (); +static void book_insert (const char file_name[]); +static void book_filter (); +static void book_sort (); +static void book_save (const char file_name[]); + +static int find_entry (const board_t * board, int move); +static void resize (); +static void halve_stats (uint64 key); + +static bool keep_entry (int pos); + +static int entry_score (const entry_t * entry); + +static int key_compare (const void * p1, const void * p2); + +static void write_integer (FILE * file, int size, uint64 n); +static uint64 read_integer(FILE * file, int size); + +static void read_entry_file(FILE *f, entry_t *entry); +static void write_entry_file(FILE * f, const entry_t * entry); + +// functions + +// book_make() + +void book_make(int argc, char * argv[]) { + + int i; + const char * pgn_file; + const char * bin_file; + + pgn_file = NULL; + my_string_set(&pgn_file,"book.pgn"); + + bin_file = NULL; + my_string_set(&bin_file,"book.bin"); + + MaxPly = 1024; + MinGame = 3; + MinScore = 0.0; + RemoveWhite = FALSE; + RemoveBlack = FALSE; + Uniform = FALSE; + + for (i = 1; i < argc; i++) { + + if (FALSE) { + + } else if (my_string_equal(argv[i],"make-book")) { + + // skip + + } else if (my_string_equal(argv[i],"-pgn")) { + + i++; + if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); + + my_string_set(&pgn_file,argv[i]); + + } else if (my_string_equal(argv[i],"-bin")) { + + i++; + if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); + + my_string_set(&bin_file,argv[i]); + + } else if (my_string_equal(argv[i],"-max-ply")) { + + i++; + if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); + + MaxPly = atoi(argv[i]); + ASSERT(MaxPly>=0); + + } else if (my_string_equal(argv[i],"-min-game")) { + + i++; + if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); + + MinGame = atoi(argv[i]); + ASSERT(MinGame>0); + + } else if (my_string_equal(argv[i],"-min-score")) { + + i++; + if (argv[i] == NULL) my_fatal("book_make(): missing argument\n"); + + MinScore = atof(argv[i]) / 100.0; + ASSERT(MinScore>=0.0&&MinScore<=1.0); + + } else if (my_string_equal(argv[i],"-only-white")) { + + RemoveWhite = FALSE; + RemoveBlack = TRUE; + + } else if (my_string_equal(argv[i],"-only-black")) { + + RemoveWhite = TRUE; + RemoveBlack = FALSE; + + } else if (my_string_equal(argv[i],"-uniform")) { + + Uniform = TRUE; + + } else { + + my_fatal("book_make(): unknown option \"%s\"\n",argv[i]); + } + } + + book_clear(); + + printf("inserting games ...\n"); + book_insert(pgn_file); + + printf("filtering entries ...\n"); + book_filter(); + + printf("sorting entries ...\n"); + book_sort(); + + printf("saving entries ...\n"); + book_save(bin_file); + + printf("all done!\n"); +} + +// book_clear() + +static void book_clear() { + + int index; + + Book->alloc = 1; + Book->mask = (Book->alloc * 2) - 1; + + Book->entry = (entry_t *) my_malloc(Book->alloc*sizeof(entry_t)); + Book->size = 0; + + Book->hash = (sint32 *) my_malloc((Book->alloc*2)*sizeof(sint32)); + for (index = 0; index < Book->alloc*2; index++) { + Book->hash[index] = NIL; + } +} + +// book_insert() + +static void book_insert(const char file_name[]) { + + pgn_t pgn[1]; + board_t board[1]; + int ply; + int result; + char string[256]; + int move; + int pos; + + ASSERT(file_name!=NULL); + + // init + + pgn->game_nb=1; + // scan loop + + pgn_open(pgn,file_name); + + while (pgn_next_game(pgn)) { + + board_start(board); + ply = 0; + result = 0; + + if (FALSE) { + } else if (my_string_equal(pgn->result,"1-0")) { + result = +1; + } else if (my_string_equal(pgn->result,"0-1")) { + result = -1; + } + + while (pgn_next_move(pgn,string,256)) { + + if (ply < MaxPly) { + + move = move_from_san(string,board); + + if (move == MoveNone || !move_is_legal(move,board)) { + 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); + } + + pos = find_entry(board,move); + + Book->entry[pos].n++; + Book->entry[pos].sum += result+1; + + if (Book->entry[pos].n >= COUNT_MAX) { + halve_stats(board->key); + } + + move_do(board,move); + ply++; + result = -result; + } + } + pgn->game_nb++; + if (pgn->game_nb % 10000 == 0) printf("%d games ...\n",pgn->game_nb); + } + + pgn_close(pgn); + + printf("%d game%s.\n",pgn->game_nb,(pgn->game_nb>2)?"s":""); + printf("%d entries.\n",Book->size); + + return; +} + +// book_filter() + +static void book_filter() { + + int src, dst; + + // entry loop + + dst = 0; + + for (src = 0; src < Book->size; src++) { + if (keep_entry(src)) Book->entry[dst++] = Book->entry[src]; + } + + ASSERT(dst>=0&&dst<=Book->size); + Book->size = dst; + + printf("%d entries.\n",Book->size); +} + +// book_sort() + +static void book_sort() { + + // sort keys for binary search + + qsort(Book->entry,Book->size,sizeof(entry_t),&key_compare); +} + +// book_save() + +static void book_save(const char file_name[]) { + + FILE * file; + int pos; + + ASSERT(file_name!=NULL); + + file = fopen(file_name,"wb"); + if (file == NULL) my_fatal("book_save(): can't open file \"%s\" for writing: %s\n",file_name,strerror(errno)); + + // entry loop + + for (pos = 0; pos < Book->size; pos++) { + + ASSERT(keep_entry(pos)); + + write_integer(file,8,Book->entry[pos].key); + write_integer(file,2,Book->entry[pos].move); + write_integer(file,2,entry_score(&Book->entry[pos])); + write_integer(file,2,0); + write_integer(file,2,0); + } + + fclose(file); +} + +// find_entry() + +static int find_entry(const board_t * board, int move) { + + uint64 key; + int index; + int pos; + + ASSERT(board!=NULL); + ASSERT(move==MoveNone || move_is_ok(move)); + + ASSERT(move==MoveNone || move_is_legal(move,board)); + + // init + + key = board->key; + + // search + + for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) { + + ASSERT(pos>=0&&possize); + + if (Book->entry[pos].key == key && Book->entry[pos].move == move) { + return pos; // found + } + } + + // not found + + ASSERT(Book->size<=Book->alloc); + + if (Book->size == Book->alloc) { + + // allocate more memory + + resize(); + + for (index = key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask) + ; + } + + // create a new entry + + ASSERT(Book->sizealloc); + pos = Book->size++; + + Book->entry[pos].key = key; + Book->entry[pos].move = move; + Book->entry[pos].n = 0; + Book->entry[pos].sum = 0; + Book->entry[pos].colour = board->turn; + + // insert into the hash table + + ASSERT(index>=0&&indexalloc*2); + ASSERT(Book->hash[index]==NIL); + Book->hash[index] = pos; + + ASSERT(pos>=0&&possize); + + return pos; +} + +// rebuild_hash_table + +static void rebuild_hash_table(){ + int index,pos; + for (index = 0; index < Book->alloc*2; index++) { + Book->hash[index] = NIL; + } + for (pos = 0; pos < Book->size; pos++) { + for (index = Book->entry[pos].key & (uint64) Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask) + ; + ASSERT(index>=0&&indexalloc*2); + Book->hash[index] = pos; + } +} + +static void resize() { + + int size; + + ASSERT(Book->size==Book->alloc); + + Book->alloc *= 2; + Book->mask = (Book->alloc * 2) - 1; + + size = 0; + size += Book->alloc * sizeof(entry_t); + size += (Book->alloc*2) * sizeof(sint32); + + if (size >= 1048576) if(!Quiet){ + printf("allocating %gMB ...\n",((double)size)/1048576.0); + } + + // resize arrays + + Book->entry = (entry_t *) my_realloc(Book->entry,Book->alloc*sizeof(entry_t)); + Book->hash = (sint32 *) my_realloc(Book->hash,(Book->alloc*2)*sizeof(sint32)); + + // rebuild hash table + + rebuild_hash_table(); +} + + +// halve_stats() + +static void halve_stats(uint64 key) { + + int index; + int pos; + + // search + + for (index = key & (uint64) Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) { + + ASSERT(pos>=0&&possize); + + if (Book->entry[pos].key == key) { + Book->entry[pos].n = (Book->entry[pos].n + 1) / 2; + Book->entry[pos].sum = (Book->entry[pos].sum + 1) / 2; + } + } +} + +// keep_entry() + +static bool keep_entry(int pos) { + + const entry_t * entry; + int colour; + double score; + + ASSERT(pos>=0&&possize); + + entry = &Book->entry[pos]; + + // if (entry->n == 0) return FALSE; + if (entry->n < MinGame) return FALSE; + + if (entry->sum == 0) return FALSE; + + score = (((double)entry->sum) / ((double)entry->n)) / 2.0; + ASSERT(score>=0.0&&score<=1.0); + + if (score < MinScore) return FALSE; + + colour = entry->colour; + + if ((RemoveWhite && colour_is_white(colour)) + || (RemoveBlack && colour_is_black(colour))) { + return FALSE; + } + + if (entry_score(entry) == 0) return FALSE; // REMOVE ME? + + return TRUE; +} + +// entry_score() + +static int entry_score(const entry_t * entry) { + + int score; + + ASSERT(entry!=NULL); + + // score = entry->n; // popularity + score = entry->sum; // "expectancy" + + if (Uniform) score = 1; + + ASSERT(score>=0); + + return score; +} + +// key_compare() + +static int key_compare(const void * p1, const void * p2) { + + const entry_t * entry_1, * entry_2; + + ASSERT(p1!=NULL); + ASSERT(p2!=NULL); + + entry_1 = (const entry_t *) p1; + entry_2 = (const entry_t *) p2; + + if (entry_1->key > entry_2->key) { + return +1; + } else if (entry_1->key < entry_2->key) { + return -1; + } else { + return entry_score(entry_2) - entry_score(entry_1); // highest score first + } +} + +// write_integer() + +static void write_integer(FILE * file, int size, uint64 n) { + + int i; + int b; + + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + ASSERT(size==8||n>>(size*8)==0); + + for (i = size-1; i >= 0; i--) { + b = (n >> (i*8)) & 0xFF; + ASSERT(b>=0&&b<256); + fputc(b,file); + } +} + +// read_integer() + +static uint64 read_integer(FILE * file, int size) { + uint64 n; + int i; + int b; + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + n = 0; + for (i = 0; i < size; i++) { + b = fgetc(file); + if (b == EOF) { + if (feof(file)) { + my_fatal("read_integer(): fgetc(): EOF reached\n"); + } else { // error + my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); + } + } + ASSERT(b>=0&&b<256); + n = (n << 8) | b; + } + return n; +} + +// read_entry_file + +static void read_entry_file(FILE *f, entry_t *entry){ + uint64 n; + ASSERT(entry!=NULL); + n = entry->key = read_integer(f,8); + entry->move = read_integer(f,2); + entry->count = read_integer(f,2); + entry->n = read_integer(f,2); + entry->sum = read_integer(f,2); + ASSERT(n==entry->key); // test for mingw compiler bug with anon structs +} + +// write_entry_file + +static void write_entry_file(FILE * f, const entry_t * entry) { + ASSERT(entry!=NULL); + write_integer(f,8,entry->key); + write_integer(f,2,entry->move); + write_integer(f,2,entry->count); + write_integer(f,2,entry->n); + write_integer(f,2,entry->sum); +} + +static void print_list(const board_t *board, list_t *list){ + int i; + uint16 move; + char move_string[256]; + for (i = 0; i < list_size(list); i++) { + move = list_move(list,i); + move_to_san(move,board,move_string,256); + printf("%s",move_string); + } + printf("\n"); +} + +// book_load() +// loads a polyglot book + +static void book_load(const char filename[]){ + FILE* f; + entry_t entry[1]; + int size; + int i; + int pos; + int index; + ASSERT(filename!=NULL); + if(!(f=fopen(filename,"rb"))){ + my_fatal("book_load() : can't open file \"%s\" for reading: %s\n",filename,strerror(errno)); + } + fseek(f,0L,SEEK_END); // superportable way to get size of book! + size=ftell(f)/16; + fseek(f,0,SEEK_SET); + for(i=0L;isize<=Book->alloc); + if (Book->size == Book->alloc) { + // allocate more memoryx + resize(); + } + // insert into the book + pos = Book->size++; + Book->entry[pos].key = entry->key; + ASSERT(entry->move!=MoveNone); + Book->entry[pos].move = entry->move; + Book->entry[pos].count = entry->count; + Book->entry[pos].n = entry->n; + Book->entry[pos].sum = entry->sum; + Book->entry[pos].colour = ColourNone; + // find free hash table spot + for (index = entry->key & (uint64) Book->mask; + Book->hash[index] != NIL; + index = (index+1) & Book->mask); + // insert into the hash table + ASSERT(index>=0&&indexalloc*2); + ASSERT(Book->hash[index]==NIL); + Book->hash[index] = pos; + ASSERT(pos>=0&&possize); + } + fclose(f); +} + +// gen_book_moves() +// similar signature as gen_legal_moves +static int gen_book_moves(list_t * list, const board_t * board){ + int first_pos, pos, index; + entry_t entry[1]; + list_clear(list); + bool found; + found=FALSE; + for (index = board->key & (uint64) Book->mask; (first_pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) { + ASSERT(first_pos>=0&&first_possize); + if (Book->entry[first_pos].key == board->key) { + found=TRUE; + break; // found + } + } + if(!found) return -1; + if(Book->entry[first_pos].move==MoveNone) return -1; + for (pos = first_pos; pos < Book->size; pos++) { + *entry=Book->entry[pos]; + if (entry->key != board->key) break; + if (entry->count > 0 && + entry->move != MoveNone && + move_is_legal(entry->move,board)) { + list_add_ex(list,entry->move,entry->count); + } + } + return first_pos; +} + +// gen_opp_book_moves() +// moves to which opponent has a reply in book +// similar signature as gen_legal_moves +static void gen_opp_book_moves(list_t * list, const board_t * board){ + int move; + list_t new_list[1], legal_moves[1]; + board_t new_board[1]; + int i; + list_clear(list); + gen_legal_moves(legal_moves,board); + for (i = 0; i < list_size(legal_moves); i++) { + move = list_move(legal_moves,i); + // scratch_board + memcpy(new_board, board, sizeof(board_t)); + move_do(new_board,move); + gen_book_moves(new_list,new_board); // wasteful in time but tested! + if(list_size(new_list)!=0){ + list_add(list,move); + } + } +} + +static void print_moves(info_t *info){ + board_t board[1]; + char move_string[256]; + int i; + int color=White; + if(!info->output){ + return; + } + board_start(board); + for(i=0;iheight;i++){ + if(color==White){ + fprintf(info->output,"%d. ",i/2+1); + color=Black; + }else{ + color=White; + } + move_to_san(info->moves[i],board,move_string,256); + fprintf(info->output,"%s", move_string); + if(color==colour_opp(info->initial_color)){ + fprintf(info->output,"{%.0f%%} ",100*info->probs[i]); + }else{ + fprintf(info->output," "); + } + move_do(board,info->moves[i]); + } +} + +static int search_book(board_t *board, info_t *info, search_t search){ + list_t list[1]; + board_t new_board[1]; + uint16 move; + int count; + int ret; + int i; + int offset; + int pos; + int size; + int prob_sum; + double probs[256]; + for(i=0;i<256;i++){ + probs[i]=0.0; // kill compiler warnings + } + for(i=0;iheight;i++){ + if(board->key==info->keys[i]){ + if(info->output){ + fprintf(info->output,"%d: ",info->line); + print_moves(info); + fprintf(info->output,"{cycle: ply=%d}\n",i); + } + info->line++; + return 1; // end of line because of cycle + } + } + if(!info->book_trans_only || (info->book_trans_only && search==BOOK)){ + info->keys[info->height]=board->key; + size=Book->size; // hack + pos=find_entry(board,MoveNone); + if(size==Book->size){ + if(info->output){ + fprintf(info->output,"%d: ",info->line); + print_moves(info); + fprintf(info->output,"{trans: line=%d, ply=%d}\n", + Book->entry[pos].line, + Book->entry[pos].height); + } + info->line++; + return 1; // end of line because of transposition + }else{ + Book->entry[pos].height=info->height; + Book->entry[pos].line=info->line; + } + } + count=0; + if(search==BOOK){ + offset=gen_book_moves(list,board); + if(info->extended_search){ + gen_legal_moves(list,board); + } +// ASSERT(offset!=-1); + if(offset!=-1){ // only FALSE in starting position for black book + Book->entry[offset].colour=board->turn; + prob_sum=0; + if(!info->extended_search){ + for(i=0;imoves[info->height++]=move; + if(search==BOOK){ + info->probs[info->height-1]=probs[i]; + } + ret=search_book(new_board, info, opp_search(search)); + if(ret==0 && search==BOOK){ + if(info->output){ + fprintf(info->output,"%d: ",info->line); + print_moves(info); + fprintf(info->output,"\n"); + } + info->line++; + ret=1; // end of line book move counts for 1 + } + info->height--; + ASSERT(info->height>=0); + count+=ret; + } + return count; +} + +void init_info(info_t *info){ + info->line=1; + info->height=0; + info->output=NULL; + info->initial_color=White; + info->book_trans_only=FALSE; +} + +// book_clean() +// remove MoveNone entries from book and rebuild hash table +void book_clean(){ + int read_ptr,write_ptr; + write_ptr=0; + for(read_ptr=0;read_ptrsize;read_ptr++){ + if(Book->entry[read_ptr].move!=MoveNone){ + Book->entry[write_ptr++]=Book->entry[read_ptr]; + } + } + Book->size=write_ptr; + rebuild_hash_table(); +} + +// book_dump() + +void book_dump(int argc, char * argv[]) { + const char * bin_file=NULL; + const char * txt_file=NULL; + char string[StringSize]; + int color=ColourNone; + board_t board[1]; + info_t info[1]; + int i; + FILE *f; + my_string_set(&bin_file,"book.bin"); + for (i = 1; i < argc; i++) { + if (FALSE) { + } else if (my_string_equal(argv[i],"dump-book")) { + // skip + } else if (my_string_equal(argv[i],"-bin")) { + i++; + if (i==argc) my_fatal("book_dump(): missing argument\n"); + my_string_set(&bin_file,argv[i]); + } else if (my_string_equal(argv[i],"-out")) { + i++; + if (i==argc) my_fatal("book_dump(): missing argument\n"); + my_string_set(&txt_file,argv[i]); + } else if (my_string_equal(argv[i],"-color") || my_string_equal(argv[i],"-colour")) { + i++; + if (i == argc) my_fatal("book_dump(): missing argument\n"); + if(my_string_equal(argv[i],"white")){ + color=White; + }else if (my_string_equal(argv[i],"black")){ + color=Black; + }else{ + my_fatal("book_dump(): unknown color \"%s\"\n",argv[i]); + } + } else { + my_fatal("book_dump(): unknown option \"%s\"\n",argv[i]); + } + } + if(color==ColourNone){ + my_fatal("book_dump(): you must specify a color\n"); + } + if(txt_file==NULL){ + snprintf(string,StringSize,"book_%s.txt",color?"white":"black"); + my_string_set(&txt_file,string); + } + + book_clear(); + if(!Quiet){printf("loading book ...\n");} + book_load(bin_file); + board_start(board); + init_info(info); + info->initial_color=color; + if(!(f=fopen(txt_file,"w"))){ + my_fatal("book_dump(): can't open file \"%s\" for writing: %s", + txt_file,strerror(errno)); + } + info->output=f; + fprintf(info->output,"Dump of \"%s\" for %s.\n", + bin_file,color==White?"white":"black"); + if(color==White){ + if(!Quiet){printf("generating lines for white...\n");} + search_book(board,info, BOOK); + }else{ + if(!Quiet){printf("generating lines for black...\n");} + search_book(board,info, ALL); + } +} + +// book_info() + +void book_info(int argc,char* argv[]){ + const char *bin_file=NULL; + board_t board[1]; + info_t info[1]; + uint64 last_key; + int pos; + int white_pos,black_pos,total_pos,white_pos_extended, + black_pos_extended,white_pos_extended_diff,black_pos_extended_diff; + int s; + bool extended_search=FALSE; + int i; + Quiet=TRUE; + my_string_set(&bin_file,"book.bin"); + + for (i = 1; i < argc; i++) { + if (FALSE) { + } else if (my_string_equal(argv[i],"info-book")) { + // skip + } else if (my_string_equal(argv[i],"-bin")) { + i++; + if (i==argc) my_fatal("book_info(): missing argument\n"); + my_string_set(&bin_file,argv[i]); + } else if (my_string_equal(argv[i],"-exact")) { + extended_search=TRUE; + } else { + my_fatal("book_info(): unknown option \"%s\"\n",argv[i]); + } + } + book_clear(); + if(!Quiet){printf("loading book ...\n");} + book_load(bin_file); + s=Book->size; + + board_start(board); + init_info(info); + info->book_trans_only=FALSE; + info->initial_color=White; + info->extended_search=FALSE; + search_book(board,info, BOOK); + printf("Lines for white : %8d\n",info->line-1); + + + info->line=1; + info->height=0; + info->initial_color=Black; + book_clean(); + ASSERT(Book->size==s); + board_start(board); + search_book(board,info, ALL); + printf("Lines for black : %8d\n",info->line-1); + + book_clean(); + ASSERT(Book->size==s); + white_pos=0; + black_pos=0; + total_pos=0; + last_key=0; + for(pos=0;possize;pos++){ + if(Book->entry[pos].key==last_key){ + ASSERT(Book->entry[pos].colour==ColourNone); + continue; + } + last_key=Book->entry[pos].key; + total_pos++; + if(Book->entry[pos].colour==White){ + white_pos++; + }else if(Book->entry[pos].colour==Black){ + black_pos++; + } + } + printf("Positions on lines for white : %8d\n",white_pos); + printf("Positions on lines for black : %8d\n",black_pos); + + + if(extended_search){ + init_info(info); + info->book_trans_only=TRUE; + info->initial_color=White; + info->extended_search=TRUE; + book_clean(); + board_start(board); + search_book(board,info, BOOK); + + init_info(info); + info->book_trans_only=TRUE; + info->initial_color=Black; + info->extended_search=TRUE; + book_clean(); + board_start(board); + search_book(board,info, ALL); + book_clean(); + ASSERT(Book->size==s); + white_pos_extended=0; + black_pos_extended=0; + last_key=0; + for(pos=0;possize;pos++){ + if(Book->entry[pos].key==last_key){ + ASSERT(Book->entry[pos].colour==ColourNone); + continue; + } + last_key=Book->entry[pos].key; + if(Book->entry[pos].colour==White){ + white_pos_extended++; + }else if(Book->entry[pos].colour==Black){ + black_pos_extended++; + } + } + white_pos_extended_diff=white_pos_extended-white_pos; + black_pos_extended_diff=black_pos_extended-black_pos; + printf("Unreachable white positions(?) : %8d\n", + white_pos_extended_diff); + printf("Unreachable black positions(?) : %8d\n", + black_pos_extended_diff); + + } + if(extended_search){ + printf("Isolated positions : %8d\n", + total_pos-white_pos_extended-black_pos_extended); + }else{ + printf("Isolated positions : %8d\n", + total_pos-white_pos-black_pos); + } +} + + + +// end of book_make.cpp + diff --git a/book_merge.c b/book_merge.c new file mode 100644 index 0000000..f68e2cc --- /dev/null +++ b/book_merge.c @@ -0,0 +1,304 @@ + +// book_merge.c + +// includes + +#include +#include +#include +#include + +#include "book_merge.h" +#include "util.h" + +// types + +typedef struct { + FILE * file; + int size; +} book_t; + +typedef struct { + uint64 key; + uint16 move; + uint16 count; + uint16 n; + uint16 sum; +} entry_t; + +// variables + +static book_t In1[1]; +static book_t In2[1]; +static book_t Out[1]; + +// prototypes + +static void book_clear (book_t * book); + +static void book_open (book_t * book, const char file_name[], const char mode[]); +static void book_close (book_t * book); + +static bool read_entry (book_t * book, entry_t * entry, int n); +static void write_entry (book_t * book, const entry_t * entry); + +static uint64 read_integer (FILE * file, int size); +static void write_integer (FILE * file, int size, uint64 n); + +// functions + +// book_merge() + +void book_merge(int argc, char * argv[]) { + + int i; + const char * in_file_1; + const char * in_file_2; + const char * out_file; + int i1, i2; + bool b1, b2; + entry_t e1[1], e2[1]; + int skip; + + in_file_1 = NULL; + my_string_clear(&in_file_1); + + in_file_2 = NULL; + my_string_clear(&in_file_2); + + out_file = NULL; + my_string_set(&out_file,"out.bin"); + + for (i = 1; i < argc; i++) { + + if (FALSE) { + + } else if (my_string_equal(argv[i],"merge-book")) { + + // skip + + } else if (my_string_equal(argv[i],"-in1")) { + + i++; + if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); + + my_string_set(&in_file_1,argv[i]); + + } else if (my_string_equal(argv[i],"-in2")) { + + i++; + if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); + + my_string_set(&in_file_2,argv[i]); + + } else if (my_string_equal(argv[i],"-out")) { + + i++; + if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); + + my_string_set(&out_file,argv[i]); + + } else { + + my_fatal("book_merge(): unknown option \"%s\"\n",argv[i]); + } + } + + book_clear(In1); + book_clear(In2); + book_clear(Out); + + book_open(In1,in_file_1,"rb"); + book_open(In2,in_file_2,"rb"); + book_open(Out,out_file,"wb"); + + skip = 0; + + i1 = 0; + i2 = 0; + + while (TRUE) { + + b1 = read_entry(In1,e1,i1); + b2 = read_entry(In2,e2,i2); + + if (FALSE) { + + } else if (!b1 && !b2) { + + break; + + } else if (b1 && !b2) { + + write_entry(Out,e1); + i1++; + + } else if (b2 && !b1) { + + write_entry(Out,e2); + i2++; + + } else { + + ASSERT(b1); + ASSERT(b2); + + if (FALSE) { + } else if (e1->key < e2->key) { + write_entry(Out,e1); + i1++; + } else if (e1->key > e2->key) { + write_entry(Out,e2); + i2++; + } else { + ASSERT(e1->key==e2->key); + skip++; + i2++; + } + } + } + + book_close(In1); + book_close(In2); + book_close(Out); + + if (skip != 0) { + printf("skipped %d entr%s.\n",skip,(skip>1)?"ies":"y"); + } + + printf("done!\n"); +} + +// book_clear() + +static void book_clear(book_t * book) { + + ASSERT(book!=NULL); + + book->file = NULL; + book->size = 0; +} + +// book_open() + +static void book_open(book_t * book, const char file_name[], const char mode[]) { + + ASSERT(book!=NULL); + ASSERT(file_name!=NULL); + ASSERT(mode!=NULL); + + book->file = fopen(file_name,mode); + if (book->file == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); + + if (fseek(book->file,0,SEEK_END) == -1) { + my_fatal("book_open(): fseek(): %s\n",strerror(errno)); + } + + book->size = ftell(book->file) / 16; +} + +// book_close() + +static void book_close(book_t * book) { + + ASSERT(book!=NULL); + + if (fclose(book->file) == EOF) { + my_fatal("book_close(): fclose(): %s\n",strerror(errno)); + } +} + +// read_entry() + +static bool read_entry(book_t * book, entry_t * entry, int n) { + + ASSERT(book!=NULL); + ASSERT(entry!=NULL); + + if (n < 0 || n >= book->size) return FALSE; + + ASSERT(n>=0&&nsize); + + if (fseek(book->file,n*16,SEEK_SET) == -1) { + my_fatal("read_entry(): fseek(): %s\n",strerror(errno)); + } + + entry->key = read_integer(book->file,8); + entry->move = read_integer(book->file,2); + entry->count = read_integer(book->file,2); + entry->n = read_integer(book->file,2); + entry->sum = read_integer(book->file,2); + + return TRUE; +} + +// write_entry() + +static void write_entry(book_t * book, const entry_t * entry) { + + ASSERT(book!=NULL); + ASSERT(entry!=NULL); + + write_integer(book->file,8,entry->key); + write_integer(book->file,2,entry->move); + write_integer(book->file,2,entry->count); + write_integer(book->file,2,entry->n); + write_integer(book->file,2,entry->sum); +} + +// read_integer() + +static uint64 read_integer(FILE * file, int size) { + + uint64 n; + int i; + int b; + + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + + n = 0; + + for (i = 0; i < size; i++) { + + b = fgetc(file); + + if (b == EOF) { + if (feof(file)) { + my_fatal("read_integer(): fgetc(): EOF reached\n"); + } else { // error + my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); + } + } + + ASSERT(b>=0&&b<256); + n = (n << 8) | b; + } + + return n; +} + +// write_integer() + +static void write_integer(FILE * file, int size, uint64 n) { + + int i; + int b; + + ASSERT(file!=NULL); + ASSERT(size>0&&size<=8); + ASSERT(size==8||n>>(size*8)==0); + + for (i = size-1; i >= 0; i--) { + + b = (n >> (i*8)) & 0xFF; + ASSERT(b>=0&&b<256); + + if (fputc(b,file) == EOF) { + my_fatal("write_integer(): fputc(): %s\n",strerror(errno)); + } + } +} + +// end of book_merge.cpp + diff --git a/colour.c b/colour.c new file mode 100644 index 0000000..e0936b9 --- /dev/null +++ b/colour.c @@ -0,0 +1,55 @@ + +// colour.c + +// includes + +#include "colour.h" +#include "util.h" + +// functions + +// colour_is_ok() + +bool colour_is_ok(int colour) { + + return colour == Black || colour == White; +} + +// colour_is_white() + +bool colour_is_white(int colour) { + + ASSERT(colour_is_ok(colour)); + + return colour == White; +} + +// colour_is_black() + +bool colour_is_black(int colour) { + + ASSERT(colour_is_ok(colour)); + + return colour == Black; +} + +// colour_equal() + +bool colour_equal(int colour_1, int colour_2) { + + ASSERT(colour_is_ok(colour_2)); + + return (colour_1 & colour_2) != 0; +} + +// colour_opp() + +int colour_opp(int colour) { + + ASSERT(colour_is_ok(colour)); + + return colour ^ (BlackFlag^WhiteFlag); +} + +// end of colour.cpp + diff --git a/colour.h b/colour.h index 5cb7b02..82a7d7b 100644 --- a/colour.h +++ b/colour.h @@ -8,15 +8,14 @@ #include "util.h" -// constants - -const int BlackFlag = 1 << 0; -const int WhiteFlag = 1 << 1; - -const int ColourNone = 0; -const int Black = BlackFlag; -const int White = WhiteFlag; -const int ColourNb = 3; +// defines + +#define BlackFlag (1 << 0) +#define WhiteFlag (1 << 1) +#define ColourNone 0 +#define Black BlackFlag +#define White WhiteFlag +#define ColourNb 3 // functions diff --git a/config.h b/config.h index 9064aad..259287a 100644 --- a/config.h +++ b/config.h @@ -115,13 +115,13 @@ #define PACKAGE_NAME "polyglot" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "polyglot 1.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 @@ -150,7 +150,7 @@ #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 diff --git a/configure b/configure index a5adf30..cf92c98 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for polyglot 1.4b27. +# Generated by GNU Autoconf 2.61 for polyglot 1.4.30b. # # Report bugs to . # @@ -574,11 +574,11 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='polyglot' PACKAGE_TARNAME='polyglot' -PACKAGE_VERSION='1.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 @@ -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 if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if you have headers in a nonstandard directory - 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 ." _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 diff --git a/configure.ac b/configure.ac index 03d2aa1..13bbd54 100644 --- a/configure.ac +++ b/configure.ac @@ -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 index 0000000..4dffd4a --- /dev/null +++ b/engine.c @@ -0,0 +1,120 @@ +// engine.c + +// includes + +#include +#include +#include +#include + + +#include "engine.h" +#include "option.h" +#include "pipex.h" +#include "util.h" + +// defines + +#define StringSize 4096 + +// variables + +static int write_index = 0; +static char write_buffer[StringSize]; +engine_t Engine[1]; + +// functions + +// set_affinity() + +void set_affinity(engine_t *engine, int value){ + pipex_set_affinity(engine->pipex,value); +} + +// engine_set_nice_value() + +void engine_set_nice_value(engine_t *engine, int value){ + pipex_set_priority(engine->pipex,value); +} + +// engine_send_queue() + +void engine_send_queue(engine_t * engine, const char *format, ...) { + if(write_index>=StringSize){ + my_fatal("engine_send_queue(): write_buffer overflow\n"); + } + write_index += vsnprintf(write_buffer + write_index, + StringSize-write_index, + format, + (va_list) (&format + 1)); +} + +// engine_send() + +void engine_send(engine_t * engine, const char *format, ...) { + if(write_index>=StringSize){ + my_fatal("engine_send(): write_buffer overflow\n"); + } + vsnprintf(write_buffer + write_index, + StringSize-write_index, + format, + (va_list) (&format + 1)); + pipex_writeln(engine->pipex,write_buffer); + write_index = 0; +} + +// engine_close() + +void engine_close(engine_t * engine){ + char string[StringSize]; + pipex_send_eof(engine->pipex); + // TODO: Timeout + while (!engine_eof(engine)) { + engine_get(Engine,string); + } + pipex_exit(engine->pipex); +} + +// engine_open() + +void engine_open(engine_t * engine){ + int affinity; + char *my_dir; + if( (my_dir = my_getcwd( NULL, 0 )) == NULL ) + my_fatal("engine_open(): no current directory: %s\n",strerror(errno)); + if(my_chdir(option_get_string("EngineDir"))){ + my_fatal("engine_open(): cannot change directory: %s\n",strerror(errno)); + } + pipex_open(engine->pipex,"Engine",option_get_string("EngineCommand")); + if(pipex_active(engine->pipex)){ + //play with affinity (bad idea) + affinity=option_get_int("Affinity"); + if(affinity!=-1) set_affinity(engine,affinity); //AAA + //lets go back + my_chdir(my_dir); + // set a low priority + if (option_get_bool("UseNice")){ + my_log("POLYGLOT Adjust Engine Piority\n"); + engine_set_nice_value(engine, option_get_int("NiceValue")); + } + } + +} + +bool engine_active(engine_t *engine){ + return pipex_active(engine->pipex); +} + +bool engine_eof(engine_t *engine){ + return pipex_eof(engine->pipex); +} + +bool engine_get_non_blocking(engine_t * engine, char *string){ + return pipex_readln_nb(engine->pipex,string); + } + +void engine_get(engine_t * engine, char *string){ + pipex_readln(engine->pipex,string); +} + + diff --git a/engine.h b/engine.h index b3a950c..2a408e3 100644 --- a/engine.h +++ b/engine.h @@ -3,28 +3,17 @@ #ifndef ENGINE_H #define ENGINE_H -// defines - -#define ENGINE_EOF 1 -#define ENGINE_ACTIVE 2 - // includes #include "io.h" #include "util.h" -#include "pipe.h" +#include "pipex.h" // types -struct engine_t { -#ifndef _WIN32 - io_t io[1]; - pid_t pid; -#else - PipeStruct io; -#endif - uint32 state; -}; +typedef struct { + pipex_t pipex[1]; +} engine_t; @@ -41,8 +30,8 @@ extern bool engine_active (engine_t * engine); extern bool engine_eof (engine_t * engine); extern void engine_send (engine_t * engine, const char format[], ...); extern void engine_send_queue (engine_t * engine, const char format[], ...); -extern bool engine_get_non_blocking(engine_t * engine, char string[], int size); -extern void engine_get (engine_t * engine, char string[], int size); +extern bool engine_get_non_blocking(engine_t * engine, char string[]); +extern void engine_get (engine_t * engine, char string[]); extern void engine_set_nice_value(engine_t * engine, int value); #endif // !defined ENGINE_H diff --git a/epd.c b/epd.c new file mode 100644 index 0000000..c79c399 --- /dev/null +++ b/epd.c @@ -0,0 +1,444 @@ + +// epd.c + +// includes + +#include +#include +#include +#include + +#include "board.h" +#include "engine.h" +#include "epd.h" +#include "fen.h" +#include "line.h" +#include "main.h" +#include "move.h" +#include "move_legal.h" +#include "option.h" +#include "parse.h" +#include "san.h" +#include "uci.h" +#include "util.h" + +// constants + +static const bool UseDebug = FALSE; +static const bool UseTrace = FALSE; + +static const int StringSize = 4096; + +// variables + +static int MinDepth; +static int MaxDepth; + +static double MaxTime; +static double MinTime; + +static int DepthDelta; + +static int FirstMove; +static int FirstDepth; +static int FirstSelDepth; +static int FirstScore; +static double FirstTime; +static uint64 FirstNodeNb; +static move_t FirstPV[LineSize]; + +static int LastMove; +static int LastDepth; +static int LastSelDepth; +static int LastScore; +static double LastTime; +static uint64 LastNodeNb; +static move_t LastPV[LineSize]; + +static my_timer_t Timer[1]; + +// prototypes + +static void epd_test_file (const char file_name[]); + +static bool is_solution (int move, const board_t * board, const char bm[], const char am[]); +static bool string_contain (const char string[], const char substring[]); + +static bool engine_step (); + +// functions + +// epd_test() + +void epd_test(int argc, char * argv[]) { + + int i; + const char * epd_file; + + epd_file = NULL; + my_string_set(&epd_file,"wac.epd"); + + MinDepth = 8; + MaxDepth = 63; + + MinTime = 1.0; + MaxTime = 5.0; + + DepthDelta = 3; + + for (i = 1; i < argc; i++) { + + if (FALSE) { + + } else if (my_string_equal(argv[i],"epd-test")) { + + // skip + + } else if (my_string_equal(argv[i],"-epd")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + my_string_set(&epd_file,argv[i]); + + } else if (my_string_equal(argv[i],"-min-depth")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + MinDepth = atoi(argv[i]); + + } else if (my_string_equal(argv[i],"-max-depth")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + MaxDepth = atoi(argv[i]); + + } else if (my_string_equal(argv[i],"-min-time")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + MinTime = atof(argv[i]); + + } else if (my_string_equal(argv[i],"-max-time")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + MaxTime = atof(argv[i]); + + } else if (my_string_equal(argv[i],"-depth-delta")) { + + i++; + if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); + + DepthDelta = atoi(argv[i]); + + } else { + + my_fatal("epd_test(): unknown option \"%s\"\n",argv[i]); + } + } + + if(MinTime>MaxTime){ + MaxTime=MinTime; + } + + epd_test_file(epd_file); +} + +// epd_test_file() + +static void epd_test_file(const char file_name[]) { + + FILE * file; + int hit, tot; + char epd[StringSize]; + char am[StringSize], bm[StringSize], id[StringSize]; + board_t board[1]; + char string[StringSize]; + int move; + char pv_string[StringSize]; + bool correct; + double depth_tot, time_tot, node_tot; + int line=0; + + ASSERT(file_name!=NULL); + + // init + + file = fopen(file_name,"r"); + if (file == NULL) my_fatal("epd_test_file(): can't open file \"%s\": %s\n",file_name,strerror(errno)); + + hit = 0; + tot = 0; + + depth_tot = 0.0; + time_tot = 0.0; + node_tot = 0.0; + + printf("\nEngineName=%s\n",option_get_string("EngineName")); + + printf("\n[Search parameters: MaxDepth=%d MaxTime=%.1f DepthDelta=%d MinDepth=%d MinTime=%.1f]\n\n",MaxDepth,MaxTime,DepthDelta,MinDepth,MinTime); + + // loop + + while (my_file_read_line(file,epd,StringSize)) { + line++; + if(my_string_whitespace(epd)) continue; + if (UseTrace) printf("%s\n",epd); + + if (!epd_get_op(epd,"am",am,StringSize)) strcpy(am,""); + if (!epd_get_op(epd,"bm",bm,StringSize)) strcpy(bm,""); + if (!epd_get_op(epd,"id",id,StringSize)) strcpy(id,""); + + if (my_string_empty(am) && my_string_empty(bm)) { + my_fatal("epd_test(): no am or bm field at line %d\n",line); + } + + // init + + uci_send_ucinewgame(Uci); + uci_send_isready_sync(Uci); + + ASSERT(!Uci->searching); + + // position + if (!board_from_fen(board,epd)) ASSERT(FALSE); + if (!board_to_fen(board,string,StringSize)) ASSERT(FALSE); + + engine_send(Engine,"position fen %s"); + + // search + + my_timer_start(Timer); // also resets + + // which ones of the next two alternatives is best? + engine_send(Engine,"go movetime %.0f depth %d",MaxTime*1000.0,MaxDepth); + //engine_send(Engine,"go infinite"); + + // engine data + + board_copy(Uci->board,board); + + uci_clear(Uci); + Uci->searching = TRUE; + Uci->pending_nb++; + + FirstMove = MoveNone; + FirstDepth = 0; + FirstSelDepth = 0; + FirstScore = 0; + FirstTime = 0.0; + FirstNodeNb = 0; + line_clear(FirstPV); + + LastMove = MoveNone; + LastDepth = 0; + LastSelDepth = 0; + LastScore = 0; + LastTime = 0.0; + LastNodeNb = 0; + line_clear(LastPV); + + // parse engine output + + while (!engine_eof(Engine) && engine_step()) { + bool stop=FALSE; + + // stop search? +// printf("Uci->time=%.2f time=%.2f\n",Uci->time,my_timer_elapsed_real(Timer)); + if (Uci->depth > MaxDepth){ + my_log("POLYGLOT Maximum depth %d reached\n",MaxDepth); + stop=TRUE; + }else if(my_timer_elapsed_real(Timer) >= MaxTime){ + my_log("POLYGLOT Maximum search time %.2fs reached\n",MaxTime); + stop=TRUE; + }else if(Uci->depth - FirstDepth >= DepthDelta){ + if(Uci->depth > MinDepth){ + if(Uci->time >= MinTime){ + if(is_solution(FirstMove,board,bm,am)){ + my_log("POLYGLOT Solution found\n",MaxTime); + stop=TRUE; + } + } + } + } + if(stop){ + my_log("POLYGLOT Stopping engine\n"); + engine_send(Engine,"stop"); + break; + } + } + + move = FirstMove; + correct = is_solution(move,board,bm,am); + + if (correct) hit++; + tot++; + + if (correct) { + depth_tot += ((double)FirstDepth); + time_tot += FirstTime; + node_tot += ((double)((sint64)FirstNodeNb)); + } + + printf("%2d: %-15s %s %4d",tot,id,correct?"OK":"--",hit); + + if (!line_to_san(LastPV,Uci->board,pv_string,StringSize)) ASSERT(FALSE); + printf(" score=%+6.2f pv [D=%2d, T=%7.2fs, N=%6dk] =%s\n",((double)LastScore)/100.0,FirstDepth,FirstTime,(int)FirstNodeNb/1000,pv_string); + } + + printf("\nscore=%d/%d",hit,tot); + + if (hit != 0) { + + depth_tot /= ((double)hit); + time_tot /= ((double)hit); + node_tot /= ((double)hit); + + printf(" [averages on correct positions: depth=%.1f time=%.2f nodes=%.0f]",depth_tot,time_tot,node_tot); + } + + printf("\n"); + + fclose(file); + quit(); +} + +// is_solution() + +static bool is_solution(int move, const board_t * board, const char bm[], const char am[]) { + + char move_string[256]; + bool correct; + + ASSERT(move!=MoveNone); + ASSERT(bm!=NULL); + ASSERT(am!=NULL); + + if (!move_is_legal(move,board)) { + board_disp(board); + move_disp(move,board); + printf("\n\n"); + } + + ASSERT(move_is_legal(move,board)); + + if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE); + + correct = FALSE; + if (!my_string_empty(bm)) { + correct = string_contain(bm,move_string); + } else if (!my_string_empty(am)) { + correct = !string_contain(am,move_string); + } else { + ASSERT(FALSE); + } + + return correct; +} + +// epd_get_op() + +bool epd_get_op(const char record[], const char opcode[], char string[], int size) { + + char op[256]; + int len; + const char *p_start, *p_end; + + ASSERT(record!=NULL); + ASSERT(opcode!=NULL); + ASSERT(string!=NULL); + ASSERT(size>0); + + // find the opcode + + sprintf(op," %s ",opcode); + + p_start = strstr(record,op); + if (p_start == NULL){ + sprintf(op,";%s ",opcode); + p_start = strstr(record,op); + if (p_start == NULL){ + return FALSE; + } + } + + // skip the opcode + + p_start += strlen(op); + + // find the end + p_end = strchr(p_start,';'); + if (p_end == NULL) return FALSE; + + // calculate the length + + len = p_end - p_start; + if (size < len+1) my_fatal("epd_get_op(): size < len+1\n"); + + strncpy(string,p_start,len); + string[len] = '\0'; + + return TRUE; +} + +// string_contain() + +static bool string_contain(const char string[], const char substring[]) { + + char new_string[StringSize], *p; + + strcpy(new_string,string); // HACK + + for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) { + if (my_string_equal(p,substring)) return TRUE; + } + + return FALSE; +} + +// engine_step() + +static bool engine_step() { + + char string[StringSize]; + int event; + + engine_get(Engine,string); + event = uci_parse(Uci,string); + + if ((event & EVENT_MOVE) != 0) { + + return FALSE; + } + + if ((event & EVENT_PV) != 0) { + + LastMove = Uci->best_pv[0]; + LastDepth = Uci->best_depth; + LastSelDepth = Uci->best_sel_depth; + LastScore = Uci->best_score; + LastTime = Uci->time; + LastNodeNb = Uci->node_nb; + line_copy(LastPV,Uci->best_pv); + + if (LastMove != FirstMove) { + FirstMove = LastMove; + FirstDepth = LastDepth; + FirstSelDepth = LastSelDepth; + FirstScore = LastScore; + FirstTime = LastTime; + FirstNodeNb = LastNodeNb; + line_copy(FirstPV,LastPV); + } + } + + return TRUE; +} + +// end of epd.cpp + diff --git a/fen.c b/fen.c new file mode 100644 index 0000000..be3ec17 --- /dev/null +++ b/fen.c @@ -0,0 +1,392 @@ + +// fen.c + +// includes + +#include +#include +#include + +#include "board.h" +#include "colour.h" +#include "fen.h" +#include "option.h" +#include "piece.h" +#include "square.h" +#include "util.h" + +// "constants" + +// const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1"; +const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; + +// variables + +static const bool Strict = FALSE; + +// macros + +#define skip_white_space() \ + c=string[pos];\ + if (c != ' ' && c!='\t') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); \ + while(c==' ' || c=='\t') c=string[++pos]; + + +// functions + +// board_from_fen() + +bool board_from_fen(board_t * board, const char string[]) { + + int pos; + int file, rank, sq; + int c; + int i, len; + int piece; + int king_pos[ColourNb]; + + ASSERT(board!=NULL); + ASSERT(string!=NULL); + + board_clear(board); + + king_pos[White] = SquareNone; + king_pos[Black] = SquareNone; + + pos = 0; + c = string[pos]; + + // piece placement + + for (rank = 7; rank >= 0; rank--) { + + for (file = 0; file < 8;) { + + sq = square_make(file,rank); + + if (c >= '1' && c <= '8') { // empty square(s) + + len = c - '0'; + if (file + len > 8) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + + for (i = 0; i < len; i++) { + board->square[sq++] = Empty; + file++; + } + + } else { // piece + + piece = piece_from_char(c); + if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + + if (piece_is_king(piece)) king_pos[piece_colour(piece)] = sq; + + board->square[sq++] = piece; + file++; + } + + c = string[++pos]; + } + + if (rank > 0) { + if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + c = string[++pos]; + } + } + + // active colour + + skip_white_space(); + + switch (c) { + case 'w': + board->turn = White; + break; + case 'b': + board->turn = Black; + break; + default: + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + break; + } + + c = string[++pos]; + + // castling + + skip_white_space(); + + board->castle[White][SideH] = SquareNone; + board->castle[White][SideA] = SquareNone; + board->castle[Black][SideH] = SquareNone; + board->castle[Black][SideA] = SquareNone; + + if (c == '-') { // no castling rights + + c = string[++pos]; + + } else { + + // TODO: filter out illegal rights + + do { + + if (FALSE) { + + } else if (c == 'K') { + + for (sq = H1; sq > king_pos[White]; sq--) { + if (board->square[sq] == WhiteRook256) { + board->castle[White][SideH] = sq; + break; + } + } + + } else if (c == 'Q') { + + for (sq = A1; sq < king_pos[White]; sq++) { + if (board->square[sq] == WhiteRook256) { + board->castle[White][SideA] = sq; + break; + } + } + + } else if (c == 'k') { + + for (sq = H8; sq > king_pos[Black]; sq--) { + if (board->square[sq] == BlackRook256) { + board->castle[Black][SideH] = sq; + break; + } + } + + } else if (c == 'q') { + + for (sq = A8; sq < king_pos[Black]; sq++) { + if (board->square[sq] == BlackRook256) { + board->castle[Black][SideA] = sq; + break; + } + } + + } else if (c >= 'A' && c <= 'H') { + + // white castling right + + sq = square_make(file_from_char(tolower(c)),Rank1); + + if (sq > king_pos[White]) { // h side + board->castle[White][SideH] = sq; + } else { // a side + board->castle[White][SideA] = sq; + } + + } else if (c >= 'a' && c <= 'h') { + + // black castling right + + sq = square_make(file_from_char(tolower(c)),Rank8); + + if (sq > king_pos[Black]) { // h side + board->castle[Black][SideH] = sq; + } else { // a side + board->castle[Black][SideA] = sq; + } + + } else { + + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + } + + c = string[++pos]; + + } while (c != ' '); + } + + // en-passant + + skip_white_space(); + + if (c == '-') { // no en-passant + + sq = SquareNone; + c = string[++pos]; + + } else { + + if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + file = file_from_char(c); + c = string[++pos]; + + if (c < '1' || c > '8') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + rank = rank_from_char(c); + c = string[++pos]; + + sq = square_make(file,rank); + } + + board->ep_square = sq; + + // halfmove clock + + board->ply_nb = 0; + board->move_nb = 0; // HACK, in case of broken syntax + + if (c != ' ') { + if (!Strict) goto update; + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + } + c = string[++pos]; + + if (!isdigit(c)) { + if (!Strict) goto update; + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + } + + board->ply_nb = atoi(&string[pos]); + do c = string[++pos]; while (isdigit(c)); + + // fullmove number + + board->move_nb = 0; + + if (c != ' ') { + if (!Strict) goto update; + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + } + c = string[++pos]; + + if (!isdigit(c)) { + if (!Strict) goto update; + my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); + } + + board->move_nb = atoi(&string[pos]) - 1; + do c = string[++pos]; while (isdigit(c)); + + // board update + +update: + board_init_list(board); + + return TRUE; +} + +// board_to_fen() + +bool board_to_fen(const board_t * board, char string[], int size) { + + int pos; + int file, rank; + int sq, piece; + int c; + int len; + int old_pos; + + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=92); + + // init + + if (size < 92) return FALSE; + + pos = 0; + + // piece placement + + for (rank = 7; rank >= 0; rank--) { + + for (file = 0; file < 8;) { + + sq = square_make(file,rank); + piece = board->square[sq]; + ASSERT(piece==Empty||piece_is_ok(piece)); + + if (piece == Empty) { + + len = 0; + for (; file < 8 && board->square[square_make(file,rank)] == Empty; file++) { + len++; + } + + ASSERT(len>=1&&len<=8); + c = '0' + len; + + } else { + + c = piece_to_char(piece); + file++; + } + + string[pos++] = c; + } + + string[pos++] = '/'; + } + + string[pos-1] = ' '; // HACK: remove the last '/' + + // active colour + + string[pos++] = (colour_is_white(board->turn)) ? 'w' : 'b'; + string[pos++] = ' '; + + // castling + + old_pos = pos; + + if (option_get_bool("Chess960")) { + + // FEN-960 + + if (board->castle[White][SideH] != SquareNone) { + string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideH]))); + } + + if (board->castle[White][SideA] != SquareNone) { + string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideA]))); + } + + if (board->castle[Black][SideH] != SquareNone) { + string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideH]))); + } + + if (board->castle[Black][SideA] != SquareNone) { + string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideA]))); + } + + } else { + + // FEN + + if (board->castle[White][SideH] != SquareNone) string[pos++] = 'K'; + if (board->castle[White][SideA] != SquareNone) string[pos++] = 'Q'; + if (board->castle[Black][SideH] != SquareNone) string[pos++] = 'k'; + if (board->castle[Black][SideA] != SquareNone) string[pos++] = 'q'; + } + + if (pos == old_pos) string[pos++] = '-'; + + string[pos++] = ' '; + + // en-passant + + if (board->ep_square == SquareNone) { + string[pos++] = '-'; + } else { + if (!square_to_string(board->ep_square,&string[pos],3)) return FALSE; + pos += 2; + } + + string[pos++] = ' '; + + // halfmove clock and fullmove number + + sprintf(&string[pos],"%d %d",board->ply_nb,board->move_nb+1); + + return TRUE; +} + +// end of fen.cpp + diff --git a/game.c b/game.c new file mode 100644 index 0000000..199d344 --- /dev/null +++ b/game.c @@ -0,0 +1,361 @@ + +// game.c + +// includes + +#include "attack.h" +#include "board.h" +#include "fen.h" +#include "game.h" +#include "list.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "piece.h" +#include "square.h" +#include "util.h" + +// constants + +static const bool UseSlowDebug = FALSE; + +// variables + +game_t Game[1]; + +// prototypes + +static void game_update (game_t * game); +static int game_comp_status (const game_t * game); + +// functions + +// game_is_ok() + +bool game_is_ok(const game_t * game) { + + board_t board[1]; + int pos, move; + + if (game == NULL) return FALSE; + + if (game->size < 0 || game->size > GameSize) return FALSE; + if (game->pos < 0 || game->pos > game->size) return FALSE; + + // optional heavy DEBUG mode + + if (!UseSlowDebug) return TRUE; + + if (!board_is_ok(game->start_board)) return FALSE; + + board_copy(board,game->start_board); + + for (pos = 0; pos <= game->size; pos++) { + + if (pos == game->pos) { + if (!board_equal(game->board,board)) return FALSE; + } + + if (pos >= game->size) break; + + if (game->key[pos] != board->key) return FALSE; + + move = game->move[pos]; + //if (!move_is_legal(move,board)); //huh?? + if (!move_is_legal(move,board)) return FALSE; + + move_do(board,move); + } + + if (game->status != game_comp_status(game)) return FALSE; + + return TRUE; +} + +// game_clear() + +void game_clear(game_t * game) { + + ASSERT(game!=NULL); + + game_init(game,StartFen); +} + +// game_init() + +bool game_init(game_t * game, const char fen[]) { + + ASSERT(game!=NULL); + ASSERT(fen!=NULL); + + if (!board_from_fen(game->start_board,fen)) return FALSE; + + game->size = 0; + + board_copy(game->board,game->start_board); + game->pos = 0; + + game_update(game); + + return TRUE; +} + +// game_status() + +int game_status(const game_t * game) { + + ASSERT(game!=NULL); + + return game->status; +} + +// game_size() + +int game_size(const game_t * game) { + + ASSERT(game!=NULL); + + return game->size; +} + +// game_pos() + +int game_pos(const game_t * game) { + + ASSERT(game!=NULL); + + return game->pos; +} + +// game_move() + +int game_move(const game_t * game, int pos) { + + ASSERT(game!=NULL); + ASSERT(pos>=0&&pospos); + + return game->move[pos]; +} + +// game_get_board() + +void game_get_board(const game_t * game, board_t * board) { + game_get_board_ex(game, board, -1); +} + +// game_get_board_ex() + +void game_get_board_ex(const game_t * game, board_t * board, int pos) { + + int start; + int i; + + ASSERT(game!=NULL); + ASSERT(board!=NULL); + ASSERT(pos==-1||(pos>=0&&pos<=game->size)); // HACK + + if (pos < 0) pos = game->pos; + + if (pos >= game->pos) { // forward from current position + start = game->pos; + board_copy(board,game->board); + } else { // backward => replay the whole game + start = 0; + board_copy(board,game->start_board); + } + + for (i = start; i < pos; i++) move_do(board,game->move[i]); +} + +// game_turn() + +int game_turn(const game_t * game) { + + ASSERT(game!=NULL); + + return game->board->turn; +} + +// game_move_nb() + +int game_move_nb(const game_t * game) { + + ASSERT(game!=NULL); + + return game->board->move_nb; +} + +// game_add_move() + +void game_add_move(game_t * game, int move) { + + ASSERT(game!=NULL); + ASSERT(move_is_ok(move)); + + ASSERT(move_is_legal(move,game->board)); + + if (game->pos >= GameSize) my_fatal("game_add_move(): game overflow\n"); + + game->move[game->pos] = move; + game->key[game->pos] = game->board->key; + + move_do(game->board,move); + game->pos++; + + game->size = game->pos; // truncate game, HACK: before calling game_is_ok() in game_update() + + game_update(game); +} + +// game_rem_move() + +void game_rem_move(game_t * game) { + + ASSERT(game!=NULL); + + game_goto(game,game->pos-1); + + game->size = game->pos; // truncate game +} + +// game_goto() + +void game_goto(game_t * game, int pos) { + + int i; + + ASSERT(game!=NULL); + ASSERT(pos>=0&&pos<=game->size); + + if (pos < game->pos) { // going backward => replay the whole game + board_copy(game->board,game->start_board); + game->pos = 0; + } + + for (i = game->pos; i < pos; i++) move_do(game->board,game->move[i]); + ASSERT(i==pos); + + game->pos = pos; + + game_update(game); +} + +// game_disp() + +void game_disp(const game_t * game) { + + board_t board[1]; + int i, move; + + ASSERT(game_is_ok(game)); + + board_copy(board,game->start_board); + + board_disp(board); + + for (i = 0; i < game->pos; i++) { + + move = game->move[i]; + move_disp(move,board); + + move_do(board,move); + } + + my_log("POLYGLOT\n"); + + board_disp(board); +} + +// game_update() + +static void game_update(game_t * game) { + + ASSERT(game!=NULL); + + game->status = game_comp_status(game); + + ASSERT(game_is_ok(game)); +} + +// game_comp_status() + +static int game_comp_status(const game_t * game) { + + int i, n; + int wb, bb; + const board_t * board; + uint64 key; + int start; + + ASSERT(game!=NULL); + + // init + + board = game->board; + + // mate and stalemate + + if (!board_can_play(board)) { + if (FALSE) { + } else if (is_in_check(board,Black)) { // HACK + return WHITE_MATES; + } else if (is_in_check(board,White)) { // HACK + return BLACK_MATES; + } else { + return STALEMATE; + } + } + + // insufficient material + + if (board->number[WhitePawn12] == 0 + && board->number[BlackPawn12] == 0 + && board->number[WhiteQueen12] == 0 + && board->number[BlackQueen12] == 0 + && board->number[WhiteRook12] == 0 + && board->number[BlackRook12] == 0) { + + if (board->number[WhiteBishop12] + + board->number[BlackBishop12] + + board->number[WhiteKnight12] + + board->number[BlackKnight12] <= 1) { // KK, KBK and KNK + + return DRAW_MATERIAL; + + } else if (board->number[WhiteBishop12] == 1 + && board->number[BlackBishop12] == 1 + && board->number[WhiteKnight12] == 0 + && board->number[BlackKnight12] == 0) { + + wb = board->list[White][1]; // HACK + bb = board->list[Black][1]; // HACK + + if (square_colour(wb) == square_colour(bb)) { // KBKB + return DRAW_MATERIAL; + } + } + } + + // 50-move rule + + if (board->ply_nb >= 100) return DRAW_FIFTY; + + // position repetition + + key = board->key; + n = 0; + + start = game->pos - board->ply_nb; + if (start < 0) start = 0; + + for (i = game->pos-4; i >= start; i -= 2) { + if (game->key[i] == key) { + if (++n == 2) return DRAW_REPETITION; + } + } + + return PLAYING; +} + +// end of game.cpp + diff --git a/game.h b/game.h index ec50ab2..e0fce79 100644 --- a/game.h +++ b/game.h @@ -10,11 +10,13 @@ #include "move.h" #include "util.h" -// constants +// defines -const int GameSize = 4096; +#define GameSize 4096 -enum status_t { +// types + +typedef enum { PLAYING, WHITE_MATES, BLACK_MATES, @@ -22,11 +24,11 @@ enum status_t { DRAW_MATERIAL, DRAW_FIFTY, DRAW_REPETITION -}; +} status_t; // types -struct game_t { +typedef struct { board_t start_board[1]; board_t board[1]; sint16 size; @@ -34,7 +36,7 @@ struct game_t { sint8 status; move_t move[GameSize]; uint64 key[GameSize]; -}; +} game_t; // variables @@ -53,7 +55,8 @@ extern int game_size (const game_t * game); extern int game_pos (const game_t * game); extern int game_move (const game_t * game, int pos); -extern void game_get_board (const game_t * game, board_t * board, int pos = -1); +extern void game_get_board (const game_t * game, board_t * board); +extern void game_get_board_ex (const game_t * game, board_t * board, int pos); extern int game_turn (const game_t * game); extern int game_move_nb (const game_t * game); diff --git a/gui.c b/gui.c new file mode 100644 index 0000000..9dbe6f5 --- /dev/null +++ b/gui.c @@ -0,0 +1,104 @@ +// gui.c + +// includes + +#include +#include + +#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 --- 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 index 0000000..4baa0aa --- /dev/null +++ b/hash.c @@ -0,0 +1,128 @@ + +// hash.c + +// includes + +#include "board.h" +#include "hash.h" +#include "piece.h" +#include "random.h" +#include "square.h" +#include "util.h" + +// variables + +static uint64 Castle64[16]; + +// prototypes + +static uint64 hash_castle_key_debug (int flags); + +// functions + +// hash_init() + +void hash_init() { + + int i; + + for (i = 0; i < 16; i++) Castle64[i] = hash_castle_key_debug(i); +} + +// hash_key() + +uint64 hash_key(const board_t * board) { + + uint64 key; + int colour; + const uint8 * ptr; + int sq, piece; + + ASSERT(board_is_ok(board)); + + // init + + key = 0; + + // pieces + + for (colour = 1; colour <= 2; colour++) { // HACK + for (ptr = board->list[colour]; (sq=*ptr) != SquareNone; ptr++) { + piece = board->square[sq]; + key ^= hash_piece_key(piece,sq); + } + } + + // castle flags + + key ^= hash_castle_key(board_flags(board)); + + // en-passant square + + sq = board->ep_square; + if (sq != SquareNone) key ^= hash_ep_key(sq); + + // turn + + key ^= hash_turn_key(board->turn); + + return key; +} + +// hash_piece_key() + +uint64 hash_piece_key(int piece, int square) { + + ASSERT(piece_is_ok(piece)); + ASSERT(square_is_ok(square)); + + return random_64(RandomPiece+piece_to_12(piece)*64+square_to_64(square)); +} + +// hash_castle_key() + +uint64 hash_castle_key(int flags) { + + ASSERT((flags&~0xF)==0); + + return Castle64[flags]; +} + +// hash_castle_key_debug() + +static uint64 hash_castle_key_debug(int flags) { + + uint64 key; + int i; + + ASSERT((flags&~0xF)==0); + + key = 0; + + for (i = 0; i < 4; i++) { + if ((flags & (1< +#include +#include +#include +#include + +#include +#include + +#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 --- a/io.h +++ b/io.h @@ -8,13 +8,13 @@ #include "util.h" -// constants +// defined -const int BufferSize = 16384; +#define BufferSize 16384 // types -struct io_t { +typedef struct { int in_fd; int out_fd; @@ -28,7 +28,7 @@ struct io_t { char in_buffer[BufferSize]; char out_buffer[BufferSize]; -}; +} io_t; // functions diff --git a/line.c b/line.c new file mode 100644 index 0000000..de8c5bb --- /dev/null +++ b/line.c @@ -0,0 +1,205 @@ + +// line.c + +// includes + +#include + +#include "board.h" +#include "line.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "san.h" +#include "util.h" + +// constants + +static const bool Strict = FALSE; // FALSE +static const bool UseDebug = FALSE; // FALSE + +static const int StringSize = 1024; + +// functions + +// line_is_ok() + +bool line_is_ok(const move_t line[]) { + + int move; + + if (line == NULL) return FALSE; + + while ((move = *line++) != MoveNone) { + if (!move_is_ok(move)) return FALSE; + } + + return TRUE; +} + +// line_clear() + +void line_clear(move_t line[]) { + + ASSERT(line!=NULL); + + *line = MoveNone; +} + +// line_copy() + +void line_copy(move_t dst[], const move_t src[]) { + + ASSERT(dst!=NULL); + ASSERT(src!=NULL); + + ASSERT(dst!=src); + + while ((*dst++ = *src++) != MoveNone) + ; +} + +// line_from_can() + +bool line_from_can (move_t line[], const board_t * board, const char string[], int size) { + + int pos; + char new_string[StringSize], *p; + int move; + board_t new_board[1]; + + ASSERT(line!=NULL); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=LineSize); + + // init + + pos = 0; + board_copy(new_board,board); + + // loop + + strcpy(new_string,string); // HACK + + for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) { + + move = move_from_can(p,new_board); + + ASSERT(move!=MoveNone); + ASSERT(move_is_legal(move,new_board)); + + if (move == MoveNone || !move_is_legal(move,new_board)) break; // HACK: ignore illegal moves + + if (pos >= size) return FALSE; + line[pos++] = move; + + move_do(new_board,move); + } + + if (pos >= size) return FALSE; + line[pos] = MoveNone; + + return TRUE; +} + +// line_to_can() + +bool line_to_can(const move_t line[], const board_t * board, char string[], int size) { + + board_t new_board[1]; + int pos; + int move; + + ASSERT(line_is_ok(line)); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=StringSize); + + // init + + if (size < StringSize) return FALSE; + + board_copy(new_board,board); + pos = 0; + + // loop + + while ((move = *line++) != MoveNone) { + + if (pos != 0) { + if (pos >= size) return FALSE; + string[pos++] = ' '; + } + + if (!move_to_can(move,new_board,&string[pos],size-pos)) return FALSE; + pos += strlen(&string[pos]); + + move_do(new_board,move); + } + + if (pos >= size) return FALSE; + string[pos] = '\0'; + + return TRUE; +} + +// line_to_san() + +bool line_to_san(const move_t line[], const board_t * board, char string[], int size) { + + board_t new_board[1]; + int pos; + int move; + char move_string[256]; + + ASSERT(line_is_ok(line)); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=StringSize); + + // init + + if (size < StringSize) return FALSE; + + board_copy(new_board,board); + pos = 0; + + // loop + + while ((move = *line++) != MoveNone) { + + if (pos != 0) { + if (pos >= size) return FALSE; + string[pos++] = ' '; + } + + if (!move_is_legal(move,new_board) + || !move_to_san(move,new_board,&string[pos],size-pos)) { + + if (Strict || UseDebug) { + + move_to_can(move,new_board,move_string,256); + my_log("POLYGLOT ILLEGAL MOVE IN LINE %s\n",move_string); + + board_disp(new_board); + } + + if (Strict) my_fatal("line_to_san(): illegal move\n"); + + break; + } + + pos += strlen(&string[pos]); + + move_do(new_board,move); + } + + if (pos >= size) return FALSE; + string[pos] = '\0'; + + return TRUE; +} + +// end of line.cpp + diff --git a/line.h b/line.h index b41eed8..6460edf 100644 --- a/line.h +++ b/line.h @@ -12,7 +12,7 @@ // constants -const int LineSize = 256; +#define LineSize 256 // functions diff --git a/list.c b/list.c new file mode 100644 index 0000000..4c2b08f --- /dev/null +++ b/list.c @@ -0,0 +1,275 @@ + +// list.c + +// includes + +#include "board.h" +#include "list.h" +#include "move.h" +#include "util.h" + +// functions + +// list_is_ok() + +bool list_is_ok(const list_t * list) { + + if (list == NULL) return FALSE; + + if (list->size >= ListSize) return FALSE; + + return TRUE; +} + +// list_clear() + +void list_clear(list_t * list) { + + ASSERT(list!=NULL); + + list->size = 0; +} + +// list_add + +void list_add(list_t * list, int move){ + list_add_ex(list, move, 0); +} + +// list_add_ex() + +void list_add_ex(list_t * list, int move, int value) { + + ASSERT(list_is_ok(list)); + ASSERT(move_is_ok(move)); + ASSERT(value>=-32767&&value<=+32767); + + ASSERT(list->sizemove[list->size] = move; + list->value[list->size] = value; + list->size++; +} + +// list_remove() + +void list_remove(list_t * list, int index) { + + int i; + + ASSERT(list_is_ok(list)); + ASSERT(index>=0&&indexsize); + + for (i = index; i < list->size-1; i++) { + list->move[i] = list->move[i+1]; + list->value[i] = list->value[i+1]; + } + + list->size--; +} + +// list_is_empty() + +bool list_is_empty(const list_t * list) { + + ASSERT(list_is_ok(list)); + + return list->size == 0; +} + +// list_size() + +int list_size(const list_t * list) { + + ASSERT(list_is_ok(list)); + + return list->size; +} + +// list_move() + +int list_move(const list_t * list, int index) { + + ASSERT(list_is_ok(list)); + ASSERT(index>=0&&indexsize); + + return list->move[index]; +} + +// list_value() + +int list_value(const list_t * list, int index) { + + ASSERT(list_is_ok(list)); + ASSERT(index>=0&&indexsize); + + return list->value[index]; +} + +// list_copy() + +void list_copy(list_t * dst, const list_t * src) { + + int i; + + ASSERT(dst!=NULL); + ASSERT(list_is_ok(src)); + + dst->size = src->size; + + for (i = 0; i < src->size; i++) { + dst->move[i] = src->move[i]; + dst->value[i] = src->value[i]; + } +} + +// list_move_to_front() + +void list_move_to_front(list_t * list, int index) { + + int i; + int move, value; + + ASSERT(list_is_ok(list)); + ASSERT(index>=0&&indexsize); + + if (index != 0) { + + move = list->move[index]; + value = list->value[index]; + + for (i = index; i > 0; i--) { + list->move[i] = list->move[i-1]; + list->value[i] = list->value[i-1]; + } + + list->move[0] = move; + list->value[0] = value; + } +} + +// list_note() + +void list_note(list_t * list) { + + int i, move; + + ASSERT(list_is_ok(list)); + + for (i = 0; i < list->size; i++) { + move = list->move[i]; + ASSERT(move_is_ok(move)); + list->value[i] = -move_order(move); + } +} + +// list_sort() + +void list_sort(list_t * list) { + + int i, j; + int best_index, best_move, best_value; + + ASSERT(list_is_ok(list)); + + for (i = 0; i < list->size-1; i++) { + + best_index = i; + best_value = list->value[i]; + + for (j = i+1; j < list->size; j++) { + if (list->value[j] > best_value) { + best_index = j; + best_value = list->value[j]; + } + } + + if (best_index != i) { + + best_move = list->move[best_index]; + ASSERT(best_value==list->value[best_index]); + + for (j = best_index; j > i; j--) { + list->move[j] = list->move[j-1]; + list->value[j] = list->value[j-1]; + } + + list->move[i] = best_move; + list->value[i] = best_value; + } + } + + if (DEBUG) { + for (i = 0; i < list->size-1; i++) { + ASSERT(list->value[i]>=list->value[i+1]); + } + } +} + +// list_contain() + +bool list_contain(const list_t * list, int move) { + + int i; + + ASSERT(list_is_ok(list)); + ASSERT(move_is_ok(move)); + + for (i = 0; i < list->size; i++) { + if (list->move[i] == move) return TRUE; + } + + return FALSE; +} + +// list_equal() + +bool list_equal(list_t * list_1, list_t * list_2) { + + list_t copy_1[1], copy_2[1]; + int i; + + ASSERT(list_is_ok(list_1)); + ASSERT(list_is_ok(list_2)); + + if (list_1->size != list_2->size) return FALSE; + + list_copy(copy_1,list_1); + list_note(copy_1); + list_sort(copy_1); + + list_copy(copy_2,list_2); + list_note(copy_2); + list_sort(copy_2); + + for (i = 0; i < copy_1->size; i++) { + if (copy_1->move[i] != copy_2->move[i]) return FALSE; + } + + return TRUE; +} + +// list_disp() + +void list_disp(const list_t * list, const board_t * board) { + + int i, move, value; + char string[256]; + + ASSERT(list_is_ok(list)); + ASSERT(board_is_ok(board)); + + for (i = 0; i < list->size; i++) { + + move = list->move[i]; + value = list->value[i]; + + if (!move_to_can(move,board,string,256)) ASSERT(FALSE); + my_log("POLYGLOT %-5s %04X %+4d\n",string,move,value); + } + + my_log("POLYGLOT\n"); +} + +// end of list.cpp + diff --git a/list.h b/list.h index 9004602..d366896 100644 --- a/list.h +++ b/list.h @@ -10,24 +10,26 @@ #include "move.h" #include "util.h" -// constants +// defines -const int ListSize = 256; +#define ListSize 256 // types -struct list_t { +typedef struct { sint16 size; move_t move[ListSize]; sint16 value[ListSize]; -}; +} list_t; // functions extern bool list_is_ok (const list_t * list); extern void list_clear (list_t * list); -extern void list_add (list_t * list, int move, int value = 0); +extern void list_add (list_t * list, int move); +extern void list_add_ex (list_t * list, int move, int value); + extern void list_remove (list_t * list, int index); extern bool list_is_empty (const list_t * list); diff --git a/main.c b/main.c new file mode 100644 index 0000000..ad9ecca --- /dev/null +++ b/main.c @@ -0,0 +1,384 @@ + +// main.c + +// includes + +#include +#include +#include +#include + +#include "attack.h" +#include "board.h" +#include "book.h" +#include "book_make.h" +#include "book_merge.h" +#include "engine.h" +#include "epd.h" +#include "fen.h" +#include "gui.h" +#include "hash.h" +#include "list.h" +#include "main.h" +#include "mainloop.h" +#include "move.h" +#include "move_gen.h" +#include "option.h" +#include "piece.h" +#include "search.h" +#include "square.h" +#include "uci.h" +#include "util.h" +#include "xboard2uci.h" +#include "uci2uci.h" + +// constants + + +static const char * const Version = "1.4.30b"; +static const char * const HelpMessage = "\ +SYNTAX\n\ +* polyglot [configfile]\n\ +* polyglot -ec enginecommand\n\ +* polyglot make-book [-pgn inputfile] [-bin outputfile] [-max-ply ply] [-min-game games] [-min-score score] [-only-white] [-only-black] [-uniform]\n\ +* polyglot merge-book -in1 inputfile1 -in2 inputfile2 [-out outputfile]\n\ +* polyglot info-book [-bin inputfile] [-exact]\n\ +* polyglot dumb-book [-bin inputfile] -color color [-out outputfile]\n\ +* polyglot [configfile] epd-test [-epd inputfile] [-min-depth depth] [-max-depth depth] [-min-time time] [-max-time time] [-depth-delta delta]\n\ +* polyglot perft [-fen fen] [-max-depth depth]\ +"; + +static const int SearchDepth = 63; +static const double SearchTime = 3600.0; +static const int StringSize = 4096; + +// variables + +static bool Init; + +// prototypes + +static void parse_option (); +static void init_book (); +static bool parse_line (char line[], char * * name_ptr, char * * value_ptr); +static void stop_search (); + +// functions + +// main() + +int main(int argc, char * argv[]) { + + if(!DEBUG){ + printf("PolyGlot %s by Fabien Letouzey.\n",Version); + }else{ + printf("PolyGlot %s by Fabien Letouzey (debug build).\n",Version); + } + + 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],"/?"))){ + printf("%s\n",HelpMessage); + return EXIT_SUCCESS; + } + + // init + + Init = FALSE; + + util_init(); + option_init(); + + square_init(); + piece_init(); + attack_init(); + + hash_init(); + + my_random_init(); + + // build book + + if (argc >= 2 && my_string_equal(argv[1],"make-book")) { + book_make(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 2 && my_string_equal(argv[1],"merge-book")) { + book_merge(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 2 && my_string_equal(argv[1],"merge-book")) { + book_merge(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 2 && my_string_equal(argv[1],"dump-book")) { + book_dump(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 2 && my_string_equal(argv[1],"info-book")) { + book_info(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 2 && my_string_equal(argv[1],"perft")) { + do_perft(argc,argv); + return EXIT_SUCCESS; + } + + if (argc >= 3 && my_string_equal(argv[1],"-ec")) { + option_set("EngineCommand",argv[2]); + engine_open(Engine); + if(!engine_active(Engine)){ + my_fatal("Could not start \"%s\"\n",option_get("EngineCommand")); + } + Init=TRUE; + gui_init(GUI); + uci_open(Uci,Engine); + if (my_string_equal(option_get_string("EngineName"),"")) { + option_set("EngineName",Uci->name); + } + mainloop(); + return EXIT_SUCCESS; + } + + // read options + + if (argc == 2) option_set("OptionFile",argv[1]); // HACK for compatibility + + parse_option(); // HACK: also launches the engine + + // EPD test + + if (argc >= 2 && my_string_equal(argv[1],"epd-test")){ + epd_test(argc,argv); + return EXIT_SUCCESS; + }else if(argc >= 3 && my_string_equal(argv[2],"epd-test")){ + epd_test(argc-1,argv+1); + return EXIT_SUCCESS; + } + + if (argc >= 3) my_fatal("Too many arguments\n"); + + + init_book(); + gui_init(GUI); + mainloop(); + return EXIT_SUCCESS; +} + +// polyglot_set_option + +void polyglot_set_option(char *name, char *value){ // this must be cleaned up! + option_set(name,value); + if(option_get_bool("Book")&&(my_string_case_equal(name,"BookFile")||my_string_case_equal(name,"Book"))){ + my_log("POLYGLOT *** SETTING BOOK ***\n"); + my_log("POLYGLOT BOOK \"%s\"\n",option_get_string("BookFile")); + book_close(); + book_clear(); + book_open(option_get_string("BookFile")); + if(!book_is_open()){ + my_log("POLYGLOT Unable to open book \"%s\"\n",option_get_string("BookFile")); + } + }else if(option_get_bool("Log")&&(my_string_case_equal(name,"LogFile") ||my_string_case_equal(name,"Log"))){ + my_log("POLYGLOT *** SETTING LOGFILE ***\n"); + my_log("POLYGLOT LOGFILE \"%s\"\n",option_get_string("LogFile")); + my_log_close(); + my_log_open(option_get_string("LogFile")); + }else if(option_get_bool("UseNice") &&(my_string_case_equal(name,"NiceValue")||my_string_case_equal(name,"UseNice"))){ + my_log("POLYGLOT Adjust Engine Piority\n"); + engine_set_nice_value(Engine,atoi(option_get_string("NiceValue"))); + }else if(my_string_case_equal(name,"Book") && !option_get_bool("Book")){ + book_close(); + book_clear(); + }else if(my_string_case_equal(name,"UseNice") && !option_get_bool("UseNice")){ + my_log("POLYGLOT Adjust Engine Piority\n"); + engine_set_nice_value(Engine,0); + }else if(my_string_case_equal(name,"Log") && !option_get_bool("Log")){ + my_log("POLYGLOT QUIT LOGGING\n"); + my_log_close(); + } +} + + +// init_book() + +static void init_book(){ + book_clear(); + if (option_get_bool("Book")){ + my_log("POLYGLOT *** SETTING BOOK ***\n"); + my_log("POLYGLOT BOOK \"%s\"\n",option_get_string("BookFile")); + book_open(option_get_string("BookFile")); + if(!book_is_open()){ + my_log("POLYGLOT Unable to open book \"%s\"\n", + option_get_string("BookFile")); + } + } +} + +// parse_option() + +static void parse_option() { + + const char * file_name; + FILE * file; + char line[256]; + char * name, * value; + file_name = option_get_string("OptionFile"); + + file = fopen(file_name,"r"); + if (file == NULL) { + my_fatal("Can't open file \"%s\": %s\n",file_name,strerror(errno)); + } + + // PolyGlot options (assumed first) + + while (TRUE) { + + if (!my_file_read_line(file,line,256)) { + my_fatal("parse_option(): missing [Engine] section\n"); + } + + if (my_string_case_equal(line,"[engine]")) break; + + if (parse_line(line,&name,&value)) { + option_set(name,value); + option_set_default(name,value); + } + } + + if (option_get_bool("Log")) { + my_log_open(option_get_string("LogFile")); + } + + if(!DEBUG){ + my_log("PolyGlot %s by Fabien Letouzey\n",Version); + }else{ + my_log("PolyGlot %s by Fabien Letouzey (debug build)\n",Version); + } + + my_log("POLYGLOT *** START ***\n"); + my_log("POLYGLOT INI file \"%s\"\n",file_name); + engine_open(Engine); + if(!engine_active(Engine)){ + my_fatal("Could not start \"%s\"\n",option_get("EngineCommand")); + } + + if (option_get_bool("UCI")) { + my_log("POLYGLOT *** Switching to UCI mode ***\n"); + } + uci_open(Uci,Engine); + Init = TRUE; + while (my_file_read_line(file,line,256)) { + if (line[0] == '[') my_fatal("parse_option(): unknown section %s\n",line); + if (parse_line(line,&name,&value)) { + uci_send_option(Uci,name,"%s",value); + //to get a decent display in winboard_x we need to now if an engine really is doing multipv analysis + // "multipv 1" in the pv is meaningless,f.i. toga sends that all the time + //therefore check if MultiPV is set to a decent value in the polyglot ini file + if(my_string_case_equal(name,"MultiPV") && atoi(value)>1) Uci->multipv_mode=TRUE; + } + } + if (my_string_equal(option_get_string("EngineName"),"")) { + option_set("EngineName",Uci->name); + } + + fclose(file); +} + +// parse_line() + +static bool parse_line(char line[], char * * name_ptr, char * * value_ptr) { + + char * ptr; + char * name, * value; + + ASSERT(line!=NULL); + ASSERT(name_ptr!=NULL); + ASSERT(value_ptr!=NULL); + + // remove comments + + ptr = strchr(line,';'); + if (ptr != NULL) *ptr = '\0'; + + ptr = strchr(line,'#'); + if (ptr != NULL) *ptr = '\0'; + + // split at '=' + + ptr = strchr(line,'='); + if (ptr == NULL) return FALSE; + + name = line; + value = ptr+1; + + // cleanup name + + while (*name == ' ') name++; // remove leading spaces + + while (ptr > name && ptr[-1] == ' ') ptr--; // remove trailing spaces + *ptr = '\0'; + + if (*name == '\0') return FALSE; + + // cleanup value + + ptr = &value[strlen(value)]; // pointer to string terminator + + while (*value == ' ') value++; // remove leading spaces + + while (ptr > value && ptr[-1] == ' ') ptr--; // remove trailing spaces + *ptr = '\0'; + + if (*value == '\0') return FALSE; + + // end + + *name_ptr = name; + *value_ptr = value; + + return TRUE; +} + +// quit() + +void quit() { + + my_log("POLYGLOT *** QUIT ***\n"); + + if (Init) { + + stop_search(); + engine_send(Engine,"quit"); + my_log("POLYGLOT Closing engine\n"); + engine_close(Engine); + + } + my_log("POLYGLOT Calling exit\n"); + exit(EXIT_SUCCESS); +} + +// stop_search() + +static void stop_search() { + + if (Init && Uci->searching) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + my_log("POLYGLOT STOP SEARCH\n"); + + if (option_get_bool("SyncStop")) { + uci_send_stop_sync(Uci); + } else { + uci_send_stop(Uci); + } + } +} + + +// end of main.cpp + diff --git a/mainloop.c b/mainloop.c new file mode 100644 index 0000000..d41e713 --- /dev/null +++ b/mainloop.c @@ -0,0 +1,103 @@ +// mainloop.c + +// constants + +static const int StringSize = 4096; + +// includes + +#include +#include +#include +#include + +#include "main.h" +#include "engine.h" +#include "gui.h" +#include "option.h" +#include "xboard2uci.h" +#include "uci2uci.h" + +// prototypes + +static void mainloop_init (); +static void mainloop_wait_for_event (); +static void mainloop_engine_step(char * string); +static void mainloop_gui_step(char * string); + +// functions + +// mainloop_init() + +static void mainloop_init(){ + if(!option_get_bool("UCI")){ + xboard2uci_init(); // the default + } +} + +// mainloop_engine_step() + +static void mainloop_engine_step(char * string){ + if(option_get_bool("UCI")){ + uci2uci_engine_step(string); + }else{ + xboard2uci_engine_step(string); + } +} + +// mainloop_gui_step() + +static void mainloop_gui_step(char * string){ + if(option_get_bool("UCI")){ + uci2uci_gui_step(string); + }else if(my_string_equal(string,"uci")){ // mode auto detection + my_log("POLYGLOT *** Switching to UCI mode ***\n"); + option_set("UCI","TRUE"); + uci2uci_gui_step(string); + }else{ + xboard2uci_gui_step(string); + } +} + +// mainloop() + +void mainloop() { + char string[StringSize]; + mainloop_init(); + while (!engine_eof(Engine)) { + // process buffered lines + while(TRUE){ + if(gui_get_non_blocking(GUI,string)){ + mainloop_gui_step(string); + }else if(!engine_eof(Engine) && + engine_get_non_blocking(Engine,string) ){ + mainloop_engine_step(string); + }else{ + break; + } + } + mainloop_wait_for_event(); + } + my_log("POLYGLOT *** Mainloop has ended ***\n"); + // This should be handled better. + engine_close(Engine); + my_log("POLYGLOT Calling exit\n"); + exit(EXIT_SUCCESS); + +} + + + + +// mainloop_wait_for_event() + +static void mainloop_wait_for_event(){ + pipex_t *pipex[3]; + pipex[0]=GUI->pipex; + pipex[1]=Engine->pipex; + pipex[2]=NULL; + pipex_wait_event(pipex); +} + + + diff --git a/makefile.gcc b/makefile.gcc index d432b9c..8890ee9 100644 --- a/makefile.gcc +++ b/makefile.gcc @@ -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 index 0000000..8d5699f --- /dev/null +++ b/move.c @@ -0,0 +1,376 @@ + +// move.c + +// includes + +#include +#include + +#include "attack.h" +#include "colour.h" +#include "list.h" +#include "move.h" +#include "move_do.h" +#include "move_gen.h" +#include "move_legal.h" +#include "option.h" +#include "piece.h" +#include "square.h" +#include "util.h" + +// "constants" + +static const uint8 PromotePiece[5] = { PieceNone64, Knight64, Bishop64, Rook64, Queen64 }; + +// functions + +// move_is_ok() + +bool move_is_ok(int move) { + + if (move < 0 || move >= 65536) return FALSE; + + if (move == MoveNone) return FALSE; + + return TRUE; +} + +// move_make() + +int move_make(int from, int to) { + + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + + return (square_to_64(from) << 6) | square_to_64(to); +} + +// move_make_flags() + +int move_make_flags(int from, int to, int flags) { + + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + ASSERT((flags&~0xF000)==0); + + ASSERT(to!=from); + + return (square_to_64(from) << 6) | square_to_64(to) | flags; +} + +// move_from() + +int move_from(int move) { + + int from_64; + + ASSERT(move_is_ok(move)); + + from_64 = (move >> 6) & 077; + + return square_from_64(from_64); +} + +// move_to() + +int move_to(int move) { + + int to_64; + + ASSERT(move_is_ok(move)); + + to_64 = move & 077; + + return square_from_64(to_64); +} + +// move_promote_hack() + +int move_promote_hack(int move) { + + int code; + + ASSERT(move_is_ok(move)); + + ASSERT(move_is_promote(move)); + + code = move >> 12; + ASSERT(code>=1&&code<=4); + + return PromotePiece[code]; +} + +// move_is_capture() + +bool move_is_capture(int move, const board_t * board) { + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + if (move_is_en_passant(move,board)) return TRUE; + if (board->square[move_to(move)] != Empty) return TRUE; + + return FALSE; +} + +// move_is_promote() + +bool move_is_promote(int move) { + + ASSERT(move_is_ok(move)); + + return (move & MoveFlags) != 0; +} + +// move_is_en_passant() + +bool move_is_en_passant(int move, const board_t * board) { + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + return piece_is_pawn(move_piece(move,board)) + && move_to(move) == board->ep_square; +} + +// move_is_castle() + +bool move_is_castle(int move, const board_t * board) { + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + return colour_equal(board->square[move_to(move)],board->turn); +} + +// move_piece() + +int move_piece(int move, const board_t * board) { + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + return board->square[move_from(move)]; +} + +// move_capture() + +int move_capture(int move, const board_t * board) { + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + if (move_is_en_passant(move,board)) { + return piece_pawn_opp(move_piece(move,board)); + } + + return board->square[move_to(move)]; +} + +// move_promote() + +int move_promote(int move, const board_t * board) { + + int code; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + if (move_is_promote(move)) { + code = move >> 12; + ASSERT(code>=1&&code<=4); + return PromotePiece[code] | board->turn; + } + + return Empty; +} + +// move_is_check() + +bool move_is_check(int move, const board_t * board) { + + board_t new_board[1]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + board_copy(new_board,board); + move_do(new_board,move); + ASSERT(!is_in_check(new_board,colour_opp(new_board->turn))); + + return board_is_check(new_board); +} + +// move_is_mate() + +bool move_is_mate(int move, const board_t * board) { + + board_t new_board[1]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + board_copy(new_board,board); + move_do(new_board,move); + ASSERT(!is_in_check(new_board,colour_opp(new_board->turn))); + + return board_is_mate(new_board); +} + +// move_to_can() + +bool move_to_can(int move, const board_t * board, char string[], int size) { + + int from, to; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=6); + + ASSERT(move_is_legal(move,board)); + + if (size < 6) return FALSE; + + // init + + from = move_from(move); + to = move_to(move); + + // king-slide castling + + if (move_is_castle(move,board) && !option_get_bool("Chess960")) { + if (FALSE) { + } else if (from == E1 && to == H1) { + to = G1; + } else if (from == E1 && to == A1) { + to = C1; + } else if (from == E8 && to == H8) { + to = G8; + } else if (from == E8 && to == A8) { + to = C8; + } + } + + // normal moves + + if (!square_to_string(from,&string[0],3)) ASSERT(FALSE); + if (!square_to_string(to,&string[2],3)) ASSERT(FALSE); + ASSERT(strlen(string)==4); + + // promotes + + if (move_is_promote(move)) { + string[4] = piece_to_char(move_promote_hack(move)|Black); // HACK: black => lower-case + string[5] = '\0'; + } + + // debug + + ASSERT(move_from_can(string,board)==move); + + return TRUE; +} + +// move_from_can() + +int move_from_can(const char string[], const board_t * board) { + + char tmp_string[256]; + int from, to; + int side; + int move; + + ASSERT(string!=NULL); + ASSERT(board_is_ok(board)); + + // from + + tmp_string[0] = string[0]; + tmp_string[1] = string[1]; + tmp_string[2] = '\0'; + + from = square_from_string(tmp_string); + if (from == SquareNone) return MoveNone; + + // to + + tmp_string[0] = string[2]; + tmp_string[1] = string[3]; + tmp_string[2] = '\0'; + + to = square_from_string(tmp_string); + if (to == SquareNone) return MoveNone; + + // convert "king slide" castling to KxR + + if (piece_is_king(board->square[from]) + && square_rank(to) == square_rank(from) + && abs(to-from) > 1) { + side = (to > from) ? SideH : SideA; + to = board->castle[board->turn][side]; + if (to == SquareNone) return MoveNone; + } + // move + + move = move_make(from,to); + + // promote + switch (string[4]) { + case '\0': // not a promotion + if (piece_is_pawn(board->square[from]) + && square_side_rank(to,board->turn) == Rank8 + && option_get_bool("PromoteWorkAround")) { + move |= MovePromoteQueen; + } + break; + case 'N': + case 'n': + move |= MovePromoteKnight; + break; + case 'B': + case 'b': + move |= MovePromoteBishop; + break; + case 'R': + case 'r': + move |= MovePromoteRook; + break; + case 'Q': + case 'q': + move |= MovePromoteQueen; + break; + default: + return MoveNone; + break; + } + // debug + + ASSERT(move_is_legal(move,board)); + return move; +} + +// move_order() + +int move_order(int move) { + + ASSERT(move_is_ok(move)); + + return ((move & 07777) << 3) | (move >> 12); // from, to, promote +} + +// move_disp() + +void move_disp(int move, const board_t * board) { + + char string[256]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + if (!move_to_can(move,board,string,256)) ASSERT(FALSE); + my_log("POLYGLOT %s\n",string); +} + +// end of move.cpp + diff --git a/move.h b/move.h index b6e7081..c83f155 100644 --- a/move.h +++ b/move.h @@ -9,15 +9,16 @@ #include "board.h" #include "util.h" -// constants +// defined -const int MoveNone = 0; // HACK: a1a1 cannot be a legal move +// HACK: a1a1 cannot be a legal move +#define MoveNone (0) -const int MovePromoteKnight = 1 << 12; -const int MovePromoteBishop = 2 << 12; -const int MovePromoteRook = 3 << 12; -const int MovePromoteQueen = 4 << 12; -const int MoveFlags = 7 << 12; +#define MovePromoteKnight (1 << 12) +#define MovePromoteBishop (2 << 12) +#define MovePromoteRook (3 << 12) +#define MovePromoteQueen (4 << 12) +#define MoveFlags (7 << 12) // types diff --git a/move_do.c b/move_do.c new file mode 100644 index 0000000..8c00687 --- /dev/null +++ b/move_do.c @@ -0,0 +1,363 @@ + +// move_do.c + +// includes + +#include + +#include "board.h" +#include "colour.h" +#include "hash.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "piece.h" +#include "random.h" +#include "util.h" + +// prototypes + +static void square_clear (board_t * board, int square, int piece); +static void square_set (board_t * board, int square, int piece, int pos); +static void square_move (board_t * board, int from, int to, int piece); + +// functions + +// move_do() + +void move_do(board_t * board, int move) { + + int me, opp; + int from, to; + int piece, pos, capture; + int old_flags, new_flags; + int sq, ep_square; + int pawn; + + ASSERT(board_is_ok(board)); + ASSERT(move_is_ok(move)); + + ASSERT(move_is_pseudo(move,board)); + + // init + + me = board->turn; + opp = colour_opp(me); + + from = move_from(move); + to = move_to(move); + + piece = board->square[from]; + ASSERT(colour_equal(piece,me)); + + pos = board->pos[from]; + ASSERT(pos>=0); + + // update turn + + board->turn = opp; + board->key ^= random_64(RandomTurn); + + // update castling rights + + old_flags = board_flags(board); + + if (piece_is_king(piece)) { + board->castle[me][SideH] = SquareNone; + board->castle[me][SideA] = SquareNone; + } + + if (board->castle[me][SideH] == from) board->castle[me][SideH] = SquareNone; + if (board->castle[me][SideA] == from) board->castle[me][SideA] = SquareNone; + + if (board->castle[opp][SideH] == to) board->castle[opp][SideH] = SquareNone; + if (board->castle[opp][SideA] == to) board->castle[opp][SideA] = SquareNone; + + new_flags = board_flags(board); + + board->key ^= hash_castle_key(new_flags^old_flags); // HACK + + // update en-passant square + + ep_square = sq = board->ep_square; + if (sq != SquareNone) { + board->key ^= random_64(RandomEnPassant+square_file(sq)); + board->ep_square = SquareNone; + } + + if (piece_is_pawn(piece) && abs(to-from) == 32) { + pawn = piece_make_pawn(opp); + if (board->square[to-1] == pawn || board->square[to+1] == pawn) { + board->ep_square = sq = (from + to) / 2; + board->key ^= random_64(RandomEnPassant+square_file(sq)); + } + } + + // update ply number (captures are handled later) + + board->ply_nb++; + if (piece_is_pawn(piece)) board->ply_nb = 0; // conversion + + // update move number + + if (me == Black) board->move_nb++; + + // castle + + if (colour_equal(board->square[to],me)) { + + int rank; + int king_from, king_to; + int rook_from, rook_to; + int rook; + + rank = colour_is_white(me) ? Rank1 : Rank8; + + king_from = from; + rook_from = to; + + if (to > from) { // h side + king_to = square_make(FileG,rank); + rook_to = square_make(FileF,rank); + } else { // a side + king_to = square_make(FileC,rank); + rook_to = square_make(FileD,rank); + } + + // remove the rook + + pos = board->pos[rook_from]; + ASSERT(pos>=0); + + rook = Rook64 | me; // HACK + + square_clear(board,rook_from,rook); + + // move the king + + square_move(board,king_from,king_to,piece); + + // put the rook back + + square_set(board,rook_to,rook,pos); + + ASSERT(board->key==hash_key(board)); + + return; + } + + // remove the captured piece + + if (piece_is_pawn(piece) && to == ep_square) { + + // en-passant capture + + sq = square_ep_dual(to); + capture = board->square[sq]; + ASSERT(capture==piece_make_pawn(opp)); + + square_clear(board,sq,capture); + + board->ply_nb = 0; // conversion + + } else { + + capture = board->square[to]; + + if (capture != Empty) { + + // normal capture + + ASSERT(colour_equal(capture,opp)); + ASSERT(!piece_is_king(capture)); + + square_clear(board,to,capture); + + board->ply_nb = 0; // conversion + } + } + + // move the piece + + if (move_is_promote(move)) { + + // promote + + square_clear(board,from,piece); + piece = move_promote_hack(move) | me; // HACK + square_set(board,to,piece,pos); + + } else { + + // normal move + + square_move(board,from,to,piece); + } + + ASSERT(board->key==hash_key(board)); +} + +// square_clear() + +static void square_clear(board_t * board, int square, int piece) { + + int pos, piece_12, colour; + int sq, size; + + ASSERT(board!=NULL); + ASSERT(square_is_ok(square)); + ASSERT(piece_is_ok(piece)); + + // init + + pos = board->pos[square]; + ASSERT(pos>=0); + + colour = piece_colour(piece); + piece_12 = piece_to_12(piece); + + // square + + ASSERT(board->square[square]==piece); + board->square[square] = Empty; + + ASSERT(board->pos[square]==pos); + board->pos[square] = -1; // not needed + + // piece list + + ASSERT(board->list_size[colour]>=2); + size = --board->list_size[colour]; + ASSERT(pos<=size); + + if (pos != size) { + + sq = board->list[colour][size]; + ASSERT(square_is_ok(sq)); + ASSERT(sq!=square); + + ASSERT(board->pos[sq]==size); + board->pos[sq] = pos; + + ASSERT(board->list[colour][pos]==square); + board->list[colour][pos] = sq; + } + + board->list[colour][size] = SquareNone; + + // material + + ASSERT(board->number[piece_12]>=1); + board->number[piece_12]--; + + // hash key + + board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square)); +} + +// square_set() + +static void square_set(board_t * board, int square, int piece, int pos) { + + int piece_12, colour; + int sq, size; + + ASSERT(board!=NULL); + ASSERT(square_is_ok(square)); + ASSERT(piece_is_ok(piece)); + ASSERT(pos>=0); + + // init + + colour = piece_colour(piece); + piece_12 = piece_to_12(piece); + + // square + + ASSERT(board->square[square]==Empty); + board->square[square] = piece; + + ASSERT(board->pos[square]==-1); + board->pos[square] = pos; + + // piece list + + size = board->list_size[colour]++; + ASSERT(board->list[colour][size]==SquareNone); + ASSERT(pos<=size); + + if (pos != size) { + + sq = board->list[colour][pos]; + ASSERT(square_is_ok(sq)); + ASSERT(sq!=square); + + ASSERT(board->pos[sq]==pos); + board->pos[sq] = size; + + ASSERT(board->list[colour][size]==SquareNone); + board->list[colour][size] = sq; + } + + board->list[colour][pos] = square; + + // material + + ASSERT(board->number[piece_12]<=8); + board->number[piece_12]++; + + // hash key + + board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square)); +} + +// square_move() + +static void square_move(board_t * board, int from, int to, int piece) { + + int colour, pos; + int piece_index; + + ASSERT(board!=NULL); + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + ASSERT(piece_is_ok(piece)); + + // init + + colour = piece_colour(piece); + + pos = board->pos[from]; + ASSERT(pos>=0); + + // from + + ASSERT(board->square[from]==piece); + board->square[from] = Empty; + + ASSERT(board->pos[from]==pos); + board->pos[from] = -1; // not needed + + // to + + ASSERT(board->square[to]==Empty); + board->square[to] = piece; + + ASSERT(board->pos[to]==-1); + board->pos[to] = pos; + + // piece list + + ASSERT(board->list[colour][pos]==from); + board->list[colour][pos] = to; + + // hash key + + piece_index = RandomPiece + piece_to_12(piece) * 64; + + board->key ^= random_64(piece_index+square_to_64(from)) + ^ random_64(piece_index+square_to_64(to)); +} + +// end of move_do.cpp + diff --git a/move_gen.c b/move_gen.c new file mode 100644 index 0000000..2d45564 --- /dev/null +++ b/move_gen.c @@ -0,0 +1,328 @@ + +// move_gen.c + +// includes + +#include "attack.h" +#include "board.h" +#include "colour.h" +#include "list.h" +#include "move.h" +#include "move_gen.h" +#include "move_legal.h" +#include "piece.h" +#include "util.h" + +// prototypes + +static void add_all_moves (list_t * list, const board_t * board); +static void add_castle_moves (list_t * list, const board_t * board); + +static void add_pawn_move (list_t * list, int from, int to); + +// functions + +// gen_legal_moves() + +void gen_legal_moves(list_t * list, const board_t * board) { + + ASSERT(list!=NULL); + ASSERT(board_is_ok(board)); + + gen_moves(list,board); + filter_legal(list,board); +} + +// gen_moves() + +void gen_moves(list_t * list, const board_t * board) { + + ASSERT(list!=NULL); + ASSERT(board_is_ok(board)); + + list_clear(list); + + add_all_moves(list,board); + if (!is_in_check(board,board->turn)) add_castle_moves(list,board); +} + +// add_all_moves() + +static void add_all_moves(list_t * list, const board_t * board) { + + int me, opp; + const uint8 * ptr; + const sint8 * ptr_inc; + int from, to; + int inc; + int piece, capture; + + ASSERT(list_is_ok(list)); + ASSERT(board_is_ok(board)); + + me = board->turn; + opp = colour_opp(me); + + for (ptr = board->list[me]; (from=*ptr) != SquareNone; ptr++) { + + piece = board->square[from]; + ASSERT(colour_equal(piece,me)); + + switch (piece_type(piece)) { + + case WhitePawn64: + + to = from + 15; + if (to == board->ep_square || colour_equal(board->square[to],opp)) { + add_pawn_move(list,from,to); + } + + to = from + 17; + if (to == board->ep_square || colour_equal(board->square[to],opp)) { + add_pawn_move(list,from,to); + } + + to = from + 16; + if (board->square[to] == Empty) { + add_pawn_move(list,from,to); + if (square_rank(from) == Rank2) { + to = from + 32; + if (board->square[to] == Empty) { + ASSERT(!square_is_promote(to)); + list_add(list,move_make(from,to)); + } + } + } + + break; + + case BlackPawn64: + + to = from - 17; + if (to == board->ep_square || colour_equal(board->square[to],opp)) { + add_pawn_move(list,from,to); + } + + to = from - 15; + if (to == board->ep_square || colour_equal(board->square[to],opp)) { + add_pawn_move(list,from,to); + } + + to = from - 16; + if (board->square[to] == Empty) { + add_pawn_move(list,from,to); + if (square_rank(from) == Rank7) { + to = from - 32; + if (board->square[to] == Empty) { + ASSERT(!square_is_promote(to)); + list_add(list,move_make(from,to)); + } + } + } + + break; + + case Knight64: + + for (ptr_inc = KnightInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { + to = from + inc; + capture = board->square[to]; + if (capture == Empty || colour_equal(capture,opp)) { + list_add(list,move_make(from,to)); + } + } + + break; + + case Bishop64: + + for (ptr_inc = BishopInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { + for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { + list_add(list,move_make(from,to)); + } + if (colour_equal(capture,opp)) { + list_add(list,move_make(from,to)); + } + } + + break; + + case Rook64: + + for (ptr_inc = RookInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { + for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { + list_add(list,move_make(from,to)); + } + if (colour_equal(capture,opp)) { + list_add(list,move_make(from,to)); + } + } + + break; + + case Queen64: + + for (ptr_inc = QueenInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { + for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { + list_add(list,move_make(from,to)); + } + if (colour_equal(capture,opp)) { + list_add(list,move_make(from,to)); + } + } + + break; + + case King64: + + for (ptr_inc = KingInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { + to = from + inc; + capture = board->square[to]; + if (capture == Empty || colour_equal(capture,opp)) { + list_add(list,move_make(from,to)); + } + } + + break; + + default: + + ASSERT(FALSE); + break; + } + } +} + +// add_castle_moves() + +static void add_castle_moves(list_t * list, const board_t * board) { + + int me, opp; + int rank; + int king_from, king_to; + int rook_from, rook_to; + bool legal; + int inc; + int sq; + + ASSERT(list_is_ok(list)); + ASSERT(board_is_ok(board)); + + ASSERT(!is_in_check(board,board->turn)); + + me = board->turn; + opp = colour_opp(me); + + rank = colour_is_white(me) ? Rank1 : Rank8; + + // h-side castling + + if (board->castle[me][SideH] != SquareNone) { + + king_from = king_pos(board,me); + king_to = square_make(FileG,rank); + rook_from = board->castle[me][SideH]; + rook_to = square_make(FileF,rank); + + ASSERT(square_rank(king_from)==rank); + ASSERT(square_rank(rook_from)==rank); + ASSERT(board->square[king_from]==(King64|me)); // HACK + ASSERT(board->square[rook_from]==(Rook64|me)); // HACK + ASSERT(rook_from>king_from); + + legal = TRUE; + + if (king_to != king_from) { + + inc = (king_to > king_from) ? +1 : -1; + + for (sq = king_from+inc; TRUE; sq += inc) { + + if (sq != rook_from && board->square[sq] != Empty) legal = FALSE; + if (is_attacked(board,sq,opp)) legal = FALSE; + + if (sq == king_to) break; + } + } + + if (rook_to != rook_from) { + + inc = (rook_to > rook_from) ? +1 : -1; + + for (sq = rook_from+inc; TRUE; sq += inc) { + if (sq != king_from && board->square[sq] != Empty) legal = FALSE; + if (sq == rook_to) break; + } + } + + if (legal) list_add(list,move_make(king_from,rook_from)); + } + + // a-side castling + + if (board->castle[me][SideA] != SquareNone) { + + king_from = king_pos(board,me); + king_to = square_make(FileC,rank); + rook_from = board->castle[me][SideA]; + rook_to = square_make(FileD,rank); + + ASSERT(square_rank(king_from)==rank); + ASSERT(square_rank(rook_from)==rank); + ASSERT(board->square[king_from]==(King64|me)); // HACK + ASSERT(board->square[rook_from]==(Rook64|me)); // HACK + ASSERT(rook_from king_from) ? +1 : -1; + + for (sq = king_from+inc; TRUE; sq += inc) { + + if (sq != rook_from && board->square[sq] != Empty) legal = FALSE; + if (is_attacked(board,sq,opp)) legal = FALSE; + + if (sq == king_to) break; + } + } + + if (rook_to != rook_from) { + + inc = (rook_to > rook_from) ? +1 : -1; + + for (sq = rook_from+inc; TRUE; sq += inc) { + if (sq != king_from && board->square[sq] != Empty) legal = FALSE; + if (sq == rook_to) break; + } + } + + if (legal) list_add(list,move_make(king_from,rook_from)); + } +} + +// add_pawn_move() + +static void add_pawn_move(list_t * list, int from, int to) { + + int move; + + ASSERT(list_is_ok(list)); + ASSERT(square_is_ok(from)); + ASSERT(square_is_ok(to)); + + move = move_make(from,to); + + if (square_is_promote(to)) { + list_add(list,move|MovePromoteKnight); + list_add(list,move|MovePromoteBishop); + list_add(list,move|MovePromoteRook); + list_add(list,move|MovePromoteQueen); + } else { + list_add(list,move); + } +} + +// end of move_gen.cpp + diff --git a/move_legal.c b/move_legal.c new file mode 100644 index 0000000..ecf3fd2 --- /dev/null +++ b/move_legal.c @@ -0,0 +1,115 @@ + +// move_legal.c + +// includes + +#include "attack.h" +#include "colour.h" +#include "fen.h" +#include "list.h" +#include "move.h" +#include "move_do.h" +#include "move_gen.h" +#include "move_legal.h" +#include "piece.h" +#include "square.h" +#include "util.h" + +// prototypes + +static bool move_is_legal_debug (int move, const board_t * board); + +// functions + +// move_is_pseudo() + +bool move_is_pseudo(int move, const board_t * board) { + + list_t list[1]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + gen_moves(list,board); + + return list_contain(list,move); +} + +// pseudo_is_legal() + +bool pseudo_is_legal(int move, const board_t * board) { + + board_t new_board[1]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + ASSERT(move_is_pseudo(move,board)); + + board_copy(new_board,board); + move_do(new_board,move); + + return !is_in_check(new_board,colour_opp(new_board->turn)); +} + +// move_is_legal() + +bool move_is_legal(int move, const board_t * board) { + + bool legal; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + legal = move_is_pseudo(move,board) && pseudo_is_legal(move,board); + ASSERT(legal==move_is_legal_debug(move,board)); + + return legal; +} + +// filter_legal() + +void filter_legal(list_t * list, const board_t * board) { + + int pos; + int i, move, value; + + ASSERT(list_is_ok(list)); + ASSERT(board_is_ok(board)); + + pos = 0; + + for (i = 0; i < list_size(list); i++) { + + ASSERT(pos>=0&&pos<=i); + + move = list_move(list,i); + value = list_value(list,i); + + if (pseudo_is_legal(move,board)) { + list->move[pos] = move; + list->value[pos] = value; + pos++; + } + } + + ASSERT(pos>=0&&pos<=list_size(list)); + list->size = pos; +} + +// move_is_legal_debug() + +static bool move_is_legal_debug(int move, const board_t * board) { + + list_t list[1]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + + gen_legal_moves(list,board); + + return list_contain(list,move); +} + +// end of move_legal.cpp + diff --git a/option.c b/option.c new file mode 100644 index 0000000..fbf71ef --- /dev/null +++ b/option.c @@ -0,0 +1,230 @@ + +// option.c + +// includes + +#include +#include + +#include "option.h" +#include "util.h" + +// constants + +static const bool UseDebug = FALSE; + + +// variables + +#define NNB { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL } +option_t Option[] = { + + { "OptionFile", "string","0","0", "polyglot.ini", NULL,0,NNB, PG}, + + // options + + { "EngineName", "string","0","0", "" , NULL,0,NNB, PG}, + { "EngineDir", "string","0","0", "." , NULL,0,NNB, PG}, + { "EngineCommand", "string","0","0", "" , NULL,0,NNB, PG}, + + { "Log", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|UCI}, + { "LogFile", "string","0","0", "polyglot.log", NULL,0,NNB, PG|XBOARD|UCI}, + + { "UCI", "check","0","0", "false" , NULL,0,NNB, PG}, + + { "UseNice", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|UCI}, + { "NiceValue", "spin", "0","20", "5" , NULL,0,NNB, PG|XBOARD|UCI}, + + { "Chess960", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + + { "Resign", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + { "ResignMoves", "spin","0","10000", "3" , NULL,0,NNB, PG|XBOARD}, + { "ResignScore", "spin","0","10000", "600" , NULL,0,NNB, PG|XBOARD}, + + { "MateScore", "spin","0","1000000", "10000" , NULL,0,NNB, PG|XBOARD}, + + { "Book", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD|UCI}, + { "BookFile", "string","0","0", "book.bin" , NULL,0,NNB, PG|XBOARD|UCI}, + + { "BookRandom", "check","0","0", "true" , NULL,0,NNB, PG|XBOARD|UCI}, + { "BookLearn", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + + { "KibitzMove", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + { "KibitzPV", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + + { "KibitzCommand", "string","0","0", "tellall" , NULL,0,NNB, PG|XBOARD}, + { "KibitzDelay", "spin","0","10000", "5" , NULL,0,NNB, PG|XBOARD}, + { "KibitzInterval", "spin","0","10000", "0" , NULL,0,NNB, PG|XBOARD}, + + { "ShowPonder", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + { "ScoreWhite", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + + // work-arounds + + { "UCIVersion", "spin","1","2", "2" , NULL,0,NNB, PG|XBOARD}, + { "CanPonder", "check","1","2", "false" , NULL,0,NNB, PG|XBOARD}, + { "SyncStop", "check","1","2", "false" , NULL,0,NNB, PG|XBOARD}, + { "Affinity", "spin","-1","32", "-1" , NULL,0,NNB, PG}, + { "RepeatPV", "check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + { "PromoteWorkAround","check","0","0", "false" , NULL,0,NNB, PG|XBOARD}, + + { NULL, NULL,"0","0", NULL , NULL,0,NNB, 0}, +}; + +// prototypes + +static option_t * option_find (const char var[]); + +// functions + +// option_init() + +void option_init() { + + option_t *p=Option; + const char * name; + + while((name=(p++)->name)){ + option_set(name,option_get_default(name)); + } +} + + +// option_set() + +bool option_set(const char name[], const char value[]) { + + option_t * opt; + ASSERT(name!=NULL); + ASSERT(value!=NULL); + + opt = option_find(name); + if (opt == NULL) return FALSE; + + my_string_set(&opt->value,value); + + if (UseDebug) my_log("POLYGLOT OPTION SET \"%s\" -> \"%s\"\n",opt->name,opt->value); + + return TRUE; +} +// option_set() + +bool option_set_default(const char name[], const char value[]) { + + option_t * opt; + ASSERT(name!=NULL); + ASSERT(value!=NULL); + + opt = option_find(name); + if (opt == NULL) return FALSE; + + opt->default_=my_strdup(value); + + if (UseDebug) my_log("POLYGLOT OPTION DEFAULT SET \"%s\" -> \"%s\"\n",opt->name,opt->default_); + + return TRUE; +} + +// option_get() + +const char * option_get(const char name[]) { + + option_t * opt; + + ASSERT(name!=NULL); + + opt = option_find(name); + if (opt == NULL) my_fatal("option_get(): unknown option \"%s\"\n",name); + + if (UseDebug) my_log("POLYGLOT OPTION GET \"%s\" -> \"%s\"\n",opt->name,opt->value); + + return opt->value; +} + +// option_get_default() + +const char * option_get_default(const char name[]) { + + option_t * opt; + + ASSERT(name!=NULL); + + opt = option_find(name); + if (opt == NULL) my_fatal("option_get(): unknown option \"%s\"\n",name); + + if (UseDebug) my_log("POLYGLOT OPTION GET \"%s\" -> \"%s\"\n",opt->name,opt->value); + + return opt->default_; +} + +// option_get_bool() + +bool option_get_bool(const char name[]) { + + const char * value; + + value = option_get(name); + + if (FALSE) { + } else if (my_string_case_equal(value,"true") || my_string_case_equal(value,"yes") || my_string_equal(value,"1")) { + return TRUE; + } else if (my_string_case_equal(value,"false") || my_string_case_equal(value,"no") || my_string_equal(value,"0")) { + return FALSE; + } + + ASSERT(FALSE); + + return FALSE; +} + +// option_get_double() + +double option_get_double(const char name[]) { + + const char * value; + + value = option_get(name); + + return atof(value); +} + +// option_get_int() + +int option_get_int(const char name[]) { + + const char * value; + + value = option_get(name); + + return atoi(value); +} + +// option_get_string() + +const char * option_get_string(const char name[]) { + + const char * value; + + value = option_get(name); + + return value; +} + +// option_find() + +static option_t * option_find(const char name[]) { + + option_t * opt; + + ASSERT(name!=NULL); + + + for (opt = &Option[0]; opt->name != NULL; opt++) { + if (my_string_case_equal(opt->name,name)) return opt; + } + + return NULL; +} + +// end of option.cpp + diff --git a/option.h b/option.h index c57438c..050ae0e 100644 --- a/option.h +++ b/option.h @@ -8,19 +8,16 @@ #include "util.h" -// constants - -const int VarNb = 16; - // defines -#define XBOARD 1 -#define UCI 2 -#define PG 4 +#define VarNb 16 +#define XBOARD (1<<0) +#define UCI (1<<1) +#define PG (1<<2) // types -struct option_t { // TODO: put back in more logical order +typedef struct { // TODO: put back in more logical order const char * name; const char * type; const char * min; @@ -30,7 +27,7 @@ struct option_t { // TODO: put back in more logical order int var_nb; const char * var[VarNb]; int mode; -}; +} option_t; // variables diff --git a/parse.c b/parse.c new file mode 100644 index 0000000..aaacae1 --- /dev/null +++ b/parse.c @@ -0,0 +1,264 @@ + +// parse.c + +// includes + +#include + +#include "parse.h" +#include "util.h" + +// constants + +static const int StringSize = 256; + +// variables + +char * Star[STAR_NUMBER]; + +// prototypes + +static bool match_rec (char string[], const char pattern[], char * star[]); + +// functions + +// match() + +bool match(char string[], const char pattern[]) { + + ASSERT(string!=NULL); + ASSERT(pattern!=NULL); + + ASSERT(strstr(pattern,"**")==NULL); + + return match_rec(string,pattern,Star); +} + +// match_rec() + +static bool match_rec(char string[], const char pattern[], char * star[]) { + + int c; + + ASSERT(string!=NULL); + ASSERT(pattern!=NULL); + ASSERT(star!=NULL); + + // iterative matches + + while ((c=*pattern++) != '*') { + if (FALSE) { + } else if (c == '\0') { // end of pattern + while (*string == ' ') string++; // skip trailing spaces + return *string == '\0'; + } else if (c == ' ') { // spaces + if (*string++ != ' ') return FALSE; // mismatch + while (*string == ' ') string++; // skip trailing spaces + } else { // normal character + if (*string++ != c) return FALSE; // mismatch + } + } + + // recursive wildcard match + + ASSERT(c=='*'); + + while (*string == ' ') string++; // skip leading spaces + *star++ = string; // remember beginning of star + + while ((c=*string++) != '\0') { // reject empty-string match + if (c != ' ' && match_rec(string,pattern,star)) { // shortest match + ASSERT(string>star[-1]); + *string = '\0'; // truncate star + return TRUE; + } + } + + return FALSE; +} + +// parse_is_ok() + +bool parse_is_ok(const parse_t * parse) { + + if (parse == NULL) return FALSE; + if (parse->string == NULL) return FALSE; + if (parse->pos < 0 || parse->pos > (int) strlen(parse->string)) return FALSE; + if (parse->keyword_nb < 0 || parse->keyword_nb >= KEYWORD_NUMBER) return FALSE; + + return TRUE; +} + +// parse_open() + +void parse_open(parse_t * parse, const char string[]) { + + ASSERT(parse!=NULL); + ASSERT(string!=NULL); + + parse->string = string; + parse->pos = 0; + parse->keyword_nb = 0; +} + +// parse_close() + +void parse_close(parse_t * parse) { + + int i; + + ASSERT(parse_is_ok(parse)); + + parse->string = NULL; + parse->pos = 0; + + for (i = 0; i < parse->keyword_nb; i++) { + my_string_clear(&parse->keyword[i]); + } + + parse->keyword_nb = 0; +} + +// parse_add_keyword() + +void parse_add_keyword(parse_t * parse, const char keyword[]) { + + const char * * string; + + ASSERT(parse_is_ok(parse)); + ASSERT(keyword!=NULL); + + if (parse->keyword_nb < KEYWORD_NUMBER) { + + string = &parse->keyword[parse->keyword_nb]; + parse->keyword_nb++; + + *string = NULL; + my_string_set(string,keyword); + } +} + +// parse_get_word() + +bool parse_get_word(parse_t * parse, char string[], int size) { + + int pos; + int c; + + ASSERT(parse!=NULL); + ASSERT(string!=NULL); + ASSERT(size>=256); + + // skip blanks + + for (; parse->string[parse->pos] == ' '; parse->pos++) + ; + + ASSERT(parse->string[parse->pos]!=' '); + + // copy word + + pos = 0; + + while (TRUE) { + + c = parse->string[parse->pos]; + if (c == ' ' || pos >= size-1) c = '\0'; + + string[pos] = c; + if (c == '\0') break; + + parse->pos++; + pos++; + } + + ASSERT(strchr(string,' ')==NULL); + + return pos > 0; // non-empty word? +} + +// parse_get_string() + +bool parse_get_string(parse_t * parse, char string[], int size) { + + int pos; + parse_t parse_2[1]; + char word[StringSize]; + int i; + int c; + + ASSERT(parse!=NULL); + ASSERT(string!=NULL); + ASSERT(size>=256); + + // skip blanks + + for (; parse->string[parse->pos] == ' '; parse->pos++) + ; + + ASSERT(parse->string[parse->pos]!=' '); + + // copy string + + pos = 0; + + while (TRUE) { + + parse_open(parse_2,&parse->string[parse->pos]); + + if (!parse_get_word(parse_2,word,StringSize)) { + string[pos] = '\0'; + parse_close(parse_2); + goto finished; + } + + for (i = 0; i < parse->keyword_nb; i++) { + if (my_string_equal(parse->keyword[i],word)) { + string[pos] = '\0'; + parse_close(parse_2); + goto finished; + } + } + + parse_close(parse_2); + + // copy spaces + + while (TRUE) { + + c = parse->string[parse->pos]; + if (c != ' ') break; + + if (pos >= size-1) c = '\0'; + + string[pos] = c; + if (c == '\0') break; + + parse->pos++; + pos++; + } + + // copy non spaces + + while (TRUE) { + + c = parse->string[parse->pos]; + if (c == ' ' || pos >= size-1) c = '\0'; + + string[pos] = c; + if (c == '\0') break; + + parse->pos++; + pos++; + } + + string[pos] = '\0'; + } + +finished: ; + + return pos > 0; // non-empty string? +} + +// end of parse.cpp + diff --git a/parse.h b/parse.h index dbd1f4f..5c35b32 100644 --- a/parse.h +++ b/parse.h @@ -8,19 +8,19 @@ #include "util.h" -// constants +// defined -const int STAR_NUMBER = 16; -const int KEYWORD_NUMBER = 256; +#define STAR_NUMBER 16 +#define KEYWORD_NUMBER 256 // types -struct parse_t { +typedef struct { const char * string; int pos; int keyword_nb; const char * keyword[KEYWORD_NUMBER]; -}; +} parse_t; // variables diff --git a/pgn.c b/pgn.c new file mode 100644 index 0000000..3de7483 --- /dev/null +++ b/pgn.c @@ -0,0 +1,641 @@ + +// pgn.c + +// includes + +#include +#include +#include +#include + +#include "pgn.h" +#include "util.h" + +// constants + +static const bool DispMove = FALSE; +static const bool DispToken = FALSE; +static const bool DispChar = FALSE; + +static const int TAB_SIZE = 8; + +static const int CHAR_EOF = 256; + +// types + +enum token_t { + TOKEN_ERROR = -1, + TOKEN_EOF = 256, + TOKEN_SYMBOL = 257, + TOKEN_STRING = 258, + TOKEN_INTEGER = 259, + TOKEN_NAG = 260, + TOKEN_RESULT = 261 +}; + +// prototypes + +static void pgn_token_read (pgn_t * pgn); +static void pgn_token_unread (pgn_t * pgn); + +static void pgn_read_token (pgn_t * pgn); + +static bool is_symbol_start (int c); +static bool is_symbol_next (int c); + +static void pgn_skip_blanks (pgn_t * pgn); + +static void pgn_char_read (pgn_t * pgn); +static void pgn_char_unread (pgn_t * pgn); + +// functions + +// pgn_open() + +void pgn_open(pgn_t * pgn, const char file_name[]) { + + ASSERT(pgn!=NULL); + ASSERT(file_name!=NULL); + + pgn->file = fopen(file_name,"r"); + if (pgn->file == NULL) my_fatal("pgn_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); + + pgn->char_hack = CHAR_EOF; // DEBUG + pgn->char_line = 1; + pgn->char_column = 0; + pgn->char_unread = FALSE; + pgn->char_first = TRUE; + + pgn->token_type = TOKEN_ERROR; // DEBUG + strcpy(pgn->token_string,"?"); // DEBUG + pgn->token_length = -1; // DEBUG + pgn->token_line = -1; // DEBUG + pgn->token_column = -1; // DEBUG + pgn->token_unread = FALSE; + pgn->token_first = TRUE; + + strcpy(pgn->result,"?"); // DEBUG + strcpy(pgn->fen,"?"); // DEBUG + + pgn->move_line = -1; // DEBUG + pgn->move_column = -1; // DEBUG +} + +// pgn_close() + +void pgn_close(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + fclose(pgn->file); +} + +// pgn_next_game() + +bool pgn_next_game(pgn_t * pgn) { + + char name[PGN_STRING_SIZE]; + char value[PGN_STRING_SIZE]; + + ASSERT(pgn!=NULL); + + // init + + strcpy(pgn->result,"*"); + strcpy(pgn->fen,""); + + // loop + + while (TRUE) { + + pgn_token_read(pgn); + + if (pgn->token_type != '[') break; + + // tag + + pgn_token_read(pgn); + if (pgn->token_type != TOKEN_SYMBOL) { + my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + strcpy(name,pgn->token_string); + + pgn_token_read(pgn); + if (pgn->token_type != TOKEN_STRING) { + my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + strcpy(value,pgn->token_string); + + pgn_token_read(pgn); + if (pgn->token_type != ']') { + my_fatal("pgn_next_game(): malformed tag at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + + // special tag? + + if (FALSE) { + } else if (my_string_equal(name,"Result")) { + strcpy(pgn->result,value); + } else if (my_string_equal(name,"FEN")) { + strcpy(pgn->fen,value); + } + } + + if (pgn->token_type == TOKEN_EOF) return FALSE; + + pgn_token_unread(pgn); + + return TRUE; +} + +// pgn_next_move() + +bool pgn_next_move(pgn_t * pgn, char string[], int size) { + + int depth; + + ASSERT(pgn!=NULL); + ASSERT(string!=NULL); + ASSERT(size>=PGN_STRING_SIZE); + + // init + + pgn->move_line = -1; // DEBUG + pgn->move_column = -1; // DEBUG + + // loop + + depth = 0; + + while (TRUE) { + + pgn_token_read(pgn); + + if (FALSE) { + + } else if (pgn->token_type == '(') { + + // open RAV + + depth++; + + } else if (pgn->token_type == ')') { + + // close RAV + + if (depth == 0) { + my_fatal("pgn_next_move(): malformed variation at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + + depth--; + ASSERT(depth>=0); + + } else if (pgn->token_type == TOKEN_RESULT) { + + // game finished + + if (depth > 0) { + my_fatal("pgn_next_move(): malformed variation at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + + return FALSE; + + } else { + + // skip optional move number + + if (pgn->token_type == TOKEN_INTEGER) { + do pgn_token_read(pgn); while (pgn->token_type == '.'); + } + + // move must be a symbol + + if (pgn->token_type != TOKEN_SYMBOL) { + my_fatal("pgn_next_move(): malformed move at line %d, column %d, game %d\n",pgn->token_line,pgn->token_column,pgn->game_nb); + } + + // store move for later use + + if (depth == 0) { + + if (pgn->token_length >= size) { + 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); + } + + strcpy(string,pgn->token_string); + pgn->move_line = pgn->token_line; + pgn->move_column = pgn->token_column; + } + + // skip optional NAGs + + do pgn_token_read(pgn); while (pgn->token_type == TOKEN_NAG); + pgn_token_unread(pgn); + + // return move + + if (depth == 0) { + if (DispMove) printf("move=\"%s\"\n",string); + return TRUE; + } + } + } + + ASSERT(FALSE); + + return FALSE; +} + +// pgn_token_read() + +static void pgn_token_read(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + // token "stack" + + if (pgn->token_unread) { + pgn->token_unread = FALSE; + return; + } + + // consume the current token + + if (pgn->token_first) { + pgn->token_first = FALSE; + } else { + ASSERT(pgn->token_type!=TOKEN_ERROR); + ASSERT(pgn->token_type!=TOKEN_EOF); + } + + // read a new token + + pgn_read_token(pgn); + 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); + + if (DispToken) printf("< L%d C%d \"%s\" (%03X)\n",pgn->token_line,pgn->token_column,pgn->token_string,pgn->token_type); +} + +// pgn_token_unread() + +static void pgn_token_unread(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + ASSERT(!pgn->token_unread); + ASSERT(!pgn->token_first); + + pgn->token_unread = TRUE; +} + +// pgn_read_token() + +static void pgn_read_token(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + // skip white-space characters + + pgn_skip_blanks(pgn); + + // init + + pgn->token_type = TOKEN_ERROR; + strcpy(pgn->token_string,""); + pgn->token_length = 0; + pgn->token_line = pgn->char_line; + pgn->token_column = pgn->char_column; + + // determine token type + + if (FALSE) { + + } else if (pgn->char_hack == CHAR_EOF) { + + pgn->token_type = TOKEN_EOF; + + } else if (strchr(".[]()<>",pgn->char_hack) != NULL) { + + // single-character token + + pgn->token_type = pgn->char_hack; + sprintf(pgn->token_string,"%c",pgn->char_hack); + pgn->token_length = 1; + + } else if (pgn->char_hack == '*') { + + pgn->token_type = TOKEN_RESULT; + sprintf(pgn->token_string,"%c",pgn->char_hack); + pgn->token_length = 1; + + } else if (pgn->char_hack == '!') { + + pgn_char_read(pgn); + + if (FALSE) { + + } else if (pgn->char_hack == '!') { // "!!" + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"3"); + pgn->token_length = 1; + + } else if (pgn->char_hack == '?') { // "!?" + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"5"); + pgn->token_length = 1; + + } else { // "!" + + pgn_char_unread(pgn); + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"1"); + pgn->token_length = 1; + } + + } else if (pgn->char_hack == '?') { + + pgn_char_read(pgn); + + if (FALSE) { + + } else if (pgn->char_hack == '?') { // "??" + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"4"); + pgn->token_length = 1; + + } else if (pgn->char_hack == '!') { // "?!" + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"6"); + pgn->token_length = 1; + + } else { // "?" + + pgn_char_unread(pgn); + + pgn->token_type = TOKEN_NAG; + strcpy(pgn->token_string,"2"); + pgn->token_length = 1; + } + + } else if (is_symbol_start(pgn->char_hack)) { + + // symbol, integer, or result + + pgn->token_type = TOKEN_INTEGER; + pgn->token_length = 0; + + do { + + if (pgn->token_length >= PGN_STRING_SIZE-1) { + 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); + } + + if (!isdigit(pgn->char_hack)) pgn->token_type = TOKEN_SYMBOL; + + pgn->token_string[pgn->token_length++] = pgn->char_hack; + + pgn_char_read(pgn); + + } while (is_symbol_next(pgn->char_hack)); + + pgn_char_unread(pgn); + + ASSERT(pgn->token_length>0&&pgn->token_lengthtoken_string[pgn->token_length] = '\0'; + + if (my_string_equal(pgn->token_string,"1-0") + || my_string_equal(pgn->token_string,"0-1") + || my_string_equal(pgn->token_string,"1/2-1/2")) { + pgn->token_type = TOKEN_RESULT; + } + + } else if (pgn->char_hack == '"') { + + // string + + pgn->token_type = TOKEN_STRING; + pgn->token_length = 0; + + while (TRUE) { + + pgn_char_read(pgn); + + if (pgn->char_hack == CHAR_EOF) { + 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); + } + + if (pgn->char_hack == '"') break; + + if (pgn->char_hack == '\\') { + + pgn_char_read(pgn); + + if (pgn->char_hack == CHAR_EOF) { + 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); + } + + if (pgn->char_hack != '"' && pgn->char_hack != '\\') { + + // bad escape, ignore + + if (pgn->token_length >= PGN_STRING_SIZE-1) { + 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); + } + + pgn->token_string[pgn->token_length++] = '\\'; + } + } + + if (pgn->token_length >= PGN_STRING_SIZE-1) { + 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); + } + + pgn->token_string[pgn->token_length++] = pgn->char_hack; + } + + ASSERT(pgn->token_length>=0&&pgn->token_lengthtoken_string[pgn->token_length] = '\0'; + + } else if (pgn->char_hack == '$') { + + // NAG + + pgn->token_type = TOKEN_NAG; + pgn->token_length = 0; + + while (TRUE) { + + pgn_char_read(pgn); + + if (!isdigit(pgn->char_hack)) break; + + if (pgn->token_length >= 3) { + 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); + } + + pgn->token_string[pgn->token_length++] = pgn->char_hack; + } + + pgn_char_unread(pgn); + + if (pgn->token_length == 0) { + my_fatal("pgn_read_token(): malformed NAG at line %d, column %d,game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } + + ASSERT(pgn->token_length>0&&pgn->token_length<=3); + pgn->token_string[pgn->token_length] = '\0'; + + } else { + + // unknown token + + my_fatal("lexical error at line %d, column %d, game %d\n",pgn->char_line,pgn->char_column,pgn->game_nb); + } +} + +// pgn_skip_blanks() + +static void pgn_skip_blanks(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + while (TRUE) { + + pgn_char_read(pgn); + + if (FALSE) { + }else if(pgn->char_hack==CHAR_EOF){ break; + } else if (isspace(pgn->char_hack)) { + + // skip white space + + } else if (pgn->char_hack == ';') { + + // skip comment to EOL + + do { + + pgn_char_read(pgn); + + if (pgn->char_hack == CHAR_EOF) { + 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); + } + + } while (pgn->char_hack != '\n'); + + } else if (pgn->char_hack == '%' && pgn->char_column == 0) { + + // skip comment to EOL + + do { + + pgn_char_read(pgn); + + if (pgn->char_hack == CHAR_EOF) { + 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); + } + + } while (pgn->char_hack != '\n'); + + } else if (pgn->char_hack == '{') { + + // skip comment to next '}' + + do { + + pgn_char_read(pgn); + + if (pgn->char_hack == CHAR_EOF) { + 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); + } + + } while (pgn->char_hack != '}'); + + } else { // not a white space + + break; + } + } +} + +// is_symbol_start() + +static bool is_symbol_start(int c) { + + return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",c) != NULL; +} + +// is_symbol_next() + +static bool is_symbol_next(int c) { + + return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+#=:-/",c) != NULL; +} + +// pgn_char_read() + +static void pgn_char_read(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + // char "stack" + + if (pgn->char_unread) { + pgn->char_unread = FALSE; + return; + } + + // consume the current character + + if (pgn->char_first) { + + pgn->char_first = FALSE; + + } else { + + // update counters + + ASSERT(pgn->char_hack!=CHAR_EOF); + + if (FALSE) { + } else if (pgn->char_hack == '\n') { + pgn->char_line++; + pgn->char_column = 0; + } else if (pgn->char_hack == '\t') { + pgn->char_column += TAB_SIZE - (pgn->char_column % TAB_SIZE); + } else { + pgn->char_column++; + } + } + + // read a new character + + pgn->char_hack = fgetc(pgn->file); + + if (pgn->char_hack == EOF) { + if (ferror(pgn->file)) my_fatal("pgn_char_read(): fgetc(): %s\n",strerror(errno)); + pgn->char_hack = CHAR_EOF; + } + + if (DispChar) printf("< L%d C%d '%c' (%02X)\n",pgn->char_line,pgn->char_column,pgn->char_hack,pgn->char_hack); +} + +// pgn_char_unread() + +static void pgn_char_unread(pgn_t * pgn) { + + ASSERT(pgn!=NULL); + + ASSERT(!pgn->char_unread); + ASSERT(!pgn->char_first); + + pgn->char_unread = TRUE; +} + +// end of pgn.cpp + diff --git a/pgn.h b/pgn.h index e79fc3f..0f51015 100644 --- a/pgn.h +++ b/pgn.h @@ -6,17 +6,17 @@ // includes -#include +#include #include "util.h" -// constants +// defines -const int PGN_STRING_SIZE = 256; +#define PGN_STRING_SIZE 256 // types -struct pgn_t { +typedef struct { FILE * file; @@ -40,7 +40,7 @@ struct pgn_t { int move_line; int move_column; int game_nb; -}; +} pgn_t; // functions diff --git a/piece.c b/piece.c new file mode 100644 index 0000000..82ed76a --- /dev/null +++ b/piece.c @@ -0,0 +1,203 @@ + +// piece.c + +// includes + +#include + +#include "colour.h" +#include "piece.h" +#include "util.h" + +// "constants" + +static const uint8 MakePawn[ColourNb] = { PieceNone256, BlackPawn256, WhitePawn256 }; // -BW + +static const uint8 PieceFrom12[12] = { + BlackPawn256, WhitePawn256, + BlackKnight256, WhiteKnight256, + BlackBishop256, WhiteBishop256, + BlackRook256, WhiteRook256, + BlackQueen256, WhiteQueen256, + BlackKing256, WhiteKing256, +}; + +static const char PieceString[12+1] = "pPnNbBrRqQkK"; + +// variables + +static sint8 PieceTo12[256]; + +// functions + +// piece_init() + +void piece_init() { + + int piece; + + for (piece = 0; piece < 256; piece++) PieceTo12[piece] = -1; + + for (piece = 0; piece < 12; piece++) { + PieceTo12[PieceFrom12[piece]] = piece; + } +} + +// piece_is_ok() + +bool piece_is_ok(int piece) { + + if (piece < 0 || piece >= 256) return FALSE; + + if (PieceTo12[piece] < 0) return FALSE; + + return TRUE; +} + +// piece_make_pawn() + +int piece_make_pawn(int colour) { + + ASSERT(colour_is_ok(colour)); + + return MakePawn[colour]; +} + +// piece_pawn_opp() + +int piece_pawn_opp(int piece) { + + ASSERT(piece==BlackPawn256||piece==WhitePawn256); + + return piece ^ 15; +} + +// piece_colour() + +int piece_colour(int piece) { + + ASSERT(piece_is_ok(piece)); + + return piece & 3; +} + +// piece_type() + +int piece_type(int piece) { + + ASSERT(piece_is_ok(piece)); + + return piece & ~3; +} + +// piece_is_pawn() + +bool piece_is_pawn(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & PawnFlags) != 0; +} + +// piece_is_knight() + +bool piece_is_knight(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & KnightFlag) != 0; +} + +// piece_is_bishop() + +bool piece_is_bishop(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & QueenFlags) == BishopFlag; +} + +// piece_is_rook() + +bool piece_is_rook(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & QueenFlags) == RookFlag; +} + +// piece_is_queen() + +bool piece_is_queen(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & QueenFlags) == QueenFlags; +} + +// piece_is_king() + +bool piece_is_king(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & KingFlag) != 0; +} + +// piece_is_slider() + +bool piece_is_slider(int piece) { + + ASSERT(piece_is_ok(piece)); + + return (piece & QueenFlags) != 0; +} + +// piece_to_12() + +int piece_to_12(int piece) { + + ASSERT(piece_is_ok(piece)); + + return PieceTo12[piece]; +} + +// piece_from_12() + +int piece_from_12(int piece) { + + ASSERT(piece>=0&&piece<12); + + return PieceFrom12[piece]; +} + +// piece_to_char() + +int piece_to_char(int piece) { + + ASSERT(piece_is_ok(piece)); + + return PieceString[piece_to_12(piece)]; +} + +// piece_from_char() + +int piece_from_char(int c) { + + const char * ptr; + + ptr = strchr(PieceString,c); + if (ptr == NULL) return PieceNone256; + + return piece_from_12(ptr-PieceString); +} + +// char_is_piece() + +bool char_is_piece(int c) { + + return strchr("PNBRQK",c) != NULL; +} + +// end of piece.cpp + diff --git a/piece.h b/piece.h index a0bbafb..f060cb6 100644 --- a/piece.h +++ b/piece.h @@ -9,53 +9,53 @@ #include "colour.h" #include "util.h" -// constants - -const int BlackPawnFlag = 1 << 2; -const int WhitePawnFlag = 1 << 3; -const int KnightFlag = 1 << 4; -const int BishopFlag = 1 << 5; -const int RookFlag = 1 << 6; -const int KingFlag = 1 << 7; - -const int PawnFlags = BlackPawnFlag | WhitePawnFlag; -const int QueenFlags = BishopFlag | RookFlag; - -const int PieceNone64 = 0; -const int BlackPawn64 = BlackPawnFlag; -const int WhitePawn64 = WhitePawnFlag; -const int Knight64 = KnightFlag; -const int Bishop64 = BishopFlag; -const int Rook64 = RookFlag; -const int Queen64 = QueenFlags; -const int King64 = KingFlag; - -const int PieceNone256 = 0; -const int BlackPawn256 = BlackPawn64 | Black; -const int WhitePawn256 = WhitePawn64 | White; -const int BlackKnight256 = Knight64 | Black; -const int WhiteKnight256 = Knight64 | White; -const int BlackBishop256 = Bishop64 | Black; -const int WhiteBishop256 = Bishop64 | White; -const int BlackRook256 = Rook64 | Black; -const int WhiteRook256 = Rook64 | White; -const int BlackQueen256 = Queen64 | Black; -const int WhiteQueen256 = Queen64 | White; -const int BlackKing256 = King64 | Black; -const int WhiteKing256 = King64 | White; - -const int BlackPawn12 = 0; -const int WhitePawn12 = 1; -const int BlackKnight12 = 2; -const int WhiteKnight12 = 3; -const int BlackBishop12 = 4; -const int WhiteBishop12 = 5; -const int BlackRook12 = 6; -const int WhiteRook12 = 7; -const int BlackQueen12 = 8; -const int WhiteQueen12 = 9; -const int BlackKing12 = 10; -const int WhiteKing12 = 11; +// defines + +#define BlackPawnFlag (1 << 2) +#define WhitePawnFlag (1 << 3) +#define KnightFlag (1 << 4) +#define BishopFlag (1 << 5) +#define RookFlag (1 << 6) +#define KingFlag (1 << 7) + +#define PawnFlags (BlackPawnFlag | WhitePawnFlag) +#define QueenFlags (BishopFlag | RookFlag) + +#define PieceNone64 (0) +#define BlackPawn64 (BlackPawnFlag) +#define WhitePawn64 (WhitePawnFlag) +#define Knight64 (KnightFlag) +#define Bishop64 (BishopFlag) +#define Rook64 (RookFlag) +#define Queen64 (QueenFlags) +#define King64 (KingFlag) + +#define PieceNone256 (0) +#define BlackPawn256 (BlackPawn64 | Black) +#define WhitePawn256 (WhitePawn64 | White) +#define BlackKnight256 (Knight64 | Black) +#define WhiteKnight256 (Knight64 | White) +#define BlackBishop256 (Bishop64 | Black) +#define WhiteBishop256 (Bishop64 | White) +#define BlackRook256 (Rook64 | Black) +#define WhiteRook256 (Rook64 | White) +#define BlackQueen256 (Queen64 | Black) +#define WhiteQueen256 (Queen64 | White) +#define BlackKing256 (King64 | Black) +#define WhiteKing256 (King64 | White) + +#define BlackPawn12 (0) +#define WhitePawn12 (1) +#define BlackKnight12 (2) +#define WhiteKnight12 (3) +#define BlackBishop12 (4) +#define WhiteBishop12 (5) +#define BlackRook12 (6) +#define WhiteRook12 (7) +#define BlackQueen12 (8) +#define WhiteQueen12 (9) +#define BlackKing12 (10) +#define WhiteKing12 (11) // functions diff --git a/pipex.h b/pipex.h new file mode 100644 index 0000000..e96457f --- /dev/null +++ b/pipex.h @@ -0,0 +1,93 @@ +#ifndef PIPEX_H +#define PIPEX_H +#ifdef _WIN32 + +// WIN32 part + +// includes + +#include +#include +#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 +#include +#include +#include + + +#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 index 0000000..5d2edfa --- /dev/null +++ b/pipex_posix.c @@ -0,0 +1,255 @@ +#ifndef _WIN32 + +// includes + +#include +#include +#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 index 0000000..8d9e893 --- /dev/null +++ b/pipex_win32.c @@ -0,0 +1,446 @@ +// pipex_win32.c + +#ifdef _WIN32 + +// includes + +#include +#include +#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->nReadEndstate=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 diff --git a/polyglot.spec b/polyglot.spec index 9d2a734..257e04c 100644 --- a/polyglot.spec +++ b/polyglot.spec @@ -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 index 0000000..b687231 --- /dev/null +++ b/random.c @@ -0,0 +1,231 @@ + +// random.c + +// includes + +#include "random.h" +#include "util.h" + +// "constants" + +const uint64 Random64[RandomNb] = { + U64(0x9D39247E33776D41), U64(0x2AF7398005AAA5C7), U64(0x44DB015024623547), U64(0x9C15F73E62A76AE2), + U64(0x75834465489C0C89), U64(0x3290AC3A203001BF), U64(0x0FBBAD1F61042279), U64(0xE83A908FF2FB60CA), + U64(0x0D7E765D58755C10), U64(0x1A083822CEAFE02D), U64(0x9605D5F0E25EC3B0), U64(0xD021FF5CD13A2ED5), + U64(0x40BDF15D4A672E32), U64(0x011355146FD56395), U64(0x5DB4832046F3D9E5), U64(0x239F8B2D7FF719CC), + U64(0x05D1A1AE85B49AA1), U64(0x679F848F6E8FC971), U64(0x7449BBFF801FED0B), U64(0x7D11CDB1C3B7ADF0), + U64(0x82C7709E781EB7CC), U64(0xF3218F1C9510786C), U64(0x331478F3AF51BBE6), U64(0x4BB38DE5E7219443), + U64(0xAA649C6EBCFD50FC), U64(0x8DBD98A352AFD40B), U64(0x87D2074B81D79217), U64(0x19F3C751D3E92AE1), + U64(0xB4AB30F062B19ABF), U64(0x7B0500AC42047AC4), U64(0xC9452CA81A09D85D), U64(0x24AA6C514DA27500), + U64(0x4C9F34427501B447), U64(0x14A68FD73C910841), U64(0xA71B9B83461CBD93), U64(0x03488B95B0F1850F), + U64(0x637B2B34FF93C040), U64(0x09D1BC9A3DD90A94), U64(0x3575668334A1DD3B), U64(0x735E2B97A4C45A23), + U64(0x18727070F1BD400B), U64(0x1FCBACD259BF02E7), U64(0xD310A7C2CE9B6555), U64(0xBF983FE0FE5D8244), + U64(0x9F74D14F7454A824), U64(0x51EBDC4AB9BA3035), U64(0x5C82C505DB9AB0FA), U64(0xFCF7FE8A3430B241), + U64(0x3253A729B9BA3DDE), U64(0x8C74C368081B3075), U64(0xB9BC6C87167C33E7), U64(0x7EF48F2B83024E20), + U64(0x11D505D4C351BD7F), U64(0x6568FCA92C76A243), U64(0x4DE0B0F40F32A7B8), U64(0x96D693460CC37E5D), + U64(0x42E240CB63689F2F), U64(0x6D2BDCDAE2919661), U64(0x42880B0236E4D951), U64(0x5F0F4A5898171BB6), + U64(0x39F890F579F92F88), U64(0x93C5B5F47356388B), U64(0x63DC359D8D231B78), U64(0xEC16CA8AEA98AD76), + U64(0x5355F900C2A82DC7), U64(0x07FB9F855A997142), U64(0x5093417AA8A7ED5E), U64(0x7BCBC38DA25A7F3C), + U64(0x19FC8A768CF4B6D4), U64(0x637A7780DECFC0D9), U64(0x8249A47AEE0E41F7), U64(0x79AD695501E7D1E8), + U64(0x14ACBAF4777D5776), U64(0xF145B6BECCDEA195), U64(0xDABF2AC8201752FC), U64(0x24C3C94DF9C8D3F6), + U64(0xBB6E2924F03912EA), U64(0x0CE26C0B95C980D9), U64(0xA49CD132BFBF7CC4), U64(0xE99D662AF4243939), + U64(0x27E6AD7891165C3F), U64(0x8535F040B9744FF1), U64(0x54B3F4FA5F40D873), U64(0x72B12C32127FED2B), + U64(0xEE954D3C7B411F47), U64(0x9A85AC909A24EAA1), U64(0x70AC4CD9F04F21F5), U64(0xF9B89D3E99A075C2), + U64(0x87B3E2B2B5C907B1), U64(0xA366E5B8C54F48B8), U64(0xAE4A9346CC3F7CF2), U64(0x1920C04D47267BBD), + U64(0x87BF02C6B49E2AE9), U64(0x092237AC237F3859), U64(0xFF07F64EF8ED14D0), U64(0x8DE8DCA9F03CC54E), + U64(0x9C1633264DB49C89), U64(0xB3F22C3D0B0B38ED), U64(0x390E5FB44D01144B), U64(0x5BFEA5B4712768E9), + U64(0x1E1032911FA78984), U64(0x9A74ACB964E78CB3), U64(0x4F80F7A035DAFB04), U64(0x6304D09A0B3738C4), + U64(0x2171E64683023A08), U64(0x5B9B63EB9CEFF80C), U64(0x506AACF489889342), U64(0x1881AFC9A3A701D6), + U64(0x6503080440750644), U64(0xDFD395339CDBF4A7), U64(0xEF927DBCF00C20F2), U64(0x7B32F7D1E03680EC), + U64(0xB9FD7620E7316243), U64(0x05A7E8A57DB91B77), U64(0xB5889C6E15630A75), U64(0x4A750A09CE9573F7), + U64(0xCF464CEC899A2F8A), U64(0xF538639CE705B824), U64(0x3C79A0FF5580EF7F), U64(0xEDE6C87F8477609D), + U64(0x799E81F05BC93F31), U64(0x86536B8CF3428A8C), U64(0x97D7374C60087B73), U64(0xA246637CFF328532), + U64(0x043FCAE60CC0EBA0), U64(0x920E449535DD359E), U64(0x70EB093B15B290CC), U64(0x73A1921916591CBD), + U64(0x56436C9FE1A1AA8D), U64(0xEFAC4B70633B8F81), U64(0xBB215798D45DF7AF), U64(0x45F20042F24F1768), + U64(0x930F80F4E8EB7462), U64(0xFF6712FFCFD75EA1), U64(0xAE623FD67468AA70), U64(0xDD2C5BC84BC8D8FC), + U64(0x7EED120D54CF2DD9), U64(0x22FE545401165F1C), U64(0xC91800E98FB99929), U64(0x808BD68E6AC10365), + U64(0xDEC468145B7605F6), U64(0x1BEDE3A3AEF53302), U64(0x43539603D6C55602), U64(0xAA969B5C691CCB7A), + U64(0xA87832D392EFEE56), U64(0x65942C7B3C7E11AE), U64(0xDED2D633CAD004F6), U64(0x21F08570F420E565), + U64(0xB415938D7DA94E3C), U64(0x91B859E59ECB6350), U64(0x10CFF333E0ED804A), U64(0x28AED140BE0BB7DD), + U64(0xC5CC1D89724FA456), U64(0x5648F680F11A2741), U64(0x2D255069F0B7DAB3), U64(0x9BC5A38EF729ABD4), + U64(0xEF2F054308F6A2BC), U64(0xAF2042F5CC5C2858), U64(0x480412BAB7F5BE2A), U64(0xAEF3AF4A563DFE43), + U64(0x19AFE59AE451497F), U64(0x52593803DFF1E840), U64(0xF4F076E65F2CE6F0), U64(0x11379625747D5AF3), + U64(0xBCE5D2248682C115), U64(0x9DA4243DE836994F), U64(0x066F70B33FE09017), U64(0x4DC4DE189B671A1C), + U64(0x51039AB7712457C3), U64(0xC07A3F80C31FB4B4), U64(0xB46EE9C5E64A6E7C), U64(0xB3819A42ABE61C87), + U64(0x21A007933A522A20), U64(0x2DF16F761598AA4F), U64(0x763C4A1371B368FD), U64(0xF793C46702E086A0), + U64(0xD7288E012AEB8D31), U64(0xDE336A2A4BC1C44B), U64(0x0BF692B38D079F23), U64(0x2C604A7A177326B3), + U64(0x4850E73E03EB6064), U64(0xCFC447F1E53C8E1B), U64(0xB05CA3F564268D99), U64(0x9AE182C8BC9474E8), + U64(0xA4FC4BD4FC5558CA), U64(0xE755178D58FC4E76), U64(0x69B97DB1A4C03DFE), U64(0xF9B5B7C4ACC67C96), + U64(0xFC6A82D64B8655FB), U64(0x9C684CB6C4D24417), U64(0x8EC97D2917456ED0), U64(0x6703DF9D2924E97E), + U64(0xC547F57E42A7444E), U64(0x78E37644E7CAD29E), U64(0xFE9A44E9362F05FA), U64(0x08BD35CC38336615), + U64(0x9315E5EB3A129ACE), U64(0x94061B871E04DF75), U64(0xDF1D9F9D784BA010), U64(0x3BBA57B68871B59D), + U64(0xD2B7ADEEDED1F73F), U64(0xF7A255D83BC373F8), U64(0xD7F4F2448C0CEB81), U64(0xD95BE88CD210FFA7), + U64(0x336F52F8FF4728E7), U64(0xA74049DAC312AC71), U64(0xA2F61BB6E437FDB5), U64(0x4F2A5CB07F6A35B3), + U64(0x87D380BDA5BF7859), U64(0x16B9F7E06C453A21), U64(0x7BA2484C8A0FD54E), U64(0xF3A678CAD9A2E38C), + U64(0x39B0BF7DDE437BA2), U64(0xFCAF55C1BF8A4424), U64(0x18FCF680573FA594), U64(0x4C0563B89F495AC3), + U64(0x40E087931A00930D), U64(0x8CFFA9412EB642C1), U64(0x68CA39053261169F), U64(0x7A1EE967D27579E2), + U64(0x9D1D60E5076F5B6F), U64(0x3810E399B6F65BA2), U64(0x32095B6D4AB5F9B1), U64(0x35CAB62109DD038A), + U64(0xA90B24499FCFAFB1), U64(0x77A225A07CC2C6BD), U64(0x513E5E634C70E331), U64(0x4361C0CA3F692F12), + U64(0xD941ACA44B20A45B), U64(0x528F7C8602C5807B), U64(0x52AB92BEB9613989), U64(0x9D1DFA2EFC557F73), + U64(0x722FF175F572C348), U64(0x1D1260A51107FE97), U64(0x7A249A57EC0C9BA2), U64(0x04208FE9E8F7F2D6), + U64(0x5A110C6058B920A0), U64(0x0CD9A497658A5698), U64(0x56FD23C8F9715A4C), U64(0x284C847B9D887AAE), + U64(0x04FEABFBBDB619CB), U64(0x742E1E651C60BA83), U64(0x9A9632E65904AD3C), U64(0x881B82A13B51B9E2), + U64(0x506E6744CD974924), U64(0xB0183DB56FFC6A79), U64(0x0ED9B915C66ED37E), U64(0x5E11E86D5873D484), + U64(0xF678647E3519AC6E), U64(0x1B85D488D0F20CC5), U64(0xDAB9FE6525D89021), U64(0x0D151D86ADB73615), + U64(0xA865A54EDCC0F019), U64(0x93C42566AEF98FFB), U64(0x99E7AFEABE000731), U64(0x48CBFF086DDF285A), + U64(0x7F9B6AF1EBF78BAF), U64(0x58627E1A149BBA21), U64(0x2CD16E2ABD791E33), U64(0xD363EFF5F0977996), + U64(0x0CE2A38C344A6EED), U64(0x1A804AADB9CFA741), U64(0x907F30421D78C5DE), U64(0x501F65EDB3034D07), + U64(0x37624AE5A48FA6E9), U64(0x957BAF61700CFF4E), U64(0x3A6C27934E31188A), U64(0xD49503536ABCA345), + U64(0x088E049589C432E0), U64(0xF943AEE7FEBF21B8), U64(0x6C3B8E3E336139D3), U64(0x364F6FFA464EE52E), + U64(0xD60F6DCEDC314222), U64(0x56963B0DCA418FC0), U64(0x16F50EDF91E513AF), U64(0xEF1955914B609F93), + U64(0x565601C0364E3228), U64(0xECB53939887E8175), U64(0xBAC7A9A18531294B), U64(0xB344C470397BBA52), + U64(0x65D34954DAF3CEBD), U64(0xB4B81B3FA97511E2), U64(0xB422061193D6F6A7), U64(0x071582401C38434D), + U64(0x7A13F18BBEDC4FF5), U64(0xBC4097B116C524D2), U64(0x59B97885E2F2EA28), U64(0x99170A5DC3115544), + U64(0x6F423357E7C6A9F9), U64(0x325928EE6E6F8794), U64(0xD0E4366228B03343), U64(0x565C31F7DE89EA27), + U64(0x30F5611484119414), U64(0xD873DB391292ED4F), U64(0x7BD94E1D8E17DEBC), U64(0xC7D9F16864A76E94), + U64(0x947AE053EE56E63C), U64(0xC8C93882F9475F5F), U64(0x3A9BF55BA91F81CA), U64(0xD9A11FBB3D9808E4), + U64(0x0FD22063EDC29FCA), U64(0xB3F256D8ACA0B0B9), U64(0xB03031A8B4516E84), U64(0x35DD37D5871448AF), + U64(0xE9F6082B05542E4E), U64(0xEBFAFA33D7254B59), U64(0x9255ABB50D532280), U64(0xB9AB4CE57F2D34F3), + U64(0x693501D628297551), U64(0xC62C58F97DD949BF), U64(0xCD454F8F19C5126A), U64(0xBBE83F4ECC2BDECB), + U64(0xDC842B7E2819E230), U64(0xBA89142E007503B8), U64(0xA3BC941D0A5061CB), U64(0xE9F6760E32CD8021), + U64(0x09C7E552BC76492F), U64(0x852F54934DA55CC9), U64(0x8107FCCF064FCF56), U64(0x098954D51FFF6580), + U64(0x23B70EDB1955C4BF), U64(0xC330DE426430F69D), U64(0x4715ED43E8A45C0A), U64(0xA8D7E4DAB780A08D), + U64(0x0572B974F03CE0BB), U64(0xB57D2E985E1419C7), U64(0xE8D9ECBE2CF3D73F), U64(0x2FE4B17170E59750), + U64(0x11317BA87905E790), U64(0x7FBF21EC8A1F45EC), U64(0x1725CABFCB045B00), U64(0x964E915CD5E2B207), + U64(0x3E2B8BCBF016D66D), U64(0xBE7444E39328A0AC), U64(0xF85B2B4FBCDE44B7), U64(0x49353FEA39BA63B1), + U64(0x1DD01AAFCD53486A), U64(0x1FCA8A92FD719F85), U64(0xFC7C95D827357AFA), U64(0x18A6A990C8B35EBD), + U64(0xCCCB7005C6B9C28D), U64(0x3BDBB92C43B17F26), U64(0xAA70B5B4F89695A2), U64(0xE94C39A54A98307F), + U64(0xB7A0B174CFF6F36E), U64(0xD4DBA84729AF48AD), U64(0x2E18BC1AD9704A68), U64(0x2DE0966DAF2F8B1C), + U64(0xB9C11D5B1E43A07E), U64(0x64972D68DEE33360), U64(0x94628D38D0C20584), U64(0xDBC0D2B6AB90A559), + U64(0xD2733C4335C6A72F), U64(0x7E75D99D94A70F4D), U64(0x6CED1983376FA72B), U64(0x97FCAACBF030BC24), + U64(0x7B77497B32503B12), U64(0x8547EDDFB81CCB94), U64(0x79999CDFF70902CB), U64(0xCFFE1939438E9B24), + U64(0x829626E3892D95D7), U64(0x92FAE24291F2B3F1), U64(0x63E22C147B9C3403), U64(0xC678B6D860284A1C), + U64(0x5873888850659AE7), U64(0x0981DCD296A8736D), U64(0x9F65789A6509A440), U64(0x9FF38FED72E9052F), + U64(0xE479EE5B9930578C), U64(0xE7F28ECD2D49EECD), U64(0x56C074A581EA17FE), U64(0x5544F7D774B14AEF), + U64(0x7B3F0195FC6F290F), U64(0x12153635B2C0CF57), U64(0x7F5126DBBA5E0CA7), U64(0x7A76956C3EAFB413), + U64(0x3D5774A11D31AB39), U64(0x8A1B083821F40CB4), U64(0x7B4A38E32537DF62), U64(0x950113646D1D6E03), + U64(0x4DA8979A0041E8A9), U64(0x3BC36E078F7515D7), U64(0x5D0A12F27AD310D1), U64(0x7F9D1A2E1EBE1327), + U64(0xDA3A361B1C5157B1), U64(0xDCDD7D20903D0C25), U64(0x36833336D068F707), U64(0xCE68341F79893389), + U64(0xAB9090168DD05F34), U64(0x43954B3252DC25E5), U64(0xB438C2B67F98E5E9), U64(0x10DCD78E3851A492), + U64(0xDBC27AB5447822BF), U64(0x9B3CDB65F82CA382), U64(0xB67B7896167B4C84), U64(0xBFCED1B0048EAC50), + U64(0xA9119B60369FFEBD), U64(0x1FFF7AC80904BF45), U64(0xAC12FB171817EEE7), U64(0xAF08DA9177DDA93D), + U64(0x1B0CAB936E65C744), U64(0xB559EB1D04E5E932), U64(0xC37B45B3F8D6F2BA), U64(0xC3A9DC228CAAC9E9), + U64(0xF3B8B6675A6507FF), U64(0x9FC477DE4ED681DA), U64(0x67378D8ECCEF96CB), U64(0x6DD856D94D259236), + U64(0xA319CE15B0B4DB31), U64(0x073973751F12DD5E), U64(0x8A8E849EB32781A5), U64(0xE1925C71285279F5), + U64(0x74C04BF1790C0EFE), U64(0x4DDA48153C94938A), U64(0x9D266D6A1CC0542C), U64(0x7440FB816508C4FE), + U64(0x13328503DF48229F), U64(0xD6BF7BAEE43CAC40), U64(0x4838D65F6EF6748F), U64(0x1E152328F3318DEA), + U64(0x8F8419A348F296BF), U64(0x72C8834A5957B511), U64(0xD7A023A73260B45C), U64(0x94EBC8ABCFB56DAE), + U64(0x9FC10D0F989993E0), U64(0xDE68A2355B93CAE6), U64(0xA44CFE79AE538BBE), U64(0x9D1D84FCCE371425), + U64(0x51D2B1AB2DDFB636), U64(0x2FD7E4B9E72CD38C), U64(0x65CA5B96B7552210), U64(0xDD69A0D8AB3B546D), + U64(0x604D51B25FBF70E2), U64(0x73AA8A564FB7AC9E), U64(0x1A8C1E992B941148), U64(0xAAC40A2703D9BEA0), + U64(0x764DBEAE7FA4F3A6), U64(0x1E99B96E70A9BE8B), U64(0x2C5E9DEB57EF4743), U64(0x3A938FEE32D29981), + U64(0x26E6DB8FFDF5ADFE), U64(0x469356C504EC9F9D), U64(0xC8763C5B08D1908C), U64(0x3F6C6AF859D80055), + U64(0x7F7CC39420A3A545), U64(0x9BFB227EBDF4C5CE), U64(0x89039D79D6FC5C5C), U64(0x8FE88B57305E2AB6), + U64(0xA09E8C8C35AB96DE), U64(0xFA7E393983325753), U64(0xD6B6D0ECC617C699), U64(0xDFEA21EA9E7557E3), + U64(0xB67C1FA481680AF8), U64(0xCA1E3785A9E724E5), U64(0x1CFC8BED0D681639), U64(0xD18D8549D140CAEA), + U64(0x4ED0FE7E9DC91335), U64(0xE4DBF0634473F5D2), U64(0x1761F93A44D5AEFE), U64(0x53898E4C3910DA55), + U64(0x734DE8181F6EC39A), U64(0x2680B122BAA28D97), U64(0x298AF231C85BAFAB), U64(0x7983EED3740847D5), + U64(0x66C1A2A1A60CD889), U64(0x9E17E49642A3E4C1), U64(0xEDB454E7BADC0805), U64(0x50B704CAB602C329), + U64(0x4CC317FB9CDDD023), U64(0x66B4835D9EAFEA22), U64(0x219B97E26FFC81BD), U64(0x261E4E4C0A333A9D), + U64(0x1FE2CCA76517DB90), U64(0xD7504DFA8816EDBB), U64(0xB9571FA04DC089C8), U64(0x1DDC0325259B27DE), + U64(0xCF3F4688801EB9AA), U64(0xF4F5D05C10CAB243), U64(0x38B6525C21A42B0E), U64(0x36F60E2BA4FA6800), + U64(0xEB3593803173E0CE), U64(0x9C4CD6257C5A3603), U64(0xAF0C317D32ADAA8A), U64(0x258E5A80C7204C4B), + U64(0x8B889D624D44885D), U64(0xF4D14597E660F855), U64(0xD4347F66EC8941C3), U64(0xE699ED85B0DFB40D), + U64(0x2472F6207C2D0484), U64(0xC2A1E7B5B459AEB5), U64(0xAB4F6451CC1D45EC), U64(0x63767572AE3D6174), + U64(0xA59E0BD101731A28), U64(0x116D0016CB948F09), U64(0x2CF9C8CA052F6E9F), U64(0x0B090A7560A968E3), + U64(0xABEEDDB2DDE06FF1), U64(0x58EFC10B06A2068D), U64(0xC6E57A78FBD986E0), U64(0x2EAB8CA63CE802D7), + U64(0x14A195640116F336), U64(0x7C0828DD624EC390), U64(0xD74BBE77E6116AC7), U64(0x804456AF10F5FB53), + U64(0xEBE9EA2ADF4321C7), U64(0x03219A39EE587A30), U64(0x49787FEF17AF9924), U64(0xA1E9300CD8520548), + U64(0x5B45E522E4B1B4EF), U64(0xB49C3B3995091A36), U64(0xD4490AD526F14431), U64(0x12A8F216AF9418C2), + U64(0x001F837CC7350524), U64(0x1877B51E57A764D5), U64(0xA2853B80F17F58EE), U64(0x993E1DE72D36D310), + U64(0xB3598080CE64A656), U64(0x252F59CF0D9F04BB), U64(0xD23C8E176D113600), U64(0x1BDA0492E7E4586E), + U64(0x21E0BD5026C619BF), U64(0x3B097ADAF088F94E), U64(0x8D14DEDB30BE846E), U64(0xF95CFFA23AF5F6F4), + U64(0x3871700761B3F743), U64(0xCA672B91E9E4FA16), U64(0x64C8E531BFF53B55), U64(0x241260ED4AD1E87D), + U64(0x106C09B972D2E822), U64(0x7FBA195410E5CA30), U64(0x7884D9BC6CB569D8), U64(0x0647DFEDCD894A29), + U64(0x63573FF03E224774), U64(0x4FC8E9560F91B123), U64(0x1DB956E450275779), U64(0xB8D91274B9E9D4FB), + U64(0xA2EBEE47E2FBFCE1), U64(0xD9F1F30CCD97FB09), U64(0xEFED53D75FD64E6B), U64(0x2E6D02C36017F67F), + U64(0xA9AA4D20DB084E9B), U64(0xB64BE8D8B25396C1), U64(0x70CB6AF7C2D5BCF0), U64(0x98F076A4F7A2322E), + U64(0xBF84470805E69B5F), U64(0x94C3251F06F90CF3), U64(0x3E003E616A6591E9), U64(0xB925A6CD0421AFF3), + U64(0x61BDD1307C66E300), U64(0xBF8D5108E27E0D48), U64(0x240AB57A8B888B20), U64(0xFC87614BAF287E07), + U64(0xEF02CDD06FFDB432), U64(0xA1082C0466DF6C0A), U64(0x8215E577001332C8), U64(0xD39BB9C3A48DB6CF), + U64(0x2738259634305C14), U64(0x61CF4F94C97DF93D), U64(0x1B6BACA2AE4E125B), U64(0x758F450C88572E0B), + U64(0x959F587D507A8359), U64(0xB063E962E045F54D), U64(0x60E8ED72C0DFF5D1), U64(0x7B64978555326F9F), + U64(0xFD080D236DA814BA), U64(0x8C90FD9B083F4558), U64(0x106F72FE81E2C590), U64(0x7976033A39F7D952), + U64(0xA4EC0132764CA04B), U64(0x733EA705FAE4FA77), U64(0xB4D8F77BC3E56167), U64(0x9E21F4F903B33FD9), + U64(0x9D765E419FB69F6D), U64(0xD30C088BA61EA5EF), U64(0x5D94337FBFAF7F5B), U64(0x1A4E4822EB4D7A59), + U64(0x6FFE73E81B637FB3), U64(0xDDF957BC36D8B9CA), U64(0x64D0E29EEA8838B3), U64(0x08DD9BDFD96B9F63), + U64(0x087E79E5A57D1D13), U64(0xE328E230E3E2B3FB), U64(0x1C2559E30F0946BE), U64(0x720BF5F26F4D2EAA), + U64(0xB0774D261CC609DB), U64(0x443F64EC5A371195), U64(0x4112CF68649A260E), U64(0xD813F2FAB7F5C5CA), + U64(0x660D3257380841EE), U64(0x59AC2C7873F910A3), U64(0xE846963877671A17), U64(0x93B633ABFA3469F8), + U64(0xC0C0F5A60EF4CDCF), U64(0xCAF21ECD4377B28C), U64(0x57277707199B8175), U64(0x506C11B9D90E8B1D), + U64(0xD83CC2687A19255F), U64(0x4A29C6465A314CD1), U64(0xED2DF21216235097), U64(0xB5635C95FF7296E2), + U64(0x22AF003AB672E811), U64(0x52E762596BF68235), U64(0x9AEBA33AC6ECC6B0), U64(0x944F6DE09134DFB6), + U64(0x6C47BEC883A7DE39), U64(0x6AD047C430A12104), U64(0xA5B1CFDBA0AB4067), U64(0x7C45D833AFF07862), + U64(0x5092EF950A16DA0B), U64(0x9338E69C052B8E7B), U64(0x455A4B4CFE30E3F5), U64(0x6B02E63195AD0CF8), + U64(0x6B17B224BAD6BF27), U64(0xD1E0CCD25BB9C169), U64(0xDE0C89A556B9AE70), U64(0x50065E535A213CF6), + U64(0x9C1169FA2777B874), U64(0x78EDEFD694AF1EED), U64(0x6DC93D9526A50E68), U64(0xEE97F453F06791ED), + U64(0x32AB0EDB696703D3), U64(0x3A6853C7E70757A7), U64(0x31865CED6120F37D), U64(0x67FEF95D92607890), + U64(0x1F2B1D1F15F6DC9C), U64(0xB69E38A8965C6B65), U64(0xAA9119FF184CCCF4), U64(0xF43C732873F24C13), + U64(0xFB4A3D794A9A80D2), U64(0x3550C2321FD6109C), U64(0x371F77E76BB8417E), U64(0x6BFA9AAE5EC05779), + U64(0xCD04F3FF001A4778), U64(0xE3273522064480CA), U64(0x9F91508BFFCFC14A), U64(0x049A7F41061A9E60), + U64(0xFCB6BE43A9F2FE9B), U64(0x08DE8A1C7797DA9B), U64(0x8F9887E6078735A1), U64(0xB5B4071DBFC73A66), + U64(0x230E343DFBA08D33), U64(0x43ED7F5A0FAE657D), U64(0x3A88A0FBBCB05C63), U64(0x21874B8B4D2DBC4F), + U64(0x1BDEA12E35F6A8C9), U64(0x53C065C6C8E63528), U64(0xE34A1D250E7A8D6B), U64(0xD6B04D3B7651DD7E), + U64(0x5E90277E7CB39E2D), U64(0x2C046F22062DC67D), U64(0xB10BB459132D0A26), U64(0x3FA9DDFB67E2F199), + U64(0x0E09B88E1914F7AF), U64(0x10E8B35AF3EEAB37), U64(0x9EEDECA8E272B933), U64(0xD4C718BC4AE8AE5F), + U64(0x81536D601170FC20), U64(0x91B534F885818A06), U64(0xEC8177F83F900978), U64(0x190E714FADA5156E), + U64(0xB592BF39B0364963), U64(0x89C350C893AE7DC1), U64(0xAC042E70F8B383F2), U64(0xB49B52E587A1EE60), + U64(0xFB152FE3FF26DA89), U64(0x3E666E6F69AE2C15), U64(0x3B544EBE544C19F9), U64(0xE805A1E290CF2456), + U64(0x24B33C9D7ED25117), U64(0xE74733427B72F0C1), U64(0x0A804D18B7097475), U64(0x57E3306D881EDB4F), + U64(0x4AE7D6A36EB5DBCB), U64(0x2D8D5432157064C8), U64(0xD1E649DE1E7F268B), U64(0x8A328A1CEDFE552C), + U64(0x07A3AEC79624C7DA), U64(0x84547DDC3E203C94), U64(0x990A98FD5071D263), U64(0x1A4FF12616EEFC89), + U64(0xF6F7FD1431714200), U64(0x30C05B1BA332F41C), U64(0x8D2636B81555A786), U64(0x46C9FEB55D120902), + U64(0xCCEC0A73B49C9921), U64(0x4E9D2827355FC492), U64(0x19EBB029435DCB0F), U64(0x4659D2B743848A2C), + U64(0x963EF2C96B33BE31), U64(0x74F85198B05A2E7D), U64(0x5A0F544DD2B1FB18), U64(0x03727073C2E134B1), + U64(0xC7F6AA2DE59AEA61), U64(0x352787BAA0D7C22F), U64(0x9853EAB63B5E0B35), U64(0xABBDCDD7ED5C0860), + U64(0xCF05DAF5AC8D77B0), U64(0x49CAD48CEBF4A71E), U64(0x7A4C10EC2158C4A6), U64(0xD9E92AA246BF719E), + U64(0x13AE978D09FE5557), U64(0x730499AF921549FF), U64(0x4E4B705B92903BA4), U64(0xFF577222C14F0A3A), + U64(0x55B6344CF97AAFAE), U64(0xB862225B055B6960), U64(0xCAC09AFBDDD2CDB4), U64(0xDAF8E9829FE96B5F), + U64(0xB5FDFC5D3132C498), U64(0x310CB380DB6F7503), U64(0xE87FBB46217A360E), U64(0x2102AE466EBB1148), + U64(0xF8549E1A3AA5E00D), U64(0x07A69AFDCC42261A), U64(0xC4C118BFE78FEAAE), U64(0xF9F4892ED96BD438), + U64(0x1AF3DBE25D8F45DA), U64(0xF5B4B0B0D2DEEEB4), U64(0x962ACEEFA82E1C84), U64(0x046E3ECAAF453CE9), + U64(0xF05D129681949A4C), U64(0x964781CE734B3C84), U64(0x9C2ED44081CE5FBD), U64(0x522E23F3925E319E), + U64(0x177E00F9FC32F791), U64(0x2BC60A63A6F3B3F2), U64(0x222BBFAE61725606), U64(0x486289DDCC3D6780), + U64(0x7DC7785B8EFDFC80), U64(0x8AF38731C02BA980), U64(0x1FAB64EA29A2DDF7), U64(0xE4D9429322CD065A), + U64(0x9DA058C67844F20C), U64(0x24C0E332B70019B0), U64(0x233003B5A6CFE6AD), U64(0xD586BD01C5C217F6), + U64(0x5E5637885F29BC2B), U64(0x7EBA726D8C94094B), U64(0x0A56A5F0BFE39272), U64(0xD79476A84EE20D06), + U64(0x9E4C1269BAA4BF37), U64(0x17EFEE45B0DEE640), U64(0x1D95B0A5FCF90BC6), U64(0x93CBE0B699C2585D), + U64(0x65FA4F227A2B6D79), U64(0xD5F9E858292504D5), U64(0xC2B5A03F71471A6F), U64(0x59300222B4561E00), + U64(0xCE2F8642CA0712DC), U64(0x7CA9723FBB2E8988), U64(0x2785338347F2BA08), U64(0xC61BB3A141E50E8C), + U64(0x150F361DAB9DEC26), U64(0x9F6A419D382595F4), U64(0x64A53DC924FE7AC9), U64(0x142DE49FFF7A7C3D), + U64(0x0C335248857FA9E7), U64(0x0A9C32D5EAE45305), U64(0xE6C42178C4BBB92E), U64(0x71F1CE2490D20B07), + U64(0xF1BCC3D275AFE51A), U64(0xE728E8C83C334074), U64(0x96FBF83A12884624), U64(0x81A1549FD6573DA5), + U64(0x5FA7867CAF35E149), U64(0x56986E2EF3ED091B), U64(0x917F1DD5F8886C61), U64(0xD20D8C88C8FFE65F), + U64(0x31D71DCE64B2C310), U64(0xF165B587DF898190), U64(0xA57E6339DD2CF3A0), U64(0x1EF6E6DBB1961EC9), + U64(0x70CC73D90BC26E24), U64(0xE21A6B35DF0C3AD7), U64(0x003A93D8B2806962), U64(0x1C99DED33CB890A1), + U64(0xCF3145DE0ADD4289), U64(0xD0E4427A5514FB72), U64(0x77C621CC9FB3A483), U64(0x67A34DAC4356550B), + U64(0xF8D626AAAF278509), +}; + +// functions + +// random_init() + +void random_init() { + + if ((Random64[RandomNb-1] >> 32) != 0xF8D626AA) { // upper half of the last element of the array + my_fatal("random_init(): broken 64-bit types\n"); + } +} + +// random_64() + +uint64 random_64(int n) { + + ASSERT(n>=0&&n +#include +#include +#include + +#include "attack.h" +#include "board.h" +#include "list.h" +#include "move.h" +#include "move_gen.h" +#include "move_legal.h" +#include "piece.h" +#include "san.h" +#include "square.h" +#include "util.h" + +// constants + +static const bool UseSlowDebug = FALSE; + +enum ambiguity_t { + AMBIGUITY_NONE, + AMBIGUITY_FILE, + AMBIGUITY_RANK, + AMBIGUITY_SQUARE +}; + +// functions + +static bool san_to_lan (const char san[], const board_t * board, char string[], int size); +static int move_from_lan (const char string[], const board_t * board); + +static int ambiguity (int move, const board_t * board); + +// move_to_san() + +bool move_to_san(int move, const board_t * board, char string[], int size) { + + int from, to, piece; + char tmp_string[256]; + + ASSERT(move_is_ok(move)); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=8); + + ASSERT(move_is_legal(move,board)); + + if (size < 8) return FALSE; + + // init + + from = move_from(move); + to = move_to(move); + + string[0] = '\0'; + + // castle + + if (move_is_castle(move,board)) { + + if (to > from) { + strcat(string,"O-O"); + } else { + strcat(string,"O-O-O"); + } + + goto check; + } + + // from + + piece = board->square[from]; + + if (piece_is_pawn(piece)) { + + // pawn + + if (move_is_capture(move,board)) { + sprintf(tmp_string,"%c",file_to_char(square_file(from))); + strcat(string,tmp_string); + } + + } else { + + // piece + + sprintf(tmp_string,"%c",toupper(piece_to_char(piece))); + strcat(string,tmp_string); + + // ambiguity + + switch (ambiguity(move,board)) { + case AMBIGUITY_NONE: + break; + case AMBIGUITY_FILE: + sprintf(tmp_string,"%c",file_to_char(square_file(from))); + strcat(string,tmp_string); + break; + case AMBIGUITY_RANK: + sprintf(tmp_string,"%c",rank_to_char(square_rank(from))); + strcat(string,tmp_string); + break; + case AMBIGUITY_SQUARE: + if (!square_to_string(from,tmp_string,256)) return FALSE; + strcat(string,tmp_string); + break; + default: + ASSERT(FALSE); + break; + } + } + + // capture + + if (move_is_capture(move,board)) strcat(string,"x"); + + // to + + if (!square_to_string(to,tmp_string,256)) return FALSE; + strcat(string,tmp_string); + + // promote + + if (move_is_promote(move)) { + sprintf(tmp_string,"=%c",toupper(piece_to_char(move_promote(move,board)))); + strcat(string,tmp_string); + } + + // check + +check: + + if (move_is_mate(move,board)) { + strcat(string,"#"); + } else if (move_is_check(move,board)) { + strcat(string,"+"); + } + + return TRUE; +} + +// move_from_san() + +int move_from_san(const char string[], const board_t * board) { + + char s[256]; + int move; + + ASSERT(string!=NULL); + ASSERT(board_is_ok(board)); + + san_to_lan(string,board,s,256); + move = move_from_lan(s,board); + + ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board)); + + return move; +} + +// move_from_san_debug() + +int move_from_san_debug(const char string[], const board_t * board) { + + list_t list[1]; + int i, move; + char move_string[256]; + + ASSERT(string!=NULL); + ASSERT(board_is_ok(board)); + + gen_legal_moves(list,board); + + for (i = 0; i < list_size(list); i++) { + move = list_move(list,i); + if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE); + if (my_string_equal(move_string,string)) return move; + } + + return MoveNone; +} + +// san_to_lan() + +static bool san_to_lan(const char san[], const board_t * board, char string[], int size) { + + int len; + int left, right; + int c; + int king, rook; + char king_string[3], rook_string[3]; + + ASSERT(san!=NULL); + ASSERT(board_is_ok(board)); + ASSERT(string!=NULL); + ASSERT(size>=8); + + // init + + if (size < 8) return FALSE; + strcpy(string,"???????"); + + len = strlen(san); + + left = 0; + right = len; + + // skip trailing '+' or '#' + + if (left < right) { + c = san[right-1]; + if (c == '+' || c == '#') right--; + } + + // castling + + ASSERT(left==0); + + if (FALSE) { + + } else if (right == 3 && strncmp(san,"O-O",3) == 0) { + + if (board->castle[board->turn][SideH] == SquareNone) return FALSE; + + king = king_pos(board,board->turn); + rook = board->castle[board->turn][SideH]; + + square_to_string(king,king_string,3); + square_to_string(rook,rook_string,3); + + sprintf(string,"K%s?%s?",king_string,rook_string); + + } else if (right == 5 && strncmp(san,"O-O-O",5) == 0) { + + if (board->castle[board->turn][SideA] == SquareNone) return FALSE; + + king = king_pos(board,board->turn); + rook = board->castle[board->turn][SideA]; + + square_to_string(king,king_string,3); + square_to_string(rook,rook_string,3); + + sprintf(string,"K%s?%s?",king_string,rook_string); + + } else { + + // moved piece + + if (left < right) { + + c = san[left]; + + if (char_is_piece(c)) { + string[0] = c; + left++; + } + } + + // promotion + + if (left < right) { + + c = toupper(san[right-1]); + + if (char_is_piece(c)) { + + string[6] = c; + right--; + + // skip '=' + + if (left < right && san[right-1] == '=') right--; + } + } + + // to-square rank + + if (left < right) { + + c = san[right-1]; + + if (char_is_rank(c)) { + string[5] = c; + right--; + } + } + + // to-square file + + if (left < right) { + + c = san[right-1]; + + if (char_is_file(c)) { + string[4] = c; + right--; + } + } + + // captured piece + + if (left < right) { + + c = san[right-1]; + + if (char_is_piece(c)) { + string[3] = c; + right--; + } + } + + // skip middle '-' or 'x' + + if (left < right) { + c = san[right-1]; + if (c == '-' || c == 'x') right--; + } + + // from-square file + + if (left < right) { + + c = san[left]; + + if (char_is_file(c)) { + string[1] = c; + left++; + } + } + + // from-square rank + + if (left < right) { + + c = san[left]; + + if (char_is_rank(c)) { + string[2] = c; + left++; + } + } + + if (left != right) return FALSE; + } + + // end + + return TRUE; +} + +// move_from_lan() + +static int move_from_lan(const char string[], const board_t * board) { + + int len; + int move; + int promote; + char s[256]; + int from, to; + int colour; + int inc; + int piece_char; + int n; + const uint8 * ptr; + int piece; + int side; + + ASSERT(string!=NULL); + ASSERT(board_is_ok(board)); + + // init + + len = strlen(string); + if (len != 7) return MoveNone; + + move = MoveNone; + colour = board->turn; + + // promote + + promote = 0; + + switch (string[6]) { + case '?': // not a promotion + break; + case 'N': + promote = MovePromoteKnight; + break; + case 'B': + promote = MovePromoteBishop; + break; + case 'R': + promote = MovePromoteRook; + break; + case 'Q': + promote = MovePromoteQueen; + break; + default: + return MoveNone; + break; + } + + // to square + + s[0] = string[4]; + s[1] = string[5]; + s[2] = '\0'; + + to = square_from_string(s); + if (to == SquareNone) return MoveNone; + + // known from square? + + if (string[1] != '?' && string[2] != '?') { + + // from square + + s[0] = string[1]; + s[1] = string[2]; + s[2] = '\0'; + + from = square_from_string(s); + if (from == SquareNone) return MoveNone; + + // convert "king slide" castling to KxR + + if (piece_is_king(board->square[from]) + && square_rank(to) == square_rank(from) + && abs(to-from) > 1) { + side = (to > from) ? SideH : SideA; + to = board->castle[colour][side]; + if (to == SquareNone) return MoveNone; + } + + // move + + move = move_make(from,to) | promote; + + return move; + } + + // pawn non-capture? + + if (string[0] == '?' && string[1] == '?') { + + if (board->square[to] != Empty) return MoveNone; // useful? + + inc = (colour_is_white(colour)) ? +16 : -16; + + from = to - inc; + if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) { + from -= inc; + } + + if (board->square[from] != piece_make_pawn(colour)) { // useful? + return MoveNone; + } + + // move + + move = move_make(from,to) | promote; + + return move; + } + + // pawn capture? + + piece_char = string[0]; + + if (piece_char == '?' && string[1] != '?') { + piece_char = 'P'; + } + + // attack loop + + n = 0; + + for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { + + piece = board->square[from]; + + if (toupper(piece_to_char(piece)) == piece_char) { + if (piece_attack(board,piece,from,to)) { + if (TRUE + && (string[1] == '?' || file_to_char(square_file(from)) == string[1]) + && (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) { + if (!is_pinned(board,from,to,colour)) { + move = move_make(from,to) | promote; + n++; + } + } + } + } + } + + if (n != 1) move = MoveNone; + + return move; +} + +// ambiguity() + +static int ambiguity(int move, const board_t * board) { + + int from, to, piece; + list_t list[1]; + int i, n, m; + + // init + + from = move_from(move); + to = move_to(move); + piece = move_piece(move,board); + + gen_legal_moves(list,board); + + // no ambiguity? + + n = 0; + + for (i = 0; i < list_size(list); i++) { + m = list_move(list,i); + if (move_piece(m,board) == piece && move_to(m) == to) { + n++; + } + } + + if (n == 1) return AMBIGUITY_NONE; + + // file ambiguity? + + n = 0; + + for (i = 0; i < list_size(list); i++) { + m = list_move(list,i); + if (move_piece(m,board) == piece && move_to(m) == to) { + if (square_file(move_from(m)) == square_file(from)) n++; + } + } + + if (n == 1) return AMBIGUITY_FILE; + + // rank ambiguity? + + n = 0; + + for (i = 0; i < list_size(list); i++) { + m = list_move(list,i); + if (move_piece(m,board) == piece && move_to(m) == to) { + if (square_rank(move_from(m)) == square_rank(from)) n++; + } + } + + if (n == 1) return AMBIGUITY_RANK; + + // square ambiguity + + return AMBIGUITY_SQUARE; +} + +// end of san.cpp + diff --git a/search.c b/search.c new file mode 100644 index 0000000..524a874 --- /dev/null +++ b/search.c @@ -0,0 +1,252 @@ +// search.c + +// includes + +#include +#include +#include + +#include "attack.h" +#include "board.h" +#include "colour.h" +#include "engine.h" +#include "fen.h" +#include "line.h" +#include "list.h" +#include "move.h" +#include "move_do.h" +#include "move_gen.h" +#include "move_legal.h" +#include "option.h" +#include "parse.h" +#include "san.h" +#include "search.h" +#include "uci.h" +#include "util.h" + +// constants + +static const int StringSize = 4096; + +// variables + +static int Depth; + +static int BestMove; +static int BestValue; +static move_t BestPV[LineSize]; + +static sint64 NodeNb; +static sint64 LeafNb; +static double Time; + +static int Move; +static int MovePos; +static int MoveNb; + +// prototypes + +static bool depth_is_ok (int depth); +static void perft (const board_t * board, int depth); + +// functions + +// depth_is_ok() + +static bool depth_is_ok(int depth) { + + return depth >= 0 && depth < DepthMax; +} + +// search() + +void search(const board_t * board, int depth_max, double time_max) { + + char string[256]; + + ASSERT(board_is_ok(board)); + ASSERT(depth_max>=1&&depth_max=0.0); + + // engine + + Depth = 0; + + BestMove = MoveNone; + BestValue = 0; + line_clear(BestPV); + + NodeNb = 0; + LeafNb = 0; + Time = 0.0; + + Move = MoveNone; + MovePos = 0; + MoveNb = 0; + + // init + + uci_send_ucinewgame(Uci); + uci_send_isready_sync(Uci); + + // position + + if (!board_to_fen(board,string,256)) ASSERT(FALSE); + engine_send(Engine,"position fen %s",string); + + // search + + engine_send_queue(Engine,"go"); + + engine_send_queue(Engine," movetime %.0f",time_max*1000.0); + engine_send_queue(Engine," depth %d",depth_max); + + engine_send(Engine,""); // newline + + // wait for feed-back + + while (!engine_eof(Engine)) { + + engine_get(Engine,string); + + if (FALSE) { + + } else if (match(string,"bestmove * ponder *")) { + + BestMove = move_from_can(Star[0],board); + ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board)); + + break; + + } else if (match(string,"bestmove *")) { + + BestMove = move_from_can(Star[0],board); + ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board)); + + break; + } + } + + printf("\n"); +} + +// do_perft() + +void do_perft(int argc,char * argv[]){ + const char * fen=NULL; + int depth=1; + board_t board[1]; + int i; + for (i = 1; i < argc; i++) { + if (FALSE) { + } else if (my_string_equal(argv[i],"perft")) { + // skip + } else if (my_string_equal(argv[i],"-fen")) { + i++; + if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n"); + my_string_set(&fen,argv[i]); + } else if (my_string_equal(argv[i],"-max-depth")){ + i++; + if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n"); + depth=atoi(argv[i]); + if(depth<1) my_fatal("do_perft(): illegal depth %d\n",depth); + } else { + my_fatal("do_perft(): unknown option \"%s\"\n",argv[i]); + } + } + if(fen==NULL){ + my_string_set(&fen,StartFen); + } + board_from_fen(board,fen); + search_perft(board,depth); +} + +// search_perft() + +void search_perft(const board_t * board, int depth_max) { + + int depth; + my_timer_t timer[1]; + double time, speed; + char node_string[StringSize]; + char leafnode_string[StringSize]; + + ASSERT(board_is_ok(board)); + ASSERT(depth_max>=1&&depth_maxturn))); + + // init + + NodeNb++; + + // leaf + + if (depth == 0) { + LeafNb++; + return; + } + + // more init + + me = board->turn; + + // move loop + + gen_moves(list,board); + + for (i = 0; i < list_size(list); i++) { + + move = list_move(list,i); + + board_copy(new_board,board); + move_do(new_board,move); + + if (!is_in_check(new_board,me)) perft(new_board,depth-1); + } +} + +// end of search.cpp + diff --git a/search.h b/search.h index 9e55568..b537297 100644 --- a/search.h +++ b/search.h @@ -8,9 +8,9 @@ #include "board.h" #include "util.h" -// constants +// defines -const int DepthMax = 63; +#define DepthMax 63 // functions diff --git a/square.c b/square.c new file mode 100644 index 0000000..f5a0fe9 --- /dev/null +++ b/square.c @@ -0,0 +1,246 @@ + +// square.c + +// includes + +#include "colour.h" +#include "square.h" +#include "util.h" + +// "constants" + +static const uint8 SquareFrom64[64] = { + A1, B1, C1, D1, E1, F1, G1, H1, + A2, B2, C2, D2, E2, F2, G2, H2, + A3, B3, C3, D3, E3, F3, G3, H3, + A4, B4, C4, D4, E4, F4, G4, H4, + A5, B5, C5, D5, E5, F5, G5, H5, + A6, B6, C6, D6, E6, F6, G6, H6, + A7, B7, C7, D7, E7, F7, G7, H7, + A8, B8, C8, D8, E8, F8, G8, H8, +}; + +// variables + +static sint8 SquareTo64[SquareNb]; + +// functions + +// square_init() + +void square_init() { + + int sq; + + for (sq = 0; sq < SquareNb; sq++) SquareTo64[sq] = -1; + + for (sq = 0; sq < 64; sq++) { + SquareTo64[SquareFrom64[sq]] = sq; + } +} + +// square_is_ok() + +bool square_is_ok(int square) { + + if (square < 0 || square >= SquareNb) return FALSE; + + if (SquareTo64[square] < 0) return FALSE; + + return TRUE; +} + +// square_make() + +int square_make(int file, int rank) { + + int sq_64; + + ASSERT(file>=0&&file<8); + ASSERT(rank>=0&&rank<8); + + sq_64 = (rank << 3) | file; + + return square_from_64(sq_64); +} + +// square_file() + +int square_file(int square) { + + int file; + + ASSERT(square_is_ok(square)); + + file = (square - 4) & 7; + ASSERT(file==(square_to_64(square)&7)); + + return file; +} + +// square_rank() + +int square_rank(int square) { + + int rank; + + ASSERT(square_is_ok(square)); + + rank = (square >> 4) - 2; + ASSERT(rank==square_to_64(square)>>3); + + return rank; +} + +// square_side_rank() + +int square_side_rank(int square, int colour) { + + int rank; + + ASSERT(square_is_ok(square)); + ASSERT(colour_is_ok(colour)); + + rank = square_rank(square); + if (colour_is_black(colour)) rank = 7-rank; + + return rank; +} + +// square_from_64() + +int square_from_64(int square) { + + ASSERT(square>=0&&square<64); + + return SquareFrom64[square]; +} + +// square_to_64() + +int square_to_64(int square) { + + ASSERT(square_is_ok(square)); + + return SquareTo64[square]; +} + +// square_is_promote() + +bool square_is_promote(int square) { + + int rank; + + ASSERT(square_is_ok(square)); + + rank = square_rank(square); + + return rank == Rank1 || rank == Rank8; +} + +// square_ep_dual() + +int square_ep_dual(int square) { + + ASSERT(square_is_ok(square)); + ASSERT(square_rank(square)>=2&&square_rank(square)<=5); + + return square ^ 16; +} + +// square_colour() + +int square_colour(int square) { + + ASSERT(square_is_ok(square)); + + return (square ^ (square >> 4)) & 1; +} + +// file_from_char() + +int file_from_char(int c) { + + ASSERT(c>='a'&&c<='h'); + + return c - 'a'; +} + +// rank_from_char() + +int rank_from_char(int c) { + + ASSERT(c>='1'&&c<='8'); + + return c - '1'; +} + +// file_to_char() + +int file_to_char(int file) { + + ASSERT(file>=0&&file<8); + + return 'a' + file; +} + +// rank_to_char() + +int rank_to_char(int rank) { + + ASSERT(rank>=0&&rank<8); + + return '1' + rank; +} + +// char_is_file() + +bool char_is_file(int c) { + + return c >= 'a' && c <= 'h'; +} + +// char_is_rank() + +bool char_is_rank(int c) { + + return c >= '1' && c <= '8'; +} + +// square_to_string() + +bool square_to_string(int square, char string[], int size) { + + ASSERT(square_is_ok(square)); + ASSERT(string!=NULL); + ASSERT(size>=3); + + if (size < 3) return FALSE; + + string[0] = 'a' + square_file(square); + string[1] = '1' + square_rank(square); + string[2] = '\0'; + + return TRUE; +} + +// square_from_string() + +int square_from_string(const char string[]) { + + int file, rank; + + ASSERT(string!=NULL); + + if (string[0] < 'a' || string[0] > 'h') return SquareNone; + if (string[1] < '1' || string[1] > '8') return SquareNone; + if (string[2] != '\0') return SquareNone; + + file = file_from_char(string[0]); + rank = rank_from_char(string[1]); + + return square_make(file,rank); +} + +// end of square.cpp + diff --git a/square.h b/square.h index 60ef4f9..b493597 100644 --- a/square.h +++ b/square.h @@ -8,41 +8,97 @@ #include "util.h" -// constants - -const int SquareNb = 16 * 12; - -const int FileA = 0; -const int FileB = 1; -const int FileC = 2; -const int FileD = 3; -const int FileE = 4; -const int FileF = 5; -const int FileG = 6; -const int FileH = 7; - -const int Rank1 = 0; -const int Rank2 = 1; -const int Rank3 = 2; -const int Rank4 = 3; -const int Rank5 = 4; -const int Rank6 = 5; -const int Rank7 = 6; -const int Rank8 = 7; - -const int SquareNone = 0; - -const int A1=0x24, B1=0x25, C1=0x26, D1=0x27, E1=0x28, F1=0x29, G1=0x2A, H1=0x2B; -const int A2=0x34, B2=0x35, C2=0x36, D2=0x37, E2=0x38, F2=0x39, G2=0x3A, H2=0x3B; -const int A3=0x44, B3=0x45, C3=0x46, D3=0x47, E3=0x48, F3=0x49, G3=0x4A, H3=0x4B; -const int A4=0x54, B4=0x55, C4=0x56, D4=0x57, E4=0x58, F4=0x59, G4=0x5A, H4=0x5B; -const int A5=0x64, B5=0x65, C5=0x66, D5=0x67, E5=0x68, F5=0x69, G5=0x6A, H5=0x6B; -const int A6=0x74, B6=0x75, C6=0x76, D6=0x77, E6=0x78, F6=0x79, G6=0x7A, H6=0x7B; -const int A7=0x84, B7=0x85, C7=0x86, D7=0x87, E7=0x88, F7=0x89, G7=0x8A, H7=0x8B; -const int A8=0x94, B8=0x95, C8=0x96, D8=0x97, E8=0x98, F8=0x99, G8=0x9A, H8=0x9B; - -const int Dark = 0; -const int Light = 1; +// defines + +#define SquareNb (16 * 12) + +#define FileA 0 +#define FileB 1 +#define FileC 2 +#define FileD 3 +#define FileE 4 +#define FileF 5 +#define FileG 6 +#define FileH 7 + +#define Rank1 0 +#define Rank2 1 +#define Rank3 2 +#define Rank4 3 +#define Rank5 4 +#define Rank6 5 +#define Rank7 6 +#define Rank8 7 + +#define SquareNone 0 + +#define A1 0x24 +#define B1 0x25 +#define C1 0x26 +#define D1 0x27 +#define E1 0x28 +#define F1 0x29 +#define G1 0x2A +#define H1 0x2B +#define A2 0x34 +#define B2 0x35 +#define C2 0x36 +#define D2 0x37 +#define E2 0x38 +#define F2 0x39 +#define G2 0x3A +#define H2 0x3B +#define A3 0x44 +#define B3 0x45 +#define C3 0x46 +#define D3 0x47 +#define E3 0x48 +#define F3 0x49 +#define G3 0x4A +#define H3 0x4B +#define A4 0x54 +#define B4 0x55 +#define C4 0x56 +#define D4 0x57 +#define E4 0x58 +#define F4 0x59 +#define G4 0x5A +#define H4 0x5B +#define A5 0x64 +#define B5 0x65 +#define C5 0x66 +#define D5 0x67 +#define E5 0x68 +#define F5 0x69 +#define G5 0x6A +#define H5 0x6B +#define A6 0x74 +#define B6 0x75 +#define C6 0x76 +#define D6 0x77 +#define E6 0x78 +#define F6 0x79 +#define G6 0x7A +#define H6 0x7B +#define A7 0x84 +#define B7 0x85 +#define C7 0x86 +#define D7 0x87 +#define E7 0x88 +#define F7 0x89 +#define G7 0x8A +#define H7 0x8B +#define A8 0x94 +#define B8 0x95 +#define C8 0x96 +#define D8 0x97 +#define E8 0x98 +#define F8 0x99 +#define G8 0x9A +#define H8 0x9B + +#define Dark 0 +#define Light 1 // functions diff --git a/uci.c b/uci.c new file mode 100644 index 0000000..21c36e9 --- /dev/null +++ b/uci.c @@ -0,0 +1,978 @@ + +// uci.c + +// includes + +#include +#include +#include +#include + +#include "board.h" +#include "engine.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "option.h" +#include "parse.h" +#include "line.h" +#include "uci.h" + +// constants + +static const bool UseDebug = FALSE; + +static const int StringSize = 4096; + +// variables + +uci_t Uci[1]; + +// Hopefully the following confusion is temporary +// Normally we should check for the engine name but this is a hack anyway +// Some of there where provided by Marc Lacrosse + +const char * thread_options[]={ + "number of threads", // toga + "number threads", // Deep Learning Toga + "threads", // glaurung, zappa, cyclone, grapefruit, + // Deep Shredder, Deep Junior + "core threads", // HIARCS + "max cpus", // rybka + "cpus", // Deep Sjeng, Fruit2.3.5 + "maxthreads", // Naum + NULL +}; + +// prototypes + +static bool uci_is_ok (const uci_t * uci); + +static int parse_bestmove (uci_t * uci, const char string[]); +static void parse_id (uci_t * uci, const char string[]); +static int parse_info (uci_t * uci, const char string[]); +static void parse_option (uci_t * uci, const char string[]); +static void parse_score (uci_t * uci, const char string[]); + +static int mate_score (int dist); + +// functions + +// uci_set_threads() + +void uci_set_threads(uci_t * uci, int n) { + const char **thread_options_copy = thread_options; + const char *thread_option; + ASSERT(n>=1); + while((thread_option = *(thread_options_copy++))){ + uci_send_option(uci,thread_option,"%d",n); // checks also for existence + } +} + +// uci_thread_option_exists() + +bool uci_thread_option_exist(uci_t * uci) { + const char **thread_options_copy = thread_options; + const char *thread_option; + while((thread_option = *(thread_options_copy++))){ + if(uci_option_exist(uci,thread_option)) return TRUE; + } + return FALSE; +} + +const char * uci_thread_option(uci_t * uci){ + const char **thread_options_copy = thread_options; + const char *thread_option; + int i; + while((thread_option = *(thread_options_copy++))){ + i=uci_get_option(uci,thread_option); + if(i>=0){ + return Uci->option[i].name; + break; + } + } + return NULL; +} + +// uci_is_ok() + +static bool uci_is_ok(const uci_t * uci) { + + if (uci == NULL) return FALSE; + if (uci->engine == NULL) return FALSE; + if (uci->option_nb < 0 || uci->option_nb >= OptionNb) return FALSE; + + return TRUE; +} + +// uci_open() + +void uci_open(uci_t * uci, engine_t * engine) { + + char string[StringSize]; + int event; + + ASSERT(uci!=NULL); + ASSERT(engine!=NULL); + + // init + + uci->engine = engine; + + uci->name = NULL; + my_string_set(&uci->name,""); + uci->author = NULL; + my_string_set(&uci->author,""); + uci->option_nb = 0; + + uci->ready_nb = 0; + uci->searching = 0; + uci->pending_nb = 0; + uci->multipv_mode = FALSE; + board_start(uci->board); + uci_clear(uci); + + // send "uci" and wait for "uciok" + + engine_send(uci->engine,"uci"); + + do { + engine_get(uci->engine,string); + event = uci_parse(uci,string); + } while (!engine_eof(Engine) && (event & EVENT_UCI) == 0); +} + +// uci_close() + +void uci_close(uci_t * uci) { + + int i; + option_t * opt; + + ASSERT(uci_is_ok(uci)); + engine_close(uci->engine); + uci->engine = NULL; + my_string_clear(&uci->name); + my_string_clear(&uci->author); + + for (i = 0; i < uci->option_nb; i++) { + opt = &uci->option[i]; + my_string_clear(&opt->name); + my_string_clear(&opt->default_); + } + + uci->option_nb = 0; +} + +// uci_clear() + +void uci_clear(uci_t * uci) { + + ASSERT(uci_is_ok(uci)); + + ASSERT(!uci->searching); + + uci->best_move = MoveNone; + uci->ponder_move = MoveNone; + + uci->score = 0; + uci->depth = 0; + uci->sel_depth = 0; + line_clear(uci->pv); + + uci->best_score = 0; + uci->best_depth = 0; + uci->best_sel_depth = 0; + line_clear(uci->best_pv); + + uci->node_nb = 0; + uci->time = 0.0; + uci->speed = 0.0; + uci->cpu = 0.0; + uci->hash = 0.0; + line_clear(uci->current_line); + + uci->root_move = MoveNone; + uci->root_move_pos = 0; + uci->root_move_nb = board_mobility(uci->board); +} + +// uci_send_isready() + +void uci_send_isready(uci_t * uci) { + + ASSERT(uci!=NULL); + + engine_send(uci->engine,"isready"); + uci->ready_nb++; +} + +// uci_send_isready_sync() + +void uci_send_isready_sync(uci_t * uci) { + + char string[StringSize]; + int event; + + ASSERT(uci_is_ok(uci)); + + // send "isready" and wait for "readyok" + + uci_send_isready(uci); + + do { + engine_get(uci->engine,string); + event = uci_parse(uci,string); + } while (!engine_eof(Engine) && (event & EVENT_READY) == 0); +} + +// uci_send_stop() + +void uci_send_stop(uci_t * uci) { + + ASSERT(uci_is_ok(uci)); + + ASSERT(uci->searching); + ASSERT(uci->pending_nb>=1); + + engine_send(Engine,"stop"); + uci->searching = FALSE; +} + +// uci_send_stop_sync() + +void uci_send_stop_sync(uci_t * uci) { + + char string[StringSize]; + int event; + + ASSERT(uci_is_ok(uci)); + + ASSERT(uci->searching); + ASSERT(uci->pending_nb>=1); + + // send "stop" and wait for "bestmove" + + uci_send_stop(uci); + + do { + engine_get(uci->engine,string); + event = uci_parse(uci,string); + } while (!engine_eof(Engine) && (event & EVENT_STOP) == 0); +} + +// uci_send_ucinewgame() + +void uci_send_ucinewgame(uci_t * uci) { + + ASSERT(uci!=NULL); + + if (option_get_int("UCIVersion") >= 2) { + engine_send(uci->engine,"ucinewgame"); + } +} + +// uci_option_exist() + +bool uci_option_exist(uci_t * uci, const char option[]) { + + int i; + option_t * opt; + + ASSERT(uci_is_ok(uci)); + ASSERT(option!=NULL); + + // scan options + + for (i = 0; i < uci->option_nb; i++) { + opt = &uci->option[i]; + if (my_string_case_equal(opt->name,option)) return TRUE; + } + + return FALSE; +} + +// uci_send_option() + +void uci_send_option(uci_t * uci, const char option[], const char format[], ...) { + + va_list arg_list; + char value[StringSize]; + int i; + option_t * opt; + + ASSERT(uci_is_ok(uci)); + ASSERT(option!=NULL); + ASSERT(format!=NULL); + + // format + + va_start(arg_list,format); + vsprintf(value,format,arg_list); + va_end(arg_list); + + if (UseDebug) my_log("POLYGLOT OPTION %s VALUE %s\n",option,value); + + // scan options + + for (i = 0; i < uci->option_nb; i++) { + + opt = &uci->option[i]; + + if (my_string_case_equal(opt->name,option) && !my_string_equal(opt->default_,value)) { + engine_send(uci->engine,"setoption name %s value %s",opt->name,value); + my_string_set(&opt->default_,value); + break; + } + } +} + +// uci_parse() + +int uci_parse(uci_t * uci, const char string[]) { + + int event; + parse_t parse[1]; + char command[StringSize]; + char argument[StringSize]; + + ASSERT(uci_is_ok(uci)); + ASSERT(string!=NULL); + + // init + + event = EVENT_NONE; + + // parse + + parse_open(parse,string); + + if (parse_get_word(parse,command,StringSize)) { + + parse_get_string(parse,argument,StringSize); + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" ARGUMENT \"%s\"\n",command,argument); + + if (FALSE) { + + } else if (my_string_equal(command,"bestmove")) { + + // search end + + ASSERT(uci->pending_nb>0); + + if (uci->searching && uci->pending_nb == 1) { + + // current search + + uci->searching = FALSE; + uci->pending_nb--; + + event = parse_bestmove(uci,argument); // updates uci->best_move and uci->ponder_move + + } else { + + // obsolete search + + if (uci->pending_nb > 0) { + uci->pending_nb--; + if (uci->pending_nb == 0) event = EVENT_STOP; + } + } + + } else if (my_string_equal(command,"id")) { + + parse_id(uci,argument); + + } else if (my_string_equal(command,"info")) { + + // search information + + if (uci->searching && uci->pending_nb == 1) { // current search + event = parse_info(uci,argument); + } + + } else if (my_string_equal(command,"option")) { + + parse_option(uci,argument); + + } else if (my_string_equal(command,"readyok")) { + + // engine is ready + + ASSERT(uci->ready_nb>0); + + if (uci->ready_nb > 0) { + uci->ready_nb--; + if (uci->ready_nb == 0) event = EVENT_READY; + } + + } else if (my_string_equal(command,"uciok")) { + + event = EVENT_UCI; + + } else { + + if (UseDebug) my_log("POLYGLOT unknown command \"%s\"\n",command); + } + } + + parse_close(parse); + + return event; +} + +// parse_bestmove() + +static int parse_bestmove(uci_t * uci, const char string[]) { + + parse_t parse[1]; + char command[StringSize]; + char option[StringSize]; + char argument[StringSize]; + board_t board[1]; + + ASSERT(uci_is_ok(uci)); + ASSERT(string!=NULL); + + // init + + strcpy(command,"bestmove"); + + parse_open(parse,string); + parse_add_keyword(parse,"ponder"); + + // bestmove + + if (!parse_get_string(parse,argument,StringSize)) { + my_fatal("parse_bestmove(): missing argument\n"); + } + + uci->best_move = move_from_can(argument,uci->board); + if (uci->best_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument); + + ASSERT(uci->best_move!=MoveNone); + ASSERT(move_is_legal(uci->best_move,uci->board)); + + // loop + + while (parse_get_word(parse,option,StringSize)) { + + parse_get_string(parse,argument,StringSize); + + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); + + if (FALSE) { + + } else if (my_string_equal(option,"ponder")) { + + ASSERT(!my_string_empty(argument)); + + board_copy(board,uci->board); + move_do(board,uci->best_move); + + uci->ponder_move = move_from_can(argument,board); + // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument); + + ASSERT(uci->ponder_move!=MoveNone); + ASSERT(move_is_legal(uci->ponder_move,board)); + + } else { + + my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); + } + } + + parse_close(parse); + + return EVENT_MOVE; +} + +// parse_id() + +static void parse_id(uci_t * uci, const char string[]) { + + parse_t parse[1]; + char command[StringSize]; + char option[StringSize]; + char argument[StringSize]; + + ASSERT(uci!=NULL); + ASSERT(string!=NULL); + + // init + + strcpy(command,"id"); + + parse_open(parse,string); + parse_add_keyword(parse,"author"); + parse_add_keyword(parse,"name"); + + // loop + + while (parse_get_word(parse,option,StringSize)) { + + parse_get_string(parse,argument,StringSize); + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); + + if (FALSE) { + } else if (my_string_equal(option,"author")) { + ASSERT(!my_string_empty(argument)); + my_string_set(&uci->author,argument); + } else if (my_string_equal(option,"name")) { + ASSERT(!my_string_empty(argument)); + my_string_set(&uci->name,argument); + } else { + my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); + } + } + + parse_close(parse); + + if (UseDebug) my_log("POLYGLOT engine name \"%s\" author \"%s\"\n",uci->name,uci->author); +} + +// parse_info() + +static int parse_info(uci_t * uci, const char string[]) { + + int event; + parse_t parse[1]; + char command[StringSize]; + char option[StringSize]; + char argument[StringSize]; + int n; + int multipvline=0; + sint64 ln; + + ASSERT(uci_is_ok(uci)); + ASSERT(string!=NULL); + + // init + + event = EVENT_NONE; + + strcpy(command,"info"); + + parse_open(parse,string); + parse_add_keyword(parse,"cpuload"); + parse_add_keyword(parse,"currline"); + parse_add_keyword(parse,"currmove"); + parse_add_keyword(parse,"currmovenumber"); + parse_add_keyword(parse,"depth"); + parse_add_keyword(parse,"hashfull"); + parse_add_keyword(parse,"multipv"); + parse_add_keyword(parse,"nodes"); + parse_add_keyword(parse,"nps"); + parse_add_keyword(parse,"pv"); + parse_add_keyword(parse,"refutation"); + parse_add_keyword(parse,"score"); + parse_add_keyword(parse,"seldepth"); + parse_add_keyword(parse,"string"); + parse_add_keyword(parse,"tbhits"); + parse_add_keyword(parse,"time"); + + // loop + + while (parse_get_word(parse,option,StringSize)) { + + parse_get_string(parse,argument,StringSize); + + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); + + if (FALSE) { + + } else if (my_string_equal(option,"cpuload")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=0); + + if (n >= 0) uci->cpu = ((double)n) / 1000.0; + + } else if (my_string_equal(option,"currline")) { + + ASSERT(!my_string_empty(argument)); + + line_from_can(uci->current_line,uci->board,argument,LineSize); + + } else if (my_string_equal(option,"currmove")) { + + ASSERT(!my_string_empty(argument)); + + uci->root_move = move_from_can(argument,uci->board); + ASSERT(uci->root_move!=MoveNone); + + } else if (my_string_equal(option,"currmovenumber")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=1&&n<=uci->root_move_nb); + + if (n >= 1 && n <= uci->root_move_nb) { + uci->root_move_pos = n - 1; + ASSERT(uci->root_move_pos>=0&&uci->root_move_posroot_move_nb); + } + + } else if (my_string_equal(option,"depth")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=1); + + if (n >= 0) { + if (n > uci->depth) event |= EVENT_DEPTH; + uci->depth = n; + } + + } else if (my_string_equal(option,"hashfull")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=0); + + if (n >= 0) uci->hash = ((double)n) / 1000.0; + + } else if (my_string_equal(option,"multipv")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + if(Uci->multipv_mode) multipvline=n; + + ASSERT(n>=1); + + } else if (my_string_equal(option,"nodes")) { + + ASSERT(!my_string_empty(argument)); + + ln = my_atoll(argument); + ASSERT(ln>=0); + + if (ln >= 0) uci->node_nb = ln; + + } else if (my_string_equal(option,"nps")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=0); + + if (n >= 0) uci->speed = ((double)n); + + } else if (my_string_equal(option,"pv")) { + + ASSERT(!my_string_empty(argument)); + + line_from_can(uci->pv,uci->board,argument,LineSize); + event |= EVENT_PV; + + } else if (my_string_equal(option,"refutation")) { + + ASSERT(!my_string_empty(argument)); + + line_from_can(uci->pv,uci->board,argument,LineSize); + + } else if (my_string_equal(option,"score")) { + + ASSERT(!my_string_empty(argument)); + + parse_score(uci,argument); + + } else if (my_string_equal(option,"seldepth")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=0); + + if (n >= 0) uci->sel_depth = n; + + } else if (my_string_equal(option,"string")) { + if(!strncmp(argument,"DrawOffer",9)) + event |= EVENT_DRAW; + if(!strncmp(argument,"Resign",6)) + event |= EVENT_RESIGN; + + // TODO: argument to EOS + + ASSERT(!my_string_empty(argument)); + + } else if (my_string_equal(option,"tbhits")) { + + ASSERT(!my_string_empty(argument)); + + ln = my_atoll(argument); + ASSERT(ln>=0); + + } else if (my_string_equal(option,"time")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n>=0); + + if (n >= 0) uci->time = ((double)n) / 1000.0; + + } else { + + my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); + } + } + + parse_close(parse); + + // update display + //lousy uci,filter out lower depth multipv lines that have been repeated from the engine + if(multipvline>1 && uci->depthbest_depth) event &= ~EVENT_PV; + if ((event & EVENT_PV) != 0) { + uci->best_score = uci->score; + uci->best_depth = uci->depth; + if(multipvline==1)uci->depth=-1; //HACK ,clears the engine outpout window,see send_pv in adapter.cpp + uci->best_sel_depth = uci->sel_depth; + line_copy(uci->best_pv,uci->pv); + } + return event; +} + +int uci_get_option(uci_t * uci, const char * name){ + int i; + for(i=0;ioption_nb;i++){ + if(my_string_case_equal(Uci->option[i].name,name)){ + return i; + } + } + return -1; +} + + + +// uci_set_option() + +void uci_set_option(uci_t * uci, + const char * name, + const char * default_, + const char * type, + const char * max, + const char * min, + int var_nb, + const char * var[]){ + int i,j; + for(i=0;ioption_nb;i++){ + if(my_string_equal(Uci->option[i].name,name)){ + break; + } + } + if(ioption[i].name),name); + my_string_set(&(Uci->option[i].default_),default_); + my_string_set(&(Uci->option[i].type),type); + my_string_set(&(Uci->option[i].min),min); + my_string_set(&(Uci->option[i].max),max); + Uci->option[i].var_nb=var_nb; + for(j=0;joption[i].var[j]),var[j]); + } + if(i==Uci->option_nb){ + Uci->option_nb++; + } + } +} + +// parse_option() + +static void parse_option(uci_t * uci, const char string[]) { + + option_t * opt; + parse_t parse[1]; + char command[StringSize]; + char option[StringSize]; + char argument[StringSize]; + + ASSERT(uci!=NULL); + ASSERT(string!=NULL); + + // init + + strcpy(command,"option"); + + if (uci->option_nb >= OptionNb) return; + + opt = &uci->option[uci->option_nb]; + uci->option_nb++; + + opt->value=NULL; + my_string_set(&opt->value,""); + opt->mode=0; + + opt->name = NULL; + my_string_set(&opt->name,""); + + + opt->default_ = NULL; + my_string_set(&opt->default_,""); + + opt->max = NULL; + my_string_set(&opt->max,""); + + opt->min = NULL; + my_string_set(&opt->min,""); + + opt->type = NULL; + my_string_set(&opt->type,""); + + opt->var_nb=0; + + parse_open(parse,string); + parse_add_keyword(parse,"default"); + parse_add_keyword(parse,"max"); + parse_add_keyword(parse,"min"); + parse_add_keyword(parse,"name"); + parse_add_keyword(parse,"type"); + parse_add_keyword(parse,"var"); + + // loop + + while (parse_get_word(parse,option,StringSize)) { + parse_get_string(parse,argument,StringSize); + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); + + if (FALSE) { + + } else if (my_string_equal(option,"default")) { + + // ASSERT(!my_string_empty(argument)); // HACK for Pepito + + if (!my_string_empty(argument)) { + my_string_set(&opt->default_,argument); + my_string_set(&opt->value,argument); + } + + } else if (my_string_equal(option,"max")) { + + ASSERT(!my_string_empty(argument)); + my_string_set(&opt->max,argument); + + } else if (my_string_equal(option,"min")) { + + ASSERT(!my_string_empty(argument)); + my_string_set(&opt->min,argument); + + } else if (my_string_equal(option,"name")) { + + ASSERT(!my_string_empty(argument)); + + if (!my_string_empty(argument)) { + my_string_set(&opt->name,argument); + } + + } else if (my_string_equal(option,"type")) { + + ASSERT(!my_string_empty(argument)); + my_string_set(&opt->type,argument); + + } else if (my_string_equal(option,"var")) { + + ASSERT(!my_string_empty(argument)); + my_string_set(&opt->var[opt->var_nb++],argument); + if(opt->var_nb==VarNb) break; + + } else { + + my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); + } + } + + parse_close(parse); + + if (UseDebug) my_log("POLYGLOT option name \"%s\" default \"%s\"\n",opt->name,opt->default_); +} + +// parse_score() + +static void parse_score(uci_t * uci, const char string[]) { + + parse_t parse[1]; + char command[StringSize]; + char option[StringSize]; + char argument[StringSize]; + int n; + + ASSERT(uci_is_ok(uci)); + ASSERT(string!=NULL); + + // init + + strcpy(command,"score"); + + parse_open(parse,string); + parse_add_keyword(parse,"cp"); + parse_add_keyword(parse,"lowerbound"); + parse_add_keyword(parse,"mate"); + parse_add_keyword(parse,"upperbound"); + + // loop + + while (parse_get_word(parse,option,StringSize)) { + + parse_get_string(parse,argument,StringSize); + + if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); + + if (FALSE) { + + } else if (my_string_equal(option,"cp")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + + uci->score = n; + + } else if (my_string_equal(option,"lowerbound")) { + + ASSERT(my_string_empty(argument)); + + } else if (my_string_equal(option,"mate")) { + + ASSERT(!my_string_empty(argument)); + + n = atoi(argument); + ASSERT(n!=0); + + uci->score = mate_score(n); + + } else if (my_string_equal(option,"upperbound")) { + + ASSERT(my_string_empty(argument)); + + } else { + + my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); + } + } + + parse_close(parse); +} + +// mate_score() + +static int mate_score(int dist) { + + ASSERT(dist!=0); + + if (FALSE) { + } else if (dist > 0) { + return +option_get_int("MateScore") - (+dist) * 2 + 1; + } else if (dist < 0) { + return -option_get_int("MateScore") + (-dist) * 2; + } + + return 0; +} + +// end of uci.cpp + diff --git a/uci.h b/uci.h index 5d28aa5..0ac4f30 100644 --- a/uci.h +++ b/uci.h @@ -13,11 +13,13 @@ #include "option.h" #include "util.h" -// constants +// defines -const int OptionNb = 256; +#define OptionNb 256 -struct uci_t { +// types + +typedef struct { engine_t * engine; @@ -59,9 +61,9 @@ struct uci_t { int root_move_pos; int root_move_nb; bool multipv_mode; -}; +} uci_t; -enum dummy_event_t { +typedef enum { EVENT_NONE = 0, EVENT_UCI = 1 << 0, EVENT_READY = 1 << 1, @@ -71,7 +73,7 @@ enum dummy_event_t { EVENT_DEPTH = 1 << 5, EVENT_DRAW = 1 << 6, EVENT_RESIGN= 1 << 7 -}; +} dummy_event_t; // variables diff --git a/uci2uci.c b/uci2uci.c new file mode 100644 index 0000000..611697a --- /dev/null +++ b/uci2uci.c @@ -0,0 +1,247 @@ +// uci2uci.c + +// includes + +#include +#include + +#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;jvar_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;ioption_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 index 0000000..8551aca --- /dev/null +++ b/util.c @@ -0,0 +1,412 @@ + +// util.c + +// includes + +#ifdef _WIN32 +#include +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "util.h" + +// variables + +static bool Error; + +FILE * LogFile=NULL; + + +// functions + +// util_init() + +void util_init() { + + Error = FALSE; + + // init log file + + LogFile = NULL; + + // switch file buffering off + + setbuf(stdin,NULL); + setbuf(stdout,NULL); +} + +// my_random_init() + +void my_random_init() { + srand(time(NULL)); +} + +// my_random_int() + +int my_random_int(int n) { + + int r; + + ASSERT(n>0); + + r = ((int)floor(my_random_double()*((double)n))); + ASSERT(r>=0&&r=0.0&&r<1.0); + + return r; +} + +// my_atoll() + +sint64 my_atoll(const char string[]) { + + sint64 n; + + sscanf(string,S64_FORMAT,&n); + + return n; +} + +// my_round() + +int my_round(double x) { + + return ((int)floor(x+0.5)); +} + +// my_malloc() + +void * my_malloc(size_t size) { + + void * address; + + ASSERT(size>0); + + address = malloc(size); + if (address == NULL) my_fatal("my_malloc(): malloc(): %s\n",strerror(errno)); + + return address; +} + +// my_realloc() + +void * my_realloc(void * address, size_t size) { + + ASSERT(address!=NULL); + ASSERT(size>0); + + address = realloc(address,size); + if (address == NULL) my_fatal("my_realloc(): realloc(): %s\n",strerror(errno)); + + return address; +} + +// my_free() + +void my_free(void * address) { + + ASSERT(address!=NULL); + + free(address); +} + +// my_log_open() + +void my_log_open(const char file_name[]) { + + ASSERT(file_name!=NULL); + + LogFile = fopen(file_name,"a"); +#ifndef _WIN32 +//line buffering doesn't work too well in MSVC and/or windows + if (LogFile != NULL) setvbuf(LogFile,NULL,_IOLBF,0); // line buffering +#endif +} + +// my_log_close() + +void my_log_close() { + + if (LogFile != NULL) fclose(LogFile); + LogFile=NULL; +} + +// my_log() + +void my_log(const char format[], ...) { + + va_list ap; + + ASSERT(format!=NULL); + + if (LogFile != NULL) { + fprintf(LogFile,"%.3f ",now_real()); + va_start(ap,format); + + vfprintf(LogFile,format,ap); + va_end(ap); +#ifdef _WIN32 + fflush(LogFile); +#endif + } +} + +// my_fatal() + +void my_fatal(const char format[], ...) { + + va_list ap; + + ASSERT(format!=NULL); + + va_start(ap,format); + + vfprintf(stderr,format,ap); + if (LogFile != NULL) vfprintf(LogFile,format,ap); + + va_end(ap); + if (Error) { // recursive error + my_log("POLYGLOT *** RECURSIVE ERROR ***\n"); + exit(EXIT_FAILURE); + // abort(); + } else { + Error = TRUE; + quit(); + } +} + +// my_file_read_line() + +bool my_file_read_line(FILE * file, char string[], int size) { + + int src, dst; + int c; + + ASSERT(file!=NULL); + ASSERT(string!=NULL); + ASSERT(size>0); + + if (fgets(string,size,file) == NULL) { + if (feof(file)) { + return FALSE; + } else { // error + my_fatal("my_file_read_line(): fgets(): %s\n",strerror(errno)); + } + } + + // remove CRs and LFs + + src = 0; + dst = 0; + + while ((c=string[src++]) != '\0') { + if (c != '\r' && c != '\n') string[dst++] = c; + } + + string[dst] = '\0'; + + return TRUE; +} + +// my_string_empty() + +bool my_string_empty(const char string[]) { + + return string == NULL || string[0] == '\0'; +} + +// my_string_whitespace() + +bool my_string_whitespace(const char string[]){ + int pos=0; + while(string[pos]!='\0'){ + if(string[pos]!=' ' && string[pos]!='\t'){ + return FALSE; + } + pos++; + } + return TRUE; +} + +// my_string_equal() + +bool my_string_equal(const char string_1[], const char string_2[]) { + + ASSERT(string_1!=NULL); + ASSERT(string_2!=NULL); + + return strcmp(string_1,string_2) == 0; +} + +// my_string_case_equal() + +bool my_string_case_equal(const char string_1[], const char string_2[]) { + + int c1, c2; + + ASSERT(string_1!=NULL); + ASSERT(string_2!=NULL); + + while (TRUE) { + + c1 = *string_1++; + c2 = *string_2++; + + if (tolower(c1) != tolower(c2)) return FALSE; + if (c1 == '\0') return TRUE; + } + + return FALSE; +} + +// my_strdup() + +char * my_strdup(const char string[]) { + + char * address; + + ASSERT(string!=NULL); + + // strdup() is not ANSI C + + address = (char *) my_malloc(strlen(string)+1); + strcpy(address,string); + + return address; +} + +// my_string_clear() + +void my_string_clear(const char * * variable) { + + ASSERT(variable!=NULL); + + if (*variable != NULL) { + my_free((void*)(*variable)); + *variable = NULL; + } +} + +// my_string_set() + +void my_string_set(const char * * variable, const char string[]) { + + ASSERT(variable!=NULL); + ASSERT(string!=NULL); + + if (*variable != NULL) my_free((void*)(*variable)); + *variable = my_strdup(string); +} + +double now_real() { +#ifndef _WIN32 + struct timeval tv[1]; + struct timezone tz[1]; + + tz->tz_minuteswest = 0; + tz->tz_dsttime = 0; // DST_NONE not declared in linux + + if (gettimeofday(tv,tz) == -1) { + my_fatal("now_real(): gettimeofday(): %s\n",strerror(errno)); + } + + return tv->tv_sec + tv->tv_usec * 1E-6; +#else + return (double) GetTickCount() / 1000.0; // we can do better here:-) +#endif +} + + +// my_timer_reset() + +void my_timer_reset(my_timer_t * timer) { + + ASSERT(timer!=NULL); + + timer->start_real = 0.0; + timer->elapsed_real = 0.0; + timer->running = FALSE; +} + +// my_timer_start() + +void my_timer_start(my_timer_t * timer) { +// timer->start_real = 0.0; + timer->elapsed_real = 0.0; +// timer->running = FALSE; + ASSERT(timer!=NULL); + + timer->running = TRUE; + timer->start_real = now_real(); +} + +// my_timer_stop() + +void my_timer_stop(my_timer_t * timer) { + + ASSERT(timer!=NULL); + + ASSERT(timer->running); + + timer->elapsed_real += now_real() - timer->start_real; + timer->start_real = 0.0; + timer->running = FALSE; +} + +// my_timer_elapsed_real() + +double my_timer_elapsed_real(const my_timer_t * timer) { + + double elapsed; + + ASSERT(timer!=NULL); + + elapsed = timer->elapsed_real; + if (timer->running) elapsed += now_real() - timer->start_real; + + if (elapsed < 0.0) elapsed = 0.0; + + return elapsed; +} + + +char * my_getcwd(char *buf, size_t size){ +#ifdef _WIN32 + return _getcwd(buf,size); +#else + return getcwd(buf,size); +#endif +} + +int my_chdir (const char *path){ + ASSERT(path!=NULL); +#ifdef _WIN32 + return _chdir(path); +#else + return chdir(path); +#endif +} diff --git a/util.h b/util.h index 1ce7e32..cf197fe 100644 --- a/util.h +++ b/util.h @@ -6,9 +6,22 @@ // includes -#include +#include + +// defines + +#ifndef EXIT_SUCCES +#define EXIT_SUCCES 0 +#endif + +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif -// constants #undef FALSE #define FALSE 0 @@ -63,6 +76,8 @@ typedef unsigned short uint16; typedef signed int sint32; typedef unsigned int uint32; +typedef int bool; + #ifdef _MSC_VER typedef signed __int64 sint64; typedef unsigned __int64 uint64; @@ -71,28 +86,14 @@ typedef unsigned int uint32; typedef unsigned long long int uint64; #endif -struct my_timer_t { +typedef struct { double start_real; double elapsed_real; bool running; -}; +} my_timer_t; // functions -#ifdef _WIN32 - #include - inline void Idle(void) { - Sleep(1); - } - inline void Idle500msecs(void){ - Sleep(500); - } -#else - #include - inline void Idle(void) { - usleep(1000); - } -#endif extern void util_init (); extern void my_random_init (); @@ -124,6 +125,8 @@ extern char * my_strdup (const char string[]); extern void my_string_clear (const char * * variable); extern void my_string_set (const char * * variable, const char string[]); +extern double now_real (); + extern void my_timer_reset (my_timer_t * timer); extern void my_timer_start (my_timer_t * timer); extern void my_timer_stop (my_timer_t * timer); @@ -132,6 +135,9 @@ extern double my_timer_elapsed_real (const my_timer_t * timer); extern char * my_error(); +extern char * my_getcwd (char *buf, size_t size); +extern int my_chdir (const char *path); + #endif // !defined UTIL_H // end of util.h diff --git a/xboard2uci.c b/xboard2uci.c new file mode 100644 index 0000000..43bc63b --- /dev/null +++ b/xboard2uci.c @@ -0,0 +1,1553 @@ + +// xboard2uci.c + +// includes + +#include +#include +#include +#include +#include + +#include "board.h" +#include "book.h" +#include "colour.h" +#include "engine.h" +#include "fen.h" +#include "game.h" +#include "gui.h" +#include "line.h" +#include "main.h" +#include "move.h" +#include "move_do.h" +#include "move_legal.h" +#include "option.h" +#include "parse.h" +#include "san.h" +#include "uci.h" +#include "uci2uci.h" +#include "util.h" + +// defines + +#define StringSize 4096 + +// constants + +static const bool UseDebug = FALSE; +static const bool DelayPong = FALSE; + +// types + +typedef struct { + int state; + bool computer[ColourNb]; + int exp_move; + int resign_nb; + my_timer_t timer[1]; +} state_t; + +typedef struct { + bool has_feature_memory; + bool has_feature_smp; + bool has_feature_egt; + bool analyse; + bool computer; + const char * name; + bool ics; + bool new_hack; // "new" is a C++ keyword + bool ponder; + int ping; + bool post; + int proto_ver; + bool result; + + int mps; + double base; + double inc; + + bool time_limit; + double time_max; + + bool depth_limit; + int depth_max; + + double my_time; + double opp_time; +} xb_t; + +typedef enum { WAIT, THINK, PONDER, ANALYSE } dummy_state_t; + +// variables + +static state_t State[1]; +static xb_t XB[1]; + +// prototypes + +static void comp_move (int move); +static void move_step (int move); +static void board_update (); + +static void mess (); +static void no_mess (int move); + +static void search_update (); +static void search_clear (); +static void update_remaining_time(); +static int report_best_score(); +static bool kibitz_throttle (bool searching); +static void start_protected_command(); +static void end_protected_command(); + +static bool active (); +static bool ponder (); +static bool ponder_ok (int ponder_move); + +static void stop_search (); + +static void send_board (int extra_move); +static void send_pv (); + +static void send_xboard_options (); + +static void learn (int result); + + +// functions + +// xboard2uci_init() + +void xboard2uci_init() { + // init + + game_clear(Game); + + // state + + State->state = WAIT; + + State->computer[White] = FALSE; + State->computer[Black] = TRUE; + + State->exp_move = MoveNone; + State->resign_nb = 0; + my_timer_reset(State->timer); + + // yes there are engines that do not have the "Hash" option.... + XB->has_feature_memory= uci_option_exist(Uci,"Hash"); + XB->has_feature_smp = uci_thread_option_exist(Uci); + // TODO: support for other types of table bases + XB->has_feature_egt = uci_option_exist(Uci,"NalimovPath"); + XB->analyse = FALSE; + XB->computer = FALSE; + XB->name = NULL; + my_string_set(&XB->name,""); + XB->ics = FALSE; + XB->new_hack = TRUE; + XB->ping = -1; + XB->ponder = FALSE; + XB->post = FALSE; + XB->proto_ver = 1; + XB->result = FALSE; + + XB->mps = 0; + XB->base = 300.0; + XB->inc = 0.0; + + XB->time_limit = FALSE; + XB->time_max = 5.0; + + XB->depth_limit = FALSE; + XB->depth_max = 127; + + XB->my_time = 300.0; + XB->opp_time = 300.0; +} + +// xboard2uci_gui_step() + +void xboard2uci_gui_step(char string[]) { + + int move; + char move_string[256]; + board_t board[1]; + + if (FALSE) { + + } else if (match(string,"accepted *")) { + + // ignore + + } else if (match(string,"analyze")) { + + State->computer[White] = FALSE; + State->computer[Black] = FALSE; + + XB->analyse = TRUE; + XB->new_hack = FALSE; + ASSERT(!XB->result); + XB->result = FALSE; + + mess(); + + } else if (match(string,"bk")) { + + if (option_get_bool("Book")) { + game_get_board(Game,board); + book_disp(board); + } + + } else if (match(string,"black")) { + + if (colour_is_black(game_turn(Game))) { + + State->computer[White] = TRUE; + State->computer[Black] = FALSE; + + XB->new_hack = TRUE; + XB->result = FALSE; + + mess(); + } + + } else if (match(string,"computer")) { + + XB->computer = TRUE; + + } else if (match(string,"draw")) { + if(uci_option_exist(Uci,"UCI_DrawOffers")){ + my_log("POLYGLOT draw from XB received"); + uci_send_option(Uci,"DrawOffer","%s","draw");} + } else if (match(string,"easy")) { + + XB->ponder = FALSE; + + mess(); + + } else if (match(string,"edit")) { + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (match(string,"exit")) { + + State->computer[White] = FALSE; + State->computer[Black] = FALSE; + + XB->analyse = FALSE; + + mess(); + + } else if (match(string,"force")) { + + State->computer[White] = FALSE; + State->computer[Black] = FALSE; + + mess(); + + } else if (match(string,"go")) { + + State->computer[game_turn(Game)] = TRUE; + State->computer[colour_opp(game_turn(Game))] = FALSE; + + XB->new_hack = FALSE; + ASSERT(!XB->result); + XB->result = FALSE; + + mess(); + + } else if (match(string,"hard")) { + + XB->ponder = TRUE; + + mess(); + + } else if (match(string,"hint")) { + + if (option_get_bool("Book")) { + + game_get_board(Game,board); + move = book_move(board,FALSE); + + if (move != MoveNone && move_is_legal(move,board)) { + move_to_san(move,board,move_string,256); + gui_send(GUI,"Hint: %s",move_string); + } + } + + } else if (match(string,"ics *")) { + + XB->ics = TRUE; + + } else if (match(string,"level * *:* *")) { + + XB->mps = atoi(Star[0]); + XB->base = ((double)atoi(Star[1])) * 60.0 + ((double)atoi(Star[2])); + XB->inc = ((double)atoi(Star[3])); + + } else if (match(string,"level * * *")) { + + XB->mps = atoi(Star[0]); + XB->base = ((double)atoi(Star[1])) * 60.0; + XB->inc = ((double)atoi(Star[2])); + + } else if (match(string,"name *")) { + + my_string_set(&XB->name,Star[0]); + + } else if (match(string,"new")) { + + uci_send_isready(Uci); + my_log("POLYGLOT NEW GAME\n"); + + option_set("Chess960","FALSE"); + + game_clear(Game); + + if (XB->analyse) { + State->computer[White] = FALSE; + State->computer[Black] = FALSE; + } else { + State->computer[White] = FALSE; + State->computer[Black] = TRUE; + } + + XB->new_hack = TRUE; + XB->result = FALSE; + + XB->depth_limit = FALSE; + + XB->computer = FALSE; + my_string_set(&XB->name,""); + + board_update(); + mess(); + + uci_send_ucinewgame(Uci); + + } else if (match(string,"nopost")) { + + XB->post = FALSE; + + } else if (match(string,"otim *")) { + + XB->opp_time = ((double)atoi(Star[0])) / 100.0; + if (XB->opp_time < 0.0) XB->opp_time = 0.0; + + } else if (match(string,"pause")) { + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (match(string,"ping *")) { + + // HACK; TODO: answer only after an engine move + + if (DelayPong) { + if (XB->ping >= 0) gui_send(GUI,"pong %d",XB->ping); // HACK: get rid of old ping + XB->ping = atoi(Star[0]); + uci_send_isready(Uci); + } else { + ASSERT(XB->ping==-1); + gui_send(GUI,"pong %s",Star[0]); + } + + } else if (match(string,"playother")) { + + State->computer[game_turn(Game)] = FALSE; + State->computer[colour_opp(game_turn(Game))] = TRUE; + + XB->new_hack = FALSE; + ASSERT(!XB->result); + XB->result = FALSE; + + mess(); + + } else if (match(string,"post")) { + + XB->post = TRUE; + + } else if (match(string,"protover *")) { + + send_xboard_options(); + + } else if (match(string,"quit")) { + my_log("POLYGLOT *** \"quit\" from GUI ***\n"); + quit(); + } else if (match(string,"random")) { + + // ignore + + } else if (match(string,"rating * *")) { + + // ignore + + } else if (match(string,"remove")) { + + if (game_pos(Game) >= 2) { + + game_goto(Game,game_pos(Game)-2); + + ASSERT(!XB->new_hack); + XB->new_hack = FALSE; // HACK? + XB->result = FALSE; + + board_update(); + mess(); + } + + } else if (match(string,"rejected *")) { + + // ignore + + } else if (match(string,"reset")) { // protover 3? + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (FALSE + || match(string,"result * {*}") + || match(string,"result * {* }") + || match(string,"result * { *}") + || match(string,"result * { * }")) { + + my_log("POLYGLOT GAME END\n"); + + XB->result = TRUE; + + mess(); + + // book learning + + if (option_get_bool("Book") && option_get_bool("BookLearn")) { + + if (FALSE) { + } else if (my_string_equal(Star[0],"1-0")) { + learn(+1); + } else if (my_string_equal(Star[0],"0-1")) { + learn(-1); + } else if (my_string_equal(Star[0],"1/2-1/2")) { + learn(0); + } + } + } else if (match(string,"resume")) { + + // refuse + + gui_send(GUI,"Error (unknown command): %s",string); + + } else if (match(string,"option *=*")){ + char *name=Star[0]; + char *value=Star[1]; + if(match(name, "Polyglot *")){ + char *pg_name=Star[0]; + polyglot_set_option(pg_name,value); + }else{ + start_protected_command(); + engine_send(Engine,"setoption name %s value %s",name,value); + end_protected_command(); + } + } else if (match(string,"option *")){ + char *name=Star[0]; + start_protected_command(); + engine_send(Engine,"setoption name %s",name); + end_protected_command(); + } else if (XB->has_feature_smp && match(string,"cores *")){ + int cores=atoi(Star[0]); + if(cores>=1){ + // updating the number of cores + my_log("POLYGLOT setting the number of cores to %d\n",cores); + start_protected_command(); + uci_set_threads(Uci,cores); + end_protected_command(); + } else{ + // refuse + gui_send(GUI,"Error (unknown command): %s",string); + } + } else if (XB->has_feature_egt && match(string,"egtpath * *")){ + char *type=Star[0]; + char *path=Star[1]; + if(!my_string_case_equal(type,"nalimov")){ + // refuse + gui_send(GUI,"Error (unsupported table base format): %s",string); + }else if(my_string_empty(path)){ + // refuse + gui_send(GUI,"Error (unknown command): %s",string); + }else{ + // updating NalimovPath + my_log("POLYGLOT setting the Nalimov path to %s\n",path); + start_protected_command(); + uci_send_option(Uci,"NalimovPath","%s",path); + end_protected_command(); + } + } else if (XB->has_feature_memory && match(string,"memory *")){ + int memory = atoi(Star[0]); + int nalimov_cache; + int real_memory; + if(memory>=1){ + // updating the available memory + my_log("POLYGLOT setting the amount of memory to %dMb\n",memory); + if(uci_get_option(Uci,"NalimovCache")>=0){ + nalimov_cache=atoi(Uci->option[uci_get_option(Uci,"NalimovCache")].value); + }else{ + nalimov_cache=0; + } + my_log("POLYGLOT Nalimov Cache is %dMb\n",nalimov_cache); + real_memory=memory-nalimov_cache; + if(real_memory>0){ + start_protected_command(); + uci_send_option(Uci,"Hash", "%d", real_memory); + end_protected_command(); + } + }else{ + // refuse + gui_send(GUI,"Error (unknown command): %s",string); + } + + } else if (match(string,"sd *")) { + + XB->depth_limit = TRUE; + XB->depth_max = atoi(Star[0]); + + } else if (match(string,"setboard *")) { + + my_log("POLYGLOT FEN %s\n",Star[0]); + + if (!game_init(Game,Star[0])) my_fatal("xboard_step(): bad FEN \"%s\"\n",Star[0]); + + State->computer[White] = FALSE; + State->computer[Black] = FALSE; + + XB->new_hack = TRUE; // HACK? + XB->result = FALSE; + + board_update(); + mess(); + + } else if (match(string,"st *")) { + + XB->time_limit = TRUE; + XB->time_max = ((double)atoi(Star[0])); + + } else if (match(string,"time *")) { + + XB->my_time = ((double)atoi(Star[0])) / 100.0; + if (XB->my_time < 0.0) XB->my_time = 0.0; + + } else if (match(string,"undo")) { + + if (game_pos(Game) >= 1) { + + game_goto(Game,game_pos(Game)-1); + + ASSERT(!XB->new_hack); + XB->new_hack = FALSE; // HACK? + XB->result = FALSE; + + board_update(); + mess(); + } + + } else if (match(string,"usermove *")) { + + game_get_board(Game,board); + move = move_from_san(Star[0],board); + + if (move != MoveNone && move_is_legal(move,board)) { + + XB->new_hack = FALSE; + ASSERT(!XB->result); + XB->result = FALSE; + + move_step(move); + no_mess(move); + + } else { + + gui_send(GUI,"Illegal move: %s",Star[0]); + } + + } else if (match(string,"variant *")) { + + if (my_string_equal(Star[0],"fischerandom")) { + option_set("Chess960","TRUE"); + } else { + option_set("Chess960","FALSE"); + } + + } else if (match(string,"white")) { + + if (colour_is_white(game_turn(Game))) { + + State->computer[White] = FALSE; + State->computer[Black] = TRUE; + + XB->new_hack = TRUE; + XB->result = FALSE; + + mess(); + } + + } else if (match(string,"xboard")) { + + // ignore + + } else if (match(string,".")) { // analyse info + + if (State->state == ANALYSE) { + int depth=Uci->best_depth;//HACK: don't clear engine-output window... + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + if (Uci->root_move != MoveNone && move_is_legal(Uci->root_move,Uci->board)) { + move_to_san(Uci->root_move,Uci->board,move_string,256); + gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d %s",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,Uci->root_move_nb-(Uci->root_move_pos+1),Uci->root_move_nb,move_string); + } else { + gui_send(GUI,"stat01: %.0f "S64_FORMAT" %d %d %d",Uci->time*100.0,Uci->node_nb,/*Uci->*/depth,0,0); // HACK + } + } + + } else if (match(string,"?")) { // move now + + if (State->state == THINK) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + // HACK: just send "stop" to the engine + + if (Uci->searching) { + my_log("POLYGLOT STOP SEARCH\n"); + engine_send(Engine,"stop"); + } + } + + } else { // unknown command, maybe a move? + + game_get_board(Game,board); + move = move_from_san(string,board); + + if (move != MoveNone && move_is_legal(move,board)) { + + XB->new_hack = FALSE; + ASSERT(!XB->result); + XB->result = FALSE; + + move_step(move); + no_mess(move); + + } else if (move != MoveNone) { + + gui_send(GUI,"Illegal move: %s",string); + + } else { + + gui_send(GUI,"Error (unknown command): %s",string); + } + } + return; +} + +// xboard2uci_engine_step() + +void xboard2uci_engine_step(char string[]) { + + int event; + event = uci_parse(Uci,string); + + // react to events + + if ((event & EVENT_READY) != 0) { + + // the engine is now ready + + if (!Uci->ready) { + Uci->ready = TRUE; + // if (XB->proto_ver >= 2) xboard_send(XBoard,"feature done=1"); + } + + if (!DelayPong && XB->ping >= 0) { + gui_send(GUI,"pong %d",XB->ping); + XB->ping = -1; + } + } + + if ((event & EVENT_MOVE) != 0 && State->state == THINK) { + + // the engine is playing a move + + // MEGA HACK: estimate remaining time because XBoard won't send it! + + my_timer_stop(State->timer); + + XB->my_time -= my_timer_elapsed_real(State->timer); + XB->my_time += XB->inc; + if (XB->mps != 0 && (game_move_nb(Game) + 1) % XB->mps == 0) XB->my_time += XB->base; + + if (XB->my_time < 0.0) XB->my_time = 0.0; + + // play the engine move + + comp_move(Uci->best_move); + } + + if ((event & EVENT_PV) != 0) { + + // the engine has sent a new PV + + send_pv(); + } + if((event & (EVENT_DRAW|EVENT_RESIGN))!=0){ + my_log("POYGLOT draw offer/resign from engine\n"); + if(uci_option_exist(Uci,"UCI_DrawOffers")){ + if(event & EVENT_DRAW) + gui_send(GUI,"offer draw"); + else + gui_send(GUI,"resign"); + } + } +} + +// format_xboard_option_line + +void format_xboard_option_line(char * option_line, option_t *opt){ + int j; + char option_string[StringSize]; + strcpy(option_line,""); + strcat(option_line,"feature option=\""); + if(opt->mode&PG){ + strcat(option_line,"Polyglot "); + } + sprintf(option_string,"%s",opt->name); + strcat(option_line,option_string); + sprintf(option_string," -%s",opt->type); + strcat(option_line,option_string); + if(strcmp(opt->type,"button") && strcmp(opt->type,"combo")){ + if(strcmp(opt->type,"check")){ + sprintf(option_string," %s",opt->default_); + }else{ + sprintf(option_string," %d", + strcmp(opt->default_,"TRUE")?0:1); + } + strcat(option_line,option_string); + } + if(!strcmp(opt->type,"spin")){ + sprintf(option_string," %s",opt->min); + strcat(option_line,option_string); + } + if(!strcmp(opt->type,"spin")){ + sprintf(option_string," %s",opt->max); + strcat(option_line,option_string); + } + for(j=0;jvar_nb;j++){ + if(!strcmp(opt->var[j],opt->default_)){ + sprintf(option_string," *%s",opt->var[j]); + }else{ + sprintf(option_string," %s",opt->var[j]); + } + strcat(option_line,option_string); + if(j!=opt->var_nb-1){ + strcat(option_line," ///"); + } + } + strcat(option_line,"\""); +} + +// send_xboard_options + +static void send_xboard_options(){ + int i; + char option_line[StringSize]=""; + option_t *p=Option; + const char * name; + XB->proto_ver = atoi(Star[0]); + ASSERT(XB->proto_ver>=2); + + gui_send(GUI,"feature done=0"); + + gui_send(GUI,"feature analyze=1"); + gui_send(GUI,"feature colors=0"); + gui_send(GUI,"feature draw=1"); + gui_send(GUI,"feature ics=1"); + gui_send(GUI,"feature myname=\"%s\"",option_get_string("EngineName")); + gui_send(GUI,"feature name=1"); + gui_send(GUI,"feature pause=0"); + gui_send(GUI,"feature ping=1"); + gui_send(GUI,"feature playother=1"); + gui_send(GUI,"feature reuse=1"); + gui_send(GUI,"feature san=0"); + gui_send(GUI,"feature setboard=1"); + gui_send(GUI,"feature sigint=0"); + gui_send(GUI,"feature sigterm=0"); + gui_send(GUI,"feature time=1"); + gui_send(GUI,"feature usermove=1"); + if (XB->has_feature_memory){ + gui_send(GUI,"feature memory=1"); + }else{ + gui_send(GUI,"feature memory=0"); + } + if (XB->has_feature_smp){ + gui_send(GUI,"feature smp=1"); + }else{ + gui_send(GUI,"feature smp=0"); + } + if (XB->has_feature_egt){ + // TODO: support for other types of table bases + gui_send(GUI,"feature egt=\"nalimov\""); + }else{ + gui_send(GUI,"feature egt=\"\""); + } + + if (uci_option_exist(Uci,"UCI_Chess960")) { + gui_send(GUI,"feature variants=\"normal,fischerandom\""); + } else { + gui_send(GUI,"feature variants=\"normal\""); + } + + for(i=0;ioption_nb;i++){ + if(my_string_case_equal(Uci->option[i].name,"UCI_AnalyseMode")) continue; + if(my_string_case_equal(Uci->option[i].name,"Ponder")) continue; + if(my_string_case_equal(Uci->option[i].name,"Hash")) continue; + if(my_string_case_equal(Uci->option[i].name,"NalimovPath")) continue; + if((name=uci_thread_option(Uci))!=NULL && my_string_case_equal(Uci->option[i].name,name)) continue; + format_xboard_option_line(option_line,Uci->option+i); + + gui_send(GUI,"%s",option_line); + + } + while(p->name){ + if(p->mode &XBOARD){ + format_xboard_option_line(option_line,p); + gui_send(GUI,"%s",option_line); + } + p++; + } + gui_send(GUI,"feature done=1"); + +} + +// report_best_score() + +static int report_best_score(){ + if(!option_get_bool("ScoreWhite") || colour_is_white(Uci->board->turn)){ + return Uci->best_score; + }else{ + return -Uci->best_score; + } +} + +// comp_move() + +static void comp_move(int move) { + + board_t board[1]; + char string[256]; + + ASSERT(move_is_ok(move)); + + ASSERT(State->state==THINK); + ASSERT(!XB->analyse); + + if(option_get_bool("RepeatPV")) + send_pv(); // to update time and nodes + + // send the move + + game_get_board(Game,board); + + if (move_is_castle(move,board) && option_get_bool("Chess960")) { + if (!move_to_san(move,board,string,256)) my_fatal("comp_move(): move_to_san() failed\n"); // O-O/O-O-O + } else { + if (!move_to_can(move,board,string,256)) my_fatal("comp_move(): move_to_can() failed\n"); + } + + gui_send(GUI,"move %s",string); + + // resign? + + if (option_get_bool("Resign") && Uci->root_move_nb > 1) { + + if (Uci->best_score <= -abs(option_get_int("ResignScore"))) { + + State->resign_nb++; + my_log("POLYGLOT %d move%s with resign score\n",State->resign_nb,(State->resign_nb>1)?"s":""); + + if (State->resign_nb >= option_get_int("ResignMoves")) { + my_log("POLYGLOT *** RESIGN ***\n"); + gui_send(GUI,"resign"); + } + + } else { + + if (State->resign_nb > 0) my_log("POLYGLOT resign reset (State->resign_nb=%d)\n",State->resign_nb); + State->resign_nb = 0; + } + } + + // play the move + + move_step(move); + no_mess(move); +} + +// move_step() + +static void move_step(int move) { + + board_t board[1]; + char move_string[256]; + + ASSERT(move_is_ok(move)); + + // log + + game_get_board(Game,board); + + if (move != MoveNone && move_is_legal(move,board)) { + + move_to_san(move,board,move_string,256); + my_log("POLYGLOT MOVE %s\n",move_string); + + } else { + + move_to_can(move,board,move_string,256); + my_log("POLYGLOT ILLEGAL MOVE \"%s\"\n",move_string); + board_disp(board); + + my_fatal("move_step(): illegal move \"%s\"\n",move_string); + } + + // play the move + + game_add_move(Game,move); + board_update(); +} + +// board_update() + +static void board_update() { + + // handle game end + + ASSERT(!XB->result); + + switch (game_status(Game)) { + case PLAYING: + break; + case WHITE_MATES: + gui_send(GUI,"1-0 {White mates}"); + break; + case BLACK_MATES: + gui_send(GUI,"0-1 {Black mates}"); + break; + case STALEMATE: + gui_send(GUI,"1/2-1/2 {Stalemate}"); + break; + case DRAW_MATERIAL: + gui_send(GUI,"1/2-1/2 {Draw by insufficient material}"); + break; + case DRAW_FIFTY: + gui_send(GUI,"1/2-1/2 {Draw by fifty-move rule}"); + break; + case DRAW_REPETITION: + gui_send(GUI,"1/2-1/2 {Draw by repetition}"); + break; + default: + ASSERT(FALSE); + break; + } +} + +// mess() + +static void mess() { + + // clear state variables + + State->resign_nb = 0; + State->exp_move = MoveNone; + my_timer_reset(State->timer); + + // abort a possible search + + stop_search(); + + // calculate the new state + + if (FALSE) { + } else if (!active()) { + State->state = WAIT; + my_log("POLYGLOT WAIT\n"); + } else if (XB->analyse) { + State->state = ANALYSE; + my_log("POLYGLOT ANALYSE\n"); + } else if (State->computer[game_turn(Game)]) { + State->state = THINK; + my_log("POLYGLOT THINK\n"); + } else { + State->state = WAIT; + my_log("POLYGLOT WAIT\n"); + } + + search_update(); +} + +// no_mess() + +static void no_mess(int move) { + + ASSERT(move_is_ok(move)); + + // just received a move, calculate the new state + + if (FALSE) { + + } else if (!active()) { + + stop_search(); // abort a possible search + + State->state = WAIT; + State->exp_move = MoveNone; + + my_log("POLYGLOT WAIT\n"); + + } else if (State->state == WAIT) { + + ASSERT(State->computer[game_turn(Game)]); + ASSERT(!State->computer[colour_opp(game_turn(Game))]); + ASSERT(!XB->analyse); + + my_log("POLYGLOT WAIT -> THINK\n"); + + State->state = THINK; + State->exp_move = MoveNone; + + } else if (State->state == THINK) { + + ASSERT(!State->computer[game_turn(Game)]); + ASSERT(State->computer[colour_opp(game_turn(Game))]); + ASSERT(!XB->analyse); + + if (ponder() && ponder_ok(Uci->ponder_move)) { + + my_log("POLYGLOT THINK -> PONDER\n"); + + State->state = PONDER; + State->exp_move = Uci->ponder_move; + + } else { + + my_log("POLYGLOT THINK -> WAIT\n"); + + State->state = WAIT; + State->exp_move = MoveNone; + } + + } else if (State->state == PONDER) { + + ASSERT(State->computer[game_turn(Game)]); + ASSERT(!State->computer[colour_opp(game_turn(Game))]); + ASSERT(!XB->analyse); + + if (move == State->exp_move && Uci->searching) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + my_timer_start(State->timer);//also resets + + my_log("POLYGLOT PONDER -> THINK (*** HIT ***)\n"); + engine_send(Engine,"ponderhit"); + + State->state = THINK; + State->exp_move = MoveNone; + + send_pv(); // update display + + return; // do not launch a new search + + } else { + + my_log("POLYGLOT PONDER -> THINK (miss)\n"); + + stop_search(); + + State->state = THINK; + State->exp_move = MoveNone; + } + + } else if (State->state == ANALYSE) { + + ASSERT(XB->analyse); + + my_log("POLYGLOT ANALYSE -> ANALYSE\n"); + + stop_search(); + + } else { + + ASSERT(FALSE); + } + + search_update(); +} + +// start_protected_command() + +static void start_protected_command(){ + stop_search(); +} + +static void end_protected_command(){ + if(Uci->ready){ // not init faze + uci_send_isready_sync(Uci); // gobble up spurious "bestmove" + } + update_remaining_time(); + search_update(); // relaunch search if necessary +} + +// update_remaining_time() + +static void update_remaining_time(){ + double reduce; + if(State->timer->running){ + my_timer_stop(State->timer); + reduce = my_timer_elapsed_real(State->timer); + my_log("POLYGLOT reducing remaing time by %f seconds\n",reduce); + XB->my_time -= reduce; + if(XB->my_time<0.0){ + XB->my_time=0.0; + } + } +} + + +// search_update() + +static void search_update() { + + int move; + int move_nb; + board_t board[1]; + + ASSERT(!Uci->searching); + + + + + // launch a new search if needed + + + + if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) { + + // opening book + + if (State->state == THINK && option_get_bool("Book")) { + + game_get_board(Game,Uci->board); + + move = book_move(Uci->board,option_get_bool("BookRandom")); + + if (move != MoveNone && move_is_legal(move,Uci->board)) { + + my_log("POLYGLOT *BOOK MOVE*\n"); + + search_clear(); // clears Uci->ponder_move + Uci->best_move = move; + + board_copy(board,Uci->board); + move_do(board,move); + Uci->ponder_move = book_move(board,FALSE); // expected move = best book move + + Uci->best_pv[0] = Uci->best_move; + Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone + Uci->best_pv[2] = MoveNone; + + comp_move(Uci->best_move); + + return; + } + } + + // engine search + + my_log("POLYGLOT START SEARCH\n"); + + // options + + uci_send_option(Uci,"UCI_Chess960","%s",option_get_bool("Chess960")?"TRUE":"FALSE"); + + if (option_get_int("UCIVersion") >= 2) { + uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name); + uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"TRUE":"FALSE"); + } + + uci_send_option(Uci,"Ponder","%s",ponder()?"TRUE":"FALSE"); + + // position + + move = (State->state == PONDER) ? State->exp_move : MoveNone; + send_board(move); // updates Uci->board global variable + + // search + + if (State->state == THINK || State->state == PONDER) { + + engine_send_queue(Engine,"go"); + + if (XB->time_limit) { + + // fixed time per move + + engine_send_queue(Engine," movetime %.0f",XB->time_max*1000.0); + + } else { + + // time controls + + if (colour_is_white(Uci->board->turn)) { + engine_send_queue(Engine," wtime %.0f btime %.0f",XB->my_time*1000.0,XB->opp_time*1000.0); + } else { + engine_send_queue(Engine," wtime %.0f btime %.0f",XB->opp_time*1000.0,XB->my_time*1000.0); + } + + if (XB->inc != 0.0) engine_send_queue(Engine," winc %.0f binc %.0f",XB->inc*1000.0,XB->inc*1000.0); + + if (XB->mps != 0) { + + move_nb = XB->mps - (Uci->board->move_nb % XB->mps); + ASSERT(move_nb>=1&&move_nb<=XB->mps); + + engine_send_queue(Engine," movestogo %d",move_nb); + } + } + + if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max); + + if (State->state == PONDER) engine_send_queue(Engine," ponder"); + + engine_send(Engine,""); // newline + + } else if (State->state == ANALYSE) { + + engine_send(Engine,"go infinite"); + + } else { + + ASSERT(FALSE); + } + + // init search info + + ASSERT(!Uci->searching); + + search_clear(); + + Uci->searching = TRUE; + Uci->pending_nb++; + } +} + +// search_clear() + +static void search_clear() { + + uci_clear(Uci); + + // TODO: MOVE ME + + my_timer_start(State->timer);//also resets +} + +// active() + +static bool active() { + + // position state + + if (game_status(Game) != PLAYING) return FALSE; // game ended + + // xboard state + + if (XB->analyse) return TRUE; // analysing + if (!State->computer[White] && !State->computer[Black]) return FALSE; // force mode + if (XB->new_hack || XB->result) return FALSE; // unstarted or ended game + + return TRUE; // playing +} + +// ponder() + +static bool ponder() { + + return XB->ponder && (option_get_bool("CanPonder") || uci_option_exist(Uci,"Ponder")); +} +// ponder_ok() + +static bool ponder_ok(int move) { + int status; + board_t board[1]; + + ASSERT(move==MoveNone||move_is_ok(move)); + + // legal ponder move? + + if (move == MoveNone) return FALSE; + + game_get_board(Game,board); + if (!move_is_legal(move,board)) return FALSE; + + // UCI-legal resulting position? + + game_add_move(Game,move); + + game_get_board(Game,board); + status = game_status(Game); + + game_rem_move(Game); + + if (status != PLAYING) return FALSE; // game ended + + if (option_get_bool("Book") && is_in_book(board)) { + return FALSE; + } + + return TRUE; +} + +// stop_search() + +static void stop_search() { + + if (Uci->searching) { + + ASSERT(Uci->searching); + ASSERT(Uci->pending_nb>=1); + + my_log("POLYGLOT STOP SEARCH\n"); + +/* + engine_send(Engine,"stop"); + Uci->searching = FALSE; +*/ + + if (option_get_bool("SyncStop")) { + uci_send_stop_sync(Uci); + } else { + uci_send_stop(Uci); + } + } +} + +// send_board() + +static void send_board(int extra_move) { + + char fen[256]; + int start, end; + board_t board[1]; + int pos; + int move; + char string[256]; + + ASSERT(extra_move==MoveNone||move_is_ok(extra_move)); + + ASSERT(!Uci->searching); + + // init + + game_get_board(Game,Uci->board); + if (extra_move != MoveNone) move_do(Uci->board,extra_move); + + board_to_fen(Uci->board,fen,256); + my_log("POLYGLOT FEN %s\n",fen); + + ASSERT(board_can_play(Uci->board)); + + // more init + + start = 0; + end = game_pos(Game); + ASSERT(end>=start); + + // position + + game_get_board_ex(Game,board,start); + board_to_fen(board,string,256); + + engine_send_queue(Engine,"position"); + + if (my_string_equal(string,StartFen)) { + engine_send_queue(Engine," startpos"); + } else { + engine_send_queue(Engine," fen %s",string); + } + + // move list + + if (end > start || extra_move != MoveNone) engine_send_queue(Engine," moves"); + + for (pos = start; pos < end; pos++) { // game moves + + move = game_move(Game,pos); + + move_to_can(move,board,string,256); + engine_send_queue(Engine," %s",string); + + move_do(board,move); + } + + if (extra_move != MoveNone) { // move to ponder on + move_to_can(extra_move,board,string,256); + engine_send_queue(Engine," %s",string); + } + + // end + + engine_send(Engine,""); // newline +} + +// send_pv() + +static void send_pv() { + + char pv_string[StringSize]; + board_t board[1]; + int move; + char move_string[StringSize]; + + ASSERT(State->state!=WAIT); + + if (Uci->best_depth == 0) return; + + // xboard search information + + if (XB->post) { + + if (State->state == THINK || State->state == ANALYSE) { + + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + + if(Uci->depth==-1) //hack to clear the engine output window + gui_send(GUI,"%d %+d %.0f "S64_FORMAT" ",0,report_best_score(),Uci->time*100.0,Uci->node_nb); + + gui_send(GUI,"%d %+d %.0f "S64_FORMAT" %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,pv_string); + + } else if (State->state == PONDER && option_get_bool("ShowPonder")) { + + game_get_board(Game,board); + move = State->exp_move; + + if (move != MoveNone && move_is_legal(move,board)) { + move_to_san(move,board,move_string,256); + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + gui_send(GUI,"%d %+d %.0f "S64_FORMAT" (%s) %s",Uci->best_depth,report_best_score(),Uci->time*100.0,Uci->node_nb,move_string,pv_string); + } + } + } + + // kibitz + + if ((Uci->searching && option_get_bool("KibitzPV") && Uci->time >= option_get_double("KibitzDelay")) + || (!Uci->searching && option_get_bool("KibitzMove"))) { + + if (State->state == THINK || State->state == ANALYSE) { + + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + if(kibitz_throttle(Uci->searching)){ + 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); + } + } else if (State->state == PONDER) { + + game_get_board(Game,board); + move = State->exp_move; + + if (move != MoveNone && move_is_legal(move,board)) { + move_to_san(move,board,move_string,256); + line_to_san(Uci->best_pv,Uci->board,pv_string,StringSize); + if(kibitz_throttle(Uci->searching)){ + 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); + } + } + } + } +} + +// kibitz_throttle() + +static bool kibitz_throttle(bool searching){ + time_t curr_time; + static time_t lastKibitzMove=0; + static time_t lastKibitzPV=0; + curr_time = time(NULL); + if(searching){ // KibitzPV + if(curr_time >= (option_get_int("KibitzInterval") + lastKibitzPV)){ + lastKibitzPV=curr_time; + return TRUE; + } + }else{ // KibitzMove + if(curr_time >= (option_get_int("KibitzInterval") + lastKibitzMove)){ + lastKibitzPV=curr_time; + lastKibitzMove=curr_time; + return TRUE; + } + } + return FALSE; +} + +// learn() + +static void learn(int result) { + + int pos; + board_t board[1]; + int move; + + ASSERT(result>=-1&&result<=+1); + + ASSERT(XB->result); + ASSERT(State->computer[White]||State->computer[Black]); + + // init + + pos = 0; + + if (FALSE) { + } else if (State->computer[White]) { + pos = 0; + } else if (State->computer[Black]) { + pos = 1; + result = -result; + } else { + my_fatal("learn(): unknown side\n"); + } + + if (FALSE) { + } else if (result > 0) { + my_log("POLYGLOT *LEARN WIN*\n"); + } else if (result < 0) { + my_log("POLYGLOT *LEARN LOSS*\n"); + } else { + my_log("POLYGLOT *LEARN DRAW*\n"); + } + + // loop + + for (; pos < Game->size; pos += 2) { + + game_get_board_ex(Game,board,pos); + move = game_move(Game,pos); + + book_learn_move(board,move,result); + } + + book_flush(); +} + +// end of adapter.cpp -- 1.7.0.4