hoichess_0.10.3/0000750000175000017500000000000010732031250013030 5ustar oliveroliverhoichess_0.10.3/hoichess.60000640000175000017500000003267710732031250014744 0ustar oliveroliver.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "hoichess 6" .TH hoichess 6 "2007-12-18" "hoichess-0.3" "Games" .SH "NAME" hoichess \- xboard compatible chess engine .PP hoixiangqi \- xiangqi engine .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBhoichess\fR [options] .PP \&\fBhoixiangqi\fR [options] .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBhoichess\fR is a chess playing program. It implements major parts of the xboard/winboard chess engine protocol. .PP \&\fBhoichess\fR uses many of the standard techniques found in modern chess programs, like rotated bitboards, principal variation search, quiescence search, transposition table and iterative deepening. .PP See \fIxboard\fR\|(6) for instructions about how to use \fBhoichess\fR through xboard. To start up quickly, you just need the command: \fBxboard \-fcp hoichess\fR. .PP \&\fBhoixiangqi\fR is a xiangqi (\*(L"Chinese chess\*(R") playing program. Currently, it also uses the xboard/winboard protocol. However, there is no user interface that supports this protocol. In the future, a different protocol might be used. .PP \&\fBhoichess\fR and \fBhoixiangqi\fR are built from the same code base, so nearly all commands and options, as well as the text based user interface, are the same for both programs. .PP If run \fBhoichess\fR or \fBhoixiangqi\fR at the command line, the \fBhelp\fR command gives you a brief summary of available commands. See section \*(L"\s-1COMMANDS\s0\*(R" for more details about those commands. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-h\fR, \fB\-\-help\fR" 8 .IX Item "-h, --help" Display usage information. .IP "\fB\-V\fR, \fB\-\-version\fR" 8 .IX Item "-V, --version" Display version information. .IP "\fB\-v\fR, \fB\-\-verbose[=n]\fR" 8 .IX Item "-v, --verbose[=n]" Increase verbosity. Multiple \fB\-v\fR options may be given. \fB\-\-verbose=\fR\fIn\fR sets verbosity level \fIn\fR. .IP "\fB\-d\fR, \fB\-\-debug[=n]\fR" 8 .IX Item "-d, --debug[=n]" Increase debug level. Multiple \fB\-d\fR options may be given. \fB\-\-debug=\fR\fIn\fR sets debug level \fIn\fR. .IP "\fB\-L\fR \fIfilename\fR, \fB\-\-logfile\fR \fIfilename\fR" 8 .IX Item "-L filename, --logfile filename" Specify file name for logging. The log will be appended to this file. \&\fINote: Logging is not yet implemented in the current version of HoiChess, so the log will be empty.\fR .IP "\fB\-x\fR, \fB\-\-xboard\fR[=\fIarg\fR]" 8 .IX Item "-x, --xboard[=arg]" Start in xboard compatible mode. This turns off the input prompt and alters the output format to meet the requirements of the xboard protocol. Normally, this option should not be necessary because \fBhoichess\fR automatically detects when it is started under xboard. .Sp The optional argument can be one of: .RS 8 .IP "\fBoff\fR" 4 .IX Item "off" Force non-xboard mode. .IP "\fBon\fR" 4 .IX Item "on" Force xboard mode. .IP "\fBauto\fR" 4 .IX Item "auto" Automatically enable xboard mode when stdout is not a terminal, which is the case when HoiChess is started under xboard. .Sp This is the default. .RE .RS 8 .RE .IP "\fB\-\-book\fR \fIfilename\fR" 8 .IX Item "--book filename" Set location of opening book. .IP "\fB\-\-nobook\fR" 8 .IX Item "--nobook" Disable opening book. .IP "\fB\-\-hashsize\fR \fIarg\fR" 8 .IX Item "--hashsize arg" Set the size of the main hash table (transposition table). The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively. .Sp A size of 0 disables the hash table. .IP "\fB\-\-pawnhashsize\fR \fIarg\fR" 8 .IX Item "--pawnhashsize arg" Set the size of the pawn hash table. The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively. .Sp A size of 0 disables the pawn hash table. .IP "\fB\-\-evalcache\fR \fIarg\fR" 8 .IX Item "--evalcache arg" Set the size of the evaluation cache. The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively. .Sp A size of 0 disables the evaluation cache. .IP "\fB\-\-name\fR \fIname\fR" 8 .IX Item "--name name" Set engine's name to \fIname\fR. .IP "\fB\-\-rcfile\fR \fIfilename\fR" 8 .IX Item "--rcfile filename" Before accepting input from stdin, first read commands (and probably moves) from \fIfilename\fR. .IP "\fB\-\-color\fR \fIarg\fR" 8 .IX Item "--color arg" Control usage of \s-1ANSI\s0 color control sequences, e.g. when displaying the chess board. .Sp \&\fIarg\fR can be one of: .RS 8 .IP "\fBoff\fR" 4 .IX Item "off" Never use \s-1ANSI\s0 color sequences. .IP "\fBon\fR" 4 .IX Item "on" Always use \s-1ANSI\s0 color sequences. .IP "\fBauto\fR" 4 .IX Item "auto" Automatically use \s-1ANSI\s0 color sequences when stdout is a terminal. .RE .RS 8 .Sp On Unix platforms, the default is \fBauto\fR. On Windows platforms, the default is \fBoff\fR, because the Windows terminal is normally not \s-1ANSI\s0 capable. .RE .SH "COMMANDS" .IX Header "COMMANDS" \&\fBhoichess\fR supports most commands of the XBoard protocol. Those commands are described in detail at \fIhttp://www.tim\-mann.org/xboard/engine\-intf.html\fR. Furthermore, the following special commands are also available: .IP "\fBhelp\fR" 8 .IX Item "help" Give a brief summary about available commands. .IP "\fBbench\fR \fBmovegen\fR" 8 .IX Item "bench movegen" Run move generator benchmark. .IP "\fBbench\fR \fBevaluator\fR" 8 .IX Item "bench evaluator" Run evaluator benchmark. .IP "\fBbench\fR \fBmakemove\fR" 8 .IX Item "bench makemove" Run benchmark for make_move and unmake_move routines. .IP "\fBbook\fR \fBopen\fR \fIbookfile\fR" 8 .IX Item "book open bookfile" Use opening book \fIbookfile\fR. .IP "\fBbook\fR \fBclose\fR" 8 .IX Item "book close" Disable opening book. .IP "\fBbook\fR \fBcreate\fR \fIbookfile\fR \fIpgnfile\fR \fIdepth\fR \fImin_move_count\fR" 8 .IX Item "book create bookfile pgnfile depth min_move_count" Create a new opening book, from the games in \fIpgnfile\fR. The new book will be written to \fIbookfile\fR. .Sp The parameter \fIdepth\fR specifies how many moves (half\-moves, ply) of each game will be included in the opening book. If \fIdepth\fR is 0, there is no depth limit, i.e. all moves of all games will be put into the book. .Sp The parameter \fImin_move_count\fR specifies how many times a move must be played until it is added to the opening book. .IP "\fBdebug\fR \fIlevel\fR" 8 .IX Item "debug level" Set debug level to \fIlevel\fR. .Sp If \fIlevel\fR is omitted, the current debug level is printed. .IP "\fBevalcache\fR \fBclear\fR" 8 .IX Item "evalcache clear" Clear evaluation cache. .IP "\fBevalcache\fR \fBsize\fR \fIarg\fR" 8 .IX Item "evalcache size arg" Set the size of the evaluation cache. The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively. .Sp A size of 0 disables the evaluation cache. .IP "\fBevalcache\fR \fBoff\fR" 8 .IX Item "evalcache off" Disable evaluation cache. .IP "\fBevalcache\fR \fBinfo\fR" 8 .IX Item "evalcache info" Print information about evaluation cache. .IP "\fBevalcache\fR \fBstats\fR" 8 .IX Item "evalcache stats" Print evaluation cache statistics. .IP "\fBhash\fR \fBclear\fR" 8 .IX Item "hash clear" Clear hash table. .IP "\fBhash\fR \fBsize\fR \fIarg\fR" 8 .IX Item "hash size arg" Set the size of the main hash table (transposition table). The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively. .Sp A size of 0 disables the hash table. .IP "\fBhash\fR \fBoff\fR" 8 .IX Item "hash off" Disable hash table. .IP "\fBhash\fR \fBinfo\fR" 8 .IX Item "hash info" Print information about hash table. .IP "\fBhash\fR \fBstats\fR" 8 .IX Item "hash stats" Print hash table statistics. .IP "\fBhash\fR \fBreplace\fR \fIscheme\fR" 8 .IX Item "hash replace scheme" Set hash table replacement scheme. Currently available \fIscheme\fRs are: .RS 8 .IP "* \fBalways\fR" 4 .IX Item "always" Always replace existing entries by new entries. .IP "* \fBdepth\fR" 4 .IX Item "depth" Replace existing entries only by entries with same or higher search depth. .RE .RS 8 .RE .IP "\fBignore\fR \fIcommand\fR" 8 .IX Item "ignore command" From now on, ignore the command \fIcommand\fR. This is basically intended for debugging. .Sp See also command \fBobey\fR. .IP "\fBobey\fR \fIcommand\fR" 8 .IX Item "obey command" Do not ignore the command \fIcommand\fR anymore. .Sp See also command \fBignore\fR. .IP "\fBpawnhash\fR \fB...\fR" 8 .IX Item "pawnhash ..." Configure the pawn hash table. The available options are the same as for the main hash table (see command \fBhash\fR), with the exception that \&\fBpawnhash\fR \fBreplace\fR is not available, because the pawn hash table always uses the \*(L"always replace\*(R" strategy. .IP "\fBverbose\fR \fIlevel\fR" 8 .IX Item "verbose level" Set verbosity level to \fIlevel\fR. .Sp If \fIlevel\fR is omitted, the current verbosity level is printed. .IP "\fBsource\fR \fIfile\fR" 8 .IX Item "source file" Read commands from \fIfile\fR, just like command line option \fB\-\-rcfile\fR does. .IP "\fBshow\fR \fBboard\fR" 8 .IX Item "show board" Display the chess board. .IP "\fBshow\fR \fBfen\fR" 8 .IX Item "show fen" Print the current position's \s-1FEN\s0. .IP "\fBshow\fR \fBmoves\fR|\fBcaptures\fR|\fBnoncaptures\fR|\fBescapes\fR" 8 .IX Item "show moves|captures|noncaptures|escapes" Show all legal moves, captures, non-captures or escapes. .IP "\fBshow\fR \fBeval\fR" 8 .IX Item "show eval" Evaluate current position and print result. .IP "\fBshow\fR \fBclocks\fR" 8 .IX Item "show clocks" Show both players' clocks. .IP "\fBshow\fR \fBgame\fR" 8 .IX Item "show game" Show information about entire game, e.g. past positions, moves played, etc.. .IP "\fBsolve\fR \fIepdfile\fR" 8 .IX Item "solve epdfile" Run search on all positions in \fIepdfile\fR (testsuite mode). .SH "SEE ALSO" .IX Header "SEE ALSO" http://www.hoicher.de/hoichess .PP \&\fIxboard\fR\|(6) .SH "AUTHOR" .IX Header "AUTHOR" \&\fBhoichess\fR was written by Holger Ruckdeschel . .PP This manual page was generated with \fIpod2man\fR\|(1). hoichess_0.10.3/Makefile0000640000175000017500000000666210732031250014503 0ustar oliveroliver# $Id: Makefile 1462 2007-12-18 20:49:56Z holger $ # Make these variables also available to sub-makes. export top_srcdir = $(shell pwd) export prefix = /usr export bindir = $(prefix)/games export mandir = $(prefix)/share/man VERSION = $(shell grep '^Version' ChangeLog | head -n 1 | awk '{ print $$2; }') .PHONY: all all: hoichess.6 hoichess.6.html $(MAKE) -C src all hoichess.6: hoichess.6.pod pod2man -n hoichess -s 6 -r hoichess-0.3 -c Games $< $@ hoichess.6.html: hoichess.6.pod pod2html --title "HoiChess" $< > $@ .PHONY: install install: all $(MAKE) -C src install install -m 644 -D hoichess.6 $(DESTDIR)$(mandir)/man6/hoichess.6 .PHONY: clean clean: $(MAKE) -C src PLATFORM=unix clean $(MAKE) -C src PLATFORM=mingw32 clean $(MAKE) -C src PLATFORM=win32 clean rm -f hoichess.6 hoichess.6.html rm -f *.tmp rm -rf dist .PHONY: maintainer-clean maintainer-clean: clean $(MAKE) -C src maintainer-clean ############################################################################### # # Definitions and targets to build source and binary distributions # ############################################################################### DIST_SRC_NAME = hoichess-$(VERSION) DIST_MINGW32_NAME = hoichess-$(VERSION)-mingw32 DIST_WIN32_NAME = hoichess-$(VERSION)-win32 DIST_SRC_SOURCES = AUTHORS BUGS ChangeLog LICENSE README \ Makefile hoichess.6.pod \ src/Makefile src/Makefile.local \ $(wildcard src/*.cc src/*.h) \ $(wildcard src/*/*.cc src/*/*.h) \ $(wildcard src/*/*/*.cc src/*/*/*.h) \ $(wildcard src/build/*) DIST_SRC_NONSOURCES = hoichess.6 hoichess.6.html DIST_MINGW32_SOURCES = AUTHORS BUGS ChangeLog LICENSE README DIST_MINGW32_NONSOURCES = hoichess.6 hoichess.6.html DIST_MINGW32_BINS = src/.build-mingw32/hoichess.exe \ src/.build-mingw32/hoixiangqi.exe DIST_WIN32_SOURCES = AUTHORS BUGS ChangeLog LICENSE README DIST_WIN32_NONSOURCES = hoichess.6.html DIST_WIN32_BINS = src/.build-win32/hoichess.exe \ src/.build-win32/hoixiangqi.exe .PHONY: dist dist-src dist dist-src: $(DIST_SRC_NONSOURCES) mkdir -p dist rm -rf dist/$(DIST_SRC_NAME) mkdir dist/$(DIST_SRC_NAME) cp --parents $(DIST_SRC_SOURCES) dist/$(DIST_SRC_NAME) cp --parents $(DIST_SRC_NONSOURCES) dist/$(DIST_SRC_NAME) rm -f dist/$(DIST_SRC_NAME).tar.gz cd dist && tar -czf $(DIST_SRC_NAME).tar.gz $(DIST_SRC_NAME) rm -f dist/$(DIST_SRC_NAME).zip cd dist && zip -q -9 -r $(DIST_SRC_NAME).zip $(DIST_SRC_NAME) .PHONY: $(DIST_MINGW32_BINS) $(DIST_MINGW32_BINS): $(MAKE) -C src PLATFORM=mingw32 .PHONY: dist-mingw32 dist-mingw32: $(DIST_MINGW32_NONSOURCES) $(DIST_MINGW32_BINS) mkdir -p dist rm -rf dist/$(DIST_MINGW32_NAME) mkdir dist/$(DIST_MINGW32_NAME) cp --parents $(DIST_MINGW32_SOURCES) dist/$(DIST_MINGW32_NAME) cp --parents $(DIST_MINGW32_NONSOURCES) dist/$(DIST_MINGW32_NAME) mkdir dist/$(DIST_MINGW32_NAME)/bin cp $(DIST_MINGW32_BINS) dist/$(DIST_MINGW32_NAME)/bin rm -f dist/$(DIST_MINGW32_NAME).zip cd dist && zip -q -9 -r $(DIST_MINGW32_NAME).zip $(DIST_MINGW32_NAME) .PHONY: dist-win32 dist-win32: $(DIST_WIN32_NONSOURCES) mkdir -p dist rm -rf dist/$(DIST_WIN32_NAME) mkdir dist/$(DIST_WIN32_NAME) cp --parents $(DIST_WIN32_SOURCES) dist/$(DIST_WIN32_NAME) cp --parents $(DIST_WIN32_NONSOURCES) dist/$(DIST_WIN32_NAME) mkdir dist/$(DIST_WIN32_NAME)/bin cp $(DIST_WIN32_BINS) dist/$(DIST_WIN32_NAME)/bin rm -f dist/$(DIST_WIN32_NAME).zip cd dist && zip -q -9 -r $(DIST_WIN32_NAME).zip $(DIST_WIN32_NAME) hoichess_0.10.3/ChangeLog0000640000175000017500000003264010732031250014610 0ustar oliveroliverVersion 0.10.3 (2007-12-18) * When saving PGN, include FEN if starting position is non-standard. * Moved opening FEN from game.h into {chess,xiangqi}/basic.{cc,h}. * Changed piece letters for Xiangqi to be compatible with Winboard_F. * Added some #includes to make code compilable with latest gcc 4.3 snapshot. * Some additional changes to avoid warnings when compiling with latest gcc 4.3 snapshot Version 0.10.2 (2007-10-30) * Bugfix in command 'playboth': Stop background thread before switching to playboth mode. * [HoiXiangqi] Print variant 'xiangqi' in 'feature' list. Version 0.10.1 (2007-10-28) * Support 'variant' command. HoiChess supports no variant. HoiXiangqi supports variant 'xiangqi' for Winboard_F by H.G. Muller. Version 0.10.0 (2007-10-12) * [chess] Evaluation: Rook and Queen mobility. Version 0.9.0 (2007-04-23) * Search extensions: in check, recapture. * Shell: Rewrote input/script reading code. * Read commands from hoichess.rc, or hoixiangqi.rc, respectively, if such a file exists in the current directory. * Added command line option --rcfile which replaces --script (sounds better). --script remains for compatibility reasons. * Renamed shell command 'script' in 'source' (sounds better). * Clear pawn hash table and evaluation cache in testsuite mode. * Minor fixes to remove warnings when compiling with latest gcc snapshot. Version 0.8.0 (2006-11-26) * [chess] Evaluation: Fianchetto bishop, early wing pawn move. Version 0.7.0 (2006-10-17) * [chess] Evaluation: Added 2nd phase: board control. * Evaluation: Set material cutoff to 150 cp. * Moved common code from src/chess/eval.cc and src/xiangqi/eval.cc to src/eval.cc. * Added a few words about Xiangqi to man page. Version 0.6.1 (2006-08-11) * [chess] Evaluation: Pawn and bishop protecting each other. Version 0.6.0 (2006-08-04) * Experimental implementation of Xiangqi (aka. Chinese chess, elephant chess). HoiXiangqi is built mostly from the same source as HoiChess. Source code is split into common, chess, and xiangqi parts. Changes to common and chess specific code was reduced to a minimum, hopefully without introducing any new bugs. Basic stuff is already implemented and runs quite stable. Now it's time to fix bugs, complete support for Xiangqi rules, and improve speed and evaluation. * Added command 'playboth' that can be used to let the engine play against itself for testing purposes. * Added commands 'loadgame' and 'savegame' to load and save PGN files. * Added command 'redo'. * Write debugging messages to log file (even when started without '-d' option). * Some more debugging messages in search and shell. Version 0.5.1 (2006-07-17) * Small fix concerning vsnprintf() when compiling with Intel compiler on Windows. * Benchmark code: Make 1000 instead of 100 loops before checking time, to reduce system call overhead. For this reason, benchmark results from previous versions will _not_ be comparable anymore. Version 0.5.0 (2006-07-14) * Futility pruning, extended futility pruning, and razoring. * Added compile-time option COLLECT_STATISTICS to enable compilation without hash, search, and evaluator statistics. Version 0.4.3 (2006-06-12) * Fixed bug in opening book code that made books unreadable on Windows (and probably other architectures) due to the changes in 0.4.2. From now on, all books should be readable on all architectures, no matter where, and with which version they were created. Version 0.4.2 (2006-06-09) * Opening book: Reverse byte order on big endian systems, to make books interchangeable between architectures. In detail, this means: o Books created on little endian machines can now be used on on both architectures. o Books created on big endian machines with this or a later release of HoiChess will also work on both architectures. o Books created on big endian machines with older releases will not work on any architecture, but I don't think there exist such books. * Makefile: Place object/binary files in a separate directory, one per platform. * Shell: Use GNU readline library if available. Version 0.4.1 (2006-04-01) * Improved time allocation in incremental time control mode. Version 0.4.0 (2006-02-28) * Null-move forward pruning. * Evaluation: o Fixed knight and bishop mobility calculation. o Improved pawn evaluation, e.g. connected passed pawns. o Improved evaluation of development during opening phase. o Queen evaluation: get near enemy king. (disabled) o King evaluation: attacked squares around king. (disabled) o QB- and QR-combo. o More sophisticated material balance calculation. * Build Windows binary using mingw32 compiler. Version 0.3.9 (2006-02-13) * Pawn hash table. Version 0.3.8 (2006-02-04) * Start pondering not before game has actually started. This could help to avoid problems during xboard startup. * Evaluation cache. * Size of hash table is now always given in bytes, kilobytes or megabytes, setting number of entries is not possible any longer. This applies to both the command line option and the shell. * Use a new move parser when reading PGNs. This leads to a significant speedup of opening book generation. * Rewrote PGN parser. New parser partly accepts the less strict PGN import format. * Opening book: Only store moves with a user-defined minimum number of occurrences. Version 0.3.7 (2005-12-29) * Evaluation: rooks on open/half-open files. * Changed default hash replacement scheme to 'always replace'. * Enabled principal variation search again. I thought it was buggy but it wasn't. * Added some more cases where draw by insufficient material is detected. * Collect and print evaluator statistics. * Added command line option --color. * Command line option --xboard now takes optional arguments 'off', 'on' and 'auto'. If set to 'auto' (default), xboard mode is automatically enabled when stdout is not a terminal. Version 0.3.6 (2005-12-10) * Extend search time when in check, near book, or fail low. This is an experimental feature which is disabled by default, but can be enabled using the command 'set search_features' (see documentation). * Implemented replacement scheme 'always replace' for hash table. The old depth based scheme remains the default. The scheme can be changed using the new command 'hash replace' (see documentation). * Added commands 'verbose' and 'debug'. * Added commands 'set' and 'get' to allow changing some internal parameters. * Allow recursive 'script' commands, so that using the command from within a script works as expected. * Some code restructuring and cleanups. * Automatically enable ANSI color when stdout is terminal. Version 0.3.5 (2005-10-30) Some of the changes in this version were already introduced in the experimental releases 0.3.4+exp1 and 0.3.4+exp2. * Limit thinking output to 30 ply to work around xboard buffer overflow bug. * Improved pawn evaluation: isolated pawns, passed pawns, passed pawns protected by rook/queen behind them. * Completely rewrote search tree data structures. Source can be configured to use either one global board together with unmake_move, or local board copies at each node. (Default is local boards, which seems to be faster.) * Rewrote move ordering, implemented killer move heuristics. * New benchmark suite with predefined benchmarks for move generator, evaluator and make_move/unmake_move routines. * Collect more statistics during search: average nps, average depth, and average branching factor. * In solve mode, write results into log file. * Added command 'hash'. * Renamed command line option --cmdfile in --script. * Added command 'script' to read commands from file just like option --script does. * Added command line option -d/--debug. * Minor code cleanups and improvements. Version 0.3.4 (2005-09-24) * Fixed some race conditions by making sure that most output sent to xboard is atomic. * Added own commands 'ignore' and 'obey' for debugging purposes. * Added command line option --cmdfile. Version 0.3.3 (2005-09-16) * (Hopefully) fixed dual cpu ponder bug (see BUGS). * Added list of open bugs. * Small but significant speed improvement of rotated bitboard code. * Much faster repetition detection during search (compare only hash keys instead of whole Board objects). * x86 assembler versions of bitboard routines now also for Win32. * Hash table: Don't store mate scores. * Hash table: Don't read beta entries during search, since a lot of good moves were missed because of them. * Added MSVC++ project files. Version 0.3.2 (2005-07-06) * Fixed stack overflow due to infinite recursion in bool Board::parse_fen(const std::string &). * Fixed time control, implemented commands `time' and `otim'. * Fixed `force' command: pondering was turned off completely rather than only as long as force mode is active. * Completely rewrote thread code in order to fix race condition. * Skip useless promotions into bishop and rook during search. Version 0.3.1 (2005-06-25) * Fixed bug in Board::make_move(): castling flags were not cleared correctly when a king or rook captures an enemy rook. * Support most time control modes (exact, conventional, incremental, sudden death). * Rewrote Game class, keep track of both players' clocks. * Opening book support. * PGN parser, used to create opening book. * Command line option `--hashsize' now also takes size in MB. * A bit more relaxed SAN input parsing. * x86 assembler versions of first bit and population count routines. Version 0.2.4 (2005-05-25) * Thread support for Win32. * Fixed random number generator bug on Win32. * Removed Debian and RPM stuff from main sources again. From now on, I will provide extra patches in order to build such packages. * Moved most sources from win32/ into utils/ because they are not specific to Windows, and at least getopt is also needed on Solaris. * Some fixes to compile on Solaris. * Some code cleanups and minor fixes. * Begin re-implementation of class Clock. Version 0.2.3 (2005-05-16) * Do not call Search::check_time() (and thus gettimeofday()) at every node (reduce system call overhead). * Phase detection no longer based on number of moves but on material. * New EPD parser that can handle multiple operands, quoted strings, etc. * Shell::cmd_solve(): compare list of best moves, skip positions that don't have any best move associated. Version 0.2.2 (2005-05-14) * Added `help' command. * Added man page. * SIGINT now interrupts the commands `solve' and `bench'. * Added replacement functions for BUG(), WARN() and LOG() macros that didn't work with non-GNU compilers. * Support for Win32 platforms (thanks to Jim Ablett and Dann Corbit): - Compile without pthread on Win32 (-> no pondering and analyze mode for now). - Win32 support code in src/win32: getopt, gettimeofday, snprintf. - Minor fixes for buggy compilers. Version 0.2.1 (2004-12-12) * Build Debian package. * Build RPM package (experimental). Version 0.2 (2004-08-06) This is the first version that was officially released. See http://www.hoicher.de/hoichess. * Fixed bug that caused search to return an invalid move if only one move is possible. * Added top-level Makefile. Version 0.1.6 (2004-07-06) * New, improved and modular static evaluator. * Rewrote move ordering; use LVA/MVV capture ordering in full-width search too. * Again more code cleanups. Version 0.1.5 (2004-06-22) * Repetition detection in tree search. * Doubled speed of move generator. * Fixed time handling bug that caused stupid moves to be played when time runs out. Version 0.1.4 (2004-06-18) * Position solving and benchmarking functions. * Implemented a generate_escapes() function. * Simple LVA/MVV move ordering in quiescence search. * Put bitboard stuff into class Bitboard. * Better Makefile with dependency handling. * Even more code cleanups. * Cannot win against this version anymore :-( Version 0.1.3 (2004-05-23) * Simple move ordering: hashmv, captures (ordered by history), noncaptures (ordered by history). * Internal iterative deepening. * Rotated bitboards. * More code cleanups. Version 0.1.2 (2004-05-18) * Quiescence search. * Lots of small improvements and code cleanups. Version 0.1.1 (2004-04-27) * Initial release: This is the first version of my very own chess program. It features many of the standard techniques used in modern chess programs, like bitboards, principal variation search, iterative deepening, transposition table and history table. It also interacts quite well with xboard (version 4.2.6) and supports pondering and analyzing. However, it is far from being complete, and makes a lot of poor moves. hoichess_0.10.3/AUTHORS0000640000175000017500000000004710732031250014102 0ustar oliveroliverHolger Ruckdeschel hoichess_0.10.3/hoichess.6.pod0000640000175000017500000001741110732031250015512 0ustar oliveroliver=head1 NAME hoichess - xboard compatible chess engine hoixiangqi - xiangqi engine =head1 SYNOPSIS B [options] B [options] =head1 DESCRIPTION B is a chess playing program. It implements major parts of the xboard/winboard chess engine protocol. B uses many of the standard techniques found in modern chess programs, like rotated bitboards, principal variation search, quiescence search, transposition table and iterative deepening. See xboard(6) for instructions about how to use B through xboard. To start up quickly, you just need the command: B. B is a xiangqi ("Chinese chess") playing program. Currently, it also uses the xboard/winboard protocol. However, there is no user interface that supports this protocol. In the future, a different protocol might be used. B and B are built from the same code base, so nearly all commands and options, as well as the text based user interface, are the same for both programs. If run B or B at the command line, the B command gives you a brief summary of available commands. See section L for more details about those commands. =head1 OPTIONS =over 8 =item B<-h>, B<--help> Display usage information. =item B<-V>, B<--version> Display version information. =item B<-v>, B<--verbose[=n]> Increase verbosity. Multiple B<-v> options may be given. B<--verbose=>I sets verbosity level I. =item B<-d>, B<--debug[=n]> Increase debug level. Multiple B<-d> options may be given. B<--debug=>I sets debug level I. =item B<-L> I, B<--logfile> I Specify file name for logging. The log will be appended to this file. I =item B<-x>, B<--xboard>[=I] Start in xboard compatible mode. This turns off the input prompt and alters the output format to meet the requirements of the xboard protocol. Normally, this option should not be necessary because B automatically detects when it is started under xboard. The optional argument can be one of: =over 4 =item B Force non-xboard mode. =item B Force xboard mode. =item B Automatically enable xboard mode when stdout is not a terminal, which is the case when HoiChess is started under xboard. This is the default. =back =item B<--book> I Set location of opening book. =item B<--nobook> Disable opening book. =item B<--hashsize> I Set the size of the main hash table (transposition table). The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively. A size of 0 disables the hash table. =item B<--pawnhashsize> I Set the size of the pawn hash table. The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively. A size of 0 disables the pawn hash table. =item B<--evalcache> I Set the size of the evaluation cache. The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively. A size of 0 disables the evaluation cache. =item B<--name> I Set engine's name to I. =item B<--rcfile> I Before accepting input from stdin, first read commands (and probably moves) from I. =item B<--color> I Control usage of ANSI color control sequences, e.g. when displaying the chess board. I can be one of: =over 4 =item B Never use ANSI color sequences. =item B Always use ANSI color sequences. =item B Automatically use ANSI color sequences when stdout is a terminal. =back On Unix platforms, the default is B. On Windows platforms, the default is B, because the Windows terminal is normally not ANSI capable. =back =head1 COMMANDS B supports most commands of the XBoard protocol. Those commands are described in detail at I. Furthermore, the following special commands are also available: =over 8 =item B Give a brief summary about available commands. =item B B Run move generator benchmark. =item B B Run evaluator benchmark. =item B B Run benchmark for make_move and unmake_move routines. =item B B I Use opening book I. =item B B Disable opening book. =item B B I I I I Create a new opening book, from the games in I. The new book will be written to I. The parameter I specifies how many moves (half-moves, ply) of each game will be included in the opening book. If I is 0, there is no depth limit, i.e. all moves of all games will be put into the book. The parameter I specifies how many times a move must be played until it is added to the opening book. =item B I Set debug level to I. If I is omitted, the current debug level is printed. =item B B Clear evaluation cache. =item B B I Set the size of the evaluation cache. The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively. A size of 0 disables the evaluation cache. =item B B Disable evaluation cache. =item B B Print information about evaluation cache. =item B B Print evaluation cache statistics. =item B B Clear hash table. =item B B I Set the size of the main hash table (transposition table). The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively. A size of 0 disables the hash table. =item B B Disable hash table. =item B B Print information about hash table. =item B B Print hash table statistics. =item B B I Set hash table replacement scheme. Currently available Is are: =over 4 =item * B Always replace existing entries by new entries. =item * B Replace existing entries only by entries with same or higher search depth. =back =item B I From now on, ignore the command I. This is basically intended for debugging. See also command B. =item B I Do not ignore the command I anymore. See also command B. =item B B<...> Configure the pawn hash table. The available options are the same as for the main hash table (see command B), with the exception that B B is not available, because the pawn hash table always uses the "always replace" strategy. =item B I Set verbosity level to I. If I is omitted, the current verbosity level is printed. =item B I Read commands from I, just like command line option B<--rcfile> does. =item B B Display the chess board. =item B B Print the current position's FEN. =item B B|B|B|B Show all legal moves, captures, non-captures or escapes. =item B B Evaluate current position and print result. =item B B Show both players' clocks. =item B B Show information about entire game, e.g. past positions, moves played, etc.. =item B I Run search on all positions in I (testsuite mode). =back =head1 SEE ALSO http://www.hoicher.de/hoichess xboard(6) =head1 AUTHOR B was written by Holger Ruckdeschel . This manual page was generated with pod2man(1). hoichess_0.10.3/LICENSE0000640000175000017500000004311010732031250014035 0ustar oliveroliver GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. hoichess_0.10.3/src/0000750000175000017500000000000010732031250013617 5ustar oliveroliverhoichess_0.10.3/src/hash.h0000640000175000017500000000614510732031250014722 0ustar oliveroliver/* $Id: hash.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/hash.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef HASH_H #define HASH_H #include "common.h" #include "board.h" #include "move.h" #include "util.h" typedef uint64_t Hashkey; #define NULLHASHKEY ((uint64_t) 0) /***************************************************************************** * * Class HashEntry * *****************************************************************************/ class HashEntry { friend class HashTable; public: enum hashentry_type { NONE, EXACT, ALPHA, BETA, QUIESCE }; private: Hashkey hashkey; unsigned short type; unsigned short depth; int score; Move move; public: FORCEINLINE HashEntry(); HashEntry(const Board & board, int score, Move move, int depth, int type); FORCEINLINE ~HashEntry() {} public: inline unsigned int get_depth() const; inline int get_score() const; inline int get_type() const; inline Move get_move() const; }; inline HashEntry::HashEntry() { type = NONE; } inline unsigned int HashEntry::get_depth() const { return depth; } inline int HashEntry::get_score() const { return score; } inline int HashEntry::get_type() const { return type; } inline Move HashEntry::get_move() const { return move; } /***************************************************************************** * * Class HashEntry * *****************************************************************************/ class HashTable { public: enum replacement_schemes { REPL_ALWAYS, REPL_DEPTH }; private: unsigned long table_size; HashEntry * table; unsigned long entries; enum replacement_schemes replacement_scheme; #ifdef COLLECT_STATISTICS unsigned long stat_probes; unsigned long stat_hits; unsigned long stat_hits2; unsigned long stat_collisions; unsigned long stat_collisions2; #endif public: HashTable(unsigned long size); ~HashTable(); public: void clear(); bool put(const HashEntry & entry); bool probe(const Board & board, HashEntry * entry); inline void incr_hits2(); void set_replacement_scheme(enum replacement_schemes scheme); void set_replacement_scheme(const std::string & scheme); void print_info(FILE * fp = stdout) const; void print_statistics(FILE * fp = stdout) const; void reset_statistics(); }; inline void HashTable::incr_hits2() { STAT_INC(stat_hits2); } #endif // HASH_H hoichess_0.10.3/src/lib/0000750000175000017500000000000010732031250014365 5ustar oliveroliverhoichess_0.10.3/src/lib/strtok_r.h0000640000175000017500000000010410732031250016401 0ustar oliveroliverextern char *strtok_r(char *s, const char *delim, char **save_ptr); hoichess_0.10.3/src/lib/snprintf.cc0000640000175000017500000004574510732031250016557 0ustar oliveroliver/* * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef WIN32 #include #include #include #include #else #include #endif #include /* ** SNPRINTF, VSNPRINT -- counted versions of printf ** ** These versions have been grabbed off the net. They have been ** cleaned up to compile properly and support for .precision and ** %lx has been added. */ /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point. (now it does ... tgl) * * snprintf() is used instead of sprintf() as it does limit checks * for string length. This covers a nasty loophole. * * The other functions are there to prevent NULL pointers from * causing nasty effects. **************************************************************/ /*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.26 2005/03/20 13:54:53 momjian Exp $";*/ static void dopr(char *buffer, const char *format, va_list args, char *end); /* Prevent recursion */ #undef vsnprintf #undef snprintf #undef sprintf #undef fprintf #undef printf int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) { char *end; str[0] = '\0'; end = str + count - 1; dopr(str, fmt, args, end); if (count > 0) end[0] = '\0'; return strlen(str); } int pg_snprintf(char *str, size_t count, const char *fmt,...) { int len; va_list args; va_start(args, fmt); len = pg_vsnprintf(str, count, fmt, args); va_end(args); return len; } int pg_sprintf(char *str, const char *fmt,...) { int len; va_list args; char buffer[4096]; va_start(args, fmt); len = pg_vsnprintf(buffer, (size_t) 4096, fmt, args); va_end(args); /* limit output to string */ strncpy(str, buffer, (len + 1 < 4096) ? len + 1 : 4096); return len; } int pg_fprintf(FILE *stream, const char *fmt,...) { int len; va_list args; char buffer[4096]; char *p; va_start(args, fmt); len = pg_vsnprintf(buffer, (size_t) 4096, fmt, args); va_end(args); for (p = buffer; *p; p++) putc(*p, stream); return len; } int pg_printf(const char *fmt,...) { int len; va_list args; char buffer[4096]; char *p; va_start(args, fmt); len = pg_vsnprintf(buffer, (size_t) 4096, fmt, args); va_end(args); for (p = buffer; *p; p++) putchar(*p); return len; } static int adjust_sign(int is_negative, int forcesign, int *signvalue); static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen); static void leading_pad(int zpad, int *signvalue, int *padlen, char *end, char **output); static void trailing_pad(int *padlen, char *end, char **output); static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, char *end, char **output); static void fmtint(int64_t value, int base, int dosign, int forcesign, int leftjust, int minlen, int zpad, char *end, char **output); static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, char *end, char **output); static void dostr(char *str, int cut, char *end, char **output); static void dopr_outch(int c, char *end, char **output); #define FMTSTR 1 #define FMTNUM 2 #define FMTNUM_U 3 #define FMTFLOAT 4 #define FMTCHAR 5 #define FMTWIDTH 6 #define FMTLEN 7 /* * dopr(): poor man's version of doprintf */ static void dopr(char *buffer, const char *format, va_list args, char *end) { int ch; int longlongflag; int longflag; int pointflag; int maxwidth; int leftjust; int minlen; int zpad; int forcesign; int i; const char *format_save; const char *fmtbegin; int fmtpos = 1; int realpos = 0; int precision; int position; char *output; int percents = 1; const char *p; struct fmtpar { const char *fmtbegin; const char *fmtend; void *value; int64_t numvalue; double fvalue; int charvalue; int leftjust; int minlen; int zpad; int maxwidth; int base; int dosign; int forcesign; char type; int precision; int pointflag; char func; int realpos; int longflag; int longlongflag; } *fmtpar, **fmtparptr; /* Create enough structures to hold all arguments */ for (p = format; *p != '\0'; p++) if (*p == '%') /* counts %% as two, so overcounts */ percents++; /* Need to use malloc() because memory system might not be started yet. */ if ((fmtpar = (struct fmtpar *)malloc(sizeof(struct fmtpar) * percents)) == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } if ((fmtparptr = (struct fmtpar **)malloc(sizeof(struct fmtpar *) * percents)) == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } format_save = format; output = buffer; while ((ch = *format++)) { switch (ch) { case '%': leftjust = minlen = zpad = forcesign = maxwidth = 0; longflag = longlongflag = pointflag = 0; fmtbegin = format - 1; realpos = 0; position = precision = 0; nextch: ch = *format++; switch (ch) { case '\0': goto performpr; case '-': leftjust = 1; goto nextch; case '+': forcesign = 1; goto nextch; case '0': /* set zero padding if minlen not set */ if (minlen == 0 && !pointflag) zpad = '0'; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!pointflag) { minlen = minlen * 10 + ch - '0'; position = position * 10 + ch - '0'; } else { maxwidth = maxwidth * 10 + ch - '0'; precision = precision * 10 + ch - '0'; } goto nextch; case '$': realpos = position; minlen = 0; goto nextch; case '*': memset(&fmtpar[fmtpos], 0, sizeof(fmtpar[fmtpos])); if (!pointflag) fmtpar[fmtpos].func = FMTLEN; else fmtpar[fmtpos].func = FMTWIDTH; fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; fmtpos++; goto nextch; case '.': pointflag = 1; goto nextch; case 'l': if (longflag) longlongflag = 1; else longflag = 1; goto nextch; case 'h': /* ignore */ goto nextch; #ifdef NOT_USED /* * We might export this to client apps so we should * support 'qd' and 'I64d'(MinGW) also in case the * native version does. */ case 'q': longlongflag = 1; longflag = 1; goto nextch; case 'I': if (*format == '6' && *(format + 1) == '4') { format += 2; longlongflag = 1; longflag = 1; goto nextch; } break; #endif case 'u': case 'U': fmtpar[fmtpos].longflag = longflag; fmtpar[fmtpos].longlongflag = longlongflag; fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].base = 10; fmtpar[fmtpos].dosign = 0; fmtpar[fmtpos].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].func = FMTNUM_U; fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; fmtpos++; break; case 'o': case 'O': fmtpar[fmtpos].longflag = longflag; fmtpar[fmtpos].longlongflag = longlongflag; fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].base = 8; fmtpar[fmtpos].dosign = 0; fmtpar[fmtpos].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].func = FMTNUM_U; fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; fmtpos++; break; case 'd': case 'D': fmtpar[fmtpos].longflag = longflag; fmtpar[fmtpos].longlongflag = longlongflag; fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].base = 10; fmtpar[fmtpos].dosign = 1; fmtpar[fmtpos].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].func = FMTNUM; fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; fmtpos++; break; case 'x': fmtpar[fmtpos].longflag = longflag; fmtpar[fmtpos].longlongflag = longlongflag; fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].base = 16; fmtpar[fmtpos].dosign = 0; fmtpar[fmtpos].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].func = FMTNUM_U; fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; fmtpos++; break; case 'X': fmtpar[fmtpos].longflag = longflag; fmtpar[fmtpos].longlongflag = longlongflag; fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].base = -16; fmtpar[fmtpos].dosign = 1; fmtpar[fmtpos].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].func = FMTNUM_U; fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; fmtpos++; break; case 's': fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].maxwidth = maxwidth; fmtpar[fmtpos].func = FMTSTR; fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; fmtpos++; break; case 'c': fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].func = FMTCHAR; fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; fmtpos++; break; case 'e': case 'E': case 'f': case 'g': case 'G': fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].type = ch; fmtpar[fmtpos].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].precision = precision; fmtpar[fmtpos].pointflag = pointflag; fmtpar[fmtpos].func = FMTFLOAT; fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; fmtpos++; break; case '%': break; default: dostr("???????", 0, end, &output); } break; default: dopr_outch(ch, end, &output); break; } } performpr: /* reorder pointers */ for (i = 1; i < fmtpos; i++) fmtparptr[i] = &fmtpar[fmtpar[i].realpos]; /* assign values */ for (i = 1; i < fmtpos; i++) { switch (fmtparptr[i]->func) { case FMTSTR: fmtparptr[i]->value = va_arg(args, char *); break; case FMTNUM: if (fmtparptr[i]->longflag) { if (fmtparptr[i]->longlongflag) fmtparptr[i]->numvalue = va_arg(args, int64_t); else fmtparptr[i]->numvalue = va_arg(args, long); } else fmtparptr[i]->numvalue = va_arg(args, int); break; case FMTNUM_U: if (fmtparptr[i]->longflag) { if (fmtparptr[i]->longlongflag) fmtparptr[i]->numvalue = va_arg(args, uint64_t); else fmtparptr[i]->numvalue = va_arg(args, unsigned long); } else fmtparptr[i]->numvalue = va_arg(args, unsigned int); break; case FMTFLOAT: fmtparptr[i]->fvalue = va_arg(args, double); break; case FMTCHAR: fmtparptr[i]->charvalue = va_arg(args, int); break; case FMTLEN: { int minlen = va_arg(args, int); int leftjust = 0; if (minlen < 0) { minlen = -minlen; leftjust = 1; } if (i + 1 < fmtpos && fmtparptr[i + 1]->func != FMTWIDTH) { fmtparptr[i + 1]->minlen = minlen; fmtparptr[i + 1]->leftjust |= leftjust; } /* For "%*.*f", use the second arg */ if (i + 2 < fmtpos && fmtparptr[i + 1]->func == FMTWIDTH) { fmtparptr[i + 2]->minlen = minlen; fmtparptr[i + 2]->leftjust |= leftjust; } } break; case FMTWIDTH: if (i + 1 < fmtpos) fmtparptr[i + 1]->maxwidth = fmtparptr[i + 1]->precision = va_arg(args, int); break; } } /* do the output */ output = buffer; format = format_save; while ((ch = *format++)) { for (i = 1; i < fmtpos; i++) { if (ch == '%' && *format == '%') { format++; continue; } if (fmtpar[i].fmtbegin == format - 1) { switch (fmtparptr[i]->func) { case FMTSTR: fmtstr((char *)fmtparptr[i]->value, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, fmtparptr[i]->maxwidth, end, &output); break; case FMTNUM: case FMTNUM_U: fmtint(fmtparptr[i]->numvalue, fmtparptr[i]->base, fmtparptr[i]->dosign, fmtparptr[i]->forcesign, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, fmtparptr[i]->zpad, end, &output); break; case FMTFLOAT: fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type, fmtparptr[i]->forcesign, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, fmtparptr[i]->zpad, fmtparptr[i]->precision, fmtparptr[i]->pointflag, end, &output); break; case FMTCHAR: dopr_outch(fmtparptr[i]->charvalue, end, &output); break; } format = fmtpar[i].fmtend; goto nochar; } } dopr_outch(ch, end, &output); nochar: /* nothing */ ; /* semicolon required because a goto has to be * attached to a statement */ } *output = '\0'; free(fmtpar); free(fmtparptr); } static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, char *end, char **output) { int padlen, vallen; /* amount to pad */ if (value == NULL) value = ""; vallen = strlen(value); if (maxwidth && vallen > maxwidth) vallen = maxwidth; adjust_padlen(minlen, vallen, leftjust, &padlen); while (padlen > 0) { dopr_outch(' ', end, output); --padlen; } dostr(value, maxwidth, end, output); trailing_pad(&padlen, end, output); } static void fmtint(int64_t value, int base, int dosign, int forcesign, int leftjust, int minlen, int zpad, char *end, char **output) { int signvalue = 0; char convert[64]; int vallen = 0; int padlen = 0; /* amount to pad */ int caps = 0; /* Handle +/- and %X (uppercase hex) */ if (dosign && adjust_sign((value < 0), forcesign, &signvalue)) value = -value; if (base < 0) { caps = 1; base = -base; } /* make integer string */ do { convert[vallen++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") [value % (unsigned) base]; value = (value / (unsigned) base); } while (value); convert[vallen] = 0; adjust_padlen(minlen, vallen, leftjust, &padlen); leading_pad(zpad, &signvalue, &padlen, end, output); while (vallen > 0) dopr_outch(convert[--vallen], end, output); trailing_pad(&padlen, end, output); } static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, char *end, char **output) { int signvalue = 0; int vallen; char fmt[32]; char convert[512]; int padlen = 0; /* amount to pad */ /* we rely on regular C library's sprintf to do the basic conversion */ if (pointflag) sprintf(fmt, "%%.%d%c", precision, type); else sprintf(fmt, "%%%c", type); if (adjust_sign((value < 0), forcesign, &signvalue)) value = -value; vallen = sprintf(convert, fmt, value); adjust_padlen(minlen, vallen, leftjust, &padlen); leading_pad(zpad, &signvalue, &padlen, end, output); dostr(convert, 0, end, output); trailing_pad(&padlen, end, output); } static void dostr(char *str, int cut, char *end, char **output) { if (cut) while (*str && cut-- > 0) dopr_outch(*str++, end, output); else while (*str) dopr_outch(*str++, end, output); } static void dopr_outch(int c, char *end, char **output) { #ifdef NOT_USED if (iscntrl((unsigned char) c) && c != '\n' && c != '\t') { c = '@' + (c & 0x1F); if (end == 0 || *output < end) *(*output)++ = '^'; } #endif if (end == 0 || *output < end) *(*output)++ = c; } static int adjust_sign(int is_negative, int forcesign, int *signvalue) { if (is_negative) { *signvalue = '-'; return 1; } else if (forcesign) *signvalue = '+'; return 0; } static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen) { *padlen = minlen - vallen; if (*padlen < 0) *padlen = 0; if (leftjust) *padlen = -*padlen; } static void leading_pad(int zpad, int *signvalue, int *padlen, char *end, char **output) { if (*padlen > 0 && zpad) { if (*signvalue) { dopr_outch(*signvalue, end, output); --*padlen; *signvalue = 0; } while (*padlen > 0) { dopr_outch(zpad, end, output); --*padlen; } } while (*padlen > 0 + (*signvalue != 0)) { dopr_outch(' ', end, output); --*padlen; } if (*signvalue) { dopr_outch(*signvalue, end, output); if (*padlen > 0) --*padlen; if (padlen < 0) ++padlen; } } static void trailing_pad(int *padlen, char *end, char **output) { while (*padlen < 0) { dopr_outch(' ', end, output); ++*padlen; } } hoichess_0.10.3/src/lib/my_getopt.cc0000640000175000017500000002625710732031250016720 0ustar oliveroliver/* * my_getopt.c - my re-implementation of getopt. * Copyright 1997, 2000, 2001, Benjamin Sittler * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include "my_getopt.h" static int _my_getopt_internal(int argc, char *argv[], const char *shortopts, const struct option * longopts, int *longind, int long_only); int my_optind = 1, my_opterr = 1, my_optopt = 0; char *my_optarg = 0; /* this is the plain old UNIX getopt, with GNU-style extensions. */ /* if you're porting some piece of UNIX software, this is all you need. */ /* this supports GNU-style permution and optional arguments */ int my_getopt(int argc, char *argv[], const char *opts) { static int charind = 0; const char *s; char mode, colon_mode; int off = 0, opt = -1; if (getenv("POSIXLY_CORRECT")) colon_mode = mode = '+'; else { if ((colon_mode = *opts) == ':') off++; if (((mode = opts[off]) == '+') || (mode == '-')) { off++; if ((colon_mode != ':') && ((colon_mode = opts[off]) == ':')) off++; } } my_optarg = 0; if (charind) { my_optopt = argv[my_optind][charind]; for (s = opts + off; *s; s++) if (my_optopt == *s) { charind++; if ((*(++s) == ':') || ((my_optopt == 'W') && (*s == ';'))) { if (argv[my_optind][charind]) { my_optarg = &(argv[my_optind++][charind]); charind = 0; } else if (*(++s) != ':') { charind = 0; if (++my_optind >= argc) { if (my_opterr) fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], my_optopt); opt = (colon_mode == ':') ? ':' : '?'; goto my_getopt_ok; } my_optarg = argv[my_optind++]; } } opt = my_optopt; goto my_getopt_ok; } if (my_opterr) fprintf(stderr, "%s: illegal option -- %c\n", argv[0], my_optopt); opt = '?'; if (argv[my_optind][++charind] == '\0') { my_optind++; charind = 0; } my_getopt_ok: if (charind && !argv[my_optind][charind]) { my_optind++; charind = 0; } } else if ((my_optind >= argc) || ((argv[my_optind][0] == '-') && (argv[my_optind][1] == '-') && (argv[my_optind][2] == '\0'))) { my_optind++; opt = -1; } else if ((argv[my_optind][0] != '-') || (argv[my_optind][1] == '\0')) { char *tmp; int i, j, k; if (mode == '+') opt = -1; else if (mode == '-') { my_optarg = argv[my_optind++]; charind = 0; opt = 1; } else { for (i = j = my_optind; i < argc; i++) if ((argv[i][0] == '-') && (argv[i][1] != '\0')) { my_optind = i; opt = my_getopt(argc, argv, opts); while (i > j) { tmp = argv[--i]; for (k = i; k + 1 < my_optind; k++) argv[k] = argv[k + 1]; argv[--my_optind] = tmp; } break; } if (i == argc) opt = -1; } } else { charind++; opt = my_getopt(argc, argv, opts); } if (my_optind > argc) my_optind = argc; return opt; } /* this is the extended getopt_long{,_only}, with some GNU-like * extensions. Implements _getopt_internal in case any programs * expecting GNU libc getopt call it. */ static int _my_getopt_internal(int argc, char *argv[], const char *shortopts, const struct option * longopts, int *longind, int long_only) { char mode, colon_mode = *shortopts; int shortoff = 0, opt = -1; if (getenv("POSIXLY_CORRECT")) colon_mode = mode = '+'; else { if ((colon_mode = *shortopts) == ':') shortoff++; if (((mode = shortopts[shortoff]) == '+') || (mode == '-')) { shortoff++; if ((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':')) shortoff++; } } my_optarg = 0; if ((my_optind >= argc) || ((argv[my_optind][0] == '-') && (argv[my_optind][1] == '-') && (argv[my_optind][2] == '\0'))) { my_optind++; opt = -1; } else if ((argv[my_optind][0] != '-') || (argv[my_optind][1] == '\0')) { char *tmp; int i, j, k; opt = -1; if (mode == '+') return -1; else if (mode == '-') { my_optarg = argv[my_optind++]; return 1; } for (i = j = my_optind; i < argc; i++) if ((argv[i][0] == '-') && (argv[i][1] != '\0')) { my_optind = i; opt = _my_getopt_internal(argc, argv, shortopts, longopts, longind, long_only); while (i > j) { tmp = argv[--i]; for (k = i; k + 1 < my_optind; k++) argv[k] = argv[k + 1]; argv[--my_optind] = tmp; } break; } } else if ((!long_only) && (argv[my_optind][1] != '-')) opt = my_getopt(argc, argv, shortopts); else { int charind, offset; int found = 0, ind, hits = 0; if (((my_optopt = argv[my_optind][1]) != '-') && !argv[my_optind][2]) { int c; ind = shortoff; while ((c = shortopts[ind++]) != 0) { if (((shortopts[ind] == ':') || ((c == 'W') && (shortopts[ind] == ';'))) && (shortopts[++ind] == ':')) ind++; if (my_optopt == c) return my_getopt(argc, argv, shortopts); } } offset = 2 - (argv[my_optind][1] != '-'); for (charind = offset; (argv[my_optind][charind] != '\0') && (argv[my_optind][charind] != '='); charind++); /* Intentional empty loop -- work is done as * a side effect */ for (ind = 0; longopts[ind].name && !hits; ind++) if ((strlen(longopts[ind].name) == (size_t) (charind - offset)) && (strncmp(longopts[ind].name, argv[my_optind] + offset, charind - offset) == 0)) found = ind, hits++; if (!hits) for (ind = 0; longopts[ind].name; ind++) if (strncmp(longopts[ind].name, argv[my_optind] + offset, charind - offset) == 0) found = ind, hits++; if (hits == 1) { opt = 0; if (argv[my_optind][charind] == '=') { if (longopts[found].has_arg == 0) { opt = '?'; if (my_opterr) fprintf(stderr, "%s: option `--%s' doesn't allow an argument\n", argv[0], longopts[found].name); } else { my_optarg = argv[my_optind] + ++charind; charind = 0; } } else if (longopts[found].has_arg == 1) { if (++my_optind >= argc) { opt = (colon_mode == ':') ? ':' : '?'; if (my_opterr) fprintf(stderr, "%s: option `--%s' requires an argument\n", argv[0], longopts[found].name); } else my_optarg = argv[my_optind]; } if (!opt) { if (longind) *longind = found; if (!longopts[found].flag) opt = longopts[found].val; else *(longopts[found].flag) = longopts[found].val; } my_optind++; } else if (!hits) { if (offset == 1) opt = my_getopt(argc, argv, shortopts); else { opt = '?'; if (my_opterr) fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], argv[my_optind++]); } } else { opt = '?'; if (my_opterr) fprintf(stderr, "%s: option `%s' is ambiguous\n", argv[0], argv[my_optind++]); } } if (my_optind > argc) my_optind = argc; return opt; } int my_getopt_long(int argc, char *argv[], const char *shortopts, const struct option * longopts, int *longind) { return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 0); } int my_getopt_long_only(int argc, char *argv[], const char *shortopts, const struct option * longopts, int *longind) { return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 1); } hoichess_0.10.3/src/lib/getopt.h0000640000175000017500000000323610732031250016045 0ustar oliveroliver/* * getopt.h - cpp wrapper for my_getopt to make it look like getopt. * Copyright 1997, 2000, 2001, Benjamin Sittler * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef MY_WRAPPER_GETOPT_H_INCLUDED #define MY_WRAPPER_GETOPT_H_INCLUDED #include "my_getopt.h" #undef getopt #define getopt my_getopt #undef getopt_long #define getopt_long my_getopt_long #undef getopt_long_oly #define getopt_long_only my_getopt_long_only #undef opterr #define opterr my_opterr #undef optind #define optind my_optind #undef optopt #define optopt my_optopt #undef optarg #define optarg my_optarg #endif /* MY_WRAPPER_GETOPT_H_INCLUDED */ hoichess_0.10.3/src/lib/my_getopt.h0000640000175000017500000000424010732031250016546 0ustar oliveroliver/* * my_getopt.h - interface to my re-implementation of getopt. * Copyright 1997, 2000, 2001, Benjamin Sittler * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef MY_GETOPT_H_INCLUDED #define MY_GETOPT_H_INCLUDED /* UNIX-style short-argument parser */ extern int my_getopt(int argc, char *argv[], const char *opts); extern int my_optind, my_opterr, my_optopt; extern char *my_optarg; struct option { const char *name; int has_arg; int *flag; int val; }; /* human-readable values for has_arg */ #undef no_argument #define no_argument 0 #undef required_argument #define required_argument 1 #undef optional_argument #define optional_argument 2 /* GNU-style long-argument parsers */ extern int my_getopt_long(int argc, char *argv[], const char *shortopts, const struct option * longopts, int *longind); extern int my_getopt_long_only(int argc, char *argv[], const char *shortopts, const struct option * longopts, int *longind); #endif /* MY_GETOPT_H_INCLUDED */ hoichess_0.10.3/src/lib/snprintf.h0000640000175000017500000000032610732031250016403 0ustar oliveroliverextern int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args); extern int pg_snprintf(char *str, size_t count, const char *fmt, ...); #define vsnprintf pg_vsnprintf #define snprintf pg_snprintf hoichess_0.10.3/src/lib/strtok_r.cc0000640000175000017500000000423010732031250016543 0ustar oliveroliver/* Reentrant string tokenizer. Generic version. Copyright (C) 1991,1996-1999,2001,2004 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ //#ifdef HAVE_CONFIG_H //# include //#endif #include #undef strtok_r #undef __strtok_r #ifndef _LIBC /* Get specification. */ # include "strtok_r.h" # define __strtok_r strtok_r # define __rawmemchr strchr #endif /* Parse S into tokens separated by characters in DELIM. If S is NULL, the saved pointer in SAVE_PTR is used as the next starting point. For example: char s[] = "-abc-=-def"; char *sp; x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def" x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL x = strtok_r(NULL, "=", &sp); // x = NULL // s = "abc\0-def\0" */ char * __strtok_r (char *s, const char *delim, char **save_ptr) { char *token; if (s == NULL) s = *save_ptr; /* Scan leading delimiters. */ s += strspn (s, delim); if (*s == '\0') { *save_ptr = s; return NULL; } /* Find the end of the token. */ token = s; s = strpbrk (token, delim); if (s == NULL) /* This token finishes the string. */ *save_ptr = __rawmemchr (token, '\0'); else { /* Terminate the token and make *SAVE_PTR point past it. */ *s = '\0'; *save_ptr = s + 1; } return token; } #ifdef weak_alias libc_hidden_def (__strtok_r) weak_alias (__strtok_r, strtok_r) #endif hoichess_0.10.3/src/chess/0000750000175000017500000000000010732031250014724 5ustar oliveroliverhoichess_0.10.3/src/chess/move.h0000640000175000017500000001423110732031250016045 0ustar oliveroliver/* $Id: move.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/move.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef MOVE_H #define MOVE_H #include "common.h" #include "board.h" #include "basic.h" #include /* Need a forward declaration here since * move.h and board.h include each other. */ class Board; #define NO_MOVE Move() class Move { public: /* Move flags. */ enum { MOVE_NONE = 0x000, MOVE_NORMAL = 0x001, MOVE_CAPTURE = 0x002, MOVE_PROMOTION = 0x004, MOVE_ENPASSANT = 0x008, MOVE_CASTLE = 0x010, MOVE_NULL = 0x020 }; private: /* A bit field that describes the move's properties. The bits * have the following meanings: * * 0 - 5: from square * 6 - 11: to square * 12 - 14: type of moving piece, or piece type a pawn promotes to * 15 - 17: type of captured piece, if any * 18 - 31: flags */ uint32_t mov; public: FORCEINLINE Move(); inline explicit Move(uint32_t m); private: inline Move(Square from, Square to, Piece ptype, Piece cap_ptype, uint16_t flags); public: inline Square from() const; inline Square to() const; inline Piece ptype() const; inline Piece promote_to() const; inline Piece cap_ptype() const; inline uint16_t flags() const; inline bool is_normal() const; inline bool is_capture() const; inline bool is_enpassant() const; inline bool is_promotion() const; inline bool is_castle() const; inline bool is_null() const; inline int mat_gain() const; public: inline static Move normal(Square from, Square to, Piece ptype); inline static Move capture(Square from, Square to, Piece ptype, Piece cap_ptype); inline static Move enpassant(Square from, Square to); inline static Move promotion(Square from, Square to, Piece promote_to); inline static Move promotion_capture(Square from, Square to, Piece promote_to, Piece cap_ptype); inline static Move castle(Square from, Square to); inline static Move null(); public: FORCEINLINE bool operator==(Move m2) const; FORCEINLINE bool operator!=(Move m2) const; FORCEINLINE bool operator<(Move m2) const; FORCEINLINE operator uint32_t() const; //inline operator bool() const; bool is_valid(const Board & board) const; bool is_legal(const Board & board) const; std::string str() const; std::string san(const Board & board, int nonstd = 0) const; void print() const; /* Define a strict weak ordering of Move objects. This is useful * when we want to use a std::map, like we do in * Book::group_moves(). */ class strict_weak_ordering { public: bool operator()(Move a, Move b) const { return a < b; } }; /* Hmm, Borland compiler does not grant access to Move::mov. */ friend class strict_weak_ordering; }; inline Move::Move() { mov = 0; } inline Move::Move(uint32_t m) { mov = m; } inline Move::Move(Square from, Square to, Piece ptype, Piece cap_ptype, uint16_t flags) { mov = (from & 0x3f) | ((to & 0x3f) << 6) | ((ptype & 0x7) << 12) | ((cap_ptype & 0x7) << 15) | (flags << 18); } inline Square Move::from() const { return (mov & 0x3f); } inline Square Move::to() const { return ((mov >> 6) & 0x3f); } inline Piece Move::ptype() const { if (flags() & MOVE_PROMOTION) return PAWN; return ((mov >> 12) & 0x7); } inline Piece Move::promote_to() const { ASSERT_DEBUG(flags() & MOVE_PROMOTION); return ((mov >> 12) & 0x7); } inline Piece Move::cap_ptype() const { return ((mov >> 15) & 0x7); } inline uint16_t Move::flags() const { return ((uint16_t) (mov >> 18)); } inline bool Move::is_normal() const { return (flags() & MOVE_NORMAL); } inline bool Move::is_capture() const { return (flags() & MOVE_CAPTURE); } inline bool Move::is_enpassant() const { return (flags() & MOVE_ENPASSANT); } inline bool Move::is_promotion() const { return (flags() & MOVE_PROMOTION); } inline bool Move::is_castle() const { return (flags() & MOVE_CASTLE); } inline bool Move::is_null() const { return (flags() & MOVE_NULL); } inline int Move::mat_gain() const { int gain = 0; if (is_promotion()) { gain += mat_values[promote_to()] - mat_values[PAWN]; } if (is_capture() || is_enpassant()) { gain += mat_values[cap_ptype()]; } return gain; } inline Move Move::normal(Square from, Square to, Piece ptype) { return Move(from, to, ptype, NO_PIECE, MOVE_NORMAL); } inline Move Move::capture(Square from, Square to, Piece ptype, Piece cap_ptype) { return Move(from, to, ptype, cap_ptype, MOVE_CAPTURE); } inline Move Move::enpassant(Square from, Square to) { return Move(from, to, PAWN, PAWN, MOVE_ENPASSANT); } inline Move Move::promotion(Square from, Square to, Piece promote_to) { return Move(from, to, promote_to, NO_PIECE, MOVE_PROMOTION | MOVE_NORMAL); } inline Move Move::promotion_capture(Square from, Square to, Piece promote_to, Piece cap_ptype) { return Move(from, to, promote_to, cap_ptype, MOVE_PROMOTION | MOVE_CAPTURE); } inline Move Move::castle(Square from, Square to) { return Move(from, to, KING, NO_PIECE, MOVE_CASTLE); } inline Move Move::null() { return Move(NO_SQUARE, NO_SQUARE, NO_PIECE, NO_PIECE, MOVE_NULL); } inline bool Move::operator==(Move m2) const { return mov == m2.mov; } inline bool Move::operator!=(Move m2) const { return mov != m2.mov; } inline bool Move::operator<(Move m2) const { return mov < m2.mov; } inline Move::operator uint32_t() const { return mov; } #if 0 inline Move::operator bool() const { return (flags() != MOVE_NONE); } #endif #endif // MOVE_H hoichess_0.10.3/src/chess/board.h0000640000175000017500000002206110732031250016166 0ustar oliveroliver/* $Id: board.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef BOARD_H #define BOARD_H #include "common.h" #include "bitboard.h" #include "hash.h" #include "move.h" #include "movelist.h" #include "basic.h" #include /* Castling flags */ #define WKCASTLE 0x01 #define WQCASTLE 0x02 #define BKCASTLE 0x04 #define BQCASTLE 0x08 #define WCASTLE (WKCASTLE | WQCASTLE) #define BCASTLE (BKCASTLE | BQCASTLE) #ifdef USE_UNMAKE_MOVE /* Forward declaration */ class BoardHistory; #endif class Board { friend class Evaluator; /* Data Members */ private: Color side, opponent; int moveno; int movecnt50; Bitboard position[2][6]; Bitboard position_all[2]; Bitboard occupied; Bitboard occupied_l90; Bitboard occupied_l45; Bitboard occupied_r45; Square king[2]; unsigned int flags; Square epsq; int material[2]; bool has_castled[2]; unsigned int pce_movecnt[64]; Hashkey hashkey; Hashkey pawnhashkey; /* Constructors / Destructor, defined in board.cc */ public: Board(); Board(const std::string& fen); inline ~Board() {}; /* Accessors */ public: Color get_side() const { return side; } int get_moveno() const { return moveno; } int get_movecnt50() const { return movecnt50; } unsigned int get_flags() const { return flags; } Square get_epsq() const { return epsq; } Hashkey get_hashkey() const { return hashkey; } Hashkey get_pawnhashkey() const { return pawnhashkey; } inline Hashkey get_hashkey_noside() const; inline unsigned int get_pce_movecnt(Square sq) const; private: Bitboard get_pawns(Color side) const { return position[side][PAWN]; } Bitboard get_knights(Color side) const { return position[side][KNIGHT]; } Bitboard get_bishops(Color side) const { return position[side][BISHOP]; } Bitboard get_rooks(Color side) const { return position[side][ROOK]; } Bitboard get_queens(Color side) const { return position[side][QUEEN]; } Bitboard get_kings(Color side) const { return position[side][KING]; } Bitboard get_pieces(Color side) const { return position_all[side]; } Bitboard get_blocker() const { return occupied; } Square get_king(Color side) const { return king[side]; } /* Basic board functions, defined in board.cc */ public: void clear(); #ifdef USE_UNMAKE_MOVE BoardHistory make_move(Move mov); void unmake_move(const BoardHistory & hist); #else void make_move(Move mov); #endif bool is_valid_move(Move mov) const; bool is_legal_move(Move mov) const; Color color_at(Square sq) const; Piece piece_at(Square sq) const; Square get_eppawn() const; private: void set_side(Color side); void switch_sides(); void place_piece(Square sq, Color side, Piece ptype); void remove_piece(Square sq, Color side, Piece ptype); void move_piece(Square from, Square to, Color side, Piece ptype); void set_flag(unsigned int flag); void clear_flag(unsigned int flag); void set_epsq(Square sq); void clear_epsq(); public: inline bool in_check() const; inline bool is_legal() const; inline int material_difference() const; inline int get_material(Color side) const; /* Attack functions, defined in board_attack.cc */ public: bool is_attacked(Square to, Color atkside) const; private: Bitboard attackers(Square to, Color atkside) const; Bitboard pinned(Square to, Color side) const; inline Bitboard pawn_captures(Square from, Color side) const; inline Bitboard pawn_noncaptures(Square from, Color side) const; inline Bitboard knight_attacks(Square from) const; inline Bitboard bishop_attacks(Square from) const; inline Bitboard rook_attacks(Square from) const; inline Bitboard queen_attacks(Square from) const; inline Bitboard king_attacks(Square from) const; /* Move generation functions, defined in board_generate.cc */ public: void generate_moves(Movelist * movelist, bool allpromo) const; void generate_captures(Movelist * movelist, bool allpromo) const; /* * We cannot simply use 'allpromo = true' as default parameter, * because this would give these functions a different signature than * generate_noncaptures(), and we could not use a function pointer * to all generate_*() functions, like in Shell::cmd_show() */ inline void generate_moves(Movelist * movelist) const { generate_moves(movelist, true); } inline void generate_captures(Movelist * movelist) const { generate_captures(movelist, true); } void generate_noncaptures(Movelist * movelist) const; void generate_escapes(Movelist * movelist) const; private: void generate_castling(Movelist * movelist) const; void add_moves(Movelist * movelist, Square from, Bitboard to_bb) const; void add_move(Movelist * movelist, Square from, Square to) const; /* Utility functions, defined in board_util.cc */ public: bool is_mate() const; bool is_stalemate() const; bool is_valid() const; bool is_material_draw() const; void print(FILE * fp = stdout, Move last_move = Move()) const; void print_small(FILE * fp = stdout) const; std::string get_fen() const; bool parse_fen(const char * s); bool parse_fen(const std::string & str); Move parse_move(const std::string & str) const; Move parse_move_1(const std::string & str) const; Move do_parse_move_1(const std::string & str) const; bool operator==(const Board & board) const; /* Static Data Members */ private: static Hashkey hashkeys[2][6][64]; static Hashkey hash_side; static Hashkey hash_ep[64]; static Hashkey hash_wk; static Hashkey hash_wq; static Hashkey hash_bk; static Hashkey hash_bq; /* Static Member Functions */ public: static void init(); }; #ifdef USE_UNMAKE_MOVE /* * This class contains all necessary information to unmake a previous move. */ class BoardHistory { friend class Board; private: #ifdef DEBUG /* This is used by unmake_move() to verify that the board status * was correctly restored. */ Board oldboard; #endif Move move; int movecnt50; unsigned int flags; Square epsq; unsigned int pce_movecnt_to; }; #endif /***************************************************************************** * * Inline functions of class board * *****************************************************************************/ inline Hashkey Board::get_hashkey_noside() const { if (side == BLACK) { return hashkey ^ hash_side; } else { return hashkey; } } inline unsigned int Board::get_pce_movecnt(Square sq) const { ASSERT_DEBUG(sq >= 0 && sq < 64); return pce_movecnt[sq]; } inline bool Board::in_check() const { return is_attacked(get_king(side), opponent); } /* * Check if the position is legal, i.e. the enemy king * cannot be captured with the next move. */ inline bool Board::is_legal() const { return !is_attacked(get_king(opponent), side); } inline int Board::material_difference() const { return (material[side] - material[opponent]); } inline int Board::get_material(Color side) const { ASSERT_DEBUG(side != NO_COLOR); return material[side]; } /* * Basic attack functions: * * Note that they don't filter out illegal captures * of own pieces. * * Rotated bitboards are used to calculate * bishop, rook and queen attacks. */ inline Bitboard Board::pawn_captures(Square from, Color side) const { Bitboard bb = Bitboard::pawn_capt_bb[side][from] & get_blocker(); if (epsq != NO_SQUARE && Bitboard::pawn_capt_bb[side][from].testbit(epsq)) bb.setbit(epsq); return (bb); } inline Bitboard Board::pawn_noncaptures(Square from, Color side) const { const int rank2 = (side == WHITE) ? RANK2 : RANK7; const int dir = (side == WHITE) ? +8 : -8; Bitboard bb = NULLBITBOARD; if (!get_blocker().testbit(from+dir)) { bb.setbit(from+dir); if (RNK(from) == rank2 && !get_blocker().testbit(from+2*dir)) bb.setbit(from+2*dir); } return (bb); } inline Bitboard Board::knight_attacks(Square from) const { return (Bitboard::attack_bb[KNIGHT][from]); } inline Bitboard Board::bishop_attacks(Square from) const { return (occupied_l45.atkl45(from) | occupied_r45.atkr45(from)); } inline Bitboard Board::rook_attacks(Square from) const { return (occupied.atk0(from) | occupied_l90.atkl90(from)); } inline Bitboard Board::queen_attacks(Square from) const { return (bishop_attacks(from) | rook_attacks(from)); } inline Bitboard Board::king_attacks(Square from) const { return (Bitboard::attack_bb[KING][from]); } #endif // BOARD_H hoichess_0.10.3/src/chess/board_init.cc0000640000175000017500000000351310732031250017350 0ustar oliveroliver/* $Id: board_init.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board_init.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "util.h" Hashkey Board::hashkeys[2][6][64]; Hashkey Board::hash_side; Hashkey Board::hash_ep[64]; Hashkey Board::hash_wk; Hashkey Board::hash_wq; Hashkey Board::hash_bk; Hashkey Board::hash_bq; void Board::init() { unsigned int k = 0; /* Generate hash keys */ for (int c=0; c<2; c++) { for (int p=0; p<6; p++) { for (int s=0; s<64; s++) { //hashkeys[c][p][s] = random64(); hashkeys[c][p][s] = uint64_table[k++]; } } } for (int s=0; s<64; s++) { //hash_ep[s] = random64(); hash_ep[s] = uint64_table[k++]; } //hash_side = random64(); //hash_wk = random64(); //hash_wq = random64(); //hash_bk = random64(); //hash_bq = random64(); hash_side = uint64_table[k++]; hash_wk = uint64_table[k++]; hash_wq = uint64_table[k++]; hash_bk = uint64_table[k++]; hash_bq = uint64_table[k++]; /* uint64_table should have contained as many values as we needed */ ASSERT(k <= uint64_table_size); } hoichess_0.10.3/src/chess/basic.cc0000640000175000017500000000445110732031250016321 0ustar oliveroliver/* $Id: basic.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/basic.cc * * Copyright (C) 2004-2007 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "basic.h" const char piece_char[] = { 'P', 'N', 'B', 'R', 'Q', 'K' }; const char file_char[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' }; const char rank_char[] = { '1', '2', '3', '4', '5', '6', '7', '8' }; const char square_str[][3] = { "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" }; /* * Create a string with the FEN of the standard opening position. */ #define WP(p) (std::string(1, (char) toupper(piece_char[p]))) #define BP(p) (std::string(1, (char) tolower(piece_char[p]))) std::string opening_fen() { std::string fen; fen += BP(ROOK) + BP(KNIGHT) + BP(BISHOP) + BP(QUEEN) + BP(KING) + BP(BISHOP) + BP(KNIGHT) + BP(ROOK) + "/" + BP(PAWN) + BP(PAWN) + BP(PAWN) + BP(PAWN) + BP(PAWN) + BP(PAWN) + BP(PAWN) + BP(PAWN) + "/8/8/8/8/" + WP(PAWN) + WP(PAWN) + WP(PAWN) + WP(PAWN) + WP(PAWN) + WP(PAWN) + WP(PAWN) + WP(PAWN) + "/" + WP(ROOK) + WP(KNIGHT) + WP(BISHOP) + WP(QUEEN) + WP(KING) + WP(BISHOP) + WP(KNIGHT) + WP(ROOK) + " w KQkq - 0 1"; return fen; } #undef WP #undef BP /* * Initialization function for basic stuff. */ void basic_init() { } hoichess_0.10.3/src/chess/move.cc0000640000175000017500000001176610732031250016215 0ustar oliveroliver/* $Id: move.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/move.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "move.h" #include "basic.h" #include #include #include #include /* TODO Inline them. * Problem: Board::is_{valid,legal}_move() are not yet declared in * move.h due to mutual inclusion of board.h and move.h :-( */ bool Move::is_valid(const Board & board) const { return board.is_valid_move(*this); } bool Move::is_legal(const Board & board) const { return board.is_legal_move(*this); } /* * Return a string for coordinate notation, e.g. * e2e4, e7e8q, e1g1 (may be white king-side castling). */ std::string Move::str() const { char ss[6]; snprintf(ss, sizeof(ss), "%s%s%c", square_str[from()], square_str[to()], (flags() & MOVE_PROMOTION) ? tolower(piece_char[promote_to()]) : '\0' ); return std::string(ss); } /* * Return a string for standard algebraic notation, e.g. * e4, e8=Q, Nxc3#, O-O. * * If nonstd is not 0, some variations to SAN will be done, in order to * allow Board::parse_move() to accept non standard notations. * Values for nonstd: * 0: generate official SAN * 1: leave out trailing '+' or '#' * 2: leave out 'x' for captures * 3: include disambiguation by file even if not necessary * 4: include disambiguation by rank even if not necessary * 5: include disambiguation by file and rank even if not necessary */ std::string Move::san(const Board & board, int nonstd) const { char ss[8]; /* longest is 7 (exd8=Q# or Qc3xc6#) */ memset(ss, 0, sizeof(ss)); char * s = ss; if (flags() & MOVE_CASTLE) { if (FIL(to()) == 2) { strcpy(s, "O-O-O"); s += 5; } else { strcpy(s, "O-O"); s += 3; } } else if (ptype() == PAWN) { if (flags() & MOVE_CAPTURE || flags() & MOVE_ENPASSANT) { *s++ = file_char[FIL(from())]; } } else { *s++ = piece_char[ptype()]; /* ambiguity check */ bool disamb_file = false; bool disamb_rank = false; Movelist movelist; board.generate_moves(&movelist); movelist.filter_illegal(board); for (unsigned int i=0; i= 0 && from() <= 63) { printf("\tfrom = '%s'\n", square_str[from()]); } else { printf("\tfrom = %d\n", from()); } if (to() >= 0 && to() <= 63) { printf("\tto = '%s'\n", square_str[to()]); } else { printf("\tto = %d\n", to()); } if (ptype() >= PAWN && ptype() <= KING) { printf("\tptype = '%c'\n", piece_char[ptype()]); } else { printf("\tptype = %d\n", ptype()); } if (promote_to() >= PAWN && promote_to() <= KING) { printf("\tpromote_to = '%c'\n", piece_char[promote_to()]); } else { printf("\tpromote_to = %d\n", promote_to()); } if (cap_ptype() >= PAWN && cap_ptype() <= KING) { printf("\tcap_ptype = '%c'\n", piece_char[cap_ptype()]); } else { printf("\tcap_ptype = %d\n", cap_ptype()); } printf("\tflags = 0x%x\n", flags()); } hoichess_0.10.3/src/chess/board.cc0000640000175000017500000003515410732031250016333 0ustar oliveroliver/* $Id: board.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "bitboard.h" #include "move.h" #include "basic.h" Board::Board() { clear(); } Board::Board(const std::string& fen) { clear(); if (!parse_fen(fen)) { BUG("Constructor called with illegal FEN: %s", fen.c_str()); } } void Board::clear() { side = WHITE; opponent = BLACK; moveno = 1; movecnt50 = 0; for (int i=0; i<6; i++) { position[WHITE][i] = NULLBITBOARD; position[BLACK][i] = NULLBITBOARD; } position_all[WHITE] = NULLBITBOARD; position_all[BLACK] = NULLBITBOARD; occupied = NULLBITBOARD; occupied_l90 = NULLBITBOARD; occupied_l45 = NULLBITBOARD; occupied_r45 = NULLBITBOARD; king[WHITE] = NO_SQUARE; king[BLACK] = NO_SQUARE; flags = 0; epsq = NO_SQUARE; material[WHITE] = 0; material[BLACK] = 0; has_castled[WHITE] = false; has_castled[BLACK] = false; for (unsigned int sq = 0; sq < 64; sq++) { pce_movecnt[sq] = 0; } hashkey = NULLHASHKEY; pawnhashkey = NULLHASHKEY; } #ifdef USE_UNMAKE_MOVE BoardHistory Board::make_move(Move mov) #else void Board::make_move(Move mov) #endif { ASSERT_DEBUG(is_valid_move(mov)); #ifdef USE_UNMAKE_MOVE BoardHistory hist; #ifdef DEBUG hist.oldboard = *this; #endif hist.move = mov; #endif // USE_UNMAKE_MOVE /* Move pieces */ if (mov.is_castle()) { move_piece(mov.from(), mov.to(), side, KING); switch (mov.to()) { case C1: ASSERT_DEBUG(side == WHITE); ASSERT_DEBUG(flags & WQCASTLE); move_piece(A1, D1, side, ROOK); break; case G1: ASSERT_DEBUG(side == WHITE); ASSERT_DEBUG(flags & WKCASTLE); move_piece(H1, F1, side, ROOK); break; case C8: ASSERT_DEBUG(side == BLACK); ASSERT_DEBUG(flags & BQCASTLE); move_piece(A8, D8, side, ROOK); break; case G8: ASSERT_DEBUG(side == BLACK); ASSERT_DEBUG(flags & BKCASTLE); move_piece(H8, F8, side, ROOK); break; default: BUG("invalid 'to' square for castling: %d", mov.to()); break; } has_castled[side] = true; /* Castling flags will be cleared below. */ } else if (mov.is_enpassant()) { ASSERT_DEBUG(mov.to() == epsq); move_piece(mov.from(), mov.to(), side, PAWN); remove_piece(get_eppawn(), opponent, PAWN); } else if (mov.is_capture()) { if (mov.is_promotion()) { remove_piece(mov.from(), side, PAWN); remove_piece(mov.to(), opponent, mov.cap_ptype()); place_piece(mov.to(), side, mov.promote_to()); } else { remove_piece(mov.to(), opponent, mov.cap_ptype()); move_piece(mov.from(), mov.to(), side, mov.ptype()); } } else if (mov.is_normal()) { if (mov.is_promotion()) { remove_piece(mov.from(), side, PAWN); place_piece(mov.to(), side, mov.promote_to()); } else { move_piece(mov.from(), mov.to(), side, mov.ptype()); } } else if (mov.is_null()) { /* nothing */ } else { BUG("unknown move flags: %x", mov.flags()); } #ifdef USE_UNMAKE_MOVE hist.flags = flags; #endif /* Clear castling flag if a king has moved */ if (mov.ptype() == KING) { if (side == WHITE) { clear_flag(WKCASTLE); clear_flag(WQCASTLE); } else { clear_flag(BKCASTLE); clear_flag(BQCASTLE); } } /* Clear castling flag if a rook has moved */ if (mov.ptype() == ROOK) { switch (mov.from()) { case A1: clear_flag(WQCASTLE); break; case H1: clear_flag(WKCASTLE); break; case A8: clear_flag(BQCASTLE); break; case H8: clear_flag(BKCASTLE); break; } } /* Clear castling flag if a rook was captured */ if (mov.is_capture() && mov.cap_ptype() == ROOK) { switch (mov.to()) { case A1: clear_flag(WQCASTLE); break; case H1: clear_flag(WKCASTLE); break; case A8: clear_flag(BQCASTLE); break; case H8: clear_flag(BKCASTLE); break; } } /* Set/clear enpassant square. */ #ifdef USE_UNMAKE_MOVE hist.epsq = epsq; #endif if (mov.ptype() == PAWN) { if (mov.to() - mov.from() == 16) { set_epsq(mov.to() - 8); } else if (mov.to() - mov.from() == -16) { set_epsq(mov.to() + 8); } else { clear_epsq(); } } else { clear_epsq(); } /* Switch sides and update moveno */ switch_sides(); if (side == WHITE) { moveno++; } /* Update movecnt50 */ #ifdef USE_UNMAKE_MOVE hist.movecnt50 = movecnt50; #endif if (mov.ptype() == PAWN || mov.is_castle() || mov.is_capture()) { movecnt50 = 0; } else { movecnt50++; } /* Update pce_movecnt */ if (!mov.is_null()) { #ifdef USE_UNMAKE_MOVE hist.pce_movecnt_to = pce_movecnt[mov.to()]; #endif pce_movecnt[mov.to()] = pce_movecnt[mov.from()] + 1; pce_movecnt[mov.from()] = 0; } #ifdef USE_UNMAKE_MOVE return hist; #else return; #endif } #ifdef USE_UNMAKE_MOVE void Board::unmake_move(const BoardHistory & hist) { Move mov = hist.move; /* Restore pce_movecnt */ if (!mov.is_null()) { pce_movecnt[mov.from()] = pce_movecnt[mov.to()] - 1; pce_movecnt[mov.to()] = hist.pce_movecnt_to; } /* Restore movecnt50 */ movecnt50 = hist.movecnt50; /* Switch back sides */ if (side == WHITE) { moveno--; } switch_sides(); /* Restore enpassant square */ set_epsq(hist.epsq); /* Restore flags */ if (hist.flags & WKCASTLE) { set_flag(WKCASTLE); } if (hist.flags & WQCASTLE) { set_flag(WQCASTLE); } if (hist.flags & BKCASTLE) { set_flag(BKCASTLE); } if (hist.flags & BQCASTLE) { set_flag(BQCASTLE); } /* Move back pieces */ if (mov.flags() & MOVE_CASTLE) { move_piece(mov.to(), mov.from(), side, KING); switch (mov.to()) { case C1: ASSERT_DEBUG(side == WHITE); ASSERT_DEBUG(flags & WQCASTLE); move_piece(D1, A1, side, ROOK); break; case G1: ASSERT_DEBUG(side == WHITE); ASSERT_DEBUG(flags & WKCASTLE); move_piece(F1, H1, side, ROOK); break; case C8: ASSERT_DEBUG(side == BLACK); ASSERT_DEBUG(flags & BQCASTLE); move_piece(D8, A8, side, ROOK); break; case G8: ASSERT_DEBUG(side == BLACK); ASSERT_DEBUG(flags & BKCASTLE); move_piece(F8, H8, side, ROOK); break; default: BUG("invalid 'to' square for castling: %d", mov.to()); break; } has_castled[side] = false; } else if (mov.flags() & MOVE_ENPASSANT) { ASSERT_DEBUG(mov.to() == epsq); move_piece(mov.to(), mov.from(), side, PAWN); place_piece(get_eppawn(), opponent, PAWN); } else if (mov.flags() & MOVE_CAPTURE) { if (mov.flags() & MOVE_PROMOTION) { remove_piece(mov.to(), side, mov.promote_to()); place_piece(mov.to(), opponent, mov.cap_ptype()); place_piece(mov.from(), side, PAWN); } else { move_piece(mov.to(), mov.from(), side, mov.ptype()); place_piece(mov.to(), opponent, mov.cap_ptype()); } } else if (mov.flags() & MOVE_NORMAL) { if (mov.flags() & MOVE_PROMOTION) { remove_piece(mov.to(), side, mov.promote_to()); place_piece(mov.from(), side, PAWN); } else { move_piece(mov.to(), mov.from(), side, mov.ptype()); } } else if (mov.flags() & MOVE_NULL) { /* nothing */ } else { BUG("unknown move flags: %x", mov.flags()); } ASSERT_DEBUG(memcmp(this, &hist.oldboard, sizeof(Board)) == 0); ASSERT_DEBUG(is_valid_move(mov)); } #endif /* * Check if a move is valid (= pseudo-legal) on this board. */ bool Board::is_valid_move(Move mov) const { if (mov.is_null()) { return true; } Square from = mov.from(); Square to = mov.to(); /* Check castling. */ if (mov.is_castle()) { ASSERT_DEBUG(mov.ptype() == KING); ASSERT_DEBUG(mov.from() == get_king(get_side())); if (in_check()) return false; switch (to) { case G1: ASSERT_DEBUG(get_side() == WHITE); if ((get_flags() & WKCASTLE) == 0 || (get_blocker() & Bitboard::ray_bb[E1][H1]) || is_attacked(F1, BLACK)) return false; break; case C1: ASSERT_DEBUG(get_side() == WHITE); if ((get_flags() & WQCASTLE) == 0 || (get_blocker() & Bitboard::ray_bb[A1][E1]) || is_attacked(D1, BLACK)) return false; break; case G8: ASSERT_DEBUG(get_side() == BLACK); if ((get_flags() & BKCASTLE) == 0 || (get_blocker() & Bitboard::ray_bb[E8][H8]) || is_attacked(F8, WHITE)) return false; break; case C8: ASSERT_DEBUG(get_side() == BLACK); if ((get_flags() & BQCASTLE) == 0 || (get_blocker() & Bitboard::ray_bb[A8][E8]) || is_attacked(D8, WHITE)) return false; break; default: BUG("invalid 'to' square for castling: %d", to); break; } /* Ok, castling is allowed. */ return true; } /* Check origin square. */ if (color_at(from) != get_side() || piece_at(from) != mov.ptype()) return false; /* Check destination square. */ if (mov.is_capture()) { if (color_at(to) != XSIDE(get_side())) return false; } else if (mov.is_enpassant()) { if (to != get_epsq()) return false; } else { if (color_at(to) != NO_COLOR) return false; } /* Check from/to ranks if promotion. */ if (mov.is_promotion()) { if (get_side() == WHITE) { ASSERT_DEBUG(RNK(from) == RANK7); ASSERT_DEBUG(RNK(to) == RANK8); } else { ASSERT_DEBUG(RNK(from) == RANK2); ASSERT_DEBUG(RNK(to) == RANK1); } } /* Check correct piece movement. */ switch (piece_at(from)) { case PAWN: if (mov.is_capture() || mov.is_enpassant()) { if (!pawn_captures(from, color_at(from)).testbit(to)) return false; } else { if (!pawn_noncaptures(from, color_at(from)).testbit(to)) return false; } break; case KNIGHT: if (!knight_attacks(from).testbit(to)) return false; break; case BISHOP: if (!bishop_attacks(from).testbit(to)) return false; break; case ROOK: if (!rook_attacks(from).testbit(to)) return false; break; case QUEEN: if (!queen_attacks(from).testbit(to)) return false; break; case KING: if (!king_attacks(from).testbit(to)) return false; break; default: BUG("huh?"); } /* Ok, this move is pseudo-legal. */ return true; } /* * Check if a move is legal on this board. */ bool Board::is_legal_move(Move mov) const { ASSERT_DEBUG(is_valid_move(mov)); Board tmpboard = *this; tmpboard.make_move(mov); return tmpboard.is_legal(); } Color Board::color_at(Square sq) const { for (Color clr = WHITE; clr <= BLACK; clr++) if (position_all[clr].testbit(sq)) return clr; return NO_COLOR; } /* * Perhaps we should add an additional * Piece[64] array to speed up this function. */ Piece Board::piece_at(Square sq) const { for (Piece pce = PAWN; pce <= KING; pce++) if ((position[WHITE][pce] | position[BLACK][pce]).testbit(sq)) return pce; return NO_PIECE; } /* * Return the square where the enpassant pawn is * located. This is NOT the enpassant square! */ Square Board::get_eppawn() const { if (RNK(epsq) == RANK3) return epsq + 8; else if (RNK(epsq) == RANK6) return epsq - 8; else return NO_SQUARE; } void Board::set_side(Color _side) { if (side != _side) switch_sides(); } void Board::switch_sides() { side = XSIDE(side); opponent = XSIDE(opponent); hashkey ^= hash_side; pawnhashkey ^= hash_side; } void Board::place_piece(Square sq, Color side, Piece ptype) { ASSERT_DEBUG(color_at(sq) == NO_COLOR); ASSERT_DEBUG(piece_at(sq) == NO_PIECE); position[side][ptype].setbit(sq); position_all[side].setbit(sq); occupied.setbit(sq); occupied_l90.setbit(Bitboard::map_l90[sq]); occupied_l45.setbit(Bitboard::map_l45[sq]); occupied_r45.setbit(Bitboard::map_r45[sq]); if (ptype == KING) { king[side] = sq; } material[side] += mat_values[ptype]; hashkey ^= hashkeys[side][ptype][sq]; if (ptype == PAWN) { pawnhashkey ^= hashkeys[side][ptype][sq]; } } void Board::remove_piece(Square sq, Color side, Piece ptype) { ASSERT_DEBUG(color_at(sq) == side); ASSERT_DEBUG(piece_at(sq) == ptype); position[side][ptype].clearbit(sq); position_all[side].clearbit(sq); occupied.clearbit(sq); occupied_l90.clearbit(Bitboard::map_l90[sq]); occupied_l45.clearbit(Bitboard::map_l45[sq]); occupied_r45.clearbit(Bitboard::map_r45[sq]); if (ptype == KING) { king[side] = NO_SQUARE; } material[side] -= mat_values[ptype]; hashkey ^= hashkeys[side][ptype][sq]; if (ptype == PAWN) { pawnhashkey ^= hashkeys[side][ptype][sq]; } } void Board::move_piece(Square from, Square to, Color side, Piece ptype) { ASSERT_DEBUG(color_at(from) == side); ASSERT_DEBUG(piece_at(from) == ptype); ASSERT_DEBUG(color_at(to) == NO_COLOR); ASSERT_DEBUG(piece_at(to) == NO_PIECE); position[side][ptype].clearbit(from); position[side][ptype].setbit(to); position_all[side].clearbit(from); position_all[side].setbit(to); occupied.clearbit(from); occupied.setbit(to); occupied_l90.clearbit(Bitboard::map_l90[from]); occupied_l90.setbit(Bitboard::map_l90[to]); occupied_l45.clearbit(Bitboard::map_l45[from]); occupied_l45.setbit(Bitboard::map_l45[to]); occupied_r45.clearbit(Bitboard::map_r45[from]); occupied_r45.setbit(Bitboard::map_r45[to]); if (ptype == KING) { king[side] = to; } hashkey ^= hashkeys[side][ptype][from]; hashkey ^= hashkeys[side][ptype][to]; if (ptype == PAWN) { pawnhashkey ^= hashkeys[side][ptype][from]; pawnhashkey ^= hashkeys[side][ptype][to]; } } void Board::set_flag(unsigned int flag) { if (flags & flag) return; flags |= flag; switch (flag) { case WKCASTLE: hashkey ^= hash_wk; break; case WQCASTLE: hashkey ^= hash_wq; break; case BKCASTLE: hashkey ^= hash_bk; break; case BQCASTLE: hashkey ^= hash_bq; break; } } void Board::clear_flag(unsigned int flag) { if (! (flags & flag)) return; flags &= ~flag; switch (flag) { case WKCASTLE: hashkey ^= hash_wk; break; case WQCASTLE: hashkey ^= hash_wq; break; case BKCASTLE: hashkey ^= hash_bk; break; case BQCASTLE: hashkey ^= hash_bq; break; } } void Board::set_epsq(Square sq) { if (epsq != NO_SQUARE) { hashkey ^= hash_ep[epsq]; //pawnhashkey ^= hash_ep[epsq]; } if (sq != NO_SQUARE) { hashkey ^= hash_ep[sq]; //pawnhashkey ^= hash_ep[sq]; } epsq = sq; } void Board::clear_epsq() { if (epsq != NO_SQUARE) { hashkey ^= hash_ep[epsq]; //pawnhashkey ^= hash_ep[epsq]; } epsq = NO_SQUARE; } hoichess_0.10.3/src/chess/eval.h0000640000175000017500000000602310732031250016026 0ustar oliveroliver/* $Id: eval.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/chess/eval.h * * Copyright (C) 2004-2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef EVAL_H #define EVAL_H #include "common.h" #include "board.h" #include "evalcache.h" #include "pawnhash.h" /* score values */ #define INFTY 100000 #define MATE 90000 #define DRAW 0 class Evaluator { public: enum game_phase { OPENING, MIDGAME, ENDGAME }; private: static const struct score_plugin plugins[]; static const struct score_plugin plugins2[]; private: PawnHashTable * pawnhashtable; EvaluationCache * evalcache; #ifdef COLLECT_STATISTICS unsigned long stat_evals; unsigned long stat_evals_phase1; unsigned long stat_evals_phase2; #endif private: const Board * board; unsigned int phase; Color myside; PawnHashEntry pawnhashentry; Bitboard passed_pawns[2]; //Bitboard pinned_on_king[2]; public: Evaluator(); ~Evaluator(); public: int eval(const Board & board, int alpha, int beta, Color myside); void print_eval(const Board & board, Color myside, FILE * fp = stdout); public: void reset_statistics(); void print_statistics(FILE * fp = stdout) const; void set_pawnhashtable(PawnHashTable * pawnhashtable); void set_evalcache(EvaluationCache * evalcache); void set_param(const std::string& name, const std::string& value); private: void setup(const Board * board); void finish(); public: static bool is_draw(const Board & board); static int material_balance(int mat_side, int mat_xside); static unsigned int get_phase(const Board & board); private: static const int pawn_scores_opening[64]; static const int pawn_scores_midgame[64]; static const int pawn_scores_endgame[64]; static const int knight_scores[64]; static const int king_scores[64]; static const int king_scores_endgame[64]; static const int control_score[64]; static const unsigned int control_maxattackers[64]; private: int score_pawns(Color side); int score_knights(Color side); int score_bishops(Color side); int score_rooks(Color side); int score_queens(Color side); int score_king(Color side); int score_devel(Color side); int score_combo(Color side); int score_control(Color side); }; struct score_plugin { const char * name; int (Evaluator::* func)(Color); }; #endif // EVAL_H hoichess_0.10.3/src/chess/board_util.cc0000640000175000017500000004150510732031250017365 0ustar oliveroliver/* $Id: board_util.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board_util.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "move.h" #include "basic.h" #include bool Board::is_mate() const { Movelist movelist; generate_moves(&movelist); movelist.filter_illegal(*this); return (in_check() && movelist.size() == 0); } bool Board::is_stalemate() const { Movelist movelist; generate_moves(&movelist); movelist.filter_illegal(*this); return (!in_check() && movelist.size() == 0); } bool Board::is_valid() const { /* Each side must have exactly one king. */ if (get_kings(WHITE).popcnt() != 1) return false; if (get_kings(BLACK).popcnt() != 1) return false; /* Pawns cannot be on rank 1 or rank 8. */ if ((get_pawns(WHITE) | get_pawns(BLACK)) & (Bitboard::rank[RANK1] | Bitboard::rank[RANK8])) return false; /* The opponent's king must not be in check. */ if (is_attacked(get_king(opponent), side)) return false; return true; } bool Board::is_material_draw() const { if (material[WHITE] == 0 && material[BLACK] == 0) { /* only kings left -> draw */ return true; } else if (get_pawns(WHITE) || get_pawns(BLACK)) { /* there are still pawns -> no draw */ return false; } else if ((material[WHITE] < mat_values[ROOK] || (material[WHITE] == 2 * mat_values[KNIGHT] && get_knights(WHITE).popcnt() == 2)) && (material[BLACK] < mat_values[ROOK] || (material[BLACK] == 2 * mat_values[KNIGHT] && get_knights(BLACK).popcnt() == 2))) { /* both sides have only a knight or a bishop -> draw * both sides have <= 2 knights only -> draw */ return true; } /* TODO more */ return false; } void Board::print(FILE * fp, Move last_move) const { Square sq; char c; for (int i=7; i>=0; i--) { fprintf(fp, " +---+---+---+---+---+---+---+---+\n"); fprintf(fp, "%d ", i+1); for (int j=0; j<=7; j++) { sq = SQUARE(i,j); if (piece_at(sq) != NO_PIECE) { c = piece_char[piece_at(sq)]; c = (color_at(sq) == WHITE) ? toupper(c) : tolower(c); } else { c = ' '; } if (ansicolor && fp == stdout) { const char * a1 = (i+j)%2 ? "\033[47m" : "\033[40m"; const char * a2 = ""; const char * a3 = ""; if (last_move && (sq == last_move.from() || sq == last_move.to())) { a2 = XSIDE(side) == WHITE ? "\033[31;1m" : "\033[34;1m"; a3 = "\033[7m"; } else { if (color_at(sq) == WHITE) { a2 = "\033[31;1m"; } else if (color_at(sq) == BLACK) { a2 = "\033[34;1m"; } } const char * a4 = "\033[0m"; fprintf(fp, "|%s %s%s%c%s%s %s", a1, a2, a3, c, a4, a1, a4); } else { fprintf(fp, "| %c ", c); } } fprintf(fp, "|\n"); } fprintf(fp, " +---+---+---+---+---+---+---+---+\n"); fprintf(fp, " a b c d e f g h\n"); fprintf(fp, "\n [%d] %s %c%c%c%c %s\n", moveno, (side == WHITE) ? "White" : "Black", (flags & WKCASTLE) ? 'K' : ' ', (flags & WQCASTLE) ? 'Q' : ' ', (flags & BKCASTLE) ? 'k' : ' ', (flags & BQCASTLE) ? 'q' : ' ', (epsq != NO_SQUARE) ? square_str[epsq] : "-" ); } void Board::print_small(FILE * fp) const { Square sq; char c; for (int i=7; i>=0; i--) { //fprintf(fp, "%d ", i+1); for (int j=0; j<=7; j++) { sq = SQUARE(i,j); if (piece_at(sq) != NO_PIECE) { c = piece_char[piece_at(sq)]; if (color_at(sq) == WHITE) c = toupper(c); else c = tolower(c); } else { c = '.'; } fprintf(fp, " %c", c); } fprintf(fp, "\n"); } //fprintf(fp, "\n a b c d e f g h\n"); fprintf(fp, "\n [%d] %s %c%c%c%c %s\n", moveno, (side == WHITE) ? "White" : "Black", (flags & WKCASTLE) ? 'K' : ' ', (flags & WQCASTLE) ? 'Q' : ' ', (flags & BKCASTLE) ? 'k' : ' ', (flags & BQCASTLE) ? 'q' : ' ', (epsq != NO_SQUARE) ? square_str[epsq] : "-" ); } std::string Board::get_fen() const { char ss[128]; char * s = ss; /* position */ Square sq; Piece pce; int empty = 0; for (int rnk = RANK8; rnk >= RANK1; rnk--) { for (int fil = FILEA; fil <= FILEH; fil++) { sq = SQUARE(rnk, fil); pce = piece_at(sq); if (pce == NO_PIECE) { empty++; } else { if (empty != 0) { *s++ = '0' + empty; empty = 0; } if (color_at(sq) == WHITE) *s++ = toupper(piece_char[pce]); else *s++ = tolower(piece_char[pce]); } if (FIL(sq) == FILEH) { if (empty != 0) { *s++ = '0' + empty; empty = 0; } if (RNK(sq) != RANK1) *s++ = '/'; } } } /* side to move */ *s++ = ' '; *s++ = (side == WHITE) ? 'w' : 'b'; /* castling flags */ *s++ = ' '; if (flags & WKCASTLE) *s++ = 'K'; if (flags & WQCASTLE) *s++ = 'Q'; if (flags & BKCASTLE) *s++ = 'k'; if (flags & BQCASTLE) *s++ = 'q'; if (! (flags & (WCASTLE | BCASTLE))) *s++ = '-'; /* enpassant square, halfmove and fullmove clocks */ int n = snprintf(s, 20, " %s %d %d", (epsq != NO_SQUARE) ? square_str[epsq] : "-", movecnt50, moveno); s += n; return std::string(ss); } bool Board::parse_fen(const char * s) { clear(); char * p; char pos[80+1]; char clr; char flg[4+1]; char ep[2+1]; int hmc; int fmc; if (sscanf(s, "%80s %c %4s %2s %d %d", pos, &clr, flg, ep, &hmc, &fmc) != 6) return false; /* position */ int rnk = RANK8, fil = FILEA; Square sq; p = pos; while (*p) { if (fil > FILEH+1 || rnk < RANK1) return false; sq = SQUARE(rnk, fil); switch (*p++) { case 'P': place_piece(sq, WHITE, PAWN); fil++; break; case 'N': place_piece(sq, WHITE, KNIGHT); fil++; break; case 'B': place_piece(sq, WHITE, BISHOP); fil++; break; case 'R': place_piece(sq, WHITE, ROOK); fil++; break; case 'Q': place_piece(sq, WHITE, QUEEN); fil++; break; case 'K': place_piece(sq, WHITE, KING); fil++; break; case 'p': place_piece(sq, BLACK, PAWN); fil++; break; case 'n': place_piece(sq, BLACK, KNIGHT); fil++; break; case 'b': place_piece(sq, BLACK, BISHOP); fil++; break; case 'r': place_piece(sq, BLACK, ROOK); fil++; break; case 'q': place_piece(sq, BLACK, QUEEN); fil++; break; case 'k': place_piece(sq, BLACK, KING); fil++; break; case '8': fil += 8; break; case '7': fil += 7; break; case '6': fil += 6; break; case '5': fil += 5; break; case '4': fil += 4; break; case '3': fil += 3; break; case '2': fil += 2; break; case '1': fil += 1; break; case '/': fil = FILEA; rnk--; break; default: return false; } } /* side to move */ if (clr == 'w') set_side(WHITE); else if (clr == 'b') set_side(BLACK); else return false; /* castling flags */ p = flg; while (*p) { switch (*p++) { case 'K': set_flag(WKCASTLE); break; case 'Q': set_flag(WQCASTLE); break; case 'k': set_flag(BKCASTLE); break; case 'q': set_flag(BQCASTLE); break; case '-': break; default: return false; } } /* enpassant square */ if (ep[0] == '-') { clear_epsq(); } else { int f = ep[0] - 'a'; int r = ep[1] - '1'; if (f < FILEA || f > FILEH) return false; else if (r != RANK3 && r != RANK6) return false; set_epsq(SQUARE(r, f)); } /* halfmove and fullmove clocks */ movecnt50 = hmc; moveno = fmc; /* validate position */ if (!is_valid() || !is_legal()) return false; return true; } bool Board::parse_fen(const std::string & str) { return parse_fen(str.c_str()); } Move Board::parse_move(const std::string & str) const { /* * Compare the input against all possible moves in coordinate * notation and SAN. */ Movelist moves; generate_moves(&moves); moves.filter_illegal(*this); for (unsigned int i=0; i= 'a' && p[0] <= 'h' && p[1] >= '1' && p[1] <= '8' && p[2] >= 'a' && p[2] <= 'h' && p[3] >= '1' && p[3] <= '8') { /* * Coordinate notation */ from_file = p[0] - 'a'; from_rank = p[1] - '1'; to_file = p[2] - 'a'; to_rank = p[3] - '1'; from = SQUARE(from_rank, from_file); to = SQUARE(to_rank, to_file); ptype = piece_at(from); cap_ptype = piece_at(to); if (ptype == KING) { /* castling? */ if (side == WHITE && (flags & WKCASTLE) && from == E1 && to == G1) { return Move::castle(E1, G1); } else if (side == WHITE && (flags & WQCASTLE) && from == E1 && to == C1) { return Move::castle(E1, C1); } else if (side == BLACK && (flags & BKCASTLE) && from == E8 && to == G8) { return Move::castle(E8, G8); } else if (side == BLACK && (flags & BQCASTLE) && from == E8 && to == C8) { return Move::castle(E8, C8); } } if (len == 5) { /* Pawn promotion */ switch (p[4]) { case 'n': promo_ptype = KNIGHT; break; case 'b': promo_ptype = BISHOP; break; case 'r': promo_ptype = ROOK; break; case 'q': promo_ptype = QUEEN; break; default: return NO_MOVE; } if (cap_ptype != NO_PIECE) { return Move::promotion_capture(from, to, promo_ptype, cap_ptype); } else { return Move::promotion(from, to, promo_ptype); } } else { if (cap_ptype != NO_PIECE) { return Move::capture(from, to, ptype, cap_ptype); } else if (to == get_epsq()) { return Move::enpassant(from, to); } else { return Move::normal(from, to, ptype); } } } /* * SAN */ if (p[0] >= 'a' && p[0] <= 'h') { /* Pawn move */ if (p[1] == 'x' && p[2] >= 'a' && p[2] <= 'h' && p[3] >= '1' && p[3] <= '8') { /* capture */ from_file = p[0] - 'a'; to_file = p[2] - 'a'; to_rank = p[3] - '1'; if (side == WHITE) { from_rank = to_rank - 1; } else { from_rank = to_rank + 1; } from = SQUARE(from_rank, from_file); to = SQUARE(to_rank, to_file); cap_ptype = piece_at(to); if (p[4] == '=') { /* promotion capture */ switch (p[5]) { case 'N': promo_ptype = KNIGHT; break; case 'B': promo_ptype = BISHOP; break; case 'R': promo_ptype = ROOK; break; case 'Q': promo_ptype = QUEEN; break; default: return NO_MOVE; } return Move::promotion_capture(from, to, promo_ptype, cap_ptype); } else { /* non-promotion capture */ if (to == get_epsq()) { return Move::enpassant(from, to); } else { return Move::capture(from, to, PAWN, cap_ptype); } } } else if (p[1] >= '1' && p[1] <= '8') { /* non-capture */ from_file = p[0] - 'a'; to_file = p[0] - 'a'; to_rank = p[1] - '1'; if (side == WHITE) { if (to_rank == 3) { if (piece_at(SQUARE(2, from_file)) == PAWN) { /* one square ahead */ from_rank = 2; } else if (piece_at(SQUARE(1, from_file) == PAWN)) { /* two squares ahead */ from_rank = 1; } else { return NO_MOVE; } } else { from_rank = to_rank - 1; } } else { if (to_rank == 4) { if (piece_at(SQUARE(5, from_file)) == PAWN) { /* one square ahead */ from_rank = 5; } else if (piece_at(SQUARE(6, from_file) == PAWN)) { /* two squares ahead */ from_rank = 6; } else { return NO_MOVE; } } else { from_rank = to_rank + 1; } } from = SQUARE(from_rank, from_file); to = SQUARE(to_rank, to_file); if (p[2] == '=') { /* promotion non-capture */ switch (p[3]) { case 'N': promo_ptype = KNIGHT; break; case 'B': promo_ptype = BISHOP; break; case 'R': promo_ptype = ROOK; break; case 'Q': promo_ptype = QUEEN; break; default: return NO_MOVE; } return Move::promotion(from, to, promo_ptype); } else { /* non-promotion non-capture */ return Move::normal(from, to, PAWN); } } else { return NO_MOVE; } } /* * SAN: Non-Pawn move */ switch (*p++) { case 'N': ptype = KNIGHT; break; case 'B': ptype = BISHOP; break; case 'R': ptype = ROOK; break; case 'Q': ptype = QUEEN; break; case 'K': ptype = KING; break; default: return NO_MOVE; } int f1 = -1, r1 = -1, f2 = -1, r2 = -1; if (*p >= 'a' && *p <= 'h') { f1 = *p - 'a'; p++; } if (*p >= '1' && *p <= '8') { r1 = *p - '1'; p++; } bool capture = false; if (*p == 'x') { capture = true; p++; } if (*p >= 'a' && *p <= 'h') { f2 = *p - 'a'; p++; } if (*p >= '1' && *p <= '8') { r2 = *p - '1'; p++; } if (f2 != -1 && r2 != -1) { from_file = f1; from_rank = r1; to_file = f2; to_rank = r2; } else if (f2 == -1 && r2 == -1) { to_file = f1; to_rank = r1; } else { return NO_MOVE; } if (to_file == -1 || to_rank == -1) { return NO_MOVE; } to = SQUARE(to_rank, to_file); if (from_rank == -1 || from_file == -1) { Bitboard from_bb; switch (ptype) { case KNIGHT: from_bb = knight_attacks(to) & get_knights(side); break; case BISHOP: from_bb = bishop_attacks(to) & get_bishops(side); break; case ROOK: from_bb = rook_attacks(to) & get_rooks(side); break; case QUEEN: from_bb = queen_attacks(to) & get_queens(side); break; case KING: from_bb = king_attacks(to) & get_kings(side); break; default: BUG("should not get here"); } if (from_rank != -1) { from_bb &= Bitboard::rank[from_rank]; } if (from_file != -1) { from_bb &= Bitboard::file[from_file]; } unsigned int n = from_bb.popcnt(); if (n == 0) { return NO_MOVE; } else if (n == 1) { from = from_bb.firstbit(); } else { Bitboard pins = pinned(get_king(side), side); Bitboard ray = Bitboard::ray_bb[to][get_king(side)]; bool ok = false; while (from_bb) { from = from_bb.firstbit(); from_bb.clearbit(from); if (pins.testbit(from) && ray.testbit(from)) { ok = true; break; } else if (!pins.testbit(from)) { ok = true; break; } } if (!ok) { return NO_MOVE; } } } else { from = SQUARE(from_rank, from_file); } if (piece_at(from) != ptype) { return NO_MOVE; } cap_ptype = piece_at(to); if (capture && cap_ptype == NO_PIECE) { return NO_MOVE; } else if (!capture && cap_ptype != NO_PIECE) { return NO_MOVE; } if (cap_ptype != NO_PIECE) { return Move::capture(from, to, ptype, cap_ptype); } else { return Move::normal(from, to, ptype); } } bool Board::operator==(const Board & board) const { for (Piece pce = PAWN; pce <= KING; pce++) { if (position[WHITE][pce] != board.position[WHITE][pce]) return false; if (position[BLACK][pce] != board.position[BLACK][pce]) return false; } if (side != board.side || flags != board.flags || epsq != board.epsq) return false; return true; } hoichess_0.10.3/src/chess/board_attack.cc0000640000175000017500000000717410732031250017663 0ustar oliveroliver/* $Id: board_attack.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board_attack.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "bitboard.h" #include "basic.h" /* * Returns true if square 'to' is attacked by any piece of 'atkside'. */ bool Board::is_attacked(Square to, Color atkside) const { /* pawns */ if (pawn_captures(to, !atkside) & get_pawns(atkside)) return true; /* rooks and queens */ if (rook_attacks(to) & (get_rooks(atkside) | get_queens(atkside))) return true; /* bishops and queens */ if (bishop_attacks(to) & (get_bishops(atkside) | get_queens(atkside))) return true; /* knights */ if (knight_attacks(to) & get_knights(atkside)) return true; /* kings */ if (king_attacks(to) & get_kings(atkside)) return true; return false; } /* * Returns a Bitboard with all pieces of 'atkside' * that attack the square 'to'. */ Bitboard Board::attackers(Square to, Color atkside) const { Bitboard ret_bb = NULLBITBOARD; /* pawns */ ret_bb |= (pawn_captures(to, XSIDE(atkside)) & get_pawns(atkside)); /* knights */ ret_bb |= (knight_attacks(to) & get_knights(atkside)); /* bishops */ ret_bb |= (bishop_attacks(to) & get_bishops(atkside)); /* rooks */ ret_bb |= (rook_attacks(to) & get_rooks(atkside)); /* queens */ ret_bb |= (queen_attacks(to) & get_queens(atkside)); /* kings */ ret_bb |= (king_attacks(to) & get_kings(atkside)); return ret_bb; } /* * Find all pieces of 'side' that are pinned to side's piece on square 'to'. */ Bitboard Board::pinned(Square to, Color side) const { ASSERT_DEBUG(piece_at(to) != NO_PIECE); ASSERT_DEBUG(color_at(to) == side); Bitboard ret_bb = NULLBITBOARD; Bitboard bb; Bitboard tmp; Color atkside = XSIDE(side); Square from; /* bishops and queens */ bb = get_bishops(atkside) | get_queens(atkside); while (bb) { from = bb.firstbit(); bb.clearbit(from); /* all pieces on diagonal between from and to */ tmp = Bitboard::attack_bb[BISHOP][to] & Bitboard::ray_bb[from][to] & get_blocker(); /* if there are any pieces of atkside, there is no pin */ if (tmp & get_pieces(atkside)) { continue; } /* if there is exactly one piece of side, it is pinned */ //tmp &= get_pieces(side); if (tmp.popcnt() == 1) { Square sq = tmp.firstbit(); ret_bb.setbit(sq); } } /* rooks and queens */ bb = get_rooks(atkside) | get_queens(atkside); while (bb) { from = bb.firstbit(); bb.clearbit(from); /* all pieces on file or rank between from and to */ tmp = Bitboard::attack_bb[ROOK][to] & Bitboard::ray_bb[from][to] & get_blocker(); /* if there are any pieces of atkside, there is no pin */ if (tmp & get_pieces(atkside)) { continue; } /* if there is exactly one piece of side, it is pinned */ //tmp &= get_pieces(side); if (tmp.popcnt() == 1) { Square sq = tmp.firstbit(); ret_bb.setbit(sq); } } return ret_bb; } hoichess_0.10.3/src/chess/bitboard.h0000640000175000017500000001530110732031250016664 0ustar oliveroliver/* $Id: bitboard.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/bitboard.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef BITBOARD_H #define BITBOARD_H #include "common.h" #include "basic.h" #define NULLBITBOARD ((uint64_t) 0) class Bitboard { private: uint64_t bits; /* Constructors */ public: FORCEINLINE Bitboard(); FORCEINLINE Bitboard(uint64_t bits); /* Operators / Casts */ public: FORCEINLINE Bitboard & operator=(const Bitboard & bb); FORCEINLINE operator uint64_t() const; FORCEINLINE Bitboard operator&(const Bitboard & bb) const; FORCEINLINE Bitboard operator|(const Bitboard & bb) const; FORCEINLINE Bitboard operator~() const; FORCEINLINE Bitboard & operator&=(const Bitboard & bb); FORCEINLINE Bitboard & operator|=(const Bitboard & bb); FORCEINLINE Bitboard & operator++(); FORCEINLINE Bitboard operator++(int); /* Basic bitboard functions */ public: FORCEINLINE void setbit(unsigned int b); FORCEINLINE void clearbit(unsigned int b); FORCEINLINE bool testbit(unsigned int b) const; inline int firstbit() const; inline int lsb() const; inline int msb() const; inline int popcnt() const; /* Rotated attack functions */ public: inline Bitboard atk0(Square from) const; inline Bitboard atkl90(Square from) const; inline Bitboard atkl45(Square from) const; inline Bitboard atkr45(Square from) const; /* Utility functions */ public: void print() const; void print2() const; /* Static Data Members */ public: static Bitboard file[8]; static Bitboard rank[8]; static Bitboard attack_bb[6][64]; static Bitboard pawn_capt_bb[2][64]; static Bitboard ray_bb[64][64]; static Bitboard passed_pawn_mask[2][64]; static Bitboard isolated_pawn_mask[64]; static Bitboard connected_pawn_mask[64]; static const int map_l90[64]; static const int map_l45[64]; static const int map_r45[64]; private: static int8_t lsb_lut[65536]; static int8_t msb_lut[65536]; static int8_t popcnt_lut[65536]; static const Square inv_map_l90[64]; static const Square inv_map_l45[64]; static const Square inv_map_r45[64]; static const int shift_0[64]; static const int shift_l90[64]; static const int shift_l45[64]; static const int shift_r45[64]; static const int diaglen_l45[64]; static const int diaglen_r45[64]; static const int mask_l45[64]; static const int mask_r45[64]; static Bitboard rot_atk_0[64][256]; static Bitboard rot_atk_l90[64][256]; static Bitboard rot_atk_l45[64][256]; static Bitboard rot_atk_r45[64][256]; /* Static Member Functions */ public: static void init(); private: static void init_attack_bb(); static void init_pawn_capt_bb(); static void init_ray_bb(); static void init_masks(); static void init_rot_atk(); }; #if defined(__GNUC__) && defined(__i386__) #define USE_ASM_LSB #define USE_ASM_MSB //#define USE_ASM_POPCNT // LUT version is faster #include "i386/bitboard_asm.h" #elif defined(WIN32) #define USE_ASM_LSB #define USE_ASM_MSB //#define USE_ASM_POPCNT // LUT version is faster #include "win32/bitboard_asm.h" #endif inline Bitboard::Bitboard() : bits((uint64_t) 0) {} inline Bitboard::Bitboard(uint64_t _bits) : bits(_bits) {} inline Bitboard & Bitboard::operator=(const Bitboard & bb) { bits = bb.bits; return *this; } inline Bitboard::operator uint64_t() const { return bits; } inline Bitboard Bitboard::operator&(const Bitboard & bb) const { return bits & bb.bits; } inline Bitboard Bitboard::operator|(const Bitboard & bb) const { return bits | bb.bits; } inline Bitboard Bitboard::operator~() const { return ~bits; } inline Bitboard & Bitboard::operator&=(const Bitboard & bb) { bits &= bb.bits; return *this; } inline Bitboard & Bitboard::operator|=(const Bitboard & bb) { bits |= bb.bits; return *this; } /* This is the prefix operator++ */ inline Bitboard & Bitboard::operator++() { bits++; return *this; } /* This is the postfix operator++ */ inline Bitboard Bitboard::operator++(int) { Bitboard tmp = *this; bits++; return tmp; } inline void Bitboard::setbit(unsigned int b) { bits |= (((uint64_t) 1) << b); } inline void Bitboard::clearbit(unsigned int b) { bits &= ~(((uint64_t) 1) << b); } inline bool Bitboard::testbit(unsigned int b) const { return (bits & (((uint64_t) 1) << b)); } inline int Bitboard::firstbit() const { /* We take msb, because the LUT version of msb() is * faster than lsb(). */ return msb(); } /* * Lookup table version of msb/lsb scan routines. * This code was taken from GNU Chess. */ #ifndef USE_ASM_LSB inline int Bitboard::lsb() const { if (bits & 0xffff) return lsb_lut[bits & 0xffff]; if ((bits >> 16) & 0xffff) return lsb_lut[(bits >> 16) & 0xffff] + 16; if ((bits >> 32) & 0xffff) return lsb_lut[(bits >> 32) & 0xffff] + 32; if ((bits >> 48) & 0xffff) return lsb_lut[(bits >> 48) & 0xffff] + 48; return -1; } #endif #ifndef USE_ASM_MSB inline int Bitboard::msb() const { if (bits >> 48) return msb_lut[bits >> 48] + 48; if (bits >> 32) return msb_lut[bits >> 32] + 32; if (bits >> 16) return msb_lut[bits >> 16] + 16; return msb_lut[bits]; } #endif /* * Lookup table version of population count routine. * This code was taken from GNU Chess. */ #ifndef USE_ASM_POPCNT inline int Bitboard::popcnt() const { return popcnt_lut[bits & 0xffff] + popcnt_lut[(bits >> 16) & 0xffff] + popcnt_lut[(bits >> 32) & 0xffff] + popcnt_lut[(bits >> 48) & 0xffff]; } #endif /* * Rotated attack functions. * They obviously only make sense when called * for the matching rotated bitboard. */ inline Bitboard Bitboard::atk0(Square from) const { return rot_atk_0[from][(bits >> shift_0[from]) & 0xff]; } inline Bitboard Bitboard::atkl90(Square from) const { return rot_atk_l90[from][(bits >> shift_l90[from]) & 0xff]; } inline Bitboard Bitboard::atkl45(Square from) const { return rot_atk_l45[from][(bits >> shift_l45[from]) & mask_l45[from]]; } inline Bitboard Bitboard::atkr45(Square from) const { return rot_atk_r45[from][(bits >> shift_r45[from]) & mask_r45[from]]; } #endif // BITBOARD_H hoichess_0.10.3/src/chess/basic.h0000640000175000017500000000451510732031250016164 0ustar oliveroliver/* $Id: basic.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/basic.h * * Copyright (C) 2004-2007 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef BASIC_H #define BASIC_H #include "common.h" /* * Basic data types, macros and functions. */ typedef int Color; typedef int Piece; typedef int Square; enum colors { NO_COLOR = -1, WHITE, BLACK }; enum pieces { NO_PIECE = -1, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING }; enum squares { NO_SQUARE = -1, 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 }; #define BOARDSIZE 64 enum files { FILEA = 0, FILEB, FILEC, FILED, FILEE, FILEF, FILEG, FILEH }; enum ranks { RANK1 = 0, RANK2, RANK3, RANK4, RANK5, RANK6, RANK7, RANK8 }; #define FIL(sq) ((sq) % 8) #define RNK(sq) ((sq) / 8) #define SQUARE(rnk,fil) ((rnk)*8 + (fil)) #define XRANK(rnk) (RANK8-(rnk)) #define XSIDE(side) (!(side)) extern const char piece_char[6]; extern const char file_char[8]; extern const char rank_char[8]; extern const char square_str[64][3]; static const int mat_values[6] = { 100, // PAWN 300, // KNIGHT 325, // BISHOP 500, // ROOK 900, // QUEEN 0 // KING }; /* Manhattan distance between two squares. */ static inline int sq_distance(Square sq1, Square sq2) { return abs(RNK(sq1)-RNK(sq2)) + abs(FIL(sq1)-FIL(sq2)); } /* FEN of standard opening position. */ std::string opening_fen(); /* * Initialization function for basic stuff. */ extern void basic_init(); #endif // BASIC_H hoichess_0.10.3/src/chess/bitboard.cc0000640000175000017500000003467010732031250017034 0ustar oliveroliver/* $Id: bitboard.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/bitboard.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "bitboard.h" void Bitboard::print() const { for (int r=0; r<8; r++) { for (int c=0; c<8; c++) { if (testbit(r*8 + c)) printf(" X"); else printf(" +"); } printf("\n"); } } void Bitboard::print2() const { for (int r=7; r>=0; r--) { printf("%d ", r+1); for (int f=0; f<8; f++) { if (testbit(SQUARE(r, f))) printf(" X"); else printf(" +"); } printf("\n"); } printf(" a b c d e f g h\n"); } /***************************************************************************** * * Bitboard initialization. * *****************************************************************************/ int8_t Bitboard::lsb_lut[65536]; int8_t Bitboard::msb_lut[65536]; int8_t Bitboard::popcnt_lut[65536]; Bitboard Bitboard::file[8]; Bitboard Bitboard::rank[8]; Bitboard Bitboard::attack_bb[6][64]; Bitboard Bitboard::pawn_capt_bb[2][64]; Bitboard Bitboard::ray_bb[64][64]; Bitboard Bitboard::passed_pawn_mask[2][64]; Bitboard Bitboard::isolated_pawn_mask[64]; Bitboard Bitboard::connected_pawn_mask[64]; void Bitboard::init() { int i; /* lsb position lookup table */ for (i=0; i<65536; i++) { lsb_lut[i] = -1; for (int j=0; j<16; j++) { if (i & (1<=0; j--) { if (i & (1< FIL(to)) { dir = -1; } else if (RNK(from) < RNK(to) && FIL(from) == FIL(to)) { dir = 16; } else if (RNK(from) > RNK(to) && FIL(from) == FIL(to)) { dir = -16; } else if (RNK(from) < RNK(to) && FIL(from) < FIL(to) && attack_bb[BISHOP][from] .testbit(to)) { dir = 17; } else if (RNK(from) < RNK(to) && FIL(from) > FIL(to) && attack_bb[BISHOP][from] .testbit(to)) { dir = 15; } else if (RNK(from) > RNK(to) && FIL(from) < FIL(to) && attack_bb[BISHOP][from] .testbit(to)) { dir = -15; } else if (RNK(from) > RNK(to) && FIL(from) > FIL(to) && attack_bb[BISHOP][from] .testbit(to)) { dir = -17; } else { continue; } int s = f+dir; while (s != t) { sq = map0x88[s]; ray_bb[from][to].setbit(sq); s += dir; } } } } void Bitboard::init_masks() { for (Square sq=A1; sq<=H8; sq++) { int r, f; /* passed_pawn_mask[WHITE]: * + + X X X + + + * + + X X X + + + * + + + P + + + + * + + + + + + + + * + + + + + + + + */ passed_pawn_mask[WHITE][sq] = NULLBITBOARD; for (r=RNK(sq)+1; r<=7; r++) { f = FIL(sq); passed_pawn_mask[WHITE][sq].setbit(SQUARE(r, f)); if (f > 0) { passed_pawn_mask[WHITE][sq] .setbit(SQUARE(r, f-1)); } if (f < 7) { passed_pawn_mask[WHITE][sq] .setbit(SQUARE(r, f+1)); } } /* passed_pawn_mask[BLACK] ... */ passed_pawn_mask[BLACK][sq] = NULLBITBOARD; for (r=RNK(sq)-1; r>=0; r--) { f = FIL(sq); passed_pawn_mask[BLACK][sq].setbit(SQUARE(r, f)); if (f > 0) { passed_pawn_mask[BLACK][sq] .setbit(SQUARE(r, f-1)); } if (f < 7) { passed_pawn_mask[BLACK][sq] .setbit(SQUARE(r, f+1)); } } /* isolated_pawn_mask: * + + X X X + + + * + + X X X + + + * + + X P X + + + * + + X X X + + + * + + X X X + + + */ f = FIL(sq); isolated_pawn_mask[sq] = file[f]; if (f > 0) { isolated_pawn_mask[sq] |= file[f-1]; } if (f < 7) { isolated_pawn_mask[sq] |= file[f+1]; } /* connected_pawn_mask: * + + + + + + + + * + + X + X + + + * + + X P X + + + * + + X + X + + + * + + + + + + + + */ connected_pawn_mask[sq] = attack_bb[KING][sq] & ~file[FIL(sq)]; } } /***************************************************************************** * * Stuff needed for rotated bitboards. * *****************************************************************************/ const int Bitboard::shift_0[] = { 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56 }; const int Bitboard::map_l90[] = { 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 28, 20, 12, 4, 61, 53, 45, 37, 29, 21, 13, 5, 62, 54, 46, 38, 30, 22, 14, 6, 63, 55, 47, 39, 31, 23, 15, 7 }; const Square Bitboard::inv_map_l90[] = { H1, H2, H3, H4, H5, H6, H7, H8, G1, G2, G3, G4, G5, G6, G7, G8, F1, F2, F3, F4, F5, F6, F7, F8, E1, E2, E3, E4, E5, E6, E7, E8, D1, D2, D3, D4, D5, D6, D7, D8, C1, C2, C3, C4, C5, C6, C7, C8, B1, B2, B3, B4, B5, B6, B7, B8, A1, A2, A3, A4, A5, A6, A7, A8 }; const int Bitboard::shift_l90[] = { 56, 48, 40, 32, 24, 16, 8, 0, 56, 48, 40, 32, 24, 16, 8, 0, 56, 48, 40, 32, 24, 16, 8, 0, 56, 48, 40, 32, 24, 16, 8, 0, 56, 48, 40, 32, 24, 16, 8, 0, 56, 48, 40, 32, 24, 16, 8, 0, 56, 48, 40, 32, 24, 16, 8, 0, 56, 48, 40, 32, 24, 16, 8, 0 }; const int Bitboard::map_l45[] = { 28, 21, 15, 10, 6, 3, 1, 0, 36, 29, 22, 16, 11, 7, 4, 2, 43, 37, 30, 23, 17, 12, 8, 5, 49, 44, 38, 31, 24, 18, 13, 9, 54, 50, 45, 39, 32, 25, 19, 14, 58, 55, 51, 46, 40, 33, 26, 20, 61, 59, 56, 52, 47, 41, 34, 27, 63, 62, 60, 57, 53, 48, 42, 35 }; const Square Bitboard::inv_map_l45[] = { H1, G1, H2, F1, G2, H3, E1, F2, G3, H4, D1, E2, F3, G4, H5, C1, D2, E3, F4, G5, H6, B1, C2, D3, E4, F5, G6, H7, A1, B2, C3, D4, E5, F6, G7, H8, A2, B3, C4, D5, E6, F7, G8, A3, B4, C5, D6, E7, F8, A4, B5, C6, D7, E8, A5, B6, C7, D8, A6, B7, C8, A7, B8, A8 }; const int Bitboard::shift_l45[] = { 28, 21, 15, 10, 6, 3, 1, 0, 36, 28, 21, 15, 10, 6, 3, 1, 43, 36, 28, 21, 15, 10, 6, 3, 49, 43, 36, 28, 21, 15, 10, 6, 54, 49, 43, 36, 28, 21, 15, 10, 58, 54, 49, 43, 36, 28, 21, 15, 61, 58, 54, 49, 43, 36, 28, 21, 63, 61, 58, 54, 49, 43, 36, 28 }; const int Bitboard::diaglen_l45[] = { 8, 7, 6, 5, 4, 3, 2, 1, 7, 8, 7, 6, 5, 4, 3, 2, 6, 7, 8, 7, 6, 5, 4, 3, 5, 6, 7, 8, 7, 6, 5, 4, 4, 5, 6, 7, 8, 7, 6, 5, 3, 4, 5, 6, 7, 8, 7, 6, 2, 3, 4, 5, 6, 7, 8, 7, 1, 2, 3, 4, 5, 6, 7, 8 }; const int Bitboard::mask_l45[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; const int Bitboard::map_r45[] = { 0, 2, 5, 9, 14, 20, 27, 35, 1, 4, 8, 13, 19, 26, 34, 42, 3, 7, 12, 18, 25, 33, 41, 48, 6, 11, 17, 24, 32, 40, 47, 53, 10, 16, 23, 31, 39, 46, 52, 57, 15, 22, 30, 38, 45, 51, 56, 60, 21, 29, 37, 44, 50, 55, 59, 62, 28, 36, 43, 49, 54, 58, 61, 63 }; const Square Bitboard::inv_map_r45[] = { A1, A2, B1, A3, B2, C1, A4, B3, C2, D1, A5, B4, C3, D2, E1, A6, B5, C4, D3, E2, F1, A7, B6, C5, D4, E3, F2, G1, A8, B7, C6, D5, E4, F3, G2, H1, B8, C7, D6, E5, F4, G3, H2, C8, D7, E6, F5, G4, H3, D8, E7, F6, G5, H4, E8, F7, G6, H5, F8, G7, H6, G8, H7, H8 }; const int Bitboard::shift_r45[] = { 0, 1, 3, 6, 10, 15, 21, 28, 1, 3, 6, 10, 15, 21, 28, 36, 3, 6, 10, 15, 21, 28, 36, 43, 6, 10, 15, 21, 28, 36, 43, 49, 10, 15, 21, 28, 36, 43, 49, 54, 15, 21, 28, 36, 43, 49, 54, 58, 21, 28, 36, 43, 49, 54, 58, 61, 28, 36, 43, 49, 54, 58, 61, 63 }; const int Bitboard::diaglen_r45[] = { 1, 2, 3, 4, 5, 6, 7, 8, 2, 3, 4, 5, 6, 7, 8, 7, 3, 4, 5, 6, 7, 8, 7, 6, 4, 5, 6, 7, 8, 7, 6, 5, 5, 6, 7, 8, 7, 6, 5, 4, 6, 7, 8, 7, 6, 5, 4, 3, 7, 8, 7, 6, 5, 4, 3, 2, 8, 7, 6, 5, 4, 3, 2, 1 }; const int Bitboard::mask_r45[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; Bitboard Bitboard::rot_atk_0[64][256]; Bitboard Bitboard::rot_atk_l90[64][256]; Bitboard Bitboard::rot_atk_l45[64][256]; Bitboard Bitboard::rot_atk_r45[64][256]; void Bitboard::init_rot_atk() { Bitboard tmp; int f, t; Square to; for (Bitboard occ=((uint64_t) 0); occ<((uint64_t) 256); occ++) { for (Square from=A1; from<=H8; from++) { /* rot_atk_0[][] */ tmp = NULLBITBOARD; f = from % 8; for (t=0; t<8; t++) { if (occ & ray_bb[f][t] || f == t) continue; tmp.setbit(t); } rot_atk_0[from][occ] = tmp << shift_0[from]; /* rot_atk_l90[][] */ tmp = NULLBITBOARD; f = map_l90[from] % 8; for (t=0; t<8; t++) { if (occ & ray_bb[f][t] || f == t) continue; to = inv_map_l90[shift_l90[from] + t]; tmp.setbit(to); } rot_atk_l90[from][occ] = tmp; /* rot_atk_l45[][] */ tmp = NULLBITBOARD; f = map_l45[from] - shift_l45[from]; for (t=0; t * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "eval.h" #include "bitboard.h" #include "board.h" /***************************************************************************** * * Main evaluation functions. * *****************************************************************************/ /* * Advanced draw detection. * Basics are done in Search::is_draw() (repetitions, 50 move rule) * and Board::is_material_draw() (insufficient material). */ bool Evaluator::is_draw(const Board & board) { /* TODO */ (void) board; return false; } #if 1 /* * Calculate material balance. To discourage piece tradeing * for side that has less material, we multiply the actual * material difference by a factor that gets higher when * the total amount of material is lower: * * / max_mat - (mat[s]+mat[xs]) \ * bal = | -------------------------- + 1 | * (mat[s]-mat[xs]) * \ max_mat * k / * * k is some scaling constant, k=8 seems to give good results. * max_mat is the maximum possible material value (2*3950 = 7900). * However, to make use of fast shift operations, we define * max_mat = 8192. * * Example: Let's say xside is one pawn behind, e.g. * ms = 1200, mxs = 1100 => bal = 108 * Now a rook is traded: * ms = 700, mxs = 600 => bal = 110 * Obviously, tradeing a rook is bad for the side that has less material. * * To avoid floating point calculations, we slightly transform above * equation so that the division becomes the last operation. */ int Evaluator::material_balance(int ms, int mxs) { const int k = 8; const int max_mat = 8192; int bal = (max_mat - (ms+mxs) + max_mat * k) * (ms-mxs) / (max_mat * k); return bal; } #else int Evaluator::material_balance(int ms, int mxs) { return ms-mxs; } #endif /* * This is a first try to implement a material based phase * detection routine. There is a least some fine-tuning that * we must do. */ unsigned int Evaluator::get_phase(const Board & board) { const int mat = board.material[WHITE] + board.material[BLACK]; /* Starting material is 7900 */ if (mat > 7000) { return OPENING; } else if (mat > 3200) { return MIDGAME; } else { return ENDGAME; } } void Evaluator::setup(const Board * board) { ASSERT_DEBUG(board != NULL); this->board = board; // const Color side = board->get_side(); // const Color xside = XSIDE(side); phase = get_phase(*board); if (pawnhashtable) { if (pawnhashtable->probe(board->get_pawnhashkey(), &pawnhashentry)){ if (pawnhashentry.get_phase() == phase) { pawnhashtable->incr_hits2(); } } /* probe() marks entry invalid if nothing was found in * the table, so we don't need to do this here again. */ } else { pawnhashentry.set_invalid(); } // pinned_on_king[side] = board->pinned(board->get_king(side), side); // pinned_on_king[xside] = board->pinned(board->get_king(xside), xside); } void Evaluator::finish() { if (pawnhashtable) { pawnhashentry.set_hashkey(board->get_pawnhashkey()); pawnhashentry.set_phase(phase); pawnhashtable->put(pawnhashentry); } } /***************************************************************************** * * Scoring plugins * *****************************************************************************/ const struct score_plugin Evaluator::plugins[] = { { "pawns", &Evaluator::score_pawns }, { "knights", &Evaluator::score_knights }, { "bishops", &Evaluator::score_bishops }, { "rooks", &Evaluator::score_rooks }, { "queens", &Evaluator::score_queens }, { "king", &Evaluator::score_king }, { "devel", &Evaluator::score_devel }, { "combo", &Evaluator::score_combo }, { NULL, NULL } }; const struct score_plugin Evaluator::plugins2[] = { { "control", &Evaluator::score_control }, { NULL, NULL } }; const int Evaluator::pawn_scores_opening[] = { 0, 0, 0, 0, 0, 0, 0, 0, 8, 5, 8,-10,-15, 8, 5, 8, -5, 5, 0, -8, -8, 0, 5, -5, -5, -5, -5, 24, 32, -5, -5, -5, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 8, 8, 8, 8, 0, 0, 0, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const int Evaluator::pawn_scores_midgame[] = { 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 4,-25,-25, 4, 5, 5, 0, 0, 0,-10,-10, 0, 0, 0, 0, 0, 0, 32, 32, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 8, 8, 8, 8, 0, 0, 0, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const int Evaluator::pawn_scores_endgame[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0 }; const int Evaluator::knight_scores[] = { -15, -5, -5, -5, -5, -5, -5,-15, -5, 0, 0, 0, 0, 0, 0, -5, -5, 0, 5, 5, 5, 5, 0, -5, -5, 0, 5, 10, 10, 5, 0, -5, -5, 0, 5, 10, 10, 5, 0, -5, -5, 0, 5, 5, 5, 5, 0, -5, -5, 0, 0, 0, 0, 0, 0, -5, -15, -5, -5, -5, -5, -5, -5,-15 }; const int Evaluator::king_scores[] = { 12, 12, 10, 0, 0, 10, 16, 16, 0,-70,-70,-70,-70,-70,-70, 0, 0,-70,-75,-75,-75,-75,-70, 0, 0,-70,-75,-80,-80,-75,-70, 0, 0,-70,-75,-80,-80,-75,-70, 0, 0,-70,-75,-75,-75,-75,-70, 0, 0,-70,-70,-70,-70,-70,-70, 0, 12, 12, 10, 0, 0, 10, 16, 16 }; const int Evaluator::king_scores_endgame[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 5, 15, 15, 15, 15, 5, 0, 0, 5, 15, 20, 20, 15, 5, 0, 0, 5, 15, 20, 20, 15, 5, 0, 0, 5, 15, 15, 15, 15, 5, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * Pawn evaluation. */ #define EVAL_DOUBLEPAWNS -5 /* TODO perhaps -50 ? */ //#define EVAL_EIGHTPAWNS -10 //#define EVAL_PAWNRAMS -10 #define EVAL_ISOLATEDPAWN -10 #define EVAL_PASSEDPAWN(dist) (25 + 80/(dist)) #define EVAL_CONNECTEDPP 20 int Evaluator::score_pawns(Color side) { int score = 0; /* * First look if pawn hash table probe was successful. */ if (pawnhashentry.is_valid() && pawnhashentry.get_phase() == phase) { passed_pawns[side] = pawnhashentry.get_passed(side); return pawnhashentry.get_score(side); } else { passed_pawns[side] = NULLBITBOARD; } /* * Do normal pawn evaluation. */ Square sq; Bitboard pawns = board->get_pawns(side); #ifdef EVAL_DOUBLEPAWNS /* Penalize doubled pawns */ for (int f=FILEA; f<=FILEH; f++) { if ((pawns & Bitboard::file[f]).popcnt() > 1) { score += EVAL_DOUBLEPAWNS; } } #endif #ifdef EVAL_EIGHTPAWNS /* Penalize having eight pawns */ if (side == myside && pawns.popcnt() == 8) { score += EVAL_EIGHTPAWNS; } #endif while (pawns) { sq = pawns.firstbit(); pawns.clearbit(sq); /* Positional score */ const Square idx = (side == WHITE) ? sq : SQUARE(XRANK(RNK(sq)),FIL(sq)); if (phase == ENDGAME) { score += pawn_scores_endgame[idx]; } else if (phase == MIDGAME) { score += pawn_scores_midgame[idx]; } else { score += pawn_scores_opening[idx]; } #ifdef EVAL_PAWNRAMS /* Pawn rams */ if (side == myside) { Square ram_sq = (side == WHITE) ? sq+8 : sq-8; if (board->get_pawns(XSIDE(side)).testbit(ram_sq)) { score += EVAL_PAWNRAMS; } } #endif #ifdef EVAL_ISOLATEDPAWN /* Isolated pawn? */ if (! (Bitboard::isolated_pawn_mask[sq] & board->get_pawns(side))) { score += EVAL_ISOLATEDPAWN; } #endif #ifdef EVAL_PASSEDPAWN /* Passed pawn? */ Bitboard pp_mask = Bitboard::passed_pawn_mask[side][sq]; if (! (pp_mask & board->get_pawns(XSIDE(side)))) { passed_pawns[side].setbit(sq); /* Bonus for small distance to promotion rank. */ const int rank8 = (side == WHITE) ? RANK8 : RANK1; const int dist = abs(rank8 - RNK(sq)); ASSERT_DEBUG(dist > 0); score += EVAL_PASSEDPAWN(dist); #ifdef EVAL_CONNECTEDPP /* Connected passed pawns. We look for passed pawns * that are already determined and stored in * passed_pawns[]. This will always work, no matter * in which order we process our pawns. */ if (passed_pawns[side] & Bitboard::connected_pawn_mask[sq]) { score += EVAL_CONNECTEDPP; } #endif } #endif /* EVAL_PASSEDPAWN */ } pawnhashentry.set_score(side, score); pawnhashentry.set_passed(side, passed_pawns[side]); return score; } /* * Knight evaluation. */ #define EVAL_KNIGHTMOBILITY 2 //#define EVAL_PINNEDKNIGHT -30 int Evaluator::score_knights(Color side) { int score = 0; Square sq; Bitboard knights = board->get_knights(side); while (knights) { sq = knights.firstbit(); knights.clearbit(sq); /* Positional score */ score += knight_scores[sq]; #ifdef EVAL_KNIGHTMOBILITY /* Simple mobility bonus */ Bitboard ka = board->knight_attacks(sq) & ~board->get_pieces(side); score += ka.popcnt() * EVAL_KNIGHTMOBILITY; #endif #ifdef EVAL_PINNEDKNIGHT /* Pinned knight? */ if (pinned_on_king[side].testbit(sq)) { score += EVAL_PINNEDKNIGHT; } #endif } return score; } /* * Bishop evaluation. */ #define EVAL_BISHOPMOBILITY 2 //#define EVAL_PINNEDBISHOP -30 #define EVAL_BISHOPPAWN 25 #define EVAL_FIANCHETTOBISHOP 15 int Evaluator::score_bishops(Color side) { int score = 0; Square sq; Bitboard bishops = board->get_bishops(side); while (bishops) { sq = bishops.firstbit(); bishops.clearbit(sq); #ifdef EVAL_BISHOPMOBILITY /* Simple mobility bonus */ Bitboard ba = board->bishop_attacks(sq) & ~board->get_pieces(side); score += ba.popcnt() * EVAL_BISHOPMOBILITY; #endif #ifdef EVAL_PINNEDBISHOP /* Pinned bishop? */ if (pinned_on_king[side].testbit(sq)) { score += EVAL_PINNEDBISHOP; } #endif #ifdef EVAL_BISHOPPAWN /* Bishop protected by pawn(s)? */ Bitboard bp = board->pawn_captures(sq, XSIDE(side)) & board->get_pawns(side); score += bp.popcnt() * EVAL_BISHOPPAWN; #endif #ifdef EVAL_FIANCHETTOBISHOP /* Fianchetto Bishop */ if ( (side == WHITE && (sq == B2 || sq == G2)) || (side == BLACK && (sq == B7 || sq == G7))) { score += EVAL_FIANCHETTOBISHOP; } #endif } return score; } /* * Rook evaluation. */ #define EVAL_ROOKMOBILITY 2 #define EVAL_ROOKOPENFILE 10 #define EVAL_ROOKHALFOPENFILE 5 #define EVAL_ROOK7PAWNS7 20 // FIXME too high? #define EVAL_ROOK7KING8 50 // FIXME too high? #define EVAL_ROOKINFRONTPP -15 #define EVAL_ROOKBEHINDPP 25 //#define EVAL_PINNEDROOK -50 int Evaluator::score_rooks(Color side) { int score = 0; const Color xside = XSIDE(side); const int rank7 = (side == WHITE) ? RANK7 : RANK2; const int rank8 = (side == WHITE) ? RANK8 : RANK1; Square sq; Bitboard rooks = board->get_rooks(side); while (rooks) { sq = rooks.firstbit(); rooks.clearbit(sq); #ifdef EVAL_ROOKMOBILITY /* Simple mobility bonus */ Bitboard ra = board->rook_attacks(sq) & ~board->get_pieces(side); score += ra.popcnt() * EVAL_ROOKMOBILITY; #endif #if defined(EVAL_ROOKOPENFILE) && defined(EVAL_ROOKHALFOPENFILE) /* Rook on open/half-open file */ if (! (Bitboard::file[FIL(sq)] & board->get_pawns(side)) ) { if (! (Bitboard::file[FIL(sq)] & board->get_pawns(xside)) ) { score += EVAL_ROOKOPENFILE; } else { score += EVAL_ROOKHALFOPENFILE; } } #endif #if defined(EVAL_ROOK7PAWNS7) || defined(EVAL_ROOK7KING8) /* Rook on 7th rank and ...*/ if (phase != ENDGAME && RNK(sq) == rank7) { #ifdef EVAL_ROOK7PAWNS7 /* ... enemy pawns on 7th rank */ if (board->get_pawns(XSIDE(side)) & Bitboard::rank[rank7]) { score += EVAL_ROOK7PAWNS7; } #endif #ifdef EVAL_ROOK7KING8 /* ... enemy king on 8th rank */ if (RNK(board->get_king(XSIDE(side))) == rank8) { score += EVAL_ROOK7KING8; } #endif } #endif #if defined(EVAL_ROOKINFRONTPP) || defined(EVAL_ROOKBEHINDPP) Bitboard pps = passed_pawns[side] & Bitboard::file[FIL(sq)]; while (pps) { Square pp = pps.firstbit(); pps.clearbit(pp); #ifdef EVAL_ROOKINFRONTPP /* Rook in front of passed pawn */ if ( (side == WHITE && RNK(sq) > RNK(pp)) || (side == BLACK && RNK(sq) < RNK(pp))) { score += EVAL_ROOKINFRONTPP; } #endif #ifdef EVAL_ROOKBEHINDPP /* Rook behind passed pawn */ if ( (side == WHITE && RNK(sq) < RNK(pp)) || (side == BLACK && RNK(sq) > RNK(pp))) { score += EVAL_ROOKBEHINDPP; } #endif } #endif /* defined(EVAL_ROOKINFRONTPP) || defined(EVAL_ROOKBEHINDPP) */ #ifdef EVAL_PINNEDROOK /* Pinned rook? */ if (pinned_on_king[side].testbit(sq)) { score += EVAL_PINNEDROOK; } #endif } return score; } /* * Queen evaluation. */ //#define EVAL_QUEENNOTPRESENT -40 #define EVAL_QUEENMOBILITY 1 //#define EVAL_QUEENNEARENEMYKING 5 //#define EVAL_PINNEDQUEEN -90 int Evaluator::score_queens(Color side) { int score = 0; Square sq; Bitboard queens = board->get_queens(side); #ifdef EVAL_QUEENNOTPRESENT if (side == myside && !queens) { score += EVAL_QUEENNOTPRESENT; return score; } #endif while (queens) { sq = queens.firstbit(); queens.clearbit(sq); #ifdef EVAL_QUEENMOBILITY /* Simple mobility bonus */ Bitboard qa = board->queen_attacks(sq) & ~board->get_pieces(side); score += qa.popcnt() * EVAL_QUEENMOBILITY; #endif #ifdef EVAL_PINNEDQUEEN /* Pinned queen? */ if (pinned_on_king[side].testbit(sq)) { score += EVAL_PINNEDQUEEN; } #endif #ifdef EVAL_QUEENNEARENEMYKING /* Queen near enemy king */ Square xking = board->get_king(XSIDE(side)); unsigned int dist = sq_distance(sq, xking); if (dist < 5) { score += dist * EVAL_QUEENNEARENEMYKING; } #endif } return score; } /* * King evaluation. */ //#define EVAL_SQAROUNDKINGATKD -4 int Evaluator::score_king(Color side) { int score = 0; const Square kingsq = board->get_king(side); if (phase == ENDGAME) { score += king_scores_endgame[kingsq]; } else { score += king_scores[kingsq]; } #ifdef EVAL_SQAROUNDKINGATKD /* Enemy pieces attacking squares around king */ Bitboard attackers = NULLBITBOARD; Bitboard bb = Bitboard::attack_bb[KING][kingsq]; while (bb) { Square sq = bb.firstbit(); bb.clearbit(sq); attackers |= board->attackers(sq, XSIDE(side)); } score += attackers.popcnt() * EVAL_SQAROUNDKINGATKD; #endif return score; } /* * Evaluation of development (in opening phase). */ #define EVAL_MINORNOTDEV -15 #define EVAL_EARLYROOKMOVE -20 #define EVAL_EARLYQUEENMOVE -25 #define EVAL_CASTLED 32 #define EVAL_CANCASTLE 16 int Evaluator::score_devel(Color side) { int score = 0; if (phase != OPENING) return score; #ifdef EVAL_MINORNOTDEV /* Penalize any unmoved knights/bishops. */ Bitboard minor = board->get_knights(side) | board->get_bishops(side); while (minor) { Square sq = minor.firstbit(); minor.clearbit(sq); if (board->get_pce_movecnt(sq) == 0) { score += EVAL_MINORNOTDEV; } } #endif #ifdef EVAL_EARLYROOKMOVE /* Penalize early rook moves. */ Bitboard rooks = board->get_rooks(side); while (rooks) { Square sq = rooks.firstbit(); rooks.clearbit(sq); if (board->get_pce_movecnt(sq) > 0) { score += EVAL_EARLYROOKMOVE; } } #endif #ifdef EVAL_EARLYQUEENMOVE /* Penalize early queen moves. */ Bitboard queens = board->get_queens(side); while (queens) { Square sq = queens.firstbit(); queens.clearbit(sq); if (board->get_pce_movecnt(sq) > 0) { score += EVAL_EARLYQUEENMOVE; } } #endif #if defined(EVAL_CASTLED) && defined(EVAL_CANCASTLE) /* Give a bonus for being castled, and a smaller bonus for * still being available to. */ if (board->has_castled[side]) { score += EVAL_CASTLED; } else if (board->flags & (side == WHITE ? WCASTLE : BCASTLE)) { score += EVAL_CANCASTLE; } #endif return score; } /* * Evaluation of mixed-piece combinations. */ #define EVAL_QBCOMBO 15 #define EVAL_QRCOMBO 30 int Evaluator::score_combo(Color side) { int score = 0; /* Look for bishop/queen and rook/queen combo. */ Bitboard queens = board->get_queens(side); while (queens) { Square q = queens.firstbit(); queens.clearbit(q); #ifdef EVAL_QBCOMBO /* bishop/queen */ Bitboard bq_bb = board->bishop_attacks(q) & board->get_bishops(side); while (bq_bb) { Square b = bq_bb.firstbit(); bq_bb.clearbit(b); if (! (board->get_blocker() & Bitboard::ray_bb[q][b])) { score += EVAL_QBCOMBO; } } #endif #ifdef EVAL_QRCOMBO /* rook/queen */ Bitboard rq_bb = board->rook_attacks(q) & board->get_rooks(side); while (rq_bb) { Square r = rq_bb.firstbit(); rq_bb.clearbit(r); if (! (board->get_blocker() & Bitboard::ray_bb[q][r])) { score += EVAL_QRCOMBO; } } #endif } return score; } /* * Control over board. */ const int Evaluator::control_score[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 2, 3, 3, 3, 3, 2, 1, 1, 2, 3, 4, 4, 3, 2, 1, 1, 2, 3, 4, 4, 3, 2, 1, 1, 2, 3, 3, 3, 3, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; const unsigned int Evaluator::control_maxattackers[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 5, 5, 5, 5, 7, 8, 8, 7, 5, 5, 5, 5, 7, 8, 8, 7, 5, 5, 5, 5, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; int Evaluator::score_control(Color side) { int score = 0; for (Square sq = A1; sq <= H8; sq++) { Bitboard attackers = board->attackers(sq, side); unsigned int nr_attackers = attackers.popcnt(); score += control_score[sq] * MIN(nr_attackers, control_maxattackers[sq]); } return score; } hoichess_0.10.3/src/chess/board_generate.cc0000640000175000017500000003717210732031250020207 0ustar oliveroliver/* $Id: board_generate.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board_generate.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "bitboard.h" #include "move.h" #include "basic.h" /* * Should we use an independent generate_moves() routine, or simply call * generate_captures() and generate_noncaptures()? */ //#define USE_INDEPENDENT_GENERATE_MOVES void Board::generate_moves(Movelist * movelist, bool allpromo) const { #ifndef USE_INDEPENDENT_GENERATE_MOVES generate_captures(movelist, allpromo); generate_noncaptures(movelist); #else Bitboard bb, to_bb; Square from, to; /* pawn promotions and promotion-captures */ bb = get_pawns(side) & (side == WHITE ? Bitboard::rank[RANK7] : Bitboard::rank[RANK2]); while (bb) { from = bb.firstbit(); bb.clearbit(from); /* promotion-captures */ to_bb = pawn_captures(from, side) & get_pieces(opponent); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); Piece cpce = piece_at(to); movelist->add(Move::promotion_capture(from, to, QUEEN, cpce)); movelist->add(Move::promotion_capture(from, to, KNIGHT, cpce)); if (allpromo) { movelist->add(Move::promotion_capture(from, to, BISHOP, cpce)); movelist->add(Move::promotion_capture(from, to, ROOK, cpce)); } } /* promotions */ to_bb = pawn_noncaptures(from, side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::promotion(from, to, QUEEN)); movelist->add(Move::promotion(from, to, KNIGHT)); if (allpromo) { movelist->add(Move::promotion(from, to, BISHOP)); movelist->add(Move::promotion(from, to, ROOK)); } } } /* pawn non-promotions */ bb = get_pawns(side) & ~(side == WHITE ? Bitboard::rank[RANK7] : Bitboard::rank[RANK2]); while (bb) { from = bb.firstbit(); bb.clearbit(from); /* captures */ to_bb = pawn_captures(from, side) & ~get_pieces(side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); if (to == epsq) { movelist->add(Move::enpassant(from, to)); } else { movelist->add(Move::capture(from, to, PAWN, piece_at(to))); } } /* non-captures */ to_bb = pawn_noncaptures(from, side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::normal(from, to, PAWN)); } } /* knights */ bb = get_knights(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = knight_attacks(from) & ~get_pieces(side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); if (get_pieces(opponent).testbit(to)) { movelist->add(Move::capture(from, to, KNIGHT, piece_at(to))); } else { movelist->add(Move::normal(from, to, KNIGHT)); } } } /* bishops */ bb = get_bishops(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = bishop_attacks(from) & ~get_pieces(side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); if (get_pieces(opponent).testbit(to)) { movelist->add(Move::capture(from, to, BISHOP, piece_at(to))); } else { movelist->add(Move::normal(from, to, BISHOP)); } } } /* rooks */ bb = get_rooks(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = rook_attacks(from) & ~get_pieces(side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); if (get_pieces(opponent).testbit(to)) { movelist->add(Move::capture(from, to, ROOK, piece_at(to))); } else { movelist->add(Move::normal(from, to, ROOK)); } } } /* queens */ bb = get_queens(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = queen_attacks(from) & ~get_pieces(side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); if (get_pieces(opponent).testbit(to)) { movelist->add(Move::capture(from, to, QUEEN, piece_at(to))); } else { movelist->add(Move::normal(from, to, QUEEN)); } } } /* king, only one */ from = get_king(side); to_bb = king_attacks(from) & ~get_pieces(side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); if (get_pieces(opponent).testbit(to)) { movelist->add(Move::capture(from, to, KING, piece_at(to))); } else { movelist->add(Move::normal(from, to, KING)); } } /* try castling */ generate_castling(movelist); #endif // USE_INDEPENDENT_GENERATE_MOVES } /* * This routine generates all moves that change the material value on * the board. This includes pawn promotions, not only captures. * Promotions into bishop and rook are only generated when allpromo == true, * because we want so skip those useless moves during search. */ void Board::generate_captures(Movelist * movelist, bool allpromo) const { Bitboard bb, to_bb; Square from, to; /* pawn promotions and promotion-captures */ bb = get_pawns(side) & (side == WHITE ? Bitboard::rank[RANK7] : Bitboard::rank[RANK2]); while (bb) { from = bb.firstbit(); bb.clearbit(from); /* promotion-captures */ to_bb = pawn_captures(from, side) & get_pieces(opponent); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); Piece cpce = piece_at(to); movelist->add(Move::promotion_capture(from, to, QUEEN, cpce)); movelist->add(Move::promotion_capture(from, to, KNIGHT, cpce)); if (allpromo) { movelist->add(Move::promotion_capture(from, to, BISHOP, cpce)); movelist->add(Move::promotion_capture(from, to, ROOK, cpce)); } } /* promotions */ to_bb = pawn_noncaptures(from, side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::promotion(from, to, QUEEN)); movelist->add(Move::promotion(from, to, KNIGHT)); if (allpromo) { movelist->add(Move::promotion(from, to, BISHOP)); movelist->add(Move::promotion(from, to, ROOK)); } } } /* pawn captures */ bb = get_pawns(side) & ~(side == WHITE ? Bitboard::rank[RANK7] : Bitboard::rank[RANK2]); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = pawn_captures(from, side) & ~get_pieces(side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); if (to == epsq) { movelist->add(Move::enpassant(from, to)); } else { movelist->add(Move::capture(from, to, PAWN, piece_at(to))); } } } /* knights */ bb = get_knights(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = knight_attacks(from) & get_pieces(opponent); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::capture(from, to, KNIGHT, piece_at(to))); } } /* bishops */ bb = get_bishops(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = bishop_attacks(from) & get_pieces(opponent); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::capture(from, to, BISHOP, piece_at(to))); } } /* rooks */ bb = get_rooks(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = rook_attacks(from) & get_pieces(opponent); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::capture(from, to, ROOK, piece_at(to))); } } /* queens */ bb = get_queens(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = queen_attacks(from) & get_pieces(opponent); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::capture(from, to, QUEEN, piece_at(to))); } } /* king, only one */ from = get_king(side); to_bb = king_attacks(from) & get_pieces(opponent); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::capture(from, to, KING, piece_at(to))); } } /* * This routine generates all moves except captures and promotions. */ void Board::generate_noncaptures(Movelist * movelist) const { Bitboard bb, to_bb; Square from, to; /* first try castling */ generate_castling(movelist); /* pawn non-captures non-promotions */ bb = get_pawns(side) & ~(side == WHITE ? Bitboard::rank[RANK7] : Bitboard::rank[RANK2]); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = pawn_noncaptures(from, side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::normal(from, to, PAWN)); } } /* knights */ bb = get_knights(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = knight_attacks(from) & ~get_blocker(); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::normal(from, to, KNIGHT)); } } /* bishops */ bb = get_bishops(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = bishop_attacks(from) & ~get_blocker(); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::normal(from, to, BISHOP)); } } /* rooks */ bb = get_rooks(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = rook_attacks(from) & ~get_blocker(); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::normal(from, to, ROOK)); } } /* queens */ bb = get_queens(side); while (bb) { from = bb.firstbit(); bb.clearbit(from); to_bb = queen_attacks(from) & ~get_blocker(); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::normal(from, to, QUEEN)); } } /* king, only one */ from = get_king(side); to_bb = king_attacks(from) & ~get_blocker(); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); movelist->add(Move::normal(from, to, KING)); } } /* * Generate all moves that bring us out of check. * * FIXME This is not really true, we only generate pseudo-legal * moves, so the king might actually be left in check! */ void Board::generate_escapes(Movelist * movelist) const { if (!in_check()) { DBG(1, "generate_escapes() called but not in check!"); return; } Bitboard from_bb, to_bb; Square from, to; Square king = get_king(side); Bitboard checkers = attackers(king, opponent); /* * Try to move the king. */ to_bb = king_attacks(king) & ~get_pieces(side); while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); if (is_attacked(to, opponent)) { continue; } else if (get_pieces(opponent).testbit(to)) { movelist->add(Move::capture(king, to, KING, piece_at(to))); } else { movelist->add(Move::normal(king, to, KING)); } } /* If our king is attacked my more than one * enemy piece, moving the king is the only * possibility */ if (checkers.popcnt() > 1) return; Square checker = checkers.firstbit(); Piece checker_ptype = piece_at(checker); ASSERT_DEBUG(checker_ptype != KING); /* * Try to capture the checking piece. * Captures taken by the king were * already considered above. */ from_bb = attackers(checker, side) & ~get_kings(side); while (from_bb) { from = from_bb.firstbit(); from_bb.clearbit(from); add_move(movelist, from, checker); } /* Also try enpassant capture. */ if (checker == get_eppawn()) { from_bb = pawn_captures(epsq, opponent) & get_pawns(side); while (from_bb) { from = from_bb.firstbit(); from_bb.clearbit(from); movelist->add(Move::enpassant(from, epsq)); } } /* * Try to block the attack. * Blocking by enpassant capture is not possible. */ if (checker_ptype == PAWN || checker_ptype == KNIGHT) return; to_bb = Bitboard::ray_bb[checker][king]; while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); ASSERT_DEBUG(piece_at(to) == NO_PIECE); from_bb = attackers(to, side); /* Hmm, pawn forward moves must * be added separately. */ if (side == WHITE) { if (RNK(to) != RANK1 && get_pawns(side).testbit(to-8)) { from_bb.setbit(to-8); } else if (RNK(to) == RANK4 && !get_blocker().testbit(to-8) && get_pawns(side).testbit(to-16)) { from_bb.setbit(to-16); } } else { if (RNK(to) != RANK8 && get_pawns(side).testbit(to+8)) { from_bb.setbit(to+8); } else if (RNK(to) == RANK5 && !get_blocker().testbit(to+8) && get_pawns(side).testbit(to+16)) { from_bb.setbit(to+16); } } while (from_bb) { from = from_bb.firstbit(); from_bb.clearbit(from); if (get_blocker() & Bitboard::ray_bb[from][to]) continue; add_move(movelist, from, to); } } } /* * Generate castling, if possible. * Note that we generate pseudo-legal moves here too, * so we might castle into check. (But not _out_of_ check * or _through_ check, since this cannot be verified later.) */ void Board::generate_castling(Movelist * movelist) const { if (in_check()) return; if (side == WHITE) { if (flags & WKCASTLE && !(get_blocker() & Bitboard::ray_bb[E1][H1]) && !is_attacked(F1, BLACK)) { movelist->add(Move::castle(E1, G1)); } if (flags & WQCASTLE && !(get_blocker() & Bitboard::ray_bb[E1][A1]) && !is_attacked(D1, BLACK)) { movelist->add(Move::castle(E1, C1)); } } else { if (flags & BKCASTLE && !(get_blocker() & Bitboard::ray_bb[E8][H8]) && !is_attacked(F8, WHITE)) { movelist->add(Move::castle(E8, G8)); } if (flags & BQCASTLE && !(get_blocker() & Bitboard::ray_bb[E8][A8]) && !is_attacked(D8, WHITE)) { movelist->add(Move::castle(E8, C8)); } } } /* * Add many moves described by from-square and to-bitboard to the movelist. * This function uses add_move(), so see its comment below. */ void Board::add_moves(Movelist * movelist, Square from, Bitboard to_bb) const { Square to; while (to_bb) { to = to_bb.firstbit(); to_bb.clearbit(to); add_move(movelist, from, to); } } /* * Add a single move described only by from- and to-square to the movelist. * This is a very inefficient function, because we must find out all * information about the move here, so avoid it if possible. */ void Board::add_move(Movelist * movelist, Square from, Square to) const { ASSERT_DEBUG(to != get_king(opponent)); Piece ptype = piece_at(from); if (ptype == PAWN && to == epsq) { movelist->add(Move::enpassant(from, to)); } else if (get_pieces(opponent).testbit(to)) { Piece cap_ptype = piece_at(to); if (ptype == PAWN && ((side == WHITE && RNK(to) == RANK8) || (side == BLACK && RNK(to) == RANK1))) { movelist->add(Move::promotion_capture(from, to, QUEEN, cap_ptype)); movelist->add(Move::promotion_capture(from, to, KNIGHT, cap_ptype)); movelist->add(Move::promotion_capture(from, to, BISHOP, cap_ptype)); movelist->add(Move::promotion_capture(from, to, ROOK, cap_ptype)); } else { movelist->add(Move::capture(from, to, ptype, cap_ptype)); } } else { if (ptype == PAWN && ((side == WHITE && RNK(to) == RANK8) || (side == BLACK && RNK(to) == RANK1))) { movelist->add(Move::promotion(from, to, QUEEN)); movelist->add(Move::promotion(from, to, KNIGHT)); movelist->add(Move::promotion(from, to, BISHOP)); movelist->add(Move::promotion(from, to, ROOK)); } else { movelist->add(Move::normal(from, to, ptype)); } } } hoichess_0.10.3/src/chess/i386/0000750000175000017500000000000010732031250015415 5ustar oliveroliverhoichess_0.10.3/src/chess/i386/bitboard_asm.h0000640000175000017500000000632710732031250020225 0ustar oliveroliver/* $Id: bitboard_asm.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/i386/bitboard_asm.h * * Copyright (C) 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ /* * x86 assembler versions of msb/lsb scan routines. * This code was taken from Crafty and slightly modified to match * our interpretation of the bit positions. */ #ifdef USE_ASM_LSB inline int Bitboard::lsb() const { uint32_t dummy1, dummy2, dummy3; asm(" bsf %2, %0" "\n\t" " jnz 2f" "\n\t" " bsf %1, %0" "\n\t" " jnz 1f" "\n\t" " movl $-1, %0" "\n\t" " jmp 2f" "\n\t" "1: addl $32,%0" "\n\t" "2:" : "=&q" (dummy1), "=&q" (dummy2), "=&q" (dummy3) : "1" ((uint32_t) (bits>>32)), "2" ((uint32_t) bits) : "cc"); return (dummy1); } #endif #ifdef USE_ASM_MSB inline int Bitboard::msb() const { uint32_t dummy1, dummy2, dummy3; asm(" bsr %1, %0" "\n\t" " jnz 1f" "\n\t" " bsr %2, %0" "\n\t" " jnz 2f" "\n\t" " movl $-1, %0" "\n\t" " jmp 2f" "\n\t" "1: addl $32,%0" "\n\t" "2:" : "=&q" (dummy1), "=&q" (dummy2), "=&q" (dummy3) : "1" ((uint32_t) (bits>>32)), "2" ((uint32_t) bits) : "cc"); return (dummy1); } #endif /* * x86 assembler version of population count routine. * This code was taken from Crafty. However, it seems to be slower * than the LUT version. */ #ifdef USE_ASM_POPCNT inline int Bitboard::popcnt() const { uint32_t dummy1, dummy2, dummy3, dummy4; asm(" xorl %0, %0" "\n\t" " testl %2, %2" "\n\t" " jz 2f" "\n\t" "1: leal -1(%2), %1" "\n\t" " incl %0" "\n\t" " andl %1, %2" "\n\t" " jnz 1b" "\n\t" "2: testl %3, %3" "\n\t" " jz 4f" "\n\t" "3: leal -1(%3), %1" "\n\t" " incl %0" "\n\t" " andl %1, %3" "\n\t" " jnz 3b" "\n\t" "4:" "\n\t" : "=&q" (dummy1), "=&q" (dummy2), "=&q" (dummy3), "=&q" (dummy4) : "2" ((uint32_t) (bits>>32)), "3" ((uint32_t) bits) : "cc"); return (dummy1); } #endif hoichess_0.10.3/src/Makefile0000640000175000017500000000622010732031250015260 0ustar oliveroliver# $Id: Makefile 1462 2007-12-18 20:49:56Z holger $ PLATFORM = unix CXX = g++ CPP = $(CXX) -E INSTALL = /usr/bin/install LIBPATH = CXXFLAGS = -W -Wall LDFLAGS = ############################################################################### -include Makefile.local #PLATFORM = unix BUILDDIR = .build-$(PLATFORM) BUILDDIR_CHESS = $(BUILDDIR)/.hoichess BUILDDIR_XIANGQI = $(BUILDDIR)/.hoixiangqi SOURCES_COMMON = $(wildcard *.cc) SOURCES_CHESS = $(wildcard chess/*.cc) SOURCES_XIANGQI = $(wildcard xiangqi/*.cc) ALL_SOURCES = $(SOURCES_COMMON) $(SOURCES_CHESS) $(SOURCES_XIANGQI) ALL_HEADERS = $(wildcard *.h chess/*.h xiangqi/*.h) ALL_OBJS = $(patsubst %.cc,%.o,$(ALL_SOURCES)) OBJS_COMMON = $(patsubst %.cc,%.o,$(SOURCES_COMMON)) OBJS_CHESS = $(patsubst %.cc,%.o,$(SOURCES_CHESS)) OBJS_XIANGQI = $(patsubst %.cc,%.o,$(SOURCES_XIANGQI)) BUILDDIR_OBJS_CHESS = $(foreach f,$(OBJS_COMMON) $(OBJS_CHESS),$(BUILDDIR_CHESS)/$(f)) BUILDDIR_OBJS_XIANGQI = $(foreach f,$(OBJS_COMMON) $(OBJS_XIANGQI),$(BUILDDIR_XIANGQI)/$(f)) INCLUDE = -I. # # Platform-specific stuff # ifeq ($(PLATFORM),unix) override CXXFLAGS += -DHAVE_PTHREAD LIBS += -lpthread BIN_CHESS = $(BUILDDIR)/hoichess BIN_XIANGQI = $(BUILDDIR)/hoixiangqi endif ifeq ($(PLATFORM),mingw32) override INCLUDE += -Iwin32 -Ilib SOURCES_COMMON += $(wildcard lib/*.cc win32/*.cc) ALL_HEADERS += $(wildcard lib/*.h win32/*.h) BIN_CHESS = $(BUILDDIR)/hoichess.exe BIN_XIANGQI = $(BUILDDIR)/hoixiangqi.exe endif # # Feature configurations # ifdef HAVE_READLINE override CXXFLAGS += -DHAVE_READLINE LIBS += -lreadline endif # # OS-specific stuff # ifeq ($(shell uname -s),SunOS) override INCLUDE += -Ilib SOURCES_COMMON += lib/my_getopt.cc endif ############################################################################### .PHONY: all all: $(MAKE) hoichess $(MAKE) hoixiangqi .PHONY: hoichess hoichess: $(BIN_CHESS) .PHONY: hoixiangqi hoixiangqi: $(BIN_XIANGQI) compile.h: $(subst compile.h,,$(ALL_SOURCES) $(ALL_HEADERS)) touch $@ debug_printconfig.h: config.h build/mk_debug_config_h.sh build/mk_debug_config_h.sh > $@ $(BIN_CHESS): INCLUDE += -Ichess $(BIN_CHESS): CXXFLAGS += -DHOICHESS $(BIN_CHESS): $(BUILDDIR_OBJS_CHESS) $(BIN_XIANGQI): INCLUDE += -Ixiangqi $(BIN_XIANGQI): CXXFLAGS += -DHOIXIANGQI $(BIN_XIANGQI): $(BUILDDIR_OBJS_XIANGQI) # link object files $(BIN_CHESS) $(BIN_XIANGQI): @mkdir -p $(dir $@) $(CXX) $(CXXFLAGS) $(LDFLAGS) $(LIBPATH) $(LIBS) -o $@ $^ # compile source files $(BUILDDIR_CHESS)/%.o $(BUILDDIR_XIANGQI)/%.o: %.cc Makefile Makefile.local @mkdir -p $(dir $@) $(CXX) $(CXXFLAGS) $(INCLUDE) -MT $@ -MD -MF $(patsubst %.o,%.d,$@) -c -o $@ $< .PHONY: install install: all $(INSTALL) -m 755 -D $(BIN_CHESS) $(DESTDIR)$(bindir)/$(notdir $(BIN_CHESS)) $(INSTALL) -m 755 -D $(BIN_XIANGQI) $(DESTDIR)$(bindir)/$(notdir $(BIN_XIANGQI)) .PHONY: clean clean: rm -rf $(BUILDDIR) .PHONY: maintainer-clean maintainer-clean: clean rm -f debug_printconfig.h # Include dependencies ifneq ($(MAKECMDGOALS),clean) ifneq ($(MAKECMDGOALS),maintainer-clean) -include $(patsubst %.o,%.d,$(BUILDDIR_OBJS_CHESS)) -include $(patsubst %.o,%.d,$(BUILDDIR_OBJS_XIANGQI)) endif endif hoichess_0.10.3/src/util.cc0000640000175000017500000000731610732031250015113 0ustar oliveroliver/* $Id: util.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/util.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "util.h" #include "signal.h" #include "thread.h" #include #include #include #include #include Mutex stdout_mutex; int atomic_printf(const char * fmt, ...) { stdout_mutex.lock(); va_list args; va_start(args, fmt); int ret = vfprintf(stdout, fmt, args); va_end(args); stdout_mutex.unlock(); return ret; } int atomic_fprintf(FILE * fp, Mutex * mutex, const char * fmt, ...) { ASSERT(mutex != NULL); mutex->lock(); va_list args; va_start(args, fmt); int ret = vfprintf(fp, fmt, args); va_end(args); mutex->unlock(); return ret; } /* * Win32 rand() returns only a 15 bit random number. We just take this * function on all systems - it is only used during initialization, so * it is not performance critical. * * Thanks to Bruce Moreland for this snippet, * and to Jim Ablett who brought it to me :-). */ uint64_t random64() { uint64_t tmp = rand(); tmp ^= ((uint64_t) rand() << 15); tmp ^= ((uint64_t) rand() << 30); tmp ^= ((uint64_t) rand() << 45); tmp ^= ((uint64_t) rand() << 60); return tmp; } #if 0 uint64_t random64() { uint64_t tmp = random(); tmp <<= 32; tmp |= random(); return tmp; } #endif std::string strprintf(const char * fmt, ...) { char buf[65536]; // should be enough va_list args; va_start(args, fmt); int ret = vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); ASSERT(ret >= 0); if ((unsigned) ret >= sizeof(buf)) { WARN("buffer overflow, output truncated"); } return std::string(buf); } bool parse_size(const char * s, long * n) { ASSERT(s != NULL); ASSERT(s != NULL); long tmp; if (s[strlen(s)-1] == 'M' && sscanf(s, "%ldM", &tmp) == 1) { *n = tmp * (1<<20); return true; } else if (s[strlen(s)-1] == 'K' && sscanf(s, "%ldK", &tmp) == 1) { *n = tmp * (1<<10); return true; } else if (sscanf(s, "%ld", &tmp) == 1) { *n = tmp; return true; } else { return false; } } FILE * logfp = NULL; Mutex logfp_mutex; void open_log(const char * logfile) { logfp = fopen(logfile, "a"); if (!logfp) { fprintf(stderr, "Cannot open logfile %s: %s\n", logfile, strerror(errno)); exit(EXIT_FAILURE); } setbuf(logfp, NULL); time_t t; time(&t); /* Note that ctime() appends '\n' */ fprintf(logfp, "---- Log for %s %s opened on %s", PROGNAME, VERSION, ctime(&t)); } void close_log() { if (!logfp) return; time_t t; time(&t); /* Note that ctime() appends '\n' */ fprintf(logfp, "---- Log for %s %s closed on %s", PROGNAME, VERSION, ctime(&t)); fclose(logfp); } void log(const char * fmt, ...) { if (!logfp) { return; } va_list args; va_start(args, fmt); logfp_mutex.lock(); vfprintf(logfp, fmt, args); logfp_mutex.unlock(); va_end(args); } void vlog(const char * fmt, va_list args) { if (!logfp) { return; } logfp_mutex.lock(); vfprintf(logfp, fmt, args); logfp_mutex.unlock(); } hoichess_0.10.3/src/game.h0000640000175000017500000000732210732031250014706 0ustar oliveroliver/* $Id: game.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/game.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef GAME_H #define GAME_H #include "common.h" #include "board.h" #include "clock.h" #include "basic.h" #include class GameEntry { public: class MoveAttributes { friend class GameEntry; public: bool computer; bool bookmove; private: MoveAttributes() {} public: MoveAttributes(bool computer, bool bookmove) : computer(computer), bookmove(bookmove) {} }; private: Board board; /* position */ Move move; /* move that was played in this position */ Clock clock[2]; /* clocks at beginning */ MoveAttributes attr; /* more information about this->move */ public: GameEntry(const Board & board, Move mov, const Clock & wclock, const Clock & bclock, const MoveAttributes & attr); ~GameEntry() {} public: Board get_board() const { return board; } Color get_side() const { return board.get_side(); } Move get_move() const { return move; } Clock get_clock(int side) const { return clock[side]; } MoveAttributes get_attr() const { return attr; } }; class Game { public: enum game_results { OPEN = 0, WHITEMATES, BLACKMATES, #if defined(HOICHESS) STALEMATE, #elif defined(HOIXIANGQI) WHITESTALEMATES, BLACKSTALEMATES, #else # error "neither HOICHESS nor HOIXIANGQI defined" #endif RULE50, REPS3, MATERIAL, ILLEGAL }; private: Board initial_board; /* initial position */ Clock initial_clock[2]; /* initial clocks */ Board current_board; /* current position */ Clock current_clock[2]; /* current clocks, one of them may be running */ Clock old_clock[2]; /* clocks at beginning of current position */ std::list entries; /* past positions (excl. current) */ std::list undone_entries; bool running; Hashkey hashkeys[100]; unsigned int nr_hashkeys; int result; std::string result_str; std::string result_comment; public: Game(const Board & board, const Clock & wclock, const Clock & bclock); ~Game() {} public: bool is_over() const; bool is_running() const; int get_result() const; std::string get_result_str() const; std::string get_result_comment() const; Board get_board() const; int get_side() const; Clock get_clock() const; Clock get_clock(Color side) const; void start(); void make_move(Move mov, const GameEntry::MoveAttributes & move_attr); bool undo_move(); Move redo_move(); bool set_board(const std::string& fen); void set_board(const Board & board); void set_clock(const Clock & clock); void set_clock(Color side, const Clock & clock); void set_clocks(const Clock & wclock, const Clock & bclock); int repetitions(const Board & board) const; int repetitions_search(const Board & board) const; int last_bookmove() const; private: void update_hashkeys(); void check_result(); public: void print(FILE * fp = stdout) const; void write_pgn(FILE * fp = stdout) const; }; #endif // GAME_H hoichess_0.10.3/src/main.cc0000640000175000017500000002213710732031250015060 0ustar oliveroliver/* $Id: main.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/main.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include #include #ifndef WIN32 # include #endif #include #include #include "common.h" #include "compile.h" #include "shell.h" #include "util.h" /* * Global variables, declared in common.h. */ unsigned int debug = 0; unsigned int verbose = 0; bool ansicolor = false; static Shell * shell; #ifndef WIN32 static void sigint_handler(int sig) { (void) sig; shell->interrupt(); } #endif extern void init(); extern void fini(); static void print_version() { printf("%s %s (%s)\n", PROGNAME, VERSION, COMPILE_DATE); } static void print_copyright() { printf( "Copyright (C) 2004-2007 %s %s\n" "This program is free software and comes with ABSOLUTELY NO WARRANTY.\n" "See the GNU General Public License for more details.\n", AUTHOR, AUTHOR_EMAIL); } static void print_info() { printf("Platform: %s\n", PLATFORM); printf("Compiler: %s %s\n", COMPILER, COMPILER_VERSION); } static void usage(const char * argv0) { print_version(); print_copyright(); printf("\nUsage: %s [options]\n\n", argv0); printf("Options:\n"); printf(" -h | --help Display usage information\n"); printf(" -V | --version Display version information\n"); printf(" -v | --verbose[=N] Increase verbosity\n"); printf(" -d | --debug[=N] Increase debug level\n"); printf(" -L | --logfile FILE Specify log file name (log will be appended)\n"); printf(" -x | --xboard Start in xboard mode\n"); printf(" --book FILE Specify file name of opening book (default: %s)\n", DEFAULT_BOOK); printf(" --nobook Disable opening book\n"); printf(" --hashsize SIZE Set size of main hash table (default: %s)\n", DEFAULT_HASHSIZE); printf(" --pawnhashsize SIZE Set size of pawn hash table (default: %s)\n", DEFAULT_PAWNHASHSIZE); #ifdef USE_EVALCACHE printf(" --evalcache SIZE Set size of evaluation cache (default: %s)\n", DEFAULT_EVALCACHESIZE); #endif printf(" --rcfile FILE Read initial commands from FILE\n"); printf( "\nThese are only the most general options. See documentation for a complete\n" "list of supported command line options, and a detailed description of them.\n" "\nSee http://www.hoicher.de/hoichess for more information and new releases.\n" "Please report any bugs and suggestions to %s.\n", AUTHOR_EMAIL); } int main(int argc, char ** argv) { const char * opt_logfile = NULL; const char * opt_xboard = "auto"; const char * opt_hashsize = DEFAULT_HASHSIZE; const char * opt_bookfile = DEFAULT_BOOK; const char * opt_name = NULL; const char * opt_rcfile = NULL; const char * opt_color = "auto"; const char * opt_evalcache = DEFAULT_EVALCACHESIZE; const char * opt_pawnhashsize = DEFAULT_PAWNHASHSIZE; /* Most Unix platforms have color terminals. But on Win32 systems, * ANSI color is normally not available. */ #ifdef WIN32 opt_color = "off"; #endif bool xboard_mode = false; /* * Parse command line. */ const char * short_opts = "hVvdL:x::"; struct option long_options[] = { { "help", 0, 0, 'h' }, { "version", 0, 0, 'V' }, { "verbose", 2, 0, 'v' }, { "debug", 2, 0, 'd' }, { "logfile", 1, 0, 'L' }, { "xboard", 2, 0, 'x' }, { "hashsize", 1, 0, 128 }, { "book", 1, 0, 129 }, { "nobook", 0, 0, 130 }, { "name", 1, 0, 131 }, { "rcfile", 1, 0, 132 }, { "script", 1, 0, 240 }, // deprecated { "color", 1, 0, 133 }, { "evalcache", 1, 0, 134 }, { "pawnhashsize", 1, 0, 135 }, { 0, 0, 0, 0 } }; int c; while ((c = getopt_long(argc, argv, short_opts, long_options, NULL)) != -1) { switch (c) { case 'h': /* --help */ usage(argv[0]); exit(0); case 'V': /* --version */ print_version(); exit(0); case 'v': /* --verbose */ if (optarg) { verbose = atoi(optarg); } else { verbose++; } break; case 'd': /* --debug */ if (optarg) { debug = atoi(optarg); } else { debug++; } break; case 'L': /* --logfile */ opt_logfile = optarg; break; case 'x': /* --xboard */ if (!optarg) { xboard_mode = true; } opt_xboard = optarg; break; case 128: /* --hashsize */ opt_hashsize = optarg; break; case 129: /* --book */ opt_bookfile = optarg; break; case 130: /* --nobook */ opt_bookfile = NULL; break; case 131: /* --name */ opt_name = optarg; break; case 132: /* --rcfile */ opt_rcfile = optarg; break; case 240: /* --script (deprecated) */ opt_rcfile = optarg; printf("Warning: option --script is deprecated." " Use --rcfile.\n"); break; case 133: /* --color */ opt_color = optarg; break; case 134: /* --evalcache */ opt_evalcache = optarg; break; case 135: /* --pawnhashsize */ opt_pawnhashsize = optarg; break; case '?': usage(argv[0]); exit(1); default: BUG("getopt_long() returned %d", c); } } print_version(); print_copyright(); printf("\n"); print_info(); printf("\n"); if (debug) { debug_print_compiletime_config(); debug_print_storagesizes(); printf("\n"); } if (verbose || debug) { printf("Verbosity set to %u.\n", verbose); printf("Debug level set to %u.\n", debug); printf("\n"); } /* * Do things depending on command line options. */ if (opt_logfile) { printf("Logging to %s\n", opt_logfile); open_log(opt_logfile); } if (opt_xboard) { if ( strcmp(opt_xboard, "true") == 0 || strcmp(opt_xboard, "on") == 0 || strcmp(opt_xboard, "yes") == 0) { xboard_mode = true; } else if ( strcmp(opt_xboard, "false") == 0 || strcmp(opt_xboard, "off") == 0 || strcmp(opt_xboard, "no") == 0) { xboard_mode = false; } else if (strcmp(opt_xboard, "auto") == 0) { if (isatty(1)) { xboard_mode = false; } else { xboard_mode = true; printf("stdout is not a terminal, enabling" " xboard mode.\n"); } } else { fprintf(stderr, "Illegal argument to option --xboard: %s\n", opt_xboard); exit(EXIT_FAILURE); } } if (opt_color) { if ( strcmp(opt_color, "true") == 0 || strcmp(opt_color, "on") == 0 || strcmp(opt_color, "yes") == 0) { ansicolor = true; } else if ( strcmp(opt_color, "false") == 0 || strcmp(opt_color, "off") == 0 || strcmp(opt_color, "no") == 0) { ansicolor = false; } else if (strcmp(opt_color, "auto") == 0) { if (isatty(1)) { ansicolor = true; } else { ansicolor = false; } } else { fprintf(stderr, "Illegal argument to option --color: %s\n", opt_color); exit(EXIT_FAILURE); } } /* * Initialize everything and start shell. */ init(); shell = new Shell(); shell->set_myname(opt_name); shell->set_xboard(xboard_mode); /* opening book */ shell->set_book(opt_bookfile); /* main hash size */ if (opt_hashsize) { long size = 0; if (!parse_size(opt_hashsize, &size) || size < 0) { printf("Error: Illegal value for hash table size: %s\n", opt_hashsize); exit(EXIT_FAILURE); } shell->set_hashsize(size); } /* pawh hash size */ if (opt_pawnhashsize) { long size = 0; if (!parse_size(opt_pawnhashsize, &size) || size < 0) { printf("Error: Illegal value for pawn hash size: %s\n", opt_pawnhashsize); exit(EXIT_FAILURE); } shell->set_pawnhashsize(size); } #ifdef USE_EVALCACHE /* evalation cache size */ if (opt_evalcache) { long size = 0; if (!parse_size(opt_evalcache, &size) || size < 0) { printf("Error: Illegal value for evaluation" " cache size: %s\n", opt_evalcache); exit(EXIT_FAILURE); } shell->set_evalcachesize(size); } #endif /* read script file if given on command line */ if (opt_rcfile) { FILE * fp = fopen(opt_rcfile, "r"); if (fp == NULL) { fprintf(stderr, "Cannot open %s for reading: %s\n", opt_rcfile, strerror(errno)); exit(EXIT_FAILURE); } shell->source_file(fp, opt_rcfile); } /* read hoichess.rc; note that commands here are executed _before_ * commands in --script file, because the last opened source is * read at as first... */ #if defined(HOICHESS) const char * rcfile = "hoichess.rc"; #elif defined(HOIXIANGQI) const char * rcfile = "hoixiangqi.rc"; #endif FILE * fp = fopen(rcfile, "r"); if (fp != NULL) { shell->source_file(fp, rcfile); } #ifndef WIN32 signal(SIGINT, sigint_handler); #endif shell->main(); /* * Clean up. */ delete shell; close_log(); fini(); return 0; } hoichess_0.10.3/src/thread.h0000640000175000017500000000742710732031250015252 0ustar oliveroliver/* $Id: thread.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/thread.h * * Copyright (C) 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef THREAD_H #define THREAD_H #include "common.h" #if defined(HAVE_PTHREAD) # include #elif defined(WIN32) # include #else # error no thread support is available #endif /***************************************************************************** * * Mutex Class * *****************************************************************************/ class Mutex { private: #if defined(HAVE_PTHREAD) pthread_mutex_t mtx; #elif defined(WIN32) HANDLE hndl; #endif public: inline Mutex(); inline ~Mutex(); public: inline void lock(); inline void unlock(); }; inline Mutex::Mutex() { #if defined(HAVE_PTHREAD) pthread_mutex_init(&mtx, NULL); #elif defined(WIN32) hndl = CreateMutex(NULL, FALSE, NULL); #endif } inline Mutex::~Mutex() { #if defined(HAVE_PTHREAD) pthread_mutex_destroy(&mtx); #elif defined(WIN32) #endif } inline void Mutex::lock() { #if defined(HAVE_PTHREAD) pthread_mutex_lock(&mtx); #elif defined(WIN32) DWORD res = WaitForSingleObject(hndl, INFINITE); ASSERT(res == WAIT_OBJECT_0); #endif } inline void Mutex::unlock() { #if defined(HAVE_PTHREAD) pthread_mutex_unlock(&mtx); #elif defined(WIN32) bool res = ReleaseMutex(hndl); ASSERT(res); #endif } /***************************************************************************** * * Thread Class * *****************************************************************************/ class Thread { private: #if defined(HAVE_PTHREAD) pthread_t threadid; #elif defined(WIN32) HANDLE hndl; #endif void * (*startfunc)(void *); public: inline Thread(void * (*startfunc)(void *)); inline ~Thread(); public: inline void start(void * arg); inline void wait(); private: #if defined(WIN32) struct win32_startfunc_wrapper_arg { Thread * thread; void * real_arg; }; static inline DWORD WINAPI win32_startfunc_wrapper(LPVOID arg); #endif }; inline Thread::Thread(void * (*_startfunc)(void *)) { startfunc = _startfunc; #if defined(HAVE_PTHREAD) #elif defined(WIN32) #endif } inline Thread::~Thread() { #if defined(HAVE_PTHREAD) #elif defined(WIN32) #endif } inline void Thread::start(void * arg) { #if defined(HAVE_PTHREAD) pthread_create(&threadid, NULL, startfunc, arg); #elif defined(WIN32) struct win32_startfunc_wrapper_arg * a = new struct win32_startfunc_wrapper_arg; a->thread = this; a->real_arg = arg; DWORD dwThreadId; hndl = CreateThread(0, 0, win32_startfunc_wrapper, (LPVOID) a, 0, &dwThreadId); #endif } inline void Thread::wait() { #if defined(HAVE_PTHREAD) pthread_join(threadid, NULL); threadid = 0; #elif defined(WIN32) WaitForSingleObject(hndl, INFINITE); CloseHandle(hndl); hndl = INVALID_HANDLE_VALUE; #endif } #if defined(WIN32) inline DWORD WINAPI Thread::win32_startfunc_wrapper(LPVOID arg) { struct win32_startfunc_wrapper_arg * a = (struct win32_startfunc_wrapper_arg *) arg; (*(a->thread->startfunc))(a->real_arg); delete a; return 0; } #endif #endif // THREAD_H hoichess_0.10.3/src/debug.cc0000640000175000017500000000674610732031250015232 0ustar oliveroliver/* $Id: debug.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/debug.cc * * Copyright (C) 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "debug.h" #include "thread.h" #include "eval.h" /* for debug_print_storagesizes() */ #include "tree.h" /* for debug_print_storagesizes() */ #include "util.h" #include #include #include #include #include #include void __debug_helper::__dbg(unsigned int level, const char * fmt, ...) { /* write message to logfile */ log("debug[%d]: %s:%d: %s: ", level, file, line, function); va_list args; va_start(args, fmt); vlog(fmt, args); va_end(args); if (fmt[strlen(fmt)-1] != '\n') { log("\n"); } if (debug < level) { return; } if (mutex) { mutex->lock(); } /* write message to fp */ fprintf(fp, "debug[%d]: %s:%d: %s: ", level, file, line, function); //va_list args; va_start(args, fmt); vfprintf(fp, fmt, args); va_end(args); if (fmt[strlen(fmt)-1] != '\n') { fprintf(fp, "\n"); } if (mutex) { mutex->unlock(); } } void __debug_helper::__warn(const char * fmt, ...) { /* write message to logfile */ log("warning: %s:%d: %s: ", file, line, function); va_list args; va_start(args, fmt); vlog(fmt, args); va_end(args); if (fmt[strlen(fmt)-1] != '\n') { log("\n"); } if (mutex) { mutex->lock(); } /* write message to fp */ fprintf(fp, "warning: %s:%d: %s: ", file, line, function); //va_list args; va_start(args, fmt); vfprintf(fp, fmt, args); va_end(args); if (fmt[strlen(fmt)-1] != '\n') { fprintf(fp, "\n"); } if (mutex) { mutex->unlock(); } } void __debug_helper::__bug(const char * fmt, ...) { /* write message to logfile */ log("bug: %s:%d: %s: ", file, line, function); va_list args; va_start(args, fmt); vlog(fmt, args); va_end(args); if (fmt[strlen(fmt)-1] != '\n') { log("\n"); } if (mutex) { mutex->lock(); } /* write message to fp */ fprintf(fp, "bug: %s:%d: %s: ", file, line, function); //va_list args; va_start(args, fmt); vfprintf(fp, fmt, args); va_end(args); if (fmt[strlen(fmt)-1] != '\n') { fprintf(fp, "\n"); } fprintf(fp, "This is a bug in %s. Please report it to %s.\n", PROGNAME, AUTHOR_EMAIL); if (mutex) { mutex->unlock(); } raise(SIGABRT); exit(EXIT_FAILURE); } void debug_print_compiletime_config() { printf("Compile-time configuration:\n"); #include "debug_printconfig.h" printf("\n"); } #define PRNT(x) printf(" " #x "=%u", (x)) void debug_print_storagesizes() { printf("Storage sizes:"); #ifdef HOICHESS PRNT(sizeof(Bitboard)); #endif PRNT(sizeof(Board)); PRNT(sizeof(Move)); PRNT(sizeof(Movelist)); PRNT(sizeof(HashEntry)); PRNT(sizeof(PawnHashEntry)); PRNT(EvaluationCache::SIZEOF_ENTRY); PRNT(sizeof(Node)); printf("\n"); } hoichess_0.10.3/src/search.cc0000640000175000017500000004452310732031250015404 0ustar oliveroliver/* $Id: search.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/search.cc * * Copyright (C) 2004-2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "search.h" #include /***************************************************************************** * * Constructor / Destructor * *****************************************************************************/ Search::Search(Shell * shell) { this->shell = shell; evaluator = new Evaluator(); hashtable = NULL; histtable[WHITE] = new HistoryTable(); histtable[BLACK] = new HistoryTable(); game = NULL; clock = NULL; maxdepth = MAXDEPTH; param_time = 0; thread = NULL; stop = false; ostat_knodes = 0; ostat_csecs = 0; ostat_depth_sum = 0; ostat_depth_cnt = 0; showthinking = false; } Search::~Search() { delete evaluator; delete histtable[WHITE]; delete histtable[BLACK]; } /* After how many nodes (full-width search only) should we check time? * Checking time (i.e. calling gettimeofday()) at every node would cause a * lot of overhead due to system calls. * This value works very well on a Pentium III 800 MHz. If you have a * considerably slower machine, try to set this a bit lower. */ #define TIMECHECK_INTERVAL 1000 /***************************************************************************** * * These functions will be called by the shell * to set up and control the search. * *****************************************************************************/ void Search::start(Game _game, int _mode, Color _myside) { DBG(2, "locking start_mutex"); start_mutex.lock(); DBG(2, "locked start_mutex"); ASSERT(!thread); ASSERT(game == NULL); game = &_game; mode = _mode; myside = _myside; stop = false; main(); stop = false; game = NULL; DBG(2, "unlocking start_mutex"); start_mutex.unlock(); DBG(2, "unlocked start_mutex"); } void Search::start(const Board & board, const Clock & clock, int mode) { Game game(board, clock, clock); game.start(); start(game, mode, NO_COLOR); } void Search::start_thread(Game _game, int _mode, Color _myside) { DBG(2, "locking start_mutex"); start_mutex.lock(); DBG(2, "locked start_mutex"); if (!thread) { DBG(2, "starting thread"); ASSERT(game == NULL); game = new Game(_game); mode = _mode; myside = _myside; stop = false; thread = new Thread(thread_main); thread->start(this); } else { DBG(2, "thread already running"); } DBG(2, "unlocking start_mutex"); start_mutex.unlock(); DBG(2, "unlocked start_mutex"); } void Search::stop_thread() { DBG(2, "locking start_mutex"); start_mutex.lock(); DBG(2, "locked start_mutex"); if (thread) { interrupt(); DBG(2, "waiting for thread to terminate"); thread->wait(); DBG(2, "thread has terminated"); delete thread; thread = NULL; delete game; game = NULL; } else { DBG(2, "thread not running"); } DBG(2, "unlocking start_mutex"); start_mutex.unlock(); DBG(2, "unlocked start_mutex"); } void * Search::thread_main(void * arg) { Search * search = (Search *) arg; search->main(); return NULL; } void Search::interrupt() { DBG(2, "interrupt"); stop = true; } Move Search::get_best() { DBG(2, "locking main_mutex"); main_mutex.lock(); DBG(2, "locked main_mutex"); Move tmp = tree[0]->get_best(); DBG(2, "unlocking main_mutex"); main_mutex.unlock(); DBG(2, "unlocked main_mutex"); return tmp; } void Search::main() { DBG(2, "locking main_mutex"); main_mutex.lock(); DBG(2, "locked main_mutex"); if (mode != MOVE) { clock = new Clock(); clock->start(); } else { clock = new Clock(game->get_clock()); } next_timecheck = TIMECHECK_INTERVAL; next_update = 0; reset_statistics(); histtable[WHITE]->reset(); histtable[BLACK]->reset(); tree.clear_killer(); /* Initialize the root node. set_root() already assigns one legal * move as best, in case search terminates without choosing a move. */ tree.set_root(game->get_board()); rootdepth = 0; const Board & rootboard = tree.get_rootboard(); int rooteval = evaluator->eval(rootboard, -INFTY, INFTY, myside); if (verbose >= 2) { printf("===================================================\n"); printf("Root node evaluation: %.2f\n", (float) rooteval / 100); evaluator->print_eval(rootboard, myside); printf("---------------------------------------------------\n"); clock->print(); printf("===================================================\n"); } else if (verbose >= 1) { printf("Root node evaluation: %.2f\n", (float) rooteval / 100); } if (mode == MOVE) { clock->allocate_time(); /* Extend search time when in check. */ if ((param_time & PARAM_TIME_IC) && rootboard.in_check()) { clock->allocate_more_time("in check at root node"); } /* Extend search time when near book. */ unsigned int lbm = game->last_bookmove(); if ((param_time & PARAM_TIME_NB) && book != NULL && lbm > 0 && lbm <= 3) { clock->allocate_more_time("near book"); } } if (showthinking && !shell->xboard) { print_header(); } /* If there is only one move, don't waste any time searching it. */ ASSERT(tree[0]->get_movelist_size() > 0); if (tree[0]->get_movelist_size() == 1 && mode == MOVE) { if (showthinking) { print_result(0, rooteval, '.'); } } else { iterate(); } if (verbose || (showthinking && !shell->xboard)) { print_statistics(); update_overall_statistics(); print_overall_statistics(); } delete clock; DBG(2, "unlocking main_mutex"); main_mutex.unlock(); DBG(2, "unlocked main_mutex"); } /***************************************************************************** * * Tree Search Functions. * *****************************************************************************/ /* Aspiration window for iterative deepening */ #define WINDOW 50 void Search::iterate() { int score; int alpha = -INFTY; int beta = INFTY; for (rootdepth = 1; rootdepth <= maxdepth; rootdepth++) { maxplyreached = 0; maxplyreached_quiesce = 0; /* Search the root node. */ score = search_root(0, rootdepth, alpha, beta); if (stop) { break; } /* If search failed low, re-search with a wider window */ if (score <= alpha && score > -MATE) { if (showthinking) { print_result(rootdepth, score, '-'); } /* If a fail-low happens after we have searched for a * considerable amount of time, add some extra time. */ if ((param_time & PARAM_TIME_FL) && clock->get_elapsed_time() > clock->get_limit()/2 && mode == MOVE) { clock->allocate_more_time("fail low"); } alpha = -INFTY; beta = beta+1; score = search_root(0, rootdepth, alpha, beta); if (stop) { break; } } /* Adjust window for next iteration */ if (score >= beta && score < MATE) { if (showthinking) { print_result(rootdepth, score, '+'); } /* If a fail-high happens after we have searched for a * considerable amount of time, add some extra time. */ if ((param_time & PARAM_TIME_FH) && clock->get_elapsed_time() > clock->get_limit()/2 && mode == MOVE) { clock->allocate_more_time("fail high"); } alpha = alpha-1; beta = INFTY; } else { if (showthinking) { print_result(rootdepth, score, '.'); } alpha = score - WINDOW; beta = score + WINDOW; } /* Check if we found a mate. */ if (score >= MATE || score <= -MATE) { break; } } } int Search::search_root(unsigned int ply, int depth, int alpha, int beta) { ASSERT_DEBUG(tree.get_current_ply() == ply); ASSERT_DEBUG(ply == 0); // DBG(3, "depth=%d, alpha=%d, beta=%d\n", depth, alpha, beta); Node * node = tree[ply]; int score; int moves = 0; #ifdef USE_PVS bool first = true; #endif for (Move mov = node->first(); mov; mov = node->next()) { tree.make_move(mov); if (!tree.get_board().is_legal()) { BUG("illegal move at root node: %s", mov.str().c_str()); } moves++; if (showthinking) { print_thinking(depth); } #ifdef USE_PVS /* Search the current move. We use a standard * principal variation search here. */ if (first) { score = -search(ply+1, depth-1, 0, -beta, -alpha); first = false; } else { score = -search(ply+1, depth-1, 0, -alpha-1, -alpha); if (score > alpha && score < beta) { score = -search(ply+1, depth-1, 0, -beta, -alpha); } } #else /* Search the current move. We use a pure * alpha-beta search here. */ score = -search(ply+1, depth-1, 0, -beta, -alpha); #endif tree.unmake_move(); if (stop) { return alpha; } node->set_current_score(score); if (score > alpha) { alpha = score; node->set_best(mov); if (showthinking) { print_result(depth, score, ' '); } if (score >= beta) { STAT_INC(stat_cut); break; } } } /* Update history table */ #ifdef USE_HISTORY histtable[tree.get_board().get_side()]->add(node->get_best()); #endif #ifdef COLLECT_STATISTICS stat_moves_sum += moves; stat_moves_cnt++; #endif if (!shell->xboard) { clear_line(); } // DBG(3, "return alpha=%d\n", alpha); return alpha; } int Search::search(unsigned int ply, int depth, int extend, int alpha, int beta) { ASSERT_DEBUG(tree.get_current_ply() == ply); Node * node = tree[ply]; /* If maximum search depth is reached, begin quiescence search. */ if (depth <= 0) { return quiescence_search(ply, alpha, beta); } if (is_draw()) { return DRAW; } int save_alpha = alpha; int score; int moves = 0; #ifdef USE_PVS bool first = true; #endif nodes++; if (ply > maxplyreached) { maxplyreached = ply; } /* * First look into the hash table if this * position has already been search before. * * TODO This surely needs some verification */ HashEntry hashentry; if (hashtable && hashtable->probe(tree.get_board(), &hashentry)) { if (hashentry.get_depth() >= (unsigned) depth) { score = hashentry.get_score(); switch (hashentry.get_type()) { case HashEntry::EXACT: hashtable->incr_hits2(); return score; case HashEntry::ALPHA: if (score <= alpha) { hashtable->incr_hits2(); return score; } break; #if 0 case HashEntry::BETA: if (score >= beta) { hashtable->incr_hits2(); return score; } break; #endif } } node->set_hashmv(hashentry.get_move()); } #ifdef USE_NULLMOVE /* Null-move forward pruning */ bool null_ok = !(tree[ply-1]->get_played_move().is_null()) && !(Evaluator::get_phase(tree.get_board()) == Evaluator::ENDGAME); if (!node->in_check() && null_ok) { tree.make_move(Move::null()); score = -search(ply+1, depth-2-1, 0, -beta, -beta+1); tree.unmake_move(); if (score >= beta) { STAT_INC(stat_nullcut); return beta; } } #endif #ifdef USE_IID /* * Internal iterative deepening: * * If we don't have a move from the hash table, search * this node with a shallower depth to get a good move * to search first. */ if (!node->get_hashmv() && depth > 2) { search(ply, depth-2, 0, alpha, beta); node->set_hashmv(node->get_best()); } #endif node->set_type(Node::FULLWIDTH); #ifdef USE_HISTORY node->set_historytable(histtable[tree.get_board().get_side()]); #endif /* * Futility pruning, extended futility pruning, and razoring. */ #ifdef USE_RAZORING if (depth == 3 && (node->material_balance() + 900 <= alpha)) { STAT_INC(stat_razcut); depth--; } #endif // USE_RAZORING #ifdef USE_FUTILITYPRUNING bool fprune = false; if (depth == 1 && (node->material_balance() + 300 <= alpha)) { fprune = true; #ifdef USE_EXTENDED_FUTILITYPRUNING } else if (depth == 2 && (node->material_balance() + 500 <= alpha)) { STAT_INC(stat_xfutcut); fprune = true; depth--; #endif // USE_EXTENDED_FUTILITYPRUNING } #endif // USE_FUTILITYPRUNING /* * Search extensions. */ if (extend == 0) { #ifdef EXTEND_IN_CHECK if (node->in_check()) { extend++; } #endif #ifdef EXTEND_RECAPTURE if (ply >= 3) { int mb = node->material_balance(); int mb1 = -tree[ply-1]->material_balance(); int mb2 = tree[ply-2]->material_balance(); int mb3 = -tree[ply-3]->material_balance(); if (abs(mb - mb1) >= 900 && abs(mb - mb2) >= 900 && abs(mb - mb3) >= 900) { extend++; } } #endif } else { depth += extend; extend = 0; } /* * Search all successor moves. */ for (Move mov = node->first(); mov; mov = node->next()) { Node * cnode = tree.make_move(mov); if (!tree.get_board().is_legal()) { tree.unmake_move(); continue; } moves++; #ifdef USE_FUTILITYPRUNING /* Futility pruning */ if (fprune && !node->in_check() && !cnode->in_check() && !mov.is_capture() #ifdef HOICHESS && !mov.is_enpassant() && !mov.is_promotion() #endif // HOICHESS ) { STAT_INC(stat_futcut); tree.unmake_move(); continue; } #endif // USE_FUTILITYPRUNING #ifdef USE_PVS /* Search the current move. We use a standard * principal variation search here. */ if (first) { score = -search(ply+1, depth-1, extend, -beta, -alpha); first = false; } else { score = -search(ply+1, depth-1, extend, -alpha-1, -alpha); if (score > alpha && score < beta) { score = -search(ply+1, depth-1, extend, -beta, -alpha); } } #else /* Search the current move. We use a pure * alpha-beta search here. */ score = -search(ply+1, depth-1, extend, -beta, -alpha); #endif tree.unmake_move(); if (nodes >= next_timecheck) { check_time(); next_timecheck = nodes + TIMECHECK_INTERVAL; } if (stop) { return alpha; } if (score > alpha) { alpha = score; node->set_best(mov); if (score >= beta) { STAT_INC(stat_cut); break; } } } /* Test for checkmate or stalemate */ #if defined(HOICHESS) if (moves == 0) { if (node->in_check()) { alpha = -INFTY + ply; } else { alpha = DRAW; } } #elif defined(HOIXIANGQI) if (moves == 0) { alpha = -INFTY + ply; } #else # error "neither HOICHESS nor HOIXIANGQI is defined" #endif /* Save search result in hash table. */ if (hashtable && alpha > -MATE && alpha < MATE) { int scoretype; if (alpha >= beta) { scoretype = HashEntry::BETA; } else if (alpha <= save_alpha) { scoretype = HashEntry::ALPHA; } else { scoretype = HashEntry::EXACT; } hashentry = HashEntry(tree.get_board(), alpha, node->get_best(), depth, scoretype); hashtable->put(hashentry); } #ifdef USE_HISTORY /* Update history table */ if (node->get_best()) { histtable[tree.get_board().get_side()]->add(node->get_best()); } #endif #ifdef USE_KILLER /* Update killer */ if (node->get_best() != node->get_hashmv() && !(node->get_best().is_capture()) #ifdef HOICHESS && !(node->get_best().is_enpassant()) && !(node->get_best().is_promotion()) #endif // HOICHESS ) { node->add_killer(node->get_best()); } #endif // USE_KILLER #ifdef COLLECT_STATISTICS stat_moves_sum += moves; stat_moves_cnt++; #endif return alpha; } int Search::quiescence_search(unsigned int ply, int alpha, int beta) { ASSERT_DEBUG(tree.get_current_ply() == ply); Node * node = tree[ply]; int score; int moves = 0; nodes_quiesce++; if (ply > maxplyreached_quiesce) { maxplyreached_quiesce = ply; } /* * First look into the hash table if this * position has already been search before. * * TODO This surely needs some verification */ HashEntry hashentry; if (hashtable && hashtable->probe(tree.get_board(), &hashentry)) { score = hashentry.get_score(); switch (hashentry.get_type()) { case HashEntry::EXACT: case HashEntry::QUIESCE: hashtable->incr_hits2(); return score; case HashEntry::ALPHA: if (score <= alpha) { hashtable->incr_hits2(); return score; } break; #if 0 case HashEntry::BETA: if (score >= beta) { hashtable->incr_hits2(); return score; } break; #endif } } /* * Evaluate board position. * * This score will be returned if none * of the moves is better than alpha. */ score = evaluator->eval(tree.get_board(), alpha, beta, myside); if (score >= beta) { /* TODO Is this really a good idea? */ return score; } else if (score > alpha) { alpha = score; } /* MAXPLY is an absolute depth limit */ if (ply == MAXPLY-1) { WARN("reached maximum tree depth: %d", ply); return score; } node->set_type(Node::QUIESCE); for (Move mov = node->first(); mov; mov = node->next()) { tree.make_move(mov); if (!tree.get_board().is_legal()) { tree.unmake_move(); continue; } moves++; score = -quiescence_search(ply+1, -beta, -alpha); tree.unmake_move(); if (score > alpha) { alpha = score; node->set_best(mov); if (score >= beta) { STAT_INC(stat_cut); break; } } } /* Test for checkmate */ if (moves == 0 && node->in_check()) alpha = -INFTY + ply; /* Save search result in hash table. */ if (hashtable && alpha > -MATE && alpha < MATE) { hashentry = HashEntry(tree.get_board(), alpha, node->get_best(), 0, HashEntry::QUIESCE); hashtable->put(hashentry); } #ifdef COLLECT_STATISTICS stat_moves_sum_quiesce += moves; stat_moves_cnt_quiesce++; #endif return alpha; } /* * Return true if the current position is a draw (draw by rule). */ bool Search::is_draw() { const Board & board = tree.get_board(); /* 50 move rule */ if (board.get_movecnt50() >= 100) { return true; } /* Draw due to insufficient material */ if (board.is_material_draw()) { return true; } /* Look for repetitions in the tree */ int rep = 1; for (int ply=tree.get_current_ply()-1; ply>=0; ply--) { if (tree[ply]->get_hashkey() == board.get_hashkey()) { rep++; } if (rep >= 2) { return true; } } /* Look for repetitions in the game history */ rep += game->repetitions_search(board); if (rep >= 2) { return true; } return false; } void Search::check_time() { if (clock->timeout() && mode == MOVE) { stop = true; } if (showthinking && clock->get_elapsed_time() >= next_update) { print_thinking(rootdepth); } } hoichess_0.10.3/src/movelist.cc0000640000175000017500000000302210732031250015766 0ustar oliveroliver/* $Id: movelist.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/movelist.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "move.h" #include "movelist.h" Movelist::Movelist() { nextin = 0; nextout = 0; } Movelist::~Movelist() {} void Movelist::filter_illegal(const Board & board) { for (unsigned int i=0; i Movelist::maxsize; void Movelist::print_stats() { printf("maximum movelist size statistics:\n"); printf("size\tcount\n"); for (std::map::iterator it = maxsize.begin(); it != maxsize.end(); it++) { printf("%d\t%d\n", it->first, it->second); } } #endif hoichess_0.10.3/src/evalcache.h0000640000175000017500000000361010732031250015704 0ustar oliveroliver/* $Id: evalcache.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/evalhash.h * * Copyright (C) 2005, 2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef EVALCACHE_H #define EVALCACHE_H #include "board.h" /***************************************************************************** * * Class EvaluationCache * *****************************************************************************/ class EvaluationCache { private: /* A cache slot is empty if score == INT_MIN. */ struct cacheentry { Hashkey hashkey; int score; }; public: static const size_t SIZEOF_ENTRY = sizeof(struct cacheentry); private: unsigned long cache_size; struct cacheentry * cache; unsigned long entries; #ifdef COLLECT_STATISTICS unsigned long stat_probes; unsigned long stat_hits; unsigned long stat_collisions; #endif public: EvaluationCache(unsigned long size); ~EvaluationCache(); public: void clear(); bool put(const Board & board, int score); bool probe(const Board & board, int * score); void print_info(FILE * fp = stdout) const; void print_statistics(FILE * fp = stdout) const; void reset_statistics(); }; #endif // EVALCACHE_H hoichess_0.10.3/src/compile.h0000640000175000017500000000266110732031250015426 0ustar oliveroliver/* $Id: compile.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/compile.h * * Copyright (C) 2004-2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef COMPILE_H #define COMPILE_H #define COMPILE_DATE __DATE__ " " __TIME__ #if defined(__GNUC__) # define COMPILER "GCC" # define COMPILER_VERSION __VERSION__ #elif defined(__INTEL_COMPILER) # define COMPILER "ICC" # define COMPILER_VERSION "unknown" #else # define COMPILER "unknown" # define COMPILER_VERSION "unknown" #endif #if defined(__unix__) # define PLATFORM "unix" #elif defined(WIN32) && defined(__MINGW32__) # define PLATFORM "mingw32" #elif defined(WIN32) # define PLATFORM "win32" #else # define PLATFORM "unknown" #endif #endif /* COMPILE_H */ hoichess_0.10.3/src/historytable.h0000640000175000017500000000345210732031250016506 0ustar oliveroliver/* $Id: historytable.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/historytable.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef HISTORYTABLE_H #define HISTORYTABLE_H #include "basic.h" #include class HistoryTable { private: unsigned long table[BOARDSIZE][BOARDSIZE]; public: inline HistoryTable(); inline ~HistoryTable(); public: inline void reset(); inline void add(Move mov); inline unsigned long get(Move mov); }; inline HistoryTable::HistoryTable() { reset(); } inline HistoryTable::~HistoryTable() {} inline void HistoryTable::reset() { memset(table, 0, sizeof(table)); } inline void HistoryTable::add(Move mov) { ASSERT_DEBUG(mov.from() >= 0 && mov.from() < BOARDSIZE); ASSERT_DEBUG(mov.to() >= 0 && mov.to() < BOARDSIZE); table[mov.from()][mov.to()]++; } inline unsigned long HistoryTable::get(Move mov) { ASSERT_DEBUG(mov.from() >= 0 && mov.from() < BOARDSIZE); ASSERT_DEBUG(mov.to() >= 0 && mov.to() < BOARDSIZE); return table[mov.from()][mov.to()]; } #endif // HISTORYTABLE_H hoichess_0.10.3/src/shell_cmd.cc0000640000175000017500000005610510732031250016070 0ustar oliveroliver/* $Id: shell_cmd.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/shell_cmd.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "shell.h" #include "bench.h" #include "pgn.h" #include #include #include struct Shell::command Shell::commands[] = { /* xboard protocol commands */ { "xboard", &Shell::cmd_xboard, false, "" }, { "protover", &Shell::cmd_protover, false, "" }, { "accepted", &Shell::cmd_accepted, false, "" }, { "rejected", &Shell::cmd_rejected, false, "" }, { "new", &Shell::cmd_new, false, "Start a new game" }, { "variant", &Shell::cmd_variant, false, "" }, { "quit", &Shell::cmd_quit, false, "Quit" }, { "random", NULL, true, "" }, { "force", &Shell::cmd_force, false, "Let engine make no moves at all" }, { "go", &Shell::cmd_go, false, "Switch sides, let computer make next move" }, { "playother", NULL, false, "" }, { "white", NULL, false, "" }, { "black", NULL, false, "" }, { "level", &Shell::cmd_level, false, "" }, { "st", &Shell::cmd_st, false, "" }, { "sd", &Shell::cmd_sd, false, "" }, { "time", &Shell::cmd_time, false, "" }, { "otim", &Shell::cmd_otim, false, "" }, { "usermove", NULL, false, "" }, { "?", NULL, false, "" }, { "ping", &Shell::cmd_ping, false, "" }, { "draw", NULL, false, "" }, { "result", NULL, true, "" }, { "setboard", &Shell::cmd_setboard, false, "" }, { "edit", NULL, false, "" }, { "hint", NULL, false, "" }, { "bk", &Shell::cmd_bk, false, "" }, { "undo", &Shell::cmd_undo, false, "" }, { "remove", &Shell::cmd_remove, false, "" }, { "hard", &Shell::cmd_hard, false, "Turn on pondering (thinking on opponent's time)" }, { "easy", &Shell::cmd_easy, false, "Turn off pondering" }, { "post", &Shell::cmd_post, false, "Show thinking output" }, { "nopost", &Shell::cmd_nopost, false, "Hide thinking output" }, { "analyze", &Shell::cmd_analyze, false, "Enter analysis mode" }, { "exit", &Shell::cmd_exit, false, "Leave analysis mode" }, { "name", NULL, true, "" }, { "rating", NULL, false, "" }, { "ics", NULL, false, "" }, { "computer", NULL, true, "" }, { "pause", NULL, false, "" }, { "resume", NULL, false, "" }, { ".", NULL, true, "" }, /* own commands */ { "verbose", &Shell::cmd_verbose, false, "" }, { "debug", &Shell::cmd_debug, false, "" }, { "ignore", &Shell::cmd_ignore, false, "" }, { "obey", &Shell::cmd_obey, false, "" }, { "help", &Shell::cmd_help, false, "" }, { "source", &Shell::cmd_source, false, "" }, { "echo", &Shell::cmd_echo, false, "" }, { "show", &Shell::cmd_show, false, "" }, { "solve", &Shell::cmd_solve, false, "" }, { "bench", &Shell::cmd_bench, false, "" }, { "book", &Shell::cmd_book, false, "" }, { "hash", &Shell::cmd_hash, false, "" }, { "pawnhash", &Shell::cmd_pawnhash, false, "" }, { "evalcache", &Shell::cmd_evalcache, false, "" }, { "set", &Shell::cmd_set, false, "" }, { "get", &Shell::cmd_get, false, "" }, { "playboth", &Shell::cmd_playboth, false, "" }, { "loadgame", &Shell::cmd_loadgame, false, "" }, { "savegame", &Shell::cmd_savegame, false, "" }, { "redo", &Shell::cmd_redo, false, "" }, { NULL, NULL, false, NULL } }; #define CMD_REQUIRE_ARGS(n) do { \ if (cmd_args.size() < (n)+1) { \ printf("Error: Command requires %d argument%s.\n", \ (n), ((n) == 1 ? "" : "s")); \ return; \ } \ } while(0) void Shell::cmd_xboard() { set_xboard(true); } void Shell::cmd_protover() { CMD_REQUIRE_ARGS(1); std::ostringstream ss; ss << "feature"; ss << " myname=\"" << myname << "\""; #if defined(HOICHESS) ss << " variants=\"normal\""; #elif defined(HOIXIANGQI) ss << " variants=\"xiangqi\""; #else # error "neither HOICHESS nor HOIXIANGQI defined" #endif ss << " ping=1 setboard=1 time=1 sigint=0 colors=0"; #if defined(HAVE_PTHREAD) || defined(WIN32) ss << " analyze=1"; #else ss << " analyze=0"; #endif ss << " name=1"; ss << " done=1\n"; atomic_printf("%s", ss.str().c_str()); } void Shell::cmd_accepted() { if (!xboard) { printf("yeah!\n"); } } void Shell::cmd_rejected() { CMD_REQUIRE_ARGS(1); printf("tellusererror Feature `%s' was rejected, expect problems\n", cmd_args[1].c_str()); } void Shell::cmd_new() { search->stop_thread(); if (!game->set_board(opening_fen())) { BUG("Failed to set up standard opening position"); } if (!flag_analyze) { flag_force = false; myside = BLACK; } } void Shell::cmd_variant() { CMD_REQUIRE_ARGS(1); const std::string& v = cmd_args[1]; #if defined(HOICHESS) if (0) { /* for standard chess, the 'variant' command is never sent */ #elif defined(HOIXIANGQI) if (v == "xiangqi") { /* used by Winboard_F by H.G. Muller */ #else # error "neither HOICHESS nor HOIXIANGQI defined" #endif } else { printf("Error (variant not supported): %s\n", v.c_str()); } } void Shell::cmd_quit() { quit = true; } void Shell::cmd_force() { search->stop_thread(); flag_force = true; flag_playboth = false; myside = NO_COLOR; } void Shell::cmd_go() { search->stop_thread(); flag_force = false; flag_playboth = false; myside = game->get_side(); } void Shell::cmd_level() { CMD_REQUIRE_ARGS(3); int moves; if (sscanf(cmd_args[1].c_str(), "%d", &moves) != 1) { moves = -1; } /* Argument might be '5' (= 5 minutes) or '0:30' (= 30 seconds) */ int mins, secs; if (sscanf(cmd_args[2].c_str(), "%d:%d", &mins, &secs) != 2) { secs = 0; if (sscanf(cmd_args[2].c_str(), "%d", &mins) != 1) { mins = -1; } } secs = mins * 60 + secs; int inc; if (sscanf(cmd_args[3].c_str(), "%d", &inc) != 1) { inc = -1; } if (moves < 0 || secs <= 0 || inc < 0) { printf("Illegal argument to command `level': %s %s %s\n", cmd_args[1].c_str(), cmd_args[2].c_str(), cmd_args[3].c_str()); return; } Clock clock(moves, secs, inc); game->set_clocks(clock, clock); } void Shell::cmd_st() { CMD_REQUIRE_ARGS(1); int secs = atoi(cmd_args[1].c_str()); if (secs > 0) { Clock clock(secs); game->set_clocks(clock, clock); } else { printf("Illegal time value.\n"); } } void Shell::cmd_sd() { CMD_REQUIRE_ARGS(1); unsigned int depth = atoi(cmd_args[1].c_str()); if (depth == 0) { printf("Unlimited search depth.\n"); } else { printf("Search depth limited to %u ply.\n", depth); } search->set_depthlimit(depth); } void Shell::cmd_time() { CMD_REQUIRE_ARGS(1); unsigned int csecs; if (sscanf(cmd_args[1].c_str(), "%u", &csecs) != 1) { printf("Illegal argument to command 'time': %s\n", cmd_args[1].c_str()); return; } if (myside != NO_COLOR) { Clock clock = game->get_clock(myside); clock.set_remaining_time(csecs); game->set_clock(myside, clock); } } void Shell::cmd_otim() { CMD_REQUIRE_ARGS(1); unsigned int csecs; if (sscanf(cmd_args[1].c_str(), "%u", &csecs) != 1) { printf("Illegal argument to command 'otim': %s\n", cmd_args[1].c_str()); return; } if (myside != NO_COLOR) { Clock clock = game->get_clock(XSIDE(myside)); clock.set_remaining_time(csecs); game->set_clock(XSIDE(myside), clock); } } void Shell::cmd_ping() { CMD_REQUIRE_ARGS(1); atomic_printf("pong %s\n", cmd_args[1].c_str()); } void Shell::cmd_setboard() { search->stop_thread(); CMD_REQUIRE_ARGS(6); std::string fen = cmd_args[1] + " " + cmd_args[2] + " " + cmd_args[3] + " " + cmd_args[4] + " " + cmd_args[5] + " " + cmd_args[6]; if (!game->set_board(fen.c_str())) { if (xboard) { printf("tellusererror Illegal position\n"); } else { printf("Error (illegal position): %s\n", fen.c_str()); } return; } print_result(); } void Shell::cmd_bk() { BookEntry entry; if (book && book->lookup(game->get_board(), &entry)) { entry.print(game->get_board()); } else { printf(" Nothing found in book\n"); } /* Must finish with an empty line */ printf("\n"); } void Shell::cmd_undo() { search->stop_thread(); if (cmd_args.size() == 2 && cmd_args[1] == "all") { while (game->undo_move()) {} } else { if (!game->undo_move()) { if (!xboard) { printf("No move to be undone.\n"); } } } } void Shell::cmd_remove() { search->stop_thread(); game->undo_move(); game->undo_move(); } void Shell::cmd_hard() { flag_ponder = true; } void Shell::cmd_easy() { search->stop_thread(); flag_ponder = false; } void Shell::cmd_post() { flag_showthinking = true; search->set_showthinking(true); } void Shell::cmd_nopost() { flag_showthinking = false; search->set_showthinking(false); } void Shell::cmd_analyze() { search->stop_thread(); cmd_force(); cmd_post(); flag_analyze = true; } void Shell::cmd_exit() { search->stop_thread(); flag_analyze = false; } void Shell::cmd_verbose() { if (cmd_args.size() == 2) { unsigned int tmp; if (sscanf(cmd_args[1].c_str(), "%d", &tmp) == 1) { verbose = tmp; printf("Verbosity set to %d.\n", verbose); } } else { printf("Verbosity set to %d.\n", verbose); } } void Shell::cmd_debug() { if(cmd_args.size() == 2) { unsigned int tmp; if (sscanf(cmd_args[1].c_str(), "%d", &tmp) == 1) { debug = tmp; printf("Debug level set to %d.\n", debug); } } else { printf("Debug level set to %d.\n", debug); } } void Shell::cmd_ignore() { CMD_REQUIRE_ARGS(1); for (int i=0; commands[i].name != NULL; i++) { if (cmd_args[1] != commands[i].name) continue; commands[i].ignore = true; if (!xboard) { printf("Ignoring command '%s' from now on.\n", cmd_args[1].c_str()); } return; } printf("Error (unknown command): %s\n", cmd_args[1].c_str()); } void Shell::cmd_obey() { CMD_REQUIRE_ARGS(1); for (int i=0; commands[i].name != NULL; i++) { if (cmd_args[1] != commands[i].name) continue; commands[i].ignore = false; if (!xboard) { printf("Won't ignore command '%s' anymore.\n", cmd_args[1].c_str()); } return; } printf("Error (unknown command): %s\n", cmd_args[1].c_str()); } void Shell::cmd_help() { printf("Available commands:\n"); printf("\t\t\tPlay move (coordinate notation or SAN)\n"); for (int i=0; commands[i].name != NULL; i++) { if (commands[i].func == NULL || commands[i].ignore) continue; printf("\t%s\t\t%s\n", commands[i].name, commands[i].usage); } } void Shell::cmd_source() { CMD_REQUIRE_ARGS(1); const char * filename = cmd_args[1].c_str(); FILE * fp = fopen(filename, "r"); if (fp == NULL) { fprintf(stderr, "Cannot open %s for reading: %s\n", filename, strerror(errno)); exit(EXIT_FAILURE); } source_file(fp, filename); } void Shell::cmd_echo() { std::string s; for (unsigned int i=1; i 1) { s += " "; } s += cmd_args[i]; } atomic_printf("%s\n", s.c_str()); } void Shell::cmd_show() { CMD_REQUIRE_ARGS(1); std::string param = cmd_args[1]; const Board & board = game->get_board(); if (param == "board") { board.print(); } else if (param == "fen") { printf("%s\n", board.get_fen().c_str()); } else if (param == "moves" || param == "captures" || param == "noncaptures" || param == "escapes") { Movelist moves; if (param == "moves") { board.generate_moves(&moves); } else if (param == "captures") { board.generate_captures(&moves); } else if (param == "noncaptures") { board.generate_noncaptures(&moves); } else if (param == "escapes") { board.generate_escapes(&moves); } else { BUG("param == %s", param.c_str()); } moves.filter_illegal(board); unsigned int j=1; for (unsigned int i=0; iget_clock(WHITE).print(); printf("\n[Black]\n"); game->get_clock(BLACK).print(); } else if (param == "game") { game->print(stdout); } else if (param == "pgn") { game->write_pgn(stdout); } else { printf("Usage: show {board|fen}\n"); printf(" show {moves|captures|noncaptures|escapes}\n"); printf(" show eval\n"); printf(" show clocks\n"); printf(" show game\n"); printf(" show pgn\n"); } } void Shell::cmd_solve() { search->stop_thread(); CMD_REQUIRE_ARGS(1); const char * filename = cmd_args[1].c_str(); FILE * fp; if ((fp = fopen(filename, "r")) == NULL) { printf("Cannot open %s: %s\n", filename, strerror(errno)); return; } log("solve: %s\n", filename); int right = 0; int wrong = 0; int total = 0; int skipped = 0; char buf[1024]; while (fgets(buf, sizeof(buf), fp) != NULL) { printf("--------------------------------------------------\n"); /* Parse EPD, print FEN and board */ EPD epd(buf); Board board(epd.get_fen().c_str()); printf("[%s] %s\n", epd.get1("id").c_str(), epd.get_fen().c_str()); printf("\n"); board.print_small(); printf("\n"); /* Get the list of best moves */ std::list bms = epd.get("bm"); std::list::const_iterator it; if (bms.size() == 0) { printf("No best move associated to this position," " skipping.\n"); skipped++; continue; } /* Print the list of best moves */ printf("Best move:"); for (it = bms.begin(); it != bms.end(); it++) printf(" %s", it->c_str()); printf("\n"); /* Start search */ if (hashtable) { printf("Clearing hash table.\n"); hashtable->clear(); } if (pawnhashtable) { printf("Clearing pawn hash table.\n"); pawnhashtable->clear(); } if (evalcache) { printf("Clearing evaluation cache.\n"); evalcache->clear(); } printf("Thinking...\n"); search->start(board, game->get_clock(), Search::MOVE); Move mov = search->get_best(); /* Look if our move is among the best */ bool correct = false; for (it = bms.begin(); it != bms.end(); it++) { if (*it == mov.san(board)) { right++; correct = true; break; } } if (it == bms.end()) { wrong++; correct = false; } printf("My move: %s (%s)\n", mov.san(board).c_str(), correct ? "correct" : "incorrect"); log("position: %s\tmove: %s\t(%s)\n", epd.get1("id").c_str(), mov.san(board).c_str(), correct ? "correct" : "incorrect"); total = right + wrong; printf("Correct: %d of %d (%d%%), skipped: %d\n", right, total, 100 * right / total, skipped); if (stop) { break; } } log("solve finished: correct %d/%d\n", right, total); fclose(fp); } void Shell::cmd_bench() { search->stop_thread(); CMD_REQUIRE_ARGS(1); const std::string type = cmd_args[1]; if (type == "movegen") { Bench bench; bench.bench_movegen(); } else if (type == "evaluator") { Bench bench; bench.bench_evaluator(); } else if (type == "makemove") { Bench bench; bench.bench_makemove(); } else { printf("Usage: bench movegen\n"); printf(" bench evaluator\n"); printf(" bench makemove\n"); return; } } void Shell::cmd_book() { CMD_REQUIRE_ARGS(1); const std::string param = cmd_args[1]; if (param == "close" || param == "off") { delete book; book = NULL; } else if (param == "open") { CMD_REQUIRE_ARGS(2); const char * file = cmd_args[2].c_str(); set_book(file); } else if (param == "create") { CMD_REQUIRE_ARGS(5); const char * destfile = cmd_args[2].c_str(); const char * srcfile = cmd_args[3].c_str(); int depth; if (sscanf(cmd_args[4].c_str(), "%d", &depth) != 1) { printf("Error: argument must be non-negative" " integer\n"); return; } int min_move_count; if (sscanf(cmd_args[5].c_str(), "%d", &min_move_count) != 1) { printf("Error: argument must be" " non-negative integer\n"); return; } printf("Creating opening book `%s' from `%s' ...\n", destfile, srcfile); Book::create_from_pgn(destfile, srcfile, depth, min_move_count); } else { printf("Usage: book close\n"); printf(" book open \n"); printf(" book create " " \n"); } } void Shell::cmd_hash() { CMD_REQUIRE_ARGS(1); const std::string param = cmd_args[1]; if (param == "clear") { if (hashtable) { search->stop_thread(); hashtable->clear(); printf("Hash table cleared.\n"); } else { printf("Error: hash table is disabled\n"); } } else if (param == "size") { CMD_REQUIRE_ARGS(2); const char * s = cmd_args[2].c_str(); long size; if (!parse_size(s, &size) || size < 0) { printf("Illegal value for hash table size: %s\n", s); return; } search->stop_thread(); set_hashsize((unsigned) size); } else if (param == "off") { search->stop_thread(); set_hashsize(0); } else if (param == "info") { if (hashtable) { hashtable->print_info(); } else { printf("Hash table is disabled.\n"); } } else if (param == "stats") { if (hashtable) { hashtable->print_statistics(); } else { printf("Error: hash table is disabled\n"); } } else if (param == "replace") { CMD_REQUIRE_ARGS(2); if (hashtable) { hashtable->set_replacement_scheme(cmd_args[2]); } else { printf("Error: hash table is disabled\n"); } } else { printf("Usage: hash clear\n"); printf(" hash size \n"); printf(" hash off\n"); printf(" hash info\n"); printf(" hash stats\n"); } } void Shell::cmd_pawnhash() { CMD_REQUIRE_ARGS(1); const std::string param = cmd_args[1]; if (param == "clear") { if (pawnhashtable) { search->stop_thread(); pawnhashtable->clear(); printf("Pawn hash table cleared.\n"); } else { printf("Error: pawn hash table is disabled\n"); } } else if (param == "size") { CMD_REQUIRE_ARGS(2); const char * s = cmd_args[2].c_str(); long size; if (!parse_size(s, &size) || size < 0) { printf("Illegal value for pawn hash table size: %s\n", s); return; } search->stop_thread(); set_pawnhashsize((unsigned) size); } else if (param == "off") { search->stop_thread(); set_pawnhashsize(0); } else if (param == "info") { if (pawnhashtable) { pawnhashtable->print_info(); } else { printf("Pawn hash table is disabled.\n"); } } else if (param == "stats") { if (pawnhashtable) { pawnhashtable->print_statistics(); } else { printf("Error: Pawn hash table is disabled\n"); } } else { printf("Usage: pawnhash clear\n"); printf(" pawnhash size \n"); printf(" pawnhash off\n"); printf(" pawnhash info\n"); printf(" pawnhash stats\n"); } } void Shell::cmd_evalcache() { CMD_REQUIRE_ARGS(1); const std::string param = cmd_args[1]; #ifdef USE_EVALCACHE if (param == "clear") { if (evalcache) { search->stop_thread(); evalcache->clear(); printf("Evaluation cache cleared.\n"); } else { printf("Error: evaluation cache is disabled\n"); } } else if (param == "size") { CMD_REQUIRE_ARGS(2); const char * s = cmd_args[2].c_str(); long size; if (!parse_size(s, &size) || size < 0) { printf("Illegal value for evaluation cache size: %s\n", s); return; } search->stop_thread(); set_evalcachesize((unsigned) size); } else if (param == "off") { search->stop_thread(); set_evalcachesize(0); } else if (param == "info") { if (evalcache) { evalcache->print_info(); } else { printf("Evaluation cache is disabled.\n"); } } else if (param == "stats") { if (evalcache) { evalcache->print_statistics(); } else { printf("Error: evaluation cache is disabled\n"); } } else { printf("Usage: evalcache clear\n"); printf(" evalcache size \n"); printf(" evalcache off\n"); printf(" evalcache info\n"); printf(" evalcache stats\n"); } #else printf("Error: This version of %s has been compiled without" " evaluation cache support.\n", PROGNAME); #endif } void Shell::cmd_set() { CMD_REQUIRE_ARGS(1); if (cmd_args[1] == "myname") { CMD_REQUIRE_ARGS(2); set_myname(cmd_args[2].c_str()); printf("myname set to %s\n", cmd_args[2].c_str()); } else if (cmd_args[1] == "searchparam") { CMD_REQUIRE_ARGS(3); const std::string& name = cmd_args[2]; const std::string& value = cmd_args[3]; search->set_param(name, value); } else if (cmd_args[1] == "evalparam") { CMD_REQUIRE_ARGS(3); const std::string& name = cmd_args[2]; const std::string& value = cmd_args[3]; search->get_evaluator()->set_param(name, value); } else { printf("Illegal argument to command 'set': '%s'\n", cmd_args[1].c_str()); } } void Shell::cmd_get() { CMD_REQUIRE_ARGS(1); if (cmd_args[1] == "myname") { printf("myname = %s\n", myname.c_str()); #if 0 } else if (cmd_args[1] == "searchparam") { //unsigned long features = search->get_features(); //printf("search_features = 0x%lx\n", features); #endif } else { printf("Illegal argument to command 'get': '%s'\n", cmd_args[1].c_str()); } } void Shell::cmd_playboth() { search->stop_thread(); flag_playboth = true; flag_force = false; } void Shell::cmd_loadgame() { CMD_REQUIRE_ARGS(1); const char * pgnfile = cmd_args[1].c_str(); FILE* fp = fopen(pgnfile, "r"); if (fp == NULL) { fprintf(stderr, "Cannot open %s for reading: %s\n", pgnfile, strerror(errno)); return; } PGN pgn; pgn.parse(fp); fclose(fp); Game g(pgn.get_opening(), Clock(), Clock()); std::list moves = pgn.get_moves(); for (std::list::const_iterator it = moves.begin(); it != moves.end(); it++) { GameEntry::MoveAttributes move_attr(false, false); g.make_move(*it, move_attr); } printf("--- begin read game ---\n"); g.write_pgn(stdout); printf("--- end read game ---\n"); search->stop_thread(); *game = g; } void Shell::cmd_savegame() { CMD_REQUIRE_ARGS(1); const char * pgnfile = cmd_args[1].c_str(); FILE* fp = fopen(pgnfile, "w"); if (fp == NULL) { fprintf(stderr, "Cannot open %s for writing: %s\n", pgnfile, strerror(errno)); return; } game->write_pgn(fp); fclose(fp); } void Shell::cmd_redo() { search->stop_thread(); Move mov; if (cmd_args.size() == 2 && cmd_args[1] == "all") { Move mov0; do { mov = mov0; mov0 = game->redo_move(); } while (mov0); if (!mov) { if (!xboard) { printf("No move to be redone.\n"); } return; } } else { mov = game->redo_move(); if (!mov) { if (!xboard) { printf("No move to be redone.\n"); } return; } } if (!xboard) { game->get_board().print(stdout, mov); if (game->get_result()) { print_result(); } } } hoichess_0.10.3/src/book.cc0000640000175000017500000003570510732031250015073 0ustar oliveroliver/* $Id: book.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/book.cc * * Copyright (C) 2005-2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "book.h" #include "pgn.h" #include #include #include #include #include #include #include #include /***************************************************************************** * * Member functions of class BookHeader. * *****************************************************************************/ BookHeader::BookHeader() { magic = s_magic; } /* * Function to convert from book to host byte order. */ BookHeader BookHeader::h2b(const BookHeader& h, bool swap_byteorder) { if (!swap_byteorder) { return h; } else { BookHeader b; b.size = reverse_byte_order(h.size); b.magic = reverse_byte_order(h.magic); return b; } } /* * Function to convert from book to host byte order. */ BookHeader BookHeader::b2h(const BookHeader& b, bool swap_byteorder) { if (!swap_byteorder) { return b; } else { /* mapping is symmetric */ return h2b(b, swap_byteorder); } } /***************************************************************************** * * Member functions of class BookEntry. * *****************************************************************************/ BookEntry::BookEntry() { hashkey = NULLHASHKEY; for (unsigned int i=0; i > moves) { hashkey = _hashkey; for (unsigned int i=0; i= moves.size()) break; move[i] = moves[i].first; count[i] = moves[i].second; } } /* * Function to convert from book to host byte order. */ BookEntry BookEntry::h2b(const BookEntry& h, bool swap_byteorder) { if (!swap_byteorder) { return h; } else { BookEntry b; b.hashkey = reverse_byte_order(h.hashkey); for (unsigned int i=0; iis_empty()) { /* Slot is totally empty */ return false; } else if (entry->hashkey != hashkey) { /* Collision */ continue; } else if (!entry->is_valid_and_legal(board)) { WARN("invalid or illegal move in book, perhaps an" "undetected hash collision"); return false; } else { return true; } } return false; } bool Book::put(const BookEntry & newentry) { unsigned long slot = 0; for (unsigned int i=0; i 5) { printf("(%d)", i); fflush(stdout); } #endif break; } else if (oldentry.hashkey != newentry.hashkey) { /* Collision */ if (i == header.size-1) { #ifdef DEBUG printf("X"); fflush(stdout); #endif return false; } continue; } else { /* Overwrite */ #ifdef DEBUG printf("O"); fflush(stdout); #endif break; } } write_entry(slot, newentry); return true; } /* * This is a simple multi hash function. It works rather well in practice. */ unsigned long Book::hashfunc(Hashkey hashkey, unsigned int i) const { return (hashkey % header.size + i * (hashkey % (header.size-1))) % header.size; } /* * Read a PGN game database and create a new opening book from the first * `depth' moves of each game. */ void Book::create_from_pgn(const char * bookfile, const char * pgnfile, unsigned int depth, unsigned int min_move_count) { FILE * fp = fopen(pgnfile, "r"); if (!fp) { fprintf(stderr, "Cannot open %s for reading: %s\n", pgnfile, strerror(errno)); exit(EXIT_FAILURE); } /* * Read all games from PGN file. Create a map with a position's * hash key and a list of moves played in this position. * * TODO This is very slow. */ std::map > pgnmap; unsigned long read = 0, skipped = 0; while (!feof(fp)) { PGN pgn; if (pgn.parse(fp)) { Board board = pgn.get_opening(); std::list moves = pgn.get_moves(); unsigned int i = 0; for (std::list::iterator it = moves.begin(); it != moves.end(); it++) { ASSERT(it->is_valid(board)); ASSERT(it->is_legal(board)); pgnmap[board.get_hashkey()].push_back(*it); i++; if (i > depth && depth > 0) break; board.make_move(*it); } read++; } else { skipped++; } if ((read+skipped) % 231 == 0) { printf("Reading games: %lu games read, " "%lu games skipped due to errors\r", read, skipped); fflush(stdout); } } fclose(fp); printf("Reading games: %lu games read, " "%lu games skipped due to errors\n", read, skipped); printf("Total number of different positions in games: %lu\n", (unsigned long) pgnmap.size()); /* * Create a BookEntry for each position stored in * the map, and store all book entries in a list. */ /* Statistics about average number of moves per BookEntry. */ unsigned long stat_mpe_sum = 0, stat_mpe_cnt = 0; unsigned long nr_entries = 0; unsigned long nr_entries_total = pgnmap.size(); std::list entries; for (std::map >::iterator it = pgnmap.begin(); it != pgnmap.end(); it++) { BookEntry entry(it->first, group_moves(it->second, min_move_count)); if (!entry.is_empty()) { entries.push_back(entry); stat_mpe_sum += entry.nr_moves(); stat_mpe_cnt++; } nr_entries++; if (nr_entries % 500 == 0 || nr_entries == nr_entries_total) { printf("Sorting and filtering book contents: %lu%%\r", nr_entries * 100 / nr_entries_total); fflush(stdout); } } printf("\n"); float stat_mpe_avg = (stat_mpe_cnt != 0) ? ((float) stat_mpe_sum / stat_mpe_cnt) : ((float) 0); printf("Average number of moves per position: %.2f\n", stat_mpe_avg); /* * Write book to file. */ unsigned long booksize = entries.size(); printf("Opening book will contain %lu positions.\n", booksize); /* Add some extra space to reduce hash collisions */ unsigned long ext_booksize = (unsigned long) (booksize * 1.1); printf("Creating opening book with %lu entries.\n", ext_booksize); Book book(bookfile, ext_booksize); unsigned long written = 0, collisions = 0; for (std::list::iterator it = entries.begin(); it != entries.end(); it++) { if (book.put(*it)) { written++; } else { collisions++; } unsigned long total = written + collisions; if (total % 500 == 0 || total == booksize) { printf("Writing book to file: %lu%%\r", total * 100 / booksize); fflush(stdout); } } printf("\n"); printf("%lu entries written, %lu irresolvable collisions\n", written, collisions); } /* * Helper class needed by group_moves() to define a * strict weak ordering of std::pair. */ class cannot_imagine_a_name_for_this_class { public: inline bool operator()(const std::pair & a, const std::pair & b) const { return a.second > b.second; } }; /* * Take a list of moves and create a vector of all distinct moves together * with their total number of occurrencies in the list. The returned vector * will be sorted descendingly by the number of occurrencies. However, only * moves that appeared at least min_move_count times are kept. * We do this because we want to have only the most frequently played moves * in the opening book. */ std::vector > Book::group_moves( std::list moves, unsigned int min_move_count) { /* Count total number of occurrencies of each move. */ std::map count; for (std::list::iterator it = moves.begin(); it != moves.end(); it++) { count[*it]++; } /* Put entries of map into vector. */ std::vector > ret; for (std::map::iterator it2 = count.begin(); it2 != count.end(); it2++) { Move mov = it2->first; unsigned int cnt = it2->second; /* Keep only frequently played moves. */ if (cnt >= min_move_count) { ret.push_back(std::pair(mov, cnt)); } } cannot_imagine_a_name_for_this_class lt; std::sort(ret.begin(), ret.end(), lt); return ret; } /***************************************************************************** * Low-level book access funtions. *****************************************************************************/ void Book::read_header() { if (fseek(fp, 0, SEEK_SET) == -1) { perror("Book::read_header(): fseek() failed"); exit(EXIT_FAILURE); } BookHeader tmp_header; if (fread(&tmp_header, sizeof(BookHeader), 1, fp) != 1) { perror("Book::read_header(): fread() failed"); exit(EXIT_FAILURE); } header = BookHeader::b2h(tmp_header, swap_byteorder); } void Book::write_header() { if (fseek(fp, 0, SEEK_SET) == -1) { perror("Book::write_header(): fseek() failed"); exit(EXIT_FAILURE); } BookHeader tmp_header = BookHeader::h2b(header, swap_byteorder); if (fwrite(&tmp_header, sizeof(BookHeader), 1, fp) != 1) { perror("Book::read_header(): fwrite() failed"); exit(EXIT_FAILURE); } } BookEntry Book::read_entry(unsigned long slot) const { if (slot >= header.size) { BUG("Slot is beyond end of book: slot = %d, size = %d", slot, header.size); } unsigned long pos = sizeof(BookHeader) + slot * sizeof(BookEntry); if (fseek(fp, pos, SEEK_SET) == -1) { perror("Book::read_entry(): fseek() failed"); exit(EXIT_FAILURE); } BookEntry tmp_entry; if (fread(&tmp_entry, sizeof(BookEntry), 1, fp) != 1) { perror("Book::read_entry(): fread() failed"); exit(EXIT_FAILURE); } return BookEntry::b2h(tmp_entry, swap_byteorder); } void Book::write_entry(unsigned long slot, const BookEntry & entry) { if (slot >= header.size) { BUG("Slot is beyond end of book: slot = %d, size = %d", slot, header.size); } unsigned long pos = sizeof(BookHeader) + slot * sizeof(BookEntry); if (fseek(fp, pos, SEEK_SET) == -1) { perror("Book::write_entry(), fseek failed"); exit(EXIT_FAILURE); } BookEntry tmp_entry = BookEntry::h2b(entry, swap_byteorder); if (fwrite(&tmp_entry, sizeof(BookEntry), 1, fp) != 1) { perror("Book::write_entry(): fwrite() failed"); exit(EXIT_FAILURE); } } hoichess_0.10.3/src/uint64_table.cc0000640000175000017500000012500310732031250016430 0ustar oliveroliver/* $Id: uint64_table.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/uint64_table.cc */ #include "common.h" /* To share an opening book between different architectures * (which are likely to have different rand() implementations), * we need some static random numbers for use as hash keys. */ uint64_t uint64_table[] = { 0xac5372998e7fa920ULL, 0x8b9287c4f3be1092ULL, 0x8014fbf5e78fe2b3ULL, 0xfa00a57c1c8aa786ULL, 0x2ec1e9271c282cf5ULL, 0xd0a5c7546ea8bdcULL, 0x5462e59e577c3634ULL, 0x12954a162eb91797ULL, 0xd479ab5d8e694519ULL, 0xadc24340b231f6e2ULL, 0x953eaeda3647dbcULL, 0xd7c3408ed070eddfULL, 0x9b8a6322dc2b47c3ULL, 0xd0faf849bbaf3ed7ULL, 0xe4b3b3d0db51a818ULL, 0x2929215c946aa57bULL, 0xe689ed10cf0a3682ULL, 0xc0266e6d28141f95ULL, 0x6a9d9698f2e1e3a5ULL, 0x156293e0e6cfa24bULL, 0xe88d11dfe0762192ULL, 0x46ddcd630e88d4a1ULL, 0x692affd61496e17aULL, 0x4880cb52b4de0cd4ULL, 0x7b501aa47553f74eULL, 0x44f0dc817329bdb9ULL, 0x789eb9a76a04ac28ULL, 0xb66d6eaad1873443ULL, 0x4ff15e00d076527aULL, 0x40eca4bd9f5476abULL, 0xdbe1157b7243817eULL, 0xa424656aa44ff5f4ULL, 0xf5ab0087f3e0d020ULL, 0xa6ea55f0b818e805ULL, 0x7757f048b0dde69fULL, 0xe54c56a0c373c950ULL, 0x51e6dd7a2bf4d640ULL, 0x676e30d7dc599a2ULL, 0x3ff443601c101e1cULL, 0x2fee07585e805df2ULL, 0x71ffed2c655f55d4ULL, 0xb4587bcc3515768ULL, 0x9627841b7983d776ULL, 0x7dac7bb5879a4953ULL, 0x9da7e26a91519edeULL, 0x9b8bea01d11f6188ULL, 0x6ecfd4e75e39d4a8ULL, 0xb7403b2f32e1a32cULL, 0x237077c3afc87cbcULL, 0x46662d01d11bffa9ULL, 0x3940fa7c7c607dc0ULL, 0x2cda89b83a2b12d6ULL, 0xf5ec34ebdb8fb2d9ULL, 0xa78c48a4bc354e99ULL, 0x8fc7ba0b3bae7103ULL, 0xf04f9f4eba78adedULL, 0xa67856c082f7a10fULL, 0x71b30fb68d4b40c6ULL, 0xebda4f499a6d81b1ULL, 0x6ec85b0295f417fcULL, 0x7d5aad9c012bb65eULL, 0x546f62fcd1cd878cULL, 0x78f1ed06a6211484ULL, 0xb9aa20022f23a096ULL, 0x904600857b312733ULL, 0x54be945cbb9948f2ULL, 0x382e4fd7cd98fe9cULL, 0x2b76d9ebdd96afb1ULL, 0x6c20755ea5762b87ULL, 0x8d4e08e5a29284e7ULL, 0xd1fc8727e81b1bf1ULL, 0xf3b73ea4238dfe6aULL, 0xe1766208e21d609aULL, 0xa73a10e4d18cabedULL, 0x276ab3784ffcaeb4ULL, 0xdde2ac3f5efaba83ULL, 0x15b7cc684e390f57ULL, 0xa12031d1aaaefd1eULL, 0x23b9a267790b86f2ULL, 0x518404a0f1a37b0aULL, 0xf7a8d936733e791ULL, 0x6e64a5587965373ULL, 0x377322483db142f1ULL, 0xc1773cfdd040fe59ULL, 0xafc8768c0922cc86ULL, 0xcf0a22358da7adb0ULL, 0xc0dad99e4579bd83ULL, 0x64574f8bf13a4869ULL, 0x9c7d25fc5c850002ULL, 0x2237d12ab2aec1faULL, 0x80245d918e361e76ULL, 0x8a4ba3afd343df65ULL, 0xf3318982d45f5e30ULL, 0x14d2bc98598ec56fULL, 0x67d1385c9458fc6bULL, 0x1efde9ef5061cff5ULL, 0x5a7fdebbc82c5bf6ULL, 0xf33860cbfbd1651fULL, 0x82c1f18828cdc96cULL, 0xed309940526f7b03ULL, 0xf6af35974429d13eULL, 0x9c4ea24dc2dbaebaULL, 0xcbf656810b7ce5d5ULL, 0x6cbb77cacf3c87b0ULL, 0xce402b39b8d0a2d9ULL, 0xdc60d993aa019d2aULL, 0xed074c495fdb83eULL, 0x1bee7560b4e0f620ULL, 0xd749bb5053d2a8f4ULL, 0x1a8f5d3d14c0b173ULL, 0xca58481cf84c1714ULL, 0x8dc5c5498189f293ULL, 0xc60575763e94e795ULL, 0xc71898b84b4cf409ULL, 0x84ea3ce6ff5d145fULL, 0x89c009ff5aa0fcfaULL, 0xa78213689da359b5ULL, 0xf2546df550101db8ULL, 0xe374b642c8780521ULL, 0x8d1591597f9441c5ULL, 0xb4ab5568b9a7c5c0ULL, 0xcc5e6ab793c413eeULL, 0xd7aba1d174f85de9ULL, 0xc49323a91f5167bcULL, 0xe6ea45b184b8e834ULL, 0xcd7988f6fde8a037ULL, 0xb694a954c9c0aa23ULL, 0x1c4a0e3097294621ULL, 0x4d390d2752044d1bULL, 0xb553e53b17f539edULL, 0x9f025cf6a7cc4e78ULL, 0x50b48ab5c2d2df18ULL, 0xc62e3dd8e1dc9dacULL, 0x2f5d9e66b46b113cULL, 0xdc87db0eeb7b38eaULL, 0x777a8fefc19c99edULL, 0x5349d507847cc330ULL, 0x5a5174c6f67a52faULL, 0x56f5181e718f7e8cULL, 0x7cc3c1e98a04df76ULL, 0xce561b50fc20c342ULL, 0x558b5af060363aa8ULL, 0x5f8fae3fa1aa8fddULL, 0xbc443e60955ca5dcULL, 0x462f8bb6bf8c6040ULL, 0x9f968a4920fe1f7fULL, 0x4e174f12f0bd0c07ULL, 0x44b134bdc8d40aa5ULL, 0xdff2c70c7fdb7a90ULL, 0x51593b600334649dULL, 0x42586047653e96c0ULL, 0x8f39d2b91ea503b2ULL, 0x4b4755a6d95bb573ULL, 0xbb156584e55f592eULL, 0x37e4ae4b627c239bULL, 0x6895b7bdcf5e58f9ULL, 0x60bdf1ddc0890c09ULL, 0x638aa6907b9d46bULL, 0x194e07cab079d67fULL, 0x805fcf22353aa59bULL, 0x6d20de966d6f2c51ULL, 0x7041f49502ab2aa0ULL, 0x8fea5a1d6a348286ULL, 0xc56ae110d28ca6d7ULL, 0x614b5a25c5fbd2d4ULL, 0xfa7be347bee59b70ULL, 0x6a1176d3254f89c4ULL, 0x12508b7e7d8ac8e6ULL, 0xd6f09ea3fe98c1efULL, 0xdf679e6f7f691d95ULL, 0xca4f526560531e9eULL, 0xfc77cf81d4313f65ULL, 0x58ee36071cfbd2cdULL, 0x70d845734d41cbb2ULL, 0x2ce8c74d1be9edf4ULL, 0x27e1deb972584f64ULL, 0xc570744e53994474ULL, 0x572e19946cf59c49ULL, 0x47b9f852d4c355ddULL, 0xb9c5edbde6176769ULL, 0x7f28a822f0a6a08fULL, 0x78dd86f04ca32625ULL, 0xa910d0a06545aa06ULL, 0x4a95cdc43a11f482ULL, 0x69809de2707a9e15ULL, 0xf41652fb4aba4120ULL, 0x5c9b9cfdd670459dULL, 0x8646a487380a3489ULL, 0x18155e2a4377fb3dULL, 0xa2a4b3233eff191aULL, 0xc0447e16847589daULL, 0x188d8cee0d7cc7a6ULL, 0xfe192bf6dfb0bb1cULL, 0x43b68f131dcbe766ULL, 0x1a2d2c6ca017eb12ULL, 0x69acb746fdcb01b4ULL, 0xc4426a325ac99471ULL, 0xfa5c3eacc862516aULL, 0xe84906f63550ba7cULL, 0x7cc0c6d909d26fecULL, 0xdfeffbebba05a9cfULL, 0xa10d2049c938c77bULL, 0xe33a35b98ca36d81ULL, 0xfe584a1ea656c141ULL, 0xf1bbe2e08e390f2dULL, 0x157d3f77c77faa5cULL, 0xb78e46ebe2ee274ULL, 0xf8d3cfbd1f68e506ULL, 0x71201edc326d5d5bULL, 0x6ee560b118473262ULL, 0x579d848438e2ccfdULL, 0xd75a0d640ff7a49cULL, 0xdad0e72689756e75ULL, 0xce85335de8c1fe07ULL, 0x7508c8f73f72c32eULL, 0xad5fd0defcf13fdaULL, 0x35eebe90270c8547ULL, 0x7f26dd0af55fe16fULL, 0x65464e6ddbbb0fc2ULL, 0x1a06f26eda5f8068ULL, 0x24bb634a3034df62ULL, 0x15e86c3b93eea116ULL, 0x50360c40ab3ed857ULL, 0xdaeeb8ce1a5f53dULL, 0xfe00c9bfab0d9772ULL, 0xbf6d05cca57a6977ULL, 0xad1f7fd49f89492cULL, 0xdd810eaff5550b41ULL, 0x58f1865dc1fecaeULL, 0xf02fbe30f9218527ULL, 0xcee6b5a99d52cf56ULL, 0xc238fb521926b09bULL, 0xcf80be8634e03790ULL, 0xe27027580c5b8b9dULL, 0x714b23e0da4f9038ULL, 0xa434d1dc1afcb047ULL, 0x6df2c9e3d7e4170bULL, 0x9feadea12e8820f4ULL, 0xde8cd3f8a8c1550eULL, 0xafc379aa6bada279ULL, 0x37891e56f9e19baULL, 0x704dce81e4ce8d5cULL, 0xfc9e3a27ba433e2ULL, 0xf54c8a1d22b3295bULL, 0xdf4b813571d87c0dULL, 0xb6bfe2be971c6939ULL, 0x5cc5c839a9098b54ULL, 0x183c32115359eca7ULL, 0xcbbc2b6f7197152cULL, 0x48a2ef572ce10ea8ULL, 0x9d03358be067e1f9ULL, 0xbf27d64d700ce911ULL, 0xcd0acecb2ad09666ULL, 0x8c034ed1213b9cfULL, 0x9a8b3df72916c3b3ULL, 0xfc65f0528bf31a13ULL, 0x52c8a29bd3d636caULL, 0xc724cfcd7dd126aeULL, 0xda05a3cadbfd5485ULL, 0x3891ba98672d4cbaULL, 0x65df7426c0774156ULL, 0xea11d614ed8f25a4ULL, 0xd7e082172ca89522ULL, 0x290d1124991f9ea1ULL, 0x2b7ded73d5cdabaaULL, 0x116f3d073e1d17bULL, 0xe77bfdc15d54c98cULL, 0x83f23aea6ec772cfULL, 0x62c69efdf790a255ULL, 0x57eca62a5f00dddbULL, 0xcd36e014a182c623ULL, 0x5991a87514e7c7a2ULL, 0x9bd843d50bdab9abULL, 0x710fdcb2320fc812ULL, 0xb507793258cfb99bULL, 0xe4519f0b2ee94368ULL, 0xfa7553b0dd3e2b41ULL, 0x8bbabba53f4360d1ULL, 0x8cbe9f7e079b84aULL, 0x9a7af6406ff8bb8ULL, 0xcbe0efea9067fa2ULL, 0x4e85f238e0645a49ULL, 0xb51cd20c9b93225eULL, 0xeac67e570dbfd22ULL, 0x95ee95437fa1bf73ULL, 0x12eee6b0eef0d96aULL, 0xe5df3143746e1ca1ULL, 0xe0b527e7bd540510ULL, 0x4890d509351903fbULL, 0x8a6d9d699ed8cdc2ULL, 0x3df8ec2c8a1a4877ULL, 0xebd57d743b7bc001ULL, 0x848e91bb52d74ca7ULL, 0xff08fe8ba93b43b0ULL, 0xd7fe00434ad5d955ULL, 0xda10233ff485c8e0ULL, 0x4b84ea86d5e767e4ULL, 0x3df62d7979100d04ULL, 0x5e9b29f250b29a7fULL, 0x2e8bdc935509fb8eULL, 0x4457b1fd150ba7c7ULL, 0x70b8be19230ec317ULL, 0xb82a8e0f12a5d74bULL, 0xb5521c9aacf4c3a4ULL, 0xf882708ade85a47eULL, 0xc8d37a43e0505433ULL, 0xa01f0e81780c94cdULL, 0x89a4e129d06cff31ULL, 0x3a2adac6ec8c8979ULL, 0x3e8873d1857f9a06ULL, 0x43df20ad884cb226ULL, 0x5b43a8365a19dd0cULL, 0x1f03cffabb6126fdULL, 0x317d9a43820a9c03ULL, 0x3404c29e0ebc3d80ULL, 0xd10afc9cc494f53dULL, 0x24ee469b9185fcb0ULL, 0x948c2b2abf8f2481ULL, 0xa5ac078824b9bf2eULL, 0xbafc1548247cda19ULL, 0x54b2bc1fdddd8465ULL, 0x5e4dd3ca925a59f2ULL, 0x48d02066d4c9b82fULL, 0x15b40b34d1fba5bbULL, 0x57f0228bc6aaf8ceULL, 0xf5beb656c47c7776ULL, 0xdbd23c22758c9faULL, 0x262048e8a011c252ULL, 0xa1a097c7d4f8f7acULL, 0xb067992c60963d05ULL, 0x23d98b493a5bfe53ULL, 0xfbc0491433c12b78ULL, 0x7f7ae08d01d8453bULL, 0xe78a94ec33b6c19dULL, 0x36b7447546202034ULL, 0x3bd73878b576ccb2ULL, 0x53608d86c5c89181ULL, 0x62b15038544c9b20ULL, 0x261e5292f752e46aULL, 0xb085f1c2962b24c2ULL, 0xaa76d33850431304ULL, 0xac7b179a1b5bf3fdULL, 0xd9ec2a08c51f1b48ULL, 0x61816237703e98b0ULL, 0x858bcbb988f03cd7ULL, 0x66900f7154977533ULL, 0x1f101d8c14dd6ffULL, 0x1c686be9e24d5569ULL, 0x1d6c4ca5c05114ffULL, 0x79c7932206b0359cULL, 0xde706d6b0ef5d259ULL, 0xaced509304bcee2dULL, 0x96bdeae496f3f089ULL, 0x5ebc8cf8946cf5beULL, 0x98c3eec0246770adULL, 0x22560e48f2b938f2ULL, 0x73e3d0aa24470c58ULL, 0xab7ae4b24089c5f7ULL, 0x9cd95b5b976c97ceULL, 0xe81cc49fa710d96ULL, 0xfcf334d5d693db37ULL, 0xd1968eed815d61e1ULL, 0x13e136dd35edf1c6ULL, 0x80b74eeba4e012aaULL, 0xe10dc820c52f891ULL, 0x52afb6bb931de98cULL, 0x2b13420ffc17b735ULL, 0x3f4524ccc0aab286ULL, 0x5fc5d9d588b9b421ULL, 0x694f632e3785eab1ULL, 0xfbde92fbdc2ee74fULL, 0x42298b48100c7500ULL, 0xc6faf190029fd483ULL, 0xd0d1d9d63d58cd23ULL, 0x209dbb6254575aecULL, 0xbf6c54fc62aa12f1ULL, 0x65a6d550db8bd612ULL, 0xd89347d629f42afbULL, 0x15839983dc6f75d4ULL, 0xcfcbba737a45d0d4ULL, 0x638e620403504c1aULL, 0xdbb0cd4984d08132ULL, 0x72ae7e8fdf0dd3faULL, 0x9973363a972d20b7ULL, 0x24a5f2776b8a8bfULL, 0xcedf0e4886c52f9dULL, 0xb2dff5e397904d71ULL, 0x6cf6077837120f00ULL, 0x2a1e8f7b105f8325ULL, 0xd591eaf7a5793977ULL, 0x5b06d6a06dbb0d72ULL, 0xf107bb2584eaec26ULL, 0xb89df019a6bceb3eULL, 0xdce57e686e532063ULL, 0xaf368c26c039bc9cULL, 0x7d1cbe311f6bdec1ULL, 0x56c8f331486d6bf4ULL, 0xf3eecc086ad92a05ULL, 0xaf747706d8db2b1eULL, 0xab2cc59b7efd6329ULL, 0x3f877b2d260a565cULL, 0x9acc7249130b192eULL, 0xcce7c75d7ccb6f1bULL, 0xa43a825759387427ULL, 0xfe5016b46711681cULL, 0xde2ecfa9b46e960cULL, 0x35cad61235738b8aULL, 0x148c5dd914505a88ULL, 0x3448caef18556250ULL, 0xf34cc4fb7c4b5b7aULL, 0x1fbf650c882296deULL, 0x2d70b17cafc5d742ULL, 0x81afc73b91618d24ULL, 0x63aaed2a8f9db34eULL, 0x196747956ff5a98dULL, 0xe1d0c20e901e444eULL, 0x959d226339b41fddULL, 0x3324fb92775aa6f3ULL, 0x68ce442973d7acdcULL, 0x4e6fe37fedf9d420ULL, 0xd717e466fa3348b8ULL, 0xe216008fe1ee07e0ULL, 0x5ce336d755730c3aULL, 0x29e76dbda77ecb44ULL, 0x8f104ffac3fbb30eULL, 0xc4ea79b0a60265fcULL, 0x9c181fc5c944e1eULL, 0x5ebb203c1ab4bac9ULL, 0xff07ea0138e61950ULL, 0x9b9fc36fef46bf2eULL, 0x13f5a20dd9bd7f3bULL, 0xace7ac67178a99eeULL, 0x1b6bfe4ca854fc17ULL, 0x56ee7accc3abaea5ULL, 0x659464c0beb308c8ULL, 0xd517614dd1878232ULL, 0xb041a2008efbc35fULL, 0xec0fbcff749d6bf2ULL, 0x7093b6127db841dULL, 0xc06094314f1875a3ULL, 0xca89db8b3249b895ULL, 0x6a34bb296849bee9ULL, 0xedcf69eb31bb40eeULL, 0x54b0386c69314eeULL, 0xef7e27bf75b3ad92ULL, 0x38618eca6f874dffULL, 0x64fddacec1a8afe6ULL, 0xcbbddfb7ef82100aULL, 0x89a45a81117763e0ULL, 0x15704e2cb44d116cULL, 0xf21b0ebc6b17da46ULL, 0xede09452e6ac033cULL, 0xd2815c4f50ab4e20ULL, 0x76edc034345f1357ULL, 0x9d5e227b47e55c4bULL, 0x99fa8badd111e2dfULL, 0x110937dcdb387acdULL, 0x4eeb64641f1b60e8ULL, 0x9eea2b2b9fb32bf8ULL, 0x1260840127e42721ULL, 0xbeb159607b23bc30ULL, 0x543b2528ce5e0692ULL, 0xbe665dd5ca5095b7ULL, 0xfb14a3cecb5a9a42ULL, 0x9fb2e52a32005750ULL, 0xc08f992a63a9ecc8ULL, 0x9d6a6358f4a7b027ULL, 0x4389aaacf41e1a2cULL, 0x37f9598a151fc84fULL, 0x7068c3147c814c2fULL, 0xed7745ddd836afb0ULL, 0x90b5ffc7f548aebcULL, 0x9756f0a4372cdf36ULL, 0xa266c189e7000163ULL, 0x7343c4caef2c18cULL, 0xe7cc2d32f61a0fd3ULL, 0xc2d6f38ac8d54492ULL, 0x7742a4a71c97647aULL, 0x424a7b15b13adcb3ULL, 0x572360cf22943204ULL, 0x61b0592d3d9d89eaULL, 0x680c2e306724d49cULL, 0x40904c57d8d52122ULL, 0x6dadc11cc6f1a900ULL, 0xa6af42b44f43e475ULL, 0x95e3693de303cbe6ULL, 0x919238a4ae5e8ce3ULL, 0x28ae5934d4b690e7ULL, 0x3aac433cb3bfcf56ULL, 0x6402042baabcb117ULL, 0x9265156370256db3ULL, 0xccf8d7b53f8ed7ffULL, 0x3440f4fed4d04d15ULL, 0x665074af8486502fULL, 0x356f97c5ed153e56ULL, 0x85ef72d012a11a76ULL, 0xda6c645247ce8e51ULL, 0xd4c417422f9f317cULL, 0x4e24a86bbbc776e9ULL, 0x3e4809f531a7a889ULL, 0x3aa3f4c71f82026ULL, 0xc8be58ad47215f21ULL, 0xdec7fdda1619b97ULL, 0x6b34034e6aa5262fULL, 0xf023e2c54904504fULL, 0x5afd94be7bafedf3ULL, 0x5f65ae812aaef59fULL, 0x3d20a9be1ebe9b83ULL, 0x6e60fc77ec7959b8ULL, 0xc9310a1734813400ULL, 0xa9a1f8cabb9bd6bbULL, 0x7c48821ad003e5cULL, 0xe1f90ca1009f4882ULL, 0xffd2952f29d6beecULL, 0xfb3d9ee314f51662ULL, 0x68ce6c67774c154ULL, 0xf276616e7f331928ULL, 0x4e6dcf36a9edad19ULL, 0xb283670f18a5a74dULL, 0x7a923872d08df0e8ULL, 0x30a0a4bce4adbb71ULL, 0xfb2b4b8ca85a2128ULL, 0x434062716432b39fULL, 0x6038f71158be3875ULL, 0x3024bead8c9f2c57ULL, 0x7e86380bd86c5f0aULL, 0xfbd85377688239bfULL, 0xcffc3bc92f7cfa32ULL, 0x2c3d873fd4624670ULL, 0xba94dfdb8108ec4ULL, 0x7348c7f753f6c468ULL, 0x618ecbedb3c36902ULL, 0x66b344c4911501caULL, 0xa9cf60162d8cd208ULL, 0x1ba51e7663bac544ULL, 0xd402f03d7bac91a5ULL, 0xc82fce8de56af66dULL, 0x94e5ee9a05e96a60ULL, 0x28f3ffd60321e59dULL, 0x954f7aab66cf2770ULL, 0x6e2eec9636238ca1ULL, 0x71bb9a3d3d0bb853ULL, 0x484916d034e4d092ULL, 0xdce2ab728c64c40cULL, 0x355c7692cc13bef7ULL, 0xc02619da4fbb4cc0ULL, 0x6b27683910011290ULL, 0x9cb802d6a3cc33f1ULL, 0xd68ba38036117ebeULL, 0x56c5f84f8b0d46abULL, 0xb04fb89d3dfd6dc8ULL, 0x3b99d87d1e48cf75ULL, 0x4fb4551a21db540fULL, 0x1023f83ceab22775ULL, 0xa5d2198311c1a217ULL, 0x4b2be37cf6e76da3ULL, 0xa94aba6a11f00ab1ULL, 0xc1ac6604c9e7b248ULL, 0x4f5c5218a0aaddbeULL, 0x65ea82f5619e8a9aULL, 0x68243ab1a9a5d1ebULL, 0x67d92cd6ecd6b209ULL, 0x26b0cb1750411c26ULL, 0x76896ecb1bee6214ULL, 0xdc0611f945bb66f1ULL, 0x5d5e3190cb24befbULL, 0xfa689761051dec82ULL, 0x60f37c6c45fc27eULL, 0x82d77ff56d946f83ULL, 0xb0ec47ba81df1435ULL, 0xd9e78f07494fac37ULL, 0x91440890a2470447ULL, 0x73aa0d596c2c4db5ULL, 0x649103de5893c612ULL, 0x2286226838db36f5ULL, 0xa5d33881c6c457d9ULL, 0xfbd887f56d301158ULL, 0x2d88c8d236a150e5ULL, 0x891c8a6153e98fa1ULL, 0xe8fd92d135398638ULL, 0xc4e680098855a34dULL, 0xe401ed7874452701ULL, 0x329839241b7463ebULL, 0xc72e66c49a2b2ea1ULL, 0xe48a630a638f34c1ULL, 0x56c8cd3b2a2d991aULL, 0xef75007d29ea4ULL, 0x4696f43eed8ce0a8ULL, 0x2aff68c100c0a343ULL, 0x7f2eb441561f9456ULL, 0x3f39d06fafe5908aULL, 0x81d167a8dd00bf0aULL, 0xede4f75a2b649511ULL, 0x243017ad74f1bf91ULL, 0xa36493b837cff4e1ULL, 0x77a6a2b0c7d7e68aULL, 0x7c0294600740001cULL, 0xe5bd2f850a207f4ULL, 0x95eea0bde4eeb0c7ULL, 0xfbda5b998acaae3fULL, 0x84ab389d2ce8cb34ULL, 0x37cddfd659260c42ULL, 0xf43c7dde09d9d0c4ULL, 0x953384abf3f84622ULL, 0x62c008e2fd3b913aULL, 0x3fa59b3935d8b28cULL, 0x3306408570db576cULL, 0x14f46859d0f9b059ULL, 0x991cb4e3ec67fb9dULL, 0xa6de6fa5e75f1c1bULL, 0xd076014cdfbb8bdbULL, 0x8c4bf8bcdde1deffULL, 0xc02b8c0c56bb0b7aULL, 0xcdf92d27ef36615bULL, 0x3d0bf84913b179e8ULL, 0xe8345c241a26160ULL, 0x9a6bc6c73191f59eULL, 0x78428cd060c08701ULL, 0xe8a09de627ed5c95ULL, 0x600c110d2902504dULL, 0x8edf57c268be3425ULL, 0xbe05e0e5fa030226ULL, 0xed85c2cf1a1c1c5fULL, 0xffcc194cc7cc8974ULL, 0xa03e85dcec55b633ULL, 0x2948ae3f7b51911fULL, 0x729666617d8055cULL, 0x727c5f92dd27d942ULL, 0x247267a64348d379ULL, 0xc85757294d5ab800ULL, 0xc7e247edd10f598fULL, 0x27f8d82651de24dfULL, 0xaf77a7c2397b6ad5ULL, 0xf1075c2637c11263ULL, 0x820db4715a2d50aeULL, 0xa78b712be7c97debULL, 0xed0c94fe16855d33ULL, 0xa9247a5cb34b1908ULL, 0x69e2281a6f315e27ULL, 0xb4c2fa5dc8f21fc0ULL, 0x1c18d4a516ae7ed3ULL, 0x5144fe3bf5006c5ULL, 0xa6db907ac13195daULL, 0x347b83cd6864c63eULL, 0x1b1be627e4a3ce73ULL, 0xc89e67970f0dd049ULL, 0xeca6db5fc9cd578dULL, 0x1b3bc14d1077658eULL, 0x3a383d471cde44c5ULL, 0xea684ef8bd63ddafULL, 0x5f26abb2190bb2eaULL, 0xc12f7d090b8d609ULL, 0x1e92b60d6e808c01ULL, 0x3b2aa7b501aed19eULL, 0xea0f366c12d042f6ULL, 0xa07669e03d57c1beULL, 0x4c8a9b08f08895a8ULL, 0xde264a416fb70d58ULL, 0x9b1fc7e60276c5a0ULL, 0xa13ad0bc3fc2a2d5ULL, 0xd0f327a295570ebdULL, 0x53d344deddd3ee07ULL, 0xb932ac93e34cce81ULL, 0xbbea4eebd5716769ULL, 0x8b356f293b55b7aULL, 0x6747db884a1f176eULL, 0xbc8025ff69e7264cULL, 0x47b18ba858ddcb12ULL, 0x61ef9e0fe8fbe954ULL, 0x3282f040e760a95aULL, 0xe7fa2c60a4e770baULL, 0xd9e83eacc5994329ULL, 0xa0b5f8217be958a6ULL, 0x80538d8f5574bccbULL, 0xa5e23a1356fb03a5ULL, 0x6b8b81717d08c6b8ULL, 0x19784f6928d15435ULL, 0x4dd883c1de3fecb7ULL, 0xe03a37af4b7eb438ULL, 0x141395327aacca7ULL, 0xbbb06e8ba95c3e95ULL, 0xee04035456ddf2e3ULL, 0x3af3a205524cc23bULL, 0x7b1c19e599593f5aULL, 0xb9099a6e35b67d6aULL, 0xbb0b7f122fe12859ULL, 0x5628095cfcf7dd6cULL, 0x91212d3737da35b4ULL, 0x85da0e439e485e61ULL, 0x195cdc84bdb9546cULL, 0x80f30462eb81520eULL, 0x14b57009e9488e31ULL, 0x218de98a5cfe0a18ULL, 0x6e515d0a33437434ULL, 0x8b592d3ba009b8feULL, 0xdafe055636a88e17ULL, 0x55b7cc52b756d680ULL, 0x9f4312b048b9f6b6ULL, 0xc4f8498f6a47e4d0ULL, 0x38792d2f4ae85b0eULL, 0x979f9c5b37c03132ULL, 0xeb17263cf26d5a6aULL, 0xd39ed5af554ab88fULL, 0x9e6a16a8ef52802aULL, 0x7ef7116d4c375633ULL, 0xc01e0fb3ea6c0256ULL, 0x83d769562d0c7c66ULL, 0x6a8dfe02b1531eacULL, 0xb1345cb90b3e8e01ULL, 0x671ba54bbf449b7fULL, 0xb5fc71e5a2de26e8ULL, 0x86197e1cb3a51367ULL, 0x45ea015872784286ULL, 0xdcf7ea97cfae1e0ULL, 0x4f96095f161db49aULL, 0x5bb361e9996a8f83ULL, 0x8565093f3783458dULL, 0x4ca84f5ff15b22b2ULL, 0xdad770b145ccdbf0ULL, 0xdb4e91da3b075631ULL, 0xbbf05db5184fb818ULL, 0xa9524f006827e5d7ULL, 0xa46d33b23bf486c6ULL, 0xc784365020a80502ULL, 0xaaf6d6eb8222cfbcULL, 0xa481efa18c724e7eULL, 0x3c28f50e91c817b1ULL, 0x4ffa6044c13753bdULL, 0x5165a99115131fc6ULL, 0x1df23586c4371867ULL, 0xb0adc11dd316941ULL, 0xb77fa479abb0c1e2ULL, 0xf84102ee7d34936eULL, 0xa4601d3246f243f2ULL, 0x83645176f9da4be2ULL, 0xda31cb15a7dc864ULL, 0x59892a3cf0dfe3a1ULL, 0x553376822529d662ULL, 0x183e80f4202c609eULL, 0x62961c853f642216ULL, 0x812963b6c01101a2ULL, 0xcd458124e25483f6ULL, 0x1183099325603964ULL, 0xd881bf090a7ccc53ULL, 0xb9e4b5831470fa07ULL, 0x7524ecc616c5d46ULL, 0xd9b1ae5a3757e142ULL, 0xbbf2b0f065a18812ULL, 0xd89d7456270bae2aULL, 0x6efd05a6708d4d8eULL, 0xbce2427f7e16033cULL, 0xed805ea3027b95cULL, 0x11de12df42b4dc2aULL, 0x4ccd718fe4979d6fULL, 0x2276c70c6b1efdf2ULL, 0x63a71827ac90f3efULL, 0xa6d23ed200978046ULL, 0x9f83ff8b2a227281ULL, 0x520a4c28d55e0aabULL, 0x9208f49a68af1d1dULL, 0x994046c8192cfd2ULL, 0xf0b84444b489fe83ULL, 0x8853cb95fe70464cULL, 0x4cdf6ba744c3f663ULL, 0xb97e0e290a5744a2ULL, 0xa3e38be2345e2581ULL, 0x569632d926151cf9ULL, 0xf950d266137b0b57ULL, 0x295162e91db30ea4ULL, 0xd3735f5fe43a9adeULL, 0x16103228f4d8e7daULL, 0x1acc2e6cbbfa2012ULL, 0x11b8e1fe0d530bc7ULL, 0x3c67d6325990507ULL, 0x88d0029f8f1da1ceULL, 0x2c34dee21d103585ULL, 0x827dc7643c331e7ULL, 0xc061afa87606fd37ULL, 0x945af6563190233eULL, 0x1aaae1598030f02dULL, 0xa00643e6538d0020ULL, 0xfab775db41f4599bULL, 0xc7b100d10ba897cdULL, 0x1e9ba05edf116aa7ULL, 0xad57b91ca3f6033cULL, 0xff2be2216e5f2340ULL, 0xed46027f12571dbfULL, 0xf11a6c6572cf2f3aULL, 0xe19dfeebdcb75017ULL, 0x54ff2f5ddc36b157ULL, 0x1b1ec099ce08e7a5ULL, 0x6e2c13c9261bf9ccULL, 0x1bb910ceaaa50e3aULL, 0xe49c82fee0833250ULL, 0xfd34c291aeba6ed6ULL, 0x88d3c964a7981c34ULL, 0x58e62c1ade2c516aULL, 0x8e3da38d2092872bULL, 0xe5a384a5eed000b7ULL, 0x31113c7ccde35296ULL, 0xe1e99889fb40cd41ULL, 0xa9ac662be5e781aULL, 0x52d6166b2719948dULL, 0x61ec0fda38934694ULL, 0x7b52c1d14a7fedd6ULL, 0x459b9dbb8be22a3eULL, 0xe208090155112bc3ULL, 0x5c48aafc21400d7eULL, 0x5f026ffdac39c927ULL, 0x1463f00c55a05409ULL, 0xfcbe1153ea53b7c2ULL, 0xde6d5dd612df0a77ULL, 0x4c584ef5e4acef1eULL, 0x50175571762f0e72ULL, 0x2b14ea3a7a7c696eULL, 0xaee1a5c2c3478afeULL, 0x30907fc495fe1da2ULL, 0xbdd853c1a88c9998ULL, 0x73a8888da79ad29fULL, 0x7b0158f8d0f4758dULL, 0x3332a586ddf6d623ULL, 0xc577eb29630c9bdeULL, 0x9f16a4ab47580a0aULL, 0xf60998a69332d184ULL, 0xb7ee92ec64025d2eULL, 0x65b7c21ae267bdb3ULL, 0xd4fd7a8e38685665ULL, 0x1cdd56d07daadc2eULL, 0x19ada51ef41839f4ULL, 0xf4bd6402ed39e817ULL, 0xf6944066d6d705fULL, 0xbfccfb1cbd1a86fbULL, 0x796dd971ef4c646fULL, 0xbc9aa06f9800cc5bULL, 0x2eacc9a4bbbe6a1eULL, 0x229bd658d433d0abULL, 0x9cb5ae758c128651ULL, // end of original table 0x60015f27ba684567ULL, 0xb70634f536c5cffULL, 0xd8731843d6ced8baULL, 0x97feb01f757be146ULL, 0x8c159cf2b6e2231bULL, 0x6b3d34d68fc5255aULL, 0x483ccb6dc26ac4c9ULL, 0x993486809e0357b7ULL, 0x38ac7d0747c2e125ULL, 0x8addf984ef325ae9ULL, 0xd5f018277330d0cdULL, 0xafaa837bceaf8611ULL, 0x42ce3d69c0e17521ULL, 0x501bcd2b6109dde9ULL, 0x25e1020c55b82dfcULL, 0x2dcf608680bd2a97ULL, 0x7d01c880a17d78fULL, 0xffd0cf198055fcb0ULL, 0x866b87d73dc78d3cULL, 0xa50d4b790ac5a45cULL, 0x760f3a7aaebf40fbULL, 0x13d206fe862e2529ULL, 0xcfb50af04751b77cULL, 0x8b859e2a51f2861ULL, 0xf7c80592537836a8ULL, 0xf3839fe145d6b5ebULL, 0xafe00fe73a270bf7ULL, 0x303d74055a520ae5ULL, 0xa379cd1788a9b148ULL, 0xef9254a501355d23ULL, 0x2d939a5a2f3b4564ULL, 0xcce3acab92ac82c5ULL, 0x716dcbc226da813bULL, 0xb816ae8212a3f09eULL, 0x14001327a794d9acULL, 0xcd54d383e80ff03bULL, 0x62a1139e87d55648ULL, 0xccaca1be8ed0016fULL, 0xb43215e85b20b07dULL, 0x66c39a1b5807811cULL, 0x820a2f1c270c18f8ULL, 0x18dc7e844c012acaULL, 0x4fad1d41e7599938ULL, 0xb40e0e9d46511a34ULL, 0xcff703b7394545faULL, 0x91aa9082faf65486ULL, 0x474d7fb42d8e6a55ULL, 0xd5cd54528bf46373ULL, 0x3659fa443e3fff36ULL, 0x8c27056c66affcf0ULL, 0xddabfa700ee70d15ULL, 0xff78a5d81542b5a9ULL, 0x768f5a4678f4058aULL, 0xc23257deb069e80aULL, 0xe93f488f761c47a8ULL, 0x8ffff6d3cf50ab8eULL, 0xe7793cc39c5e9d09ULL, 0xb4b3bde93908a233ULL, 0xd2f208a5971e7fULL, 0x1700c0a553276e47ULL, 0xcc4532664fef8c4aULL, 0x787c8b31d2826823ULL, 0x98a2bda82adb4807ULL, 0x6103c4bef88328b9ULL, 0xbe0e4e660e45763eULL, 0x635b9635299ce867ULL, 0x863d0cd51d38b9a3ULL, 0xcee13c2b0d1bda34ULL, 0xb553da99008f8110ULL, 0x177d255848390401ULL, 0x48f9432f5bcf6e78ULL, 0xb3e0bc53fc97e23ULL, 0x60a107159ee1256aULL, 0xc81f747ffc634f25ULL, 0xba63040bc0a9413aULL, 0xd8a3c91e3c061690ULL, 0xd7ed9fc46514f49bULL, 0xe87c74225dac8ecfULL, 0x4a5171d66609ac5eULL, 0xe64382ea70be8ab2ULL, 0x51e888694a589d8ULL, 0x8b4b589f47e14a82ULL, 0xb6c01d3cd9311a87ULL, 0x5f9a964b1a8a88aULL, 0xb1804b714cc67044ULL, 0xd6a9cd5e0540e74eULL, 0xba55742f5722bdadULL, 0x7489b35542c188ecULL, 0x85d747524da72b8cULL, 0x45dc426654b397c0ULL, 0xe7669718192445e4ULL, 0x6d7d9133feb4e063ULL, 0x5993b618127ae6b4ULL, 0xf3730cd9835743afULL, 0x617b7d0b75d13207ULL, 0xa9109d2ba1540e34ULL, 0x90649a709b69d089ULL, 0x5b1a5b3008d893c1ULL, 0x59680fa3975c4a67ULL, 0x2195992a7ab567ecULL, 0xa7fd7ec3809e45e5ULL, 0xc696b1756908e509ULL, 0x787010e8595956f4ULL, 0xafc34e88b78c8fcaULL, 0x8fa500e8aa9428cdULL, 0xb81ac82df63a7c7aULL, 0xa796ba0285ee6ccaULL, 0x821b35ddfa5e9f2aULL, 0x6af033b1c486afc9ULL, 0x3d7d1c6d332c2503ULL, 0x87ce98224267bf6aULL, 0xce6681912d9a7c99ULL, 0xc6359b2ee935c322ULL, 0x9bf0b3b3c271a5d1ULL, 0x71b9eca4e955be45ULL, 0xd51662df7b4681ffULL, 0xf361c3fbfa034b01ULL, 0xb5e36bc110ee0102ULL, 0xcb13c90f8d5cb662ULL, 0x84aa2cf34ac78581ULL, 0x3e27a6b82ea9043eULL, 0xcc5261df551f284bULL, 0x233206929d09564fULL, 0xf3d20d1298cdb1ffULL, 0xa54ee94ce7f8d1feULL, 0xc12f7e96ca7add0dULL, 0x734c5bace6250d32ULL, 0xb8c617e029b4f56aULL, 0x7c26b6d222181002ULL, 0xa83c710f06c49816ULL, 0x8f0e176605ce91f0ULL, 0xedb5a326f26d5fcfULL, 0x759e3a6525f1b29fULL, 0xda977c3aa55a4f61ULL, 0xdd0e75e28fc1fb0dULL, 0x7fb26238f7ec560eULL, 0x10f5a416d68895e5ULL, 0x14d12acda45ffa3eULL, 0x92f5d49c3004202eULL, 0x4059063e7da66b9ULL, 0x2db5da30c7f7e770ULL, 0x3fd1c35e19be3c89ULL, 0xae107f45bc3c301ULL, 0x670f45a5270d328bULL, 0x14a6a13af144aee3ULL, 0xde4dcabfbd2ce198ULL, 0xf25ef3d786b8e255ULL, 0x9f24f29787a262c2ULL, 0x944bfdb0c8f09613ULL, 0xf1ffe2cda849b4e2ULL, 0x20ca5d17c561a81ULL, 0x7a670ae408a37eeULL, 0x8aac786c2a63493bULL, 0x4c0d3305e5945dfbULL, 0xab2cf4173c1c0446ULL, 0xf281e6899c2ed80eULL, 0xa32b2b3a8044261fULL, 0xaa98242c09c28454ULL, 0x3cb83f50e7f239f8ULL, 0x19ca5d85fdec3973ULL, 0x679de0ea37c7f860ULL, 0x988ac4c40df89031ULL, 0xc9902740d73fb70dULL, 0x97e7bcfa657c67cdULL, 0x1284afef778f35d5ULL, 0x77e3ff65d3e5b5eaULL, 0xfa96013dc2a4359cULL, 0x87eb0463f57805aULL, 0x9b97b6f53afd4250ULL, 0x25f74d707c10655aULL, 0x368e8a6b551d0ffbULL, 0xd7a4c11a7698d29aULL, 0xa38111df85a34e4eULL, 0x1506ff16a67fba71ULL, 0x5345d23b34cde228ULL, 0xf4bf418bd6ba9237ULL, 0x3d4aaaf087df6e9cULL, 0xe9fa1f4d851cc6dULL, 0x21cfb7b3774d5273ULL, 0x63063d8497af2dc0ULL, 0x13374c7aab0b0a9cULL, 0x5d838e3ea418dcbcULL, 0x71a3eadcd64ecb3dULL, 0xc45b4bf4aed77ed4ULL, 0x13a621ea7a0e00c8ULL, 0x73af3e7ff94d5530ULL, 0xe4616cec229d1756ULL, 0x1c57d9286172f671ULL, 0xb1fa81e50f75e9a8ULL, 0xb6f6722c566f4a09ULL, 0xa5477826394fa63bULL, 0xd3fe973b8771786eULL, 0x55fc0837202f42e2ULL, 0x8c6ae8e091c13c47ULL, 0xfa4c180785a2498ULL, 0xbbf911730454c122ULL, 0xfe4f56dc71d5fca2ULL, 0x9a76c30a8c3ed049ULL, 0xd7357eb5ac212a96ULL, 0xc7e9153edee38dcbULL, 0x294282f233a5d445ULL, 0x1d5084d15febf83fULL, 0x13d7f8d17257098aULL, 0xc4129e928de3a76aULL, 0xc9b3543c9b09fc02ULL, 0xa3d14ff986a0cb8cULL, 0x125dd51bd42bbf5ULL, 0xdc0c53d9d5f0e690ULL, 0xa67bfd568bc28302ULL, 0x245e4128b5ad6cdULL, 0x917e050c32a8d574ULL, 0xbd08d9dbba9027a1ULL, 0xd4257716add7e48fULL, 0xb70e2f8d0907bfccULL, 0xac07f17fb77d2b79ULL, 0x9367eac5841c95deULL, 0x134c066de986918ULL, 0x2911abf8010d60ddULL, 0xac7e0908ed1f3154ULL, 0xc293f3c6e9fd44aeULL, 0xb9048a04607da284ULL, 0x361e6a3d598da596ULL, 0x47d2245539fd487dULL, 0x1fe68e7791b97e02ULL, 0xb9c292e1b56d357aULL, 0x4bddf8b715d54834ULL, 0xd607c7f06f58f4c7ULL, 0xec082d6984e462e4ULL, 0xb69b7b38f1233267ULL, 0xf863fe7620c9e8c4ULL, 0xbf09bba56efdbf76ULL, 0xa284f788651c7360ULL, 0x7a8a9282322243cdULL, 0xa677dd19626cde99ULL, 0xd10e2e5c2f059e9dULL, 0xd23627288e9498b7ULL, 0x40124ff5b62d1c37ULL, 0x15f4d5bc992ef1c8ULL, 0x85e237e734bb259cULL, 0xf0ec1e7dd626a7ffULL, 0x3a2c29eb8790a0dULL, 0xe236950641595013ULL, 0x2ee755eb56287487ULL, 0xa8342fc541242782ULL, 0x9e0583e278adddd5ULL, 0x31946167f39aabefULL, 0xeb3e6fa98844526bULL, 0x9590b8c28372a7fbULL, 0x45ac873605c43aa3ULL, 0xb806932368af2137ULL, 0xb72de8c1f9996c3aULL, 0x8a7ab9755a1c5ebfULL, 0x5e2caff01e1a63f1ULL, 0xaba5390e1475c2a3ULL, 0xff0b7bab9178893dULL, 0xcb046c27ef98a7faULL, 0x3bd81feda546f590ULL, 0xbf656027cd5f7940ULL, 0x17f17ba65a9503abULL, 0x9581e72bb7531dcfULL, 0x384a0a7e281b1da3ULL, 0x870301a473ffb582ULL, 0xc9275a0724bde573ULL, 0x41627b481e374674ULL, 0xe9c0541e892539abULL, 0x381e59796d055608ULL, 0x661ca086b0c0beb4ULL, 0x68b9b66584b3991eULL, 0x2a6e6223292ca3e1ULL, 0x6ed8b6d4ac7cbbadULL, 0x676c2d6842e99a9fULL, 0xdbd97e72cd92208cULL, 0x89ce8964f8f24123ULL, 0x2e19515e0a70d17dULL, 0xb3a322ea121a0d1eULL, 0xdd3ca6c80bac17cfULL, 0xdc76ee9a18e2911aULL, 0x5892a5b18422aa44ULL, 0x2ced436a4e63f30eULL, 0xb004e91551d3a800ULL, 0x38bb150ccfaa0ec3ULL, 0xa417546e0462a23ULL, 0xbe8c26a7432072bbULL, 0x7e5b1f34755f6edcULL, 0x1368393713ce6507ULL, 0xfe508acaa61b94feULL, 0x2cec37c52b76ed90ULL, 0x4418978ca3e56430ULL, 0xaa1d2506ab7f4f1bULL, 0x9af1b8ad5890996eULL, 0xca3210c8f02b92ffULL, 0xd69f6be102a1d652ULL, 0x7df4b53610551013ULL, 0xaf3218426fe2b37ULL, 0xa4f155f1ccf91346ULL, 0xe6b3326a7c6dfc58ULL, 0xfd9795c55167b714ULL, 0x3cbebb5eaff44a46ULL, 0x53653c6d293cdd67ULL, 0x862515a64a612e62ULL, 0x84226d37c3d94b45ULL, 0x2bfe92d48b3edba0ULL, 0x12ebf13a88be2e75ULL, 0xed561c6e76d9591bULL, 0xd273ca6f3f697021ULL, 0x773d13c8b33eff53ULL, 0x2d10363f51e81c03ULL, 0x25267bce1a57c986ULL, 0x607c3e8ba2a20fa8ULL, 0xca15f48a0999ec9aULL, 0x6a6489c456fa4d2dULL, 0xc07572a900ee2ef8ULL, 0xde91cb170e05af4eULL, 0xcaeaac0f381f34e0ULL, 0x9b9ba0e299d77406ULL, 0x30e2e2df59006c3cULL, 0xb481eeca88dd5b0ULL, 0x6cdda35d3bec313dULL, 0xed1c6492917fceecULL, 0x3c3426f35ccd1bb2ULL, 0x1763eb46bb47a6d2ULL, 0x3db1e47c5b163898ULL, 0x5087915d22f5524ULL, 0x8eb3c592022bd5f5ULL, 0x51d6535db4807b17ULL, 0x2aac826bc188cb24ULL, 0x66722dd6dcdb654eULL, 0x39e849ad6da80c4ULL, 0xb16ff9400b1ff4b2ULL, 0x86794176a7848a20ULL, 0xbefa06a26ee64f0eULL, 0x786856799ab8785fULL, 0x4ca1d5b75552d7b0ULL, 0x481b69aaef493751ULL, 0x5106d509f30166faULL, 0xc89cb8fabcbb755bULL, 0x4881e9aa6c4dabe9ULL, 0x9acc44c94e361d13ULL, 0x15580221625c41dbULL, 0x1ee53f4434328ff3ULL, 0xec8f14ac520043f1ULL, 0x8c561f355521eb1aULL, 0x413c0cbd7271746fULL, 0x49f07bc41d1494fULL, 0x2a79bee27e515565ULL, 0xebe16cf2516d3044ULL, 0xcced73d58f42136aULL, 0xecce64365029fdb8ULL, 0xafaeaac00d4d8000ULL, 0xdda19d1f63d9d568ULL, 0x2028739dbd5970f7ULL, 0x3a505a6de1e45ea6ULL, 0x5563c6d01c9b08b8ULL, 0xbff786b383f28b27ULL, 0xc42e34d5dd1d2d2fULL, 0xc7472b99136f3e98ULL, 0xbdf64bd9a733c4d6ULL, 0x4333618cb817e87eULL, 0x3be7bbdbaf896585ULL, 0xecb06404330cf3dbULL, 0x57e50f7735ca12d3ULL, 0xd48a981eff866c56ULL, 0x92a2512c6a0b792fULL, 0x53954bff6ae2d84eULL, 0xc23bb530cf385516ULL, 0x72af682b62d9963dULL, 0x818152ea9e808108ULL, 0x16c73f4eb15a2634ULL, 0x224aecd56ff74a69ULL, 0x634004f39c5938c2ULL, 0x7c19f020bf131e8dULL, 0x278daa1ca6cc437eULL, 0x7e56753df99e1091ULL, 0x92e0362c9040604fULL, 0x5520aa2eaebfafa8ULL, 0x5542c3b5b4002e8ULL, 0xd58c32b8c957be2bULL, 0x1a8a03971891884dULL, 0x401efa8171730892ULL, 0xf5f98ded379f94ceULL, 0x11bba64b02426f90ULL, 0xcbc289404c4b4f24ULL, 0xf88c707322a57d8cULL, 0xa76e9a12bc321f92ULL, 0x8a136b6c3f3b629dULL, 0xbf776993432c2714ULL, 0x969954579e4f6a91ULL, 0xd93c5cd62b5c7dc6ULL, 0xec646eb16a31cbedULL, 0x434dcc15d71792a4ULL, 0xe31afce748900edeULL, 0x19e8384dc98da777ULL, 0x90d937b9ffd1d414ULL, 0x42e56b0bb2ef7944ULL, 0x97bcaf4446e4a051ULL, 0x49b416e044e191c4ULL, 0x26691c039c60a8fcULL, 0x2a3348626e2a6ba1ULL, 0x47086a4bb1bb45b2ULL, 0xf2f53ed199194d90ULL, 0xd5a9a9c128a43da8ULL, 0x85c784b9c0e43e34ULL, 0xd81da08dac238fdaULL, 0xae40ee3c3b07f166ULL, 0x5b5139f1423630c2ULL, 0x8e04746a249bfe0eULL, 0xefdf689840082f1eULL, 0xd2956d9ff1df1453ULL, 0xf1dd9458b3671379ULL, 0x7033dc0befdfbba3ULL, 0xb511c5e028189288ULL, 0xdbd854da918d9684ULL, 0xf9fe2c5f6cd20264ULL, 0x528da307b60fbaa2ULL, 0x266f6c95c0edd8b5ULL, 0xbd940d4b3aad19e2ULL, 0xc70e51fe8906fa14ULL, 0x8c2b73bffc2d6145ULL, 0xaf33bf612efc6a98ULL, 0x62e4bf66077a2230ULL, 0x8a174746facae57cULL, 0xf97fa4f8fe5a8002ULL, 0x1f51af8330292f64ULL, 0xfac5a803786597a5ULL, 0x27922542b4b54c41ULL, 0xbec3ae12cbd54202ULL, 0xd1a4f1aed47b6391ULL, 0x76aa16bd824b5bb8ULL, 0xfd807863331daa7bULL, 0xe90da40938c08bb4ULL, 0x65aacb5177fc7c95ULL, 0x92969e0b5ceff359ULL, 0x9fef7e7c00e4f21dULL, 0x95d680694cec51e8ULL, 0x2c53ea040dde56a1ULL, 0xc3141604cd8c5a6eULL, 0xa5841e9574801a9bULL, 0x19e87716f7b13d88ULL, 0x3b6cdb3a94bb27b7ULL, 0x4acd6e6d7d1e0a9ULL, 0x34568d3137a9fe5aULL, 0xaf6d354a3324a831ULL, 0xa49ec70590fe62d6ULL, 0xbcb737d221bbb3d2ULL, 0x617f99267b4fa89aULL, 0x1faf4a0eb5b7a9caULL, 0x1e8da85cd51dadcfULL, 0xd1dd959a74bab720ULL, 0x607b6d303037c6f9ULL, 0xec3a63c7f1bf6663ULL, 0x3de572179c12fb2bULL, 0xc8533108b6157623ULL, 0x5c5a659a0b0014b5ULL, 0xe01e216c05f77343ULL, 0x4ea5889bfad73bc8ULL, 0x1b70bd89e82962c6ULL, 0x3568c238abec1b3eULL, 0xcb21a1e18ad6ea4dULL, 0xe595f80d3c91f748ULL, 0xb082c64f44dcf974ULL, 0x3fd9c0b522e0f12aULL, 0xd95ea1c049f0170cULL, 0x6205f7d733c017a9ULL, 0x1bff0b690387b8ffULL, 0x3fd985bf4aa1bfdbULL, 0x8dc83e1940bf6954ULL, 0xe077d0539d672824ULL, 0x2095a1e9874664a5ULL, 0x65dcb6c48e0a4a8fULL, 0x48ad18592459cb50ULL, 0xca84e7b173244f1eULL, 0xbfea78a6af52ba4cULL, 0xdcfd924307d6920eULL, 0xd5c88964b4e766dULL, 0x727480f94dcf2a11ULL, 0xabf2ff56c1f9a831ULL, 0x92960acc0f5c3200ULL, 0x6ddc94ef0abc0fb9ULL, 0x816d14182623f990ULL, 0x943b78b938eb652eULL, 0xd6db388f2100c79eULL, 0x3006b57b2a55b9acULL, 0xe80a5dacd002636ULL, 0x45d6751265c4b0e1ULL, 0xa1364a2c15db4a6dULL, 0x53d878622de68ae7ULL, 0x750a6bca8cc8439bULL, 0x57ce3c64558031e9ULL, 0x8d0e7fd549622441ULL, 0x92083919340553fULL, 0x122d0ad7d159b90dULL, 0x27236554f3cb69a0ULL, 0x6165ab09f77dda57ULL, 0x8b7d5b6696ebed52ULL, 0x223eb01348709502ULL, 0xc0b573e5425dd2d2ULL, 0x5a6c3a5f32498053ULL, 0x610f7a98af865b85ULL, 0x3706f8f2444d0b3eULL, 0xd2ab6d22817bad0cULL, 0x356589eeffa2e418ULL, 0x512f4399d0cbb240ULL, 0x37c0f03cc33b7aa0ULL, 0x8365eaffbd973186ULL, 0x195af698e69f3a72ULL, 0x33bb11981e07b200ULL, 0x4e11287798db48aULL, 0xd53e3d9c6bd036bdULL, 0x824dccca6b27544eULL, 0xde7536e52dc92afeULL, 0xc878637bf1554aa9ULL, 0x8030514c0e08cbc3ULL, 0xb8b94dd38c616a22ULL, 0xfb80a9ecaa95f58ULL, 0x20cebf470965fe98ULL, 0xf9a8c6cc40d9ab63ULL, 0xdabbacb4dff08765ULL, 0x4f0dc09cdf1a3d63ULL, 0x6bdfa0ef1dbc4c9cULL, 0x50103297435e2d28ULL, 0x68c0514f25463700ULL, 0x6ea4501b61a807e8ULL, 0xa80fe82c4121e6b9ULL, 0x1233ba53c5445f98ULL, 0xc4c6c4e619679505ULL, 0x5fb6d8a2421e4159ULL, 0xfdcbfd9624400e31ULL, 0xa94df59cc03c701bULL, 0xa99ebef5e38588d0ULL, 0xba70437edd1e5f2ULL, 0x9e1b0d2c612551b6ULL, 0xea16a8131d0349efULL, 0x2a71f38cae44e314ULL, 0x3c75118d5cf82616ULL, 0x15f531e3c2e569f2ULL, 0x37146838ae0f4faaULL, 0xb1caf5c3052ee220ULL, 0x20c6823259d0552ULL, 0xa77d155bbae1e5b4ULL, 0xdb2ef1f1dbd6ef0eULL, 0xb3c74574e8c6503bULL, 0x647ad5769ada1adeULL, 0xa7f459403e59ca4aULL, 0xe6c13e17c185613dULL, 0x8141508718005684ULL, 0x367c5d28a57d2e1ULL, 0x6d24d37f3ef1c795ULL, 0xa6bab61e7df41aeeULL, 0x46f54b8deeecafbdULL, 0xf476504ce308852dULL, 0x32311303c6f7d625ULL, 0x2d2ac3eae67ac977ULL, 0x5c88796b4ece68f1ULL, 0x1ddb46aee9126c6aULL, 0x783fed878e551553ULL, 0x7522cec4fe49f813ULL, 0xe42535b1e44482aaULL, 0xa847c4853bfa6df9ULL, 0x80f70fea9c4bb54cULL, 0xacaa5ecf7883e0bcULL, 0xc8bb05712eef674cULL, 0x304de62336f513c8ULL, 0x4f52009b10d62f2dULL, 0xb5f934346c94d17aULL, 0xee8a701eaea13688ULL, 0x83e5d5c929754bb7ULL, 0x2be0cd661f2a49b5ULL, 0x2e2c42ce4f61e6f6ULL, 0x9fab6a7dd5a7ade6ULL, 0x4ec420cbf1b59fa6ULL, 0xe483d568c16c67c7ULL, 0x1ceecfe330672004ULL, 0xf451ab4596eaaed8ULL, 0x6e3282dd66843121ULL, 0xffb7d94dd29dd4b3ULL, 0x19599ad2d301f40eULL, 0x80360c9fcf3480e7ULL, 0x45bde98ec8fc4b2eULL, 0xa05328e6b2af9075ULL, 0x4eb8641183f74144ULL, 0x5e6f032344ad3d64ULL, 0x364cf67fed02c1bfULL, 0x477322afee0bd078ULL, 0x552b458e6eff181ULL, 0x38053c83c7afd2c3ULL, 0x8530c2532e7fc7efULL, 0xeca0021f9e5bb182ULL, 0x18a364b05676c340ULL, 0x131cb0efd6d3ad22ULL, 0x435aeed1f049340fULL, 0x5b403c0aa3efae3fULL, 0x497dd1251631e3cULL, 0xa858476e82142bfaULL, 0x827fdbf32453f80cULL, 0x92bcfe4097dab001ULL, 0x29c30e85f48dc51fULL, 0x69e5ce79410f5cf4ULL, 0xf279c6bc4ff81bd2ULL, 0x8239f83d6ca47afeULL, 0x5773f1ce38549996ULL, 0xfffa68a06a10e79fULL, 0x79404e50a17e9caeULL, 0x9e3e20ee568b2dedULL, 0x86ef16022b28d753ULL, 0x6d79a79c95b435c4ULL, 0xc61987421e00e9a1ULL, 0xe80c757a9fce8a93ULL, 0x8e7d22bc367c269eULL, 0x4001ab5a67fe148aULL, 0x3abb9c29edee7b34ULL, 0x839e99c5789b589fULL, 0x9750300e3dfaed83ULL, 0xd5645f2f22d7c9b6ULL, 0x4968884bf622bf5aULL, 0xcc6d4d0adbc8a349ULL, 0xdc69e0dccf2fc330ULL, 0x8427a32cc9fba29dULL, 0x5224be3dec5e49a6ULL, 0x170a1535aec851b3ULL, 0xbb251e833ca7a830ULL, 0x60ce4ea76e65af5aULL, 0x8aaf65099ed2236bULL, 0x25fe492a6e44dee2ULL, 0x3666bf1bf5e2e662ULL, 0x5fc25c13fa7b6c1aULL, 0xeb0d2b208b3cefb2ULL, 0xefc1497ee70600c5ULL, 0x72b63d7d7caac26eULL, 0xfc8ab02e85bdc836ULL, 0xbe12259d1d6a59edULL, 0x858fd6c553eca6b1ULL, 0x256b8ca076c2483fULL, 0x4f7bd0d9b1295c0dULL, 0x8912384f92a56fdaULL, 0x4fab9cfd0cf5d484ULL, 0xb1903694c0953864ULL, 0x16afedd014094275ULL, 0xca35dc4511443d3dULL, 0x37fb6954ffd5cef1ULL, 0xc64d656a2156c414ULL, 0x5259c35507cbd0dbULL, 0x3257b62304c13fe3ULL, 0x647c0b87672b19d1ULL, 0x5aee1c65bcab75faULL, 0x670032f8798eb4c4ULL, 0x59aecc31024b3b8fULL, 0xc443fd7a8144f321ULL, 0x34baa455fedc525bULL, 0xce5853d68d4eb371ULL, 0xd6d25002de1dd08eULL, 0x23fa921421112dd4ULL, 0x8de559aadbd93b62ULL, 0x495b6cf3d81a5032ULL, 0xb7d2a5e289d7cacbULL, 0xd8ed181d392120d8ULL, 0x5d170e567ca0d92dULL, 0x31af84bbb920994ULL, 0x615dbf06eddbc39ULL, 0xe1abbf6b461caa8cULL, 0x1182bbe3e757ba59ULL, 0xee835bc3c1c942eaULL, 0x3bf9ab461efec869ULL, 0x3f5634d639adb999ULL, 0xcc7dfa63abdfc1fdULL, 0x9a88df893a3f1111ULL, 0xbe7358fb5a214c37ULL, 0x621d00de3300c516ULL, 0xbb6f87c55f129b7eULL, 0x1118eb27e6f195e9ULL, 0x43bc6bb1044d2dfbULL, 0x5b51acdd027c2cafULL, 0x4d4a310d7fc10574ULL, 0xdba6a542a2f566f5ULL, 0x4cf632ac5951228ULL, 0xe7b6f96cd54b3eeeULL, 0xe7fcdbb23094452eULL, 0xcc4e0bb0cef88538ULL, 0x6cd35d3ab60b6d4dULL, 0x7681b42f3b277408ULL, 0xd02db5103f912d5dULL, 0x8ac187714931ca1dULL, 0x69dbda145b566a33ULL, 0x93ffea868b65094cULL, 0x49fbc1ece76d3a3ULL, 0x3ff1f1e12ee6a5aULL, 0x4f7bd8c7bf83cf71ULL, 0xbe02a0d5ced9cbc0ULL, 0x2e68b8829dc21168ULL, 0x14cccadf78d05826ULL, 0x65b67f3becaaa366ULL, 0xbe6a4659d1069cc3ULL, 0xe8c9664c82af0168ULL, 0x6101bbaabecee267ULL, 0xd5216d0f78c5d625ULL, 0xcebd7c3f6a835126ULL, 0x6cb67c0611d9f8ffULL, 0x816d57d94924fd4bULL, 0x284a4e15d7125affULL, 0xdec9a9ce22f43184ULL, 0xc95d0fdb11a214fdULL, 0x3669543122accc08ULL, 0xa1d821bda03c45adULL, 0xccaf5bf016ce12fULL, 0xc296df76a9b9fccULL, 0xab6cd4061ad65156ULL, 0x93573dff99d05320ULL, 0xf01b7dfcec848b4aULL, 0xe3349615bf2b5540ULL, 0xc09f20fa71b51993ULL, 0x51b5ac768efece2cULL, 0x8be3dd580d092f88ULL, 0xb1071c823c097a43ULL, 0xb9b43fd03467b801ULL, 0x8588bc927679549fULL, 0xeae9c64b77c8e2b9ULL, 0x98d7de2c185fb289ULL, 0x592974762e52c2eeULL, 0x6beabe6ccc454c08ULL, 0x2d7ce6304af2d13eULL, 0xa6d04dcc1c4ab6d8ULL, 0xfd9ebd49547fb1b6ULL, 0x543cec633ec51501ULL, 0xd8a7f313f480acbeULL, 0x58a1a61d67f87e77ULL, 0xb43069665e6a9d1dULL, 0x39d05a53f2e9216ULL, 0x56b39a4e6b68b4cdULL, 0x9773a4face199a40ULL, 0xe3441afff8986253ULL, 0xd582deff95bc1dfcULL, 0x31168a7db9a60b1eULL, 0xd374b43b4d4e3ce9ULL, 0x34c96b8923d8775ULL, 0x61d665074afbbf4cULL, 0xf0ef58847bc44dbbULL, 0x9174d7d48b413bc4ULL, 0x6f01587c8fff7663ULL, 0x44d8729972b40087ULL, 0xc1b2fb2490ac230aULL, 0xa30b59c85b83c887ULL, 0xb2c60b8729ebf73fULL, 0x6642301e7ce8fab0ULL, 0xa63bad9a48835d63ULL, 0x5c7a7108809591abULL, 0xf81cb13328134fd1ULL, 0x944d5325e7e9e80bULL, 0x6a83a6fd4ae52fe5ULL, 0xa0b41c51fe6f020eULL, 0x51ac75960f23b325ULL, 0x9cadf04f0ceeb687ULL, 0x4f3caa328cac8e7aULL, 0x54f7a2d2d24e6c66ULL, 0x76074b35c6b2c543ULL, 0xe2be45b9764f17adULL, 0x27da5ead14e33fc9ULL, 0xf2fdb71f193e3f95ULL, 0x3c65d218ab9b81d3ULL, 0x2a529f3867d9451ULL, 0x1a05e2eeb8b52a71ULL, 0xc311835d79f6f1a0ULL, 0xafd570fcf84296e2ULL, 0x701bfd2953b3aba9ULL, 0xa09ad92f8e317e1fULL, 0xae76bb034631a4a7ULL, 0xf985bef7852f1217ULL, 0xde8279670628bbeULL, 0xf9cb9a30b28eab04ULL, 0xb23f6331fd197f8dULL, 0x249c0acd2e8d3c9eULL, 0x61509ab18b7eb17fULL, 0xcd686b91aba0a444ULL, 0x7ef8ccb4468d3f5aULL, 0x65fa22d46db8bec8ULL, 0x2afab5ac9bb2eccULL, 0xdcea243632570269ULL, 0x2302adb8667682f5ULL, 0xf319264c758dfd33ULL, 0xf41bf154385b0441ULL, 0xba892216b5ddf512ULL, 0x66f69bac317bc430ULL, 0x21fcf5d179787271ULL, 0x3f5ccce563d11ca1ULL, 0x3af35111d05cb421ULL, 0x56927dd6060b7bd4ULL, 0x3c9aad3c42c4e311ULL, 0x58bd6dd289704318ULL, 0x1185fd73580ceec2ULL, 0xf00ee21bbac845e4ULL, 0x7d43a4cf2f0a2269ULL, 0xcad580573e121a57ULL, 0xadef138484875171ULL, 0x9791347679106dcaULL, 0x8fc83be8c1990a4bULL, 0xa12c42267be55b40ULL, 0x165350b73a72cb60ULL, 0xbbb03fa134637e80ULL, 0x1d3cf774f3047e32ULL, 0x5d17bab1a45e6971ULL, 0x86cc271cbfe464bdULL, 0x51e3fd31800a898cULL, 0xb3a8b2ee3fdf2bdeULL, 0xf86a887823b6fd51ULL, 0x547b16a8fc4fc57eULL, 0x90e8d67cf1a67a60ULL, 0xc2b722ccbfc6c809ULL, 0x7acfc0f4071b0a96ULL, 0x38894f9479113d46ULL, 0x9b2b3d0f0106eddbULL, 0x42fd316f4232e2b2ULL, 0x878e9135d8149be7ULL, 0x417b58ebd1011cbbULL, 0x4ce21da70ec1b0b7ULL, 0x1ef24335b29ad074ULL, 0x247c18d1f9546123ULL, 0xf759ff9af4cd180ULL, 0xed8f73138e553445ULL, 0x7477fb74d28e7598ULL, 0x91e9a3c4806433f7ULL, 0x8356b1ed7bd5bec1ULL, 0xa76d9cd0023d3df5ULL, 0x5ae3065918fc05daULL, 0xd4fbc7b6efe3635eULL, 0xa1383c9477d8cec7ULL, 0x8d07feb88c412527ULL, 0x53c441ece6cffe29ULL, 0x7d0b59f9fb00b041ULL, 0x407bd04f65e1c31eULL, 0x217ce881ba849a6ULL, 0x7354dfe4eb00bc4dULL, 0x19a42c97052de4a9ULL, 0x5598ec6ef3cc60ebULL, 0x7cfd7fbb0260dbb6ULL, 0x94ecb81ef42e8e90ULL, 0x99599eaa45fe34f0ULL, 0x796c9299a0ef9685ULL, 0x61ac148843dc50bdULL, 0xae1b46113b1526cfULL, 0xcaffc9893d98c1e8ULL, 0x22c7fa938aa91474ULL, 0xc007bb23ccbca3aaULL, 0x9561b23745d96e3ULL, 0xae5748062c8be766ULL, 0x7e415c2d2aea3c4cULL, 0xf0bf7ddc9b2dfa1ULL, 0xf40d136ff94cd527ULL, 0x93e483467522a02aULL, 0xc680cc9970ea82dfULL, 0x4e7e905daa54edafULL, 0xae42dfe004885a44ULL, 0x3631728b121188acULL, 0xf942f2c2648aa2adULL, 0x3aec24d95e38a48cULL, 0xca3f04b9ba9bc824ULL, 0x831a49a720ea04b5ULL, 0x5fd9723666ed5d0fULL, 0x39bb8a5e6d2b9839ULL, 0x823428f4a17c5672ULL, 0xa44411c7b714754fULL, 0x41634f1a57fab015ULL, 0x10a36bfa705f57d9ULL, 0x58995552e459671aULL, 0xcb58d5efb9dc6bdfULL, 0x28a99585fdd13036ULL, 0x3036c186f8009c2bULL, 0x8bc1479e340987c6ULL, 0xac0da1e989aaf9fbULL, 0x8b49f98a4e5974ddULL, 0x5b8bdc709d7f371dULL, 0xa5a027774d63b882ULL, 0x1ab179c255cdd4e9ULL, 0x826bf72fb3199663ULL, 0x54690a377c6dcca5ULL, 0x349291e76da99a6aULL, 0x6bf28f4ee4533819ULL, 0x5fd0187fd5c18ff5ULL, 0x9b0e634e3e11f435ULL, 0xc79ab266a8adffa6ULL, 0x23f9e6d57d0d6240ULL, 0x6d83a48408e733bdULL, 0x7144c0877d7fa177ULL, 0xe816f92104e10291ULL, 0x4f4433a8f6f68974ULL, 0x2e55ff284d443e5bULL, 0xb65a7711d41d7fb2ULL, 0x9b3f4e4eddee0ba6ULL, 0x88c94d8873f30abcULL, 0xba336f2e72bdb31cULL, 0x73aa3dca2acad936ULL, 0x20eb9286fa64d1eeULL, 0xda7d8e45f84f10b8ULL, 0x409b167674c25419ULL, 0xae6a42cf20f73a38ULL, 0x9551ea0783585e28ULL, 0xedcc7661d25446d5ULL, 0x8a2376d052560536ULL, 0x6e697b54ef615bc8ULL, 0xd88cb14fdb6658f5ULL, 0x7132b77e538a07e9ULL, 0x63178aad6f43ed11ULL, 0x7cabe939826d341eULL, 0x4f9dceb6ebe0f1adULL, 0xce0276eb05607f49ULL, 0x7f49b4e07deee6aULL, 0x81969b535ef67b7eULL, 0xbbcf45b05a2a1748ULL, 0xd8cdfc141d0e7cb7ULL, 0x75f827d7c003f337ULL, 0x473ea0c6c151b595ULL, 0x4822ee1df74fe242ULL, 0x2ddfb9803e6e02dULL, 0xd7e314d94de8a6abULL, 0xea36f3c6e5b6fa4ULL, 0x6b0cd8974d6a62a2ULL, 0xb22c218c9ddd0cfaULL, 0x4d72edced81a2441ULL, 0x722f7d85cf71d0fdULL, 0x4938de818e0686efULL, 0x77b4a66fe172be8fULL, 0xf1cd58971196b432ULL, 0xb6c9c7068496e801ULL, 0xb7ee84f94fe9faabULL, 0x21871b367247ef2eULL, 0x6cd7909779e4e26dULL, 0xdb3d5fcca76b46deULL, 0xf752ab27a231e919ULL, 0xbf0e1c4c7d468b33ULL, 0x6b25d663f51d3c11ULL, 0xa352b25de4b08b7bULL, 0xbdd9aeb1d7047146ULL, 0x7d67bd9c042a015aULL, 0x7a000f07011ed1b3ULL, 0x9ff91ffce63c1fedULL, 0xb77a6e05623737eULL, 0x6f8c2f047639020fULL, 0xf80aec6678810741ULL, 0xafb4e406a8c32913ULL, 0xa3820ef12884dffeULL, 0x72da55ce9140a8fULL, 0x29951bab81d0bb3bULL, 0x817a09579fcfc685ULL, 0x9b434da5c3535f4cULL, 0x4749af9089f8a413ULL, 0xc1b7a276d38dd68ULL, 0xb55e8602c60cc207ULL, 0x9d2f929a44b1b75dULL, 0x36e9ee702b12f7edULL, 0x89a65594cfeac579ULL, 0x3047db6b9762432aULL, 0xa05b36fb873ae058ULL, 0x3709fa8004568e03ULL, 0x2e1e9af0432e3301ULL, 0x94e92cd3e692cd52ULL, 0xc0dfa2768c70f29eULL, 0x782db9321f44498dULL, 0x9cece49b7d6023f1ULL, 0x9ac997272c517e96ULL, 0x8465427beadb809eULL, 0xa06f561b6b53bae7ULL, 0x85c43a21ddf360baULL, 0xe0fad0e81f714fddULL, 0x551d372cbd38492bULL, 0xe48649627ee903e9ULL, 0x385144b1b50fe991ULL, }; unsigned int uint64_table_size = sizeof(uint64_table) / sizeof(uint64_t); hoichess_0.10.3/src/hash.cc0000640000175000017500000001154110732031250015054 0ustar oliveroliver/* $Id: hash.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/hash.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "hash.h" #include "move.h" #include /***************************************************************************** * * Member functions of class HashEntry. * *****************************************************************************/ /* TODO This should be inline, but the class definition of class Board * is not yet available in hash.h, thus get_hashkey() cannot be called. */ HashEntry::HashEntry(const Board & board, int score, Move move, int depth, int type) { this->hashkey = board.get_hashkey(); this->type = type; this->depth = depth; this->score = score; this->move = move; } /***************************************************************************** * * Member functions of class HashTable. * *****************************************************************************/ HashTable::HashTable(unsigned long size) { ASSERT(size > 0); table_size = size; table = new HashEntry[table_size]; entries = 0; replacement_scheme = REPL_ALWAYS; reset_statistics(); } HashTable::~HashTable() { delete[] table; } void HashTable::clear() { delete[] table; table = new HashEntry[table_size]; entries = 0; reset_statistics(); } bool HashTable::put(const HashEntry & entry) { const unsigned long key = entry.hashkey % table_size; const HashEntry & e = table[key]; if (e.type == HashEntry::NONE) { entries++; } else { switch (replacement_scheme) { case REPL_ALWAYS: /* Always replace. */ break; case REPL_DEPTH: /* Replace when same depth or deeper. */ if (e.depth > entry.depth) { return false; } break; default: BUG("replacement_scheme = %d", replacement_scheme); } if (e.hashkey != entry.hashkey) { STAT_INC(stat_collisions); } } table[key] = entry; return true; } bool HashTable::probe(const Board & board, HashEntry * entry) { STAT_INC(stat_probes); const unsigned long key = board.get_hashkey() % table_size; const HashEntry & e = table[key]; if (e.type == HashEntry::NONE || e.hashkey != board.get_hashkey()) { return false; } /* If this entry has a move, make sure it is * valid for the given board position. */ if (e.move) { if (!e.move.is_valid(board)) { STAT_INC(stat_collisions2); return false; } if (!e.move.is_legal(board)) { WARN("illegal move in hash table"); return false; } } *entry = e; STAT_INC(stat_hits); return true; } void HashTable::set_replacement_scheme(enum replacement_schemes scheme) { replacement_scheme = scheme; } void HashTable::set_replacement_scheme(const std::string & scheme) { if (scheme == "always") { replacement_scheme = REPL_ALWAYS; } else if (scheme == "depth") { replacement_scheme = REPL_DEPTH; } else { fprintf(stderr, "Invalid hash replacement scheme: %s\n", scheme.c_str()); } } void HashTable::print_info(FILE * fp) const { fprintf(fp, "Hash table size: %lu entries (%.1f MiB)\n", table_size, (float) table_size * sizeof(HashEntry) / (1<<20)); fprintf(fp, "Hash table usage: %lu entries (%lu%%)\n", entries, entries*100/table_size); const char * s; switch (replacement_scheme) { case REPL_ALWAYS: s = "always replace"; break; case REPL_DEPTH: s = "same depth or deeper"; break; default: BUG("replacement_scheme = %d", replacement_scheme); } fprintf(fp, "Hash table replacement scheme: %s\n", s); } void HashTable::print_statistics(FILE * fp) const { fprintf(fp, "Hash table entries: %lu (%lu%% full)\n", entries, entries*100/table_size); #ifdef COLLECT_STATISTICS if (stat_probes > 0) { fprintf(fp, "Hash table probes: %lu, hits: %lu/%lu (%lu%%/%lu%%)\n", stat_probes, stat_hits, stat_hits2, stat_hits*100/stat_probes, stat_hits2*100/stat_probes); } fprintf(fp, "Hash table collisions: %lu/%lu\n", stat_collisions, stat_collisions2); #endif // COLLECT_STATISTICS } void HashTable::reset_statistics() { #ifdef COLLECT_STATISTICS stat_probes = 0; stat_hits = 0; stat_hits2 = 0; stat_collisions = 0; stat_collisions2 = 0; #endif // COLLECT_STATISTICS } hoichess_0.10.3/src/pawnhash.cc0000640000175000017500000000606210732031250015744 0ustar oliveroliver/* $Id: pawnhash.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/pawnhash.cc * * Copyright (C) 2004-2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "pawnhash.h" #include /***************************************************************************** * * Member functions of class PawnHashTable. * *****************************************************************************/ PawnHashTable::PawnHashTable(unsigned long size) { ASSERT(size > 0); table_size = size; table = new PawnHashEntry[table_size]; entries = 0; reset_statistics(); } PawnHashTable::~PawnHashTable() { delete[] table; } void PawnHashTable::clear() { delete[] table; table = new PawnHashEntry[table_size]; entries = 0; reset_statistics(); } bool PawnHashTable::put(const PawnHashEntry & entry) { const unsigned long key = entry.hashkey % table_size; const PawnHashEntry & e = table[key]; if (e.phase == -1) { entries++; } else { /* Always replace. */ if (e.hashkey != entry.hashkey) { STAT_INC(stat_collisions); } } table[key] = entry; return true; } bool PawnHashTable::probe(Hashkey hashkey, PawnHashEntry * entry) { STAT_INC(stat_probes); const unsigned long key = hashkey % table_size; const PawnHashEntry & e = table[key]; if (e.phase == -1 || e.hashkey != hashkey) { entry->phase = -1; return false; } *entry = e; STAT_INC(stat_hits); return true; } void PawnHashTable::print_info(FILE * fp) const { fprintf(fp, "Pawn hash table size: %lu entries (%.1f MiB)\n", table_size, (float) table_size * sizeof(PawnHashEntry) / (1<<20)); fprintf(fp, "Pawn hash table usage: %lu entries (%lu%%)\n", entries, entries*100/table_size); } void PawnHashTable::print_statistics(FILE * fp) const { fprintf(fp, "Pawn hash table entries: %lu (%lu%% full)\n", entries, entries*100/table_size); #ifdef COLLECT_STATISTICS if (stat_probes > 0) { fprintf(fp, "Pawn hash table probes: %lu, hits: %lu/%lu" " (%lu%%/%lu%%)\n", stat_probes, stat_hits, stat_hits2, stat_hits*100/stat_probes, stat_hits2*100/stat_probes); } fprintf(fp, "Pawn hash table collisions: %lu\n", stat_collisions); #endif // COLLECT_STATISTICS } void PawnHashTable::reset_statistics() { #ifdef COLLECT_STATISTICS stat_probes = 0; stat_hits = 0; stat_hits2 = 0; stat_collisions = 0; #endif // COLLECT_STATISTICS } hoichess_0.10.3/src/evalcache.cc0000640000175000017500000000630610732031250016047 0ustar oliveroliver/* $Id: evalcache.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/evalcache.cc * * Copyright (C) 2005, 2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "evalcache.h" #include EvaluationCache::EvaluationCache(unsigned long size) { ASSERT(size > 0); cache_size = size; cache = new struct cacheentry[cache_size]; for (unsigned long i = 0; i < cache_size; i++) { cache[i].score = INT_MIN; } entries = 0; reset_statistics(); } EvaluationCache::~EvaluationCache() { delete[] cache; } void EvaluationCache::clear() { delete[] cache; cache = new struct cacheentry[cache_size]; for (unsigned long i = 0; i < cache_size; i++) { cache[i].score = INT_MIN; } entries = 0; reset_statistics(); } bool EvaluationCache::put(const Board & board, int score) { const Hashkey hashkey = board.get_hashkey_noside(); const unsigned long key = hashkey % cache_size; /* We use an always replace strategy. */ if (cache[key].score == INT_MIN) { entries++; } else if (cache[key].hashkey != hashkey) { STAT_INC(stat_collisions); } cache[key].hashkey = hashkey; cache[key].score = (board.get_side() == WHITE) ? score : -score; return true; } bool EvaluationCache::probe(const Board & board, int * score) { ASSERT(score != NULL); STAT_INC(stat_probes); const Hashkey hashkey = board.get_hashkey_noside(); const unsigned long key = hashkey % cache_size; if (cache[key].score == INT_MIN) { return false; } else if (cache[key].hashkey != hashkey) { return false; } *score = (board.get_side() == WHITE) ? cache[key].score : -cache[key].score; STAT_INC(stat_hits); return true; } void EvaluationCache::print_info(FILE * fp) const { fprintf(fp, "Evaluation cache size: %lu entries (%.1f MiB)\n", cache_size, (float) cache_size * SIZEOF_ENTRY / (1<<20)); fprintf(fp, "Evaluation cache usage: %lu entries (%lu%%)\n", entries, entries*100/cache_size); } void EvaluationCache::print_statistics(FILE * fp) const { fprintf(fp, "Evaluation cache entries: %lu (%lu%% full)\n", entries, entries*100/cache_size); #ifdef COLLECT_STATISTICS if (stat_probes > 0) { fprintf(fp, "Evaluation cache probes: %lu, hits: %lu (%lu%%)\n", stat_probes, stat_hits, stat_hits*100/stat_probes); } fprintf(fp, "Evaluation cache collisions: %lu\n", stat_collisions); #endif // COLLECT_STATISTICS } void EvaluationCache::reset_statistics() { #ifdef COLLECT_STATISTICS stat_probes = 0; stat_hits = 0; stat_collisions = 0; #endif // COLLECT_STATISTICS } hoichess_0.10.3/src/bench.cc0000640000175000017500000002077610732031250015222 0ustar oliveroliver/* $Id: bench.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/bench.cc * * Copyright (C) 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "bench.h" #include "board.h" #include "clock.h" #include "eval.h" const char * Bench::fens[] = { /* positions of Bratko-Kopec test */ "1k1r4/pp1b1R2/3q2pp/4p3/2B5/4Q3/PPP2B2/2K5 b - - 0 1", "3r1k2/4npp1/1ppr3p/p6P/P2PPPP1/1NR5/5K2/2R5 w - - 0 1", "2q1rr1k/3bbnnp/p2p1pp1/2pPp3/PpP1P1P1/1P2BNNP/2BQ1PRK/7R b - - 0 1", "rnbqkb1r/p3pppp/1p6/2ppP3/3N4/2P5/PPP1QPPP/R1B1KB1R w KQkq - 0 1", "r1b2rk1/2q1b1pp/p2ppn2/1p6/3QP3/1BN1B3/PPP3PP/R4RK1 w - - 0 1", "2r3k1/pppR1pp1/4p3/4P1P1/5P2/1P4K1/P1P5/8 w - - 0 1", "1nk1r1r1/pp2n1pp/4p3/q2pPp1N/b1pP1P2/B1P2R2/2P1B1PP/R2Q2K1 w - - 0 1", "4b3/p3kp2/6p1/3pP2p/2pP1P2/4K1P1/P3N2P/8 w - - 0 1", "2kr1bnr/pbpq4/2n1pp2/3p3p/3P1P1B/2N2N1Q/PPP3PP/2KR1B1R w - - 0 1", "3rr1k1/pp3pp1/1qn2np1/8/3p4/PP1R1P2/2P1NQPP/R1B3K1 b - - 0 1", "2r1nrk1/p2q1ppp/bp1p4/n1pPp3/P1P1P3/2PBB1N1/4QPPP/R4RK1 w - - 0 1", "r3r1k1/ppqb1ppp/8/4p1NQ/8/2P5/PP3PPP/R3R1K1 b - - 0 1", "r2q1rk1/4bppp/p2p4/2pP4/3pP3/3Q4/PP1B1PPP/R3R1K1 w - - 0 1", "rnb2r1k/pp2p2p/2pp2p1/q2P1p2/8/1Pb2NP1/PB2PPBP/R2Q1RK1 w - - 0 1", "2r3k1/1p2q1pp/2b1pr2/p1pp4/6Q1/1P1PP1R1/P1PN2PP/5RK1 w - - 0 1", "r1bqkb1r/4npp1/p1p4p/1p1pP1B1/8/1B6/PPPN1PPP/R2Q1RK1 w kq - 0 1", "r2q1rk1/1ppnbppp/p2p1nb1/3Pp3/2P1P1P1/2N2N1P/PPB1QP2/R1B2RK1 b - - 0 1", "r1bq1rk1/pp2ppbp/2np2p1/2n5/P3PP2/N1P2N2/1PB3PP/R1B1QRK1 b - - 0 1", "3rr3/2pq2pk/p2p1pnp/8/2QBPP2/1P6/P5PP/4RRK1 b - - 0 1", "r4k2/pb2bp1r/1p1qp2p/3pNp2/3P1P2/2N3P1/PPP1Q2P/2KRR3 w - - 0 1", "3rn2k/ppb2rpp/2ppqp2/5N2/2P1P3/1P5Q/PB3PPP/3RR1K1 w - - 0 1", "2r2rk1/1bqnbpp1/1p1ppn1p/pP6/N1P1P3/P2B1N1P/1B2QPP1/R2R2K1 b - - 0 1", "r1bqk2r/pp2bppp/2p5/3pP3/P2Q1P2/2N1B3/1PP3PP/R4RK1 b kq - 0 1", "r2qnrnk/p2b2b1/1p1p2pp/2pPpp2/1PP1P3/PRNBB3/3QNPPP/5RK1 w - - 0 1", /* some artificial positions with lots of captures */ "k2nRnR1/3PP1p1/N1Nn1Pp1/3NnPpB/qqqP1P1B/3P4/QQQB3B/K5R1 w - - 0 1", "k2nRnR1/3PP1p1/N1Nn1Pp1/1q1NnPpB/q1qP1P1B/3P4/QQQB3B/K5R1 b - - 0 1", "kqRRrQNr/rnqpbnpr/QprPqpqP/pnPqPqPn/pPqPqPpP/QqNNNNNN/RBqrqbqr/KRrRrRrR w - - 0 1", /* some artificial positions to test generate_escapes */ "k3r3/8/8/2n5/4K2q/2n5/8/7b w - - 0 1", "k2r1r2/8/8/8/4K3/8/8/4N2b w - - 0 1", "k2r1r2/8/7R/8/4K3/6N1/5P2/4N2b w - - 0 1", NULL }; Bench::Bench() { } Bench::~Bench() { } void Bench::bench_movegen() { printf("Running move generator benchmark...\n"); log("bench movegen\n"); unsigned int mps_moves = bench_movegen(&Board::generate_moves, "generate_moves"); unsigned int mps_captures = bench_movegen(&Board::generate_captures, "generate_captures"); unsigned int mps_noncaptures = bench_movegen( &Board::generate_noncaptures, "generate_noncaptures"); unsigned int mps_escapes = bench_movegen(&Board::generate_escapes, "generate_escapes"); log("mps_moves=%u\n", mps_moves); log("mps_captures=%u\n", mps_captures); log("mps_noncaptures=%u\n", mps_noncaptures); log("mps_escapes=%u\n", mps_escapes); if (verbose) { printf("Average speed of generate_moves: %9uk moves/s\n", mps_moves / 1000); printf("Average speed of generate_captures: %9uk moves/s\n", mps_captures / 1000); printf("Average speed of generate_noncaptures: %9uk moves/s\n", mps_noncaptures / 1000); printf("Average speed of generate_escapes: %9uk moves/s\n", mps_escapes / 1000); } /* Calculate weighted average. * In the current version of HoiChess, search uses generate_moves() * instead generate_escapes(), which is buggy. */ float mps_weighted = (float) ( mps_moves * 5 + mps_captures * 80 + mps_noncaptures * 15 + mps_escapes * 0 ) / 100; printf("Average move generator speed (weighted average):" " %.1fk moves/s\n", mps_weighted / 1000); log("mps_weighted=%.0f\n", mps_weighted); log("bench movegen finished\n"); } unsigned int Bench::bench_movegen(movegen_t movegen, const char * movegen_name) { ASSERT(movegen != NULL); ASSERT(movegen_name != NULL); if (verbose >= 1) { printf("Move generator: %s\n", movegen_name); } float mps_sum = 0; unsigned int mps_cnt = 0; for (const char ** p = &fens[0]; *p != NULL; p++) { const char * fen = *p; if (verbose >= 2) { printf("\tPosition: %s\n", fen); } Board board(fen); Movelist movelist; Clock clock(1); clock.start(); unsigned long moves = 0; while (!clock.timeout()) { for (unsigned int i=0; i<1000; i++) { movelist.clear(); (board.*movegen)(&movelist); moves += movelist.size(); } if (moves == 0) { break; } } clock.stop(); float secs = (float) clock.get_elapsed_time() / 100; float mps; if (moves > 0 && secs > 0) { mps = moves / secs; mps_sum += mps; mps_cnt++; log("movegen=%s, position='%s', moves=%lu, time=%.2f, " "speed=%.0f\n", movegen_name, fen, moves, secs, mps); if (verbose >= 2) { printf("\tMoves generated: %lu in %.2f s" " (%.1fk moves/s)\n", moves, secs, mps / 1000); } } } float mps_avg = (mps_cnt > 0) ? (mps_sum / mps_cnt) : 0; return (unsigned int) mps_avg; } void Bench::bench_evaluator() { printf("Running evaluator benchmark...\n"); log("bench evaluator\n"); float eps_sum = 0; unsigned int eps_cnt = 0; for (const char ** p = &fens[0]; *p != NULL; p++) { const char * fen = *p; if (verbose >= 2) { printf("\tPosition: %s\n", fen); } Board board(fen); Evaluator eval; Clock clock(1); clock.start(); unsigned long evals = 0; while (!clock.timeout()) { for (unsigned int i=0; i<1000; i++) { eval.eval(board, -INFTY, INFTY, NO_COLOR); evals++; } } clock.stop(); float secs = (float) clock.get_elapsed_time() / 100; float eps; if (evals > 0 && secs > 0) { eps = evals / secs; eps_sum += eps; eps_cnt++; log("position='%s', evals=%lu, time=%.2f, speed=%.0f\n", fen, evals, secs, eps); if (verbose >= 2) { printf("\tEvaluations: %lu in %.2f s" " (%.1fk evaluations/s)\n", evals, secs, eps / 1000); } } } float eps_avg = (eps_cnt > 0) ? (eps_sum / eps_cnt) : 0; printf("Average evaluator speed: %.1fk evaluations/s\n", eps_avg / 1000); log("eps_avg=%.0f\n", eps_avg); log("bench evaluator finished\n"); } void Bench::bench_makemove() { printf("Running makemove benchmark...\n"); log("bench makemove\n"); float mps_sum = 0; unsigned int mps_cnt = 0; for (const char ** p = &fens[0]; *p != NULL; p++) { const char * fen = *p; if (verbose >= 2) { printf("\tPosition: %s\n", fen); } Board board(fen); Board newboard; Movelist movelist; board.generate_moves(&movelist); Clock clock(1); clock.start(); unsigned long moves = 0; while (!clock.timeout()) { for (unsigned int i=0; i<1000; i++) { for (unsigned int k=0; k 0 && secs > 0) { mps = moves / secs; mps_sum += mps; mps_cnt++; log("position='%s', moves=%lu, time=%.2f, speed=%.0f\n", fen, moves, secs, mps); if (verbose >= 2) { printf("\tMoves made: %lu in %.2f s" " (%.1fk moves/s)\n", moves, secs, mps / 1000); } } } float mps_avg = (mps_cnt > 0) ? (mps_sum / mps_cnt) : 0; printf("Average makemove speed: %.1fk moves/s\n", mps_avg / 1000); log("mps_avg=%.0f\n", mps_avg); log("bench makemove finished\n"); } hoichess_0.10.3/src/tree.cc0000640000175000017500000002005310732031250015066 0ustar oliveroliver/* $Id: tree.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/tree.cc * * Copyright (C) 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "eval.h" #include "tree.h" /***************************************************************************** * * Functions of class Node * *****************************************************************************/ Node::Node() { historytable = NULL; } Move Node::first() { current_move_no = -1; switch (type) { case ROOT: /* For the root node, all moves have been generated in * Tree::set_root(). Scores were assigned by search_root() * using set_current_score(). So we can just start returning * moves. */ state = ALL; return next(); case FULLWIDTH: case QUIESCE: /* First, determine the next state. */ if (in_check()) { /* Some moves might have already been generated * due to internal iterative deepening. */ if (escapes_generated) { state = SCORE_ESCAPES; } else { state = GEN_ESCAPES; } } else { /* Some moves might have already been generated * due to internal iterative deepening. */ if (noncaptures_generated) { ASSERT_DEBUG(type != QUIESCE); state = SCORE_ALL; } else if (captures_generated) { state = SCORE_CAPTURES; } else { state = GEN_CAPTURES; } } if (hashmv) { return hashmv; } else { return next(); } default: BUG("node type is bad: %d", type); } /* This line is never reached. We add a return statement, in case * the compiler does not know that BUG() will never return. */ return NO_MOVE; } Move Node::next() { const Board & board = tree->get_board(); Move mov; switch (state) { case GEN_CAPTURES: ASSERT_DEBUG(!captures_generated); ASSERT_DEBUG(movelist.size() == 0); board.generate_captures(&movelist, false); captures_generated = true; //state = SCORE_CAPTURES; case SCORE_CAPTURES: ASSERT_DEBUG(captures_generated); score_moves(); state = CAPTURES; case CAPTURES: ASSERT_DEBUG(captures_generated); mov = pick(); if (mov) { return mov; } if (type == QUIESCE) { state = DONE; break; } //state == GEN_NONCAPTURES; case GEN_NONCAPTURES: ASSERT_DEBUG(captures_generated); ASSERT_DEBUG(!noncaptures_generated); board.generate_noncaptures(&movelist); noncaptures_generated = true; //state = SCORE_NONCAPTURES; case SCORE_NONCAPTURES: ASSERT_DEBUG(noncaptures_generated); score_moves(); state = NONCAPTURES; case NONCAPTURES: ASSERT_DEBUG(noncaptures_generated); mov = pick(); if (mov) { return mov; } state = DONE; break; case GEN_ESCAPES: ASSERT_DEBUG(in_check()); ASSERT_DEBUG(!escapes_generated); ASSERT_DEBUG(movelist.size() == 0); //board.generate_escapes(&movelist); board.generate_moves(&movelist, false); escapes_generated = true; //state = SCORE_ESCAPES; case SCORE_ESCAPES: ASSERT_DEBUG(escapes_generated); score_moves(); state = ESCAPES; case ESCAPES: ASSERT_DEBUG(escapes_generated); mov = pick(); if (mov) { return mov; } state = DONE; break; case SCORE_ALL: score_moves(); state = ALL; case ALL: mov = pick(); if (mov) { return mov; } state = DONE; break; default: BUG("node status is bad: %d", state); } return NO_MOVE; } Move Node::pick() { int score = -INFTY; int m = -1; for (unsigned int i=current_move_no+1; i score) { score = movelist.get_score(i); m = i; } } if (m == -1) { return NO_MOVE; } Move mov = movelist[m]; current_move_no++; if (current_move_no != m) { movelist.swap(current_move_no, m); } return mov; } /* * Assign scores to moves. For root node, the score are set * by Search::search_root() using set_current_score(). */ void Node::score_moves() { if (type == ROOT) return; for (unsigned int i=current_move_no+1; iget(mov); } #endif } movelist.set_score(i, score); } } /***************************************************************************** * * Functions of class Tree * *****************************************************************************/ Tree::Tree() { nodes = new Node[MAXPLY]; for (unsigned int ply=0; plyboard = board; this->rootboard = board; #else nodes[0].board = board; #endif current_ply = 0; nodes[0].hashkey = board.get_hashkey(); nodes[0].incheck = board.in_check(); nodes[0].material = board.material_difference(); nodes[0].movelist.clear(); board.generate_moves(&nodes[0].movelist, false); nodes[0].movelist.filter_illegal(board); ASSERT(nodes[0].movelist.size() > 0); nodes[0].captures_generated = true; nodes[0].noncaptures_generated = true; nodes[0].escapes_generated = true; nodes[0].set_type(Node::ROOT); /* Assign one legal move as best, in case search terminates without * choosing a move. */ nodes[0].set_best(nodes[0].movelist[0]); nodes[0].set_hashmv(NO_MOVE); nodes[0].played_move = NO_MOVE; } Node * Tree::make_move(Move mov) { ASSERT_DEBUG(current_ply < MAXPLY-1); #ifdef USE_UNMAKE_MOVE BoardHistory hist = board.make_move(mov); nodes[current_ply].hist = hist; #else nodes[current_ply+1].board = nodes[current_ply].board; nodes[current_ply+1].board.make_move(mov); #endif current_ply++; #ifdef USE_UNMAKE_MOVE nodes[current_ply].hashkey = board.get_hashkey(); nodes[current_ply].incheck = board.in_check(); nodes[current_ply].material = board.material_difference(); #else nodes[current_ply].hashkey = nodes[current_ply].board.get_hashkey(); nodes[current_ply].incheck = nodes[current_ply].board.in_check(); nodes[current_ply].material = nodes[current_ply].board.material_difference(); #endif nodes[current_ply].movelist.clear(); nodes[current_ply].captures_generated = false; nodes[current_ply].noncaptures_generated = false; nodes[current_ply].escapes_generated = false; nodes[current_ply].set_type(Node::UNKNOWN); nodes[current_ply].set_best(NO_MOVE); nodes[current_ply].set_hashmv(NO_MOVE); nodes[current_ply].played_move = mov; return &nodes[current_ply]; } void Tree::unmake_move() { ASSERT_DEBUG(current_ply > 0); #ifdef USE_UNMAKE_MOVE BoardHistory hist = nodes[current_ply-1].hist; board.unmake_move(hist); #endif current_ply--; } hoichess_0.10.3/src/debug.h0000640000175000017500000000526510732031250015067 0ustar oliveroliver/* $Id: debug.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/debug.h * * Copyright (C) 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef DEBUG_H #define DEBUG_H #include "common.h" #include #include #include #ifdef DEBUG # ifndef DEBUGLEVEL # define DEBUGLEVEL 1 # endif #else // !DEBUG # define DEBUGLEVEL 0 #endif // !DEBUG /* We cannot include util.h or thread.h, since they may use something * that is declared inside this file. */ class Mutex; extern Mutex stdout_mutex; /* * Macros like this one here would be nice, but are only supported by gcc. * #define BUG(fmt, arg...) do { \ fprintf(stderr, "BUG: %s:%d: %s: " fmt "\n", \ __FILE__, __LINE__, __PRETTY_FUNCTION__, ##arg); \ exit(EXIT_FAILURE); \ } while (0) * * The following trick however, is standard C++ and must work * with any compiler. It is much more flexible anyway. */ class __debug_helper { FILE * fp; Mutex * mutex; const char * file; int line; const char * function; public: inline __debug_helper(FILE * fp, Mutex * mutex, const char * file, int line, const char * function) : fp(fp), mutex(mutex), file(file), line(line), function(function) { } inline ~__debug_helper() { } public: void __dbg(unsigned int level, const char * fmt, ...); void __warn(const char * fmt, ...); void __bug(const char * fmt, ...) NORETURN; }; #define DBG __debug_helper(stdout, &stdout_mutex, \ __FILE__, __LINE__, __PRETTY_FUNCTION__).__dbg #define WARN __debug_helper(stdout, &stdout_mutex, \ __FILE__, __LINE__, __PRETTY_FUNCTION__).__warn #define BUG __debug_helper(stderr, NULL, \ __FILE__, __LINE__, __PRETTY_FUNCTION__).__bug #define ASSERT(expr) do { \ if (!(expr)) { \ BUG("assertion `%s' failed", #expr); \ } \ } while (0) #ifdef DEBUG # define ASSERT_DEBUG(expr) ASSERT(expr) #else # define ASSERT_DEBUG(expr) #endif void debug_print_compiletime_config(); void debug_print_storagesizes(); #endif // DEBUG_H hoichess_0.10.3/src/movelist.h0000640000175000017500000000513010732031250015632 0ustar oliveroliver/* $Id: movelist.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/movelist.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef MOVELIST_H #define MOVELIST_H #include "common.h" #include "board.h" #include "move.h" #ifdef STATS_MOVELIST # include #endif class Movelist { private: Move move[MOVELIST_MAXSIZE]; int score[MOVELIST_MAXSIZE]; unsigned int nextin; unsigned int nextout; public: Movelist(); ~Movelist(); public: inline unsigned int size() const; inline void clear(); inline void add(Move mov); inline Move & operator[](unsigned int i); inline Move operator[](unsigned int i) const; inline int get_score(unsigned int i) const; inline void set_score(unsigned int i, int s); inline void swap(int i, int j); void filter_illegal(const Board & board); #ifdef STATS_MOVELIST private: static std::map maxsize; public: static void print_stats(); #endif }; inline unsigned int Movelist::size() const { return nextin; } inline void Movelist::clear() { #ifdef STATS_MOVELIST maxsize[nextin]++; #endif nextin = 0; nextout = 0; } inline void Movelist::add(Move mov) { if (nextin >= MOVELIST_MAXSIZE) { WARN("movelist is full, move not added:"); mov.print(); return; } move[nextin] = mov; score[nextin] = 0; nextin++; } inline Move & Movelist::operator[](unsigned int i) { ASSERT_DEBUG(i < size()); return move[i]; } inline Move Movelist::operator[](unsigned int i) const { ASSERT_DEBUG(i < size()); return move[i]; } inline int Movelist::get_score(unsigned int i) const { return score[i]; } inline void Movelist::set_score(unsigned int i, int s) { score[i] = s; } inline void Movelist::swap(int i, int j) { Move tmp_move = move[i]; move[i] = move[j]; move[j] = tmp_move; int tmp_score = score[i]; score[i] = score[j]; score[j] = tmp_score; } #endif // MOVELIST_H hoichess_0.10.3/src/util.h0000640000175000017500000000447610732031250014761 0ustar oliveroliver/* $Id: util.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/util.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef UTIL_H #define UTIL_H #include "common.h" #include #include #include #include extern Mutex stdout_mutex; extern int atomic_printf(const char * fmt, ...); extern int atomic_fprintf(FILE * fp, Mutex * mutex, const char * fmt, ...); extern uint64_t random64(); extern std::string strprintf(const char * fmt, ...); extern bool parse_size(const char * s, long * n); extern FILE * logfp; extern Mutex logfp_mutex; extern void open_log(const char * logfile); extern void close_log(); extern void log(const char * fmt, ...); extern void vlog(const char * fmt, va_list args); #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) /* * reverse byte order */ #define GETBYTE(v, n) ((v) >> ((n)*8) & 0xff) #define SETBYTE(v, n) ((v) << ((n)*8)) inline uint32_t reverse_byte_order(uint16_t a) { return SETBYTE(GETBYTE(a, 0), 1) | SETBYTE(GETBYTE(a, 1), 0); } inline uint32_t reverse_byte_order(uint32_t a) { return SETBYTE(GETBYTE(a, 0), 3) | SETBYTE(GETBYTE(a, 1), 2) | SETBYTE(GETBYTE(a, 2), 1) | SETBYTE(GETBYTE(a, 3), 0); } inline uint64_t reverse_byte_order(uint64_t a) { return SETBYTE(GETBYTE(a, 0), 7) | SETBYTE(GETBYTE(a, 1), 6) | SETBYTE(GETBYTE(a, 2), 5) | SETBYTE(GETBYTE(a, 3), 4) | SETBYTE(GETBYTE(a, 4), 3) | SETBYTE(GETBYTE(a, 5), 2) | SETBYTE(GETBYTE(a, 6), 1) | SETBYTE(GETBYTE(a, 7), 0); } #undef GETBYTE #undef SETBYTE #endif // UTIL_H hoichess_0.10.3/src/shell.cc0000640000175000017500000002706110732031250015244 0ustar oliveroliver/* $Id: shell.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/shell.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "book.h" #include "shell.h" #include #ifdef HAVE_READLINE # include # include #endif #include #include Shell::Shell() { xboard = false; flag_force = false; flag_ponder = false; flag_showthinking = false; flag_analyze = false; flag_playboth = false; source.fp = NULL; myname = PROGNAME + std::string(" ") + VERSION; Clock clock(5); game = new Game(Board(), clock, clock); book = NULL; hashtable = NULL; pawnhashtable = NULL; evalcache = NULL; search = new Search(this); } Shell::~Shell() { delete search; delete hashtable; delete pawnhashtable; delete evalcache; delete book; delete game; } void Shell::main(const char * filename) { source_t mainsource; if (filename != NULL) { mainsource.name = filename; mainsource.line = 0; mainsource.fp = fopen(filename, "r"); if (mainsource.fp == NULL) { fprintf(stderr, "Cannot open %s for reading: %s\n", filename, strerror(errno)); exit(EXIT_FAILURE); } } else { mainsource.name = "(stdin)"; mainsource.line = 0; mainsource.fp = stdin; } if (sources.size() != 0) { sources.pop_front(); sources.push_front(mainsource); } else { source = mainsource; } cmd_new(); if (!xboard && source.fp == stdin) { printf("\nType \"help\" for a list of available commands.\n\n"); } quit = false; while (!quit) { stop = false; if (game->is_over()) { /* nothing */ } else if (flag_playboth) { /* let engine make a move */ myside = game->get_side(); engine_move(); continue; } else if (!flag_force && game->get_side() == myside) { /* let engine make a move */ engine_move(); continue; } else if (flag_ponder && !flag_force && game->is_running()) { /* start search in background */ DBG(1, "starting background search..."); search->start_thread(*game, Search::PONDER, myside); } else if (flag_analyze) { /* start search in background */ DBG(1, "starting background search..."); search->start_thread(*game, Search::ANALYZE, NO_COLOR); } input(); } search->stop_thread(); } /* * This function will be called by the SIGINT-handler * in main.cc, so keep it short. */ void Shell::interrupt() { if (!xboard) { printf("Interrupt\n"); } search->interrupt(); stop = true; flag_playboth = false; } /* * Set the opening book. If bookfile is NULL, disable opening book. */ void Shell::set_book(const char * bookfile) { if (bookfile) { try { delete book; book = new Book(bookfile); printf("Opening book: %s\n", bookfile); } catch (BookException & e) { if (!xboard) { printf("%s", e.get_msg().c_str()); } printf("Failed to open opening book.\n"); book = NULL; } } else { printf("Opening book disabled.\n"); delete book; book = NULL; } search->set_book(book); } /* * Set the size of the hash table in bytes. 0 disables hash table. */ void Shell::set_hashsize(unsigned long size) { search->stop_thread(); unsigned long entries = size / sizeof(HashEntry); if (entries > 0) { delete hashtable; hashtable = new HashTable(entries); hashtable->print_info(); } else { delete hashtable; hashtable = NULL; printf("Hash table disabled.\n"); } search->set_hashtable(hashtable); } /* * Set the size of the pawn hash table in bytes. 0 disables pawn hash table. */ void Shell::set_pawnhashsize(unsigned long size) { search->stop_thread(); unsigned long entries = size / sizeof(PawnHashEntry); if (entries > 0) { delete pawnhashtable; pawnhashtable = new PawnHashTable(entries); pawnhashtable->print_info(); } else { delete pawnhashtable; pawnhashtable = NULL; printf("Pawn hash table disabled.\n"); } search->set_pawnhashtable(pawnhashtable); } /* * Set the size of the evaluation cache in bytes. 0 disables evaluation cache. */ void Shell::set_evalcachesize(unsigned long size) { search->stop_thread(); #ifdef USE_EVALCACHE unsigned long entries = size / EvaluationCache::SIZEOF_ENTRY; if (entries > 0) { delete evalcache; evalcache = new EvaluationCache(entries); evalcache->print_info(); } else { delete evalcache; evalcache = NULL; printf("Evaluation cache disabled.\n"); } search->set_evalcache(evalcache); #else (void) size; WARN("This version of %s has been compiled without" " evaluation cache support.\n", PROGNAME); #endif } /* * Set the engine's name. */ void Shell::set_myname(const char * name) { if (name) { myname = name; } else { myname = PROGNAME + std::string(" ") + VERSION; } } /* * Set/unset xboard mode. */ void Shell::set_xboard(bool x) { xboard = x; if (xboard) { setbuf(stdout, NULL); printf("\n"); } } void Shell::source_file(FILE * fp, const char * name) { ASSERT(fp != NULL); /* save current source */ sources.push_back(source); /* open new source */ source.name = name; source.line = 0; source.fp = fp; } void Shell::input() { cmd_args.clear(); if (xboard) { DBG(3, "waiting for input..."); } char * line = get_line(get_prompt().c_str()); if (line == NULL) { quit = true; return; } /* Strip trailing \n */ if (line[strlen(line)-1] == '\n') { line[strlen(line)-1] = '\0'; } DBG(1, "%s:%d: line=\"%s\"", source.name.c_str(), source.line, line); /* Tokenize the input. */ const char * delim = " \t\n"; char * strtok_r_buf; for (char * p = strtok_r(line, delim, &strtok_r_buf); p != NULL; p = strtok_r(NULL, delim, &strtok_r_buf)) { //DBG(3, "p = \"%s\"", p); cmd_args.push_back(p); } free(line); /* Ignore empty commands and comments. */ if (cmd_args.size() == 0 || cmd_args[0][0] == '#') { return; } /* Walk through the list of registered commands. */ for (int i=0; commands[i].name != NULL; i++) { if (cmd_args[0] != commands[i].name) continue; /* If a function is registered, and the command is not * to be ignores, call the corresponding function. */ if (commands[i].ignore) { return; } else if (commands[i].func != NULL) { (this->*commands[i].func)(); return; } else { printf("Error (command not implemented): %s\n", cmd_args[0].c_str()); return; } } /* The input wasn't recognized as a command, * so check if it is a move. */ if (cmd_args.size() == 1) { input_move(cmd_args[0]); return; } printf("Error (unknown command): %s\n", cmd_args[0].c_str()); return; } char * Shell::get_line(const char * prompt) { again: char * line; if (source.fp == NULL) { return NULL; } int fd = fileno(source.fp); if (!xboard && fd == 0 && isatty(0)) { #ifdef HAVE_READLINE line = get_line_readline(prompt); #else line = get_line_fgets(source.fp, prompt); #endif } else { line = get_line_fgets(source.fp, NULL); } source.line++; if (line == NULL && sources.size() > 0) { fclose(source.fp); source = sources.back(); sources.pop_back(); goto again; } return line; } char * Shell::get_line_fgets(FILE * fp, const char * prompt) { ASSERT(fp != NULL); if (prompt) { printf("%s", prompt); } char buf[1024]; char * p = fgets(buf, sizeof(buf)-1, fp); if (p != NULL) { char * ret = (char *) malloc((strlen(p)+1) * sizeof(char)); strcpy(ret, p); return ret; } else { return NULL; } } #ifdef HAVE_READLINE char * Shell::get_line_readline(const char * prompt) { char * line = readline(prompt); if (line && *line) { add_history(line); } return line; } #endif std::string Shell::get_prompt() { const char * a1 = ansicolor ? "\033[1m" : ""; const char * a2 = ansicolor ? "\033[0m" : ""; if (game->is_over()) { return strprintf("%s(game over):%s ", a1, a2); } std::string s = a1; if (flag_analyze) { s += "(analyze mode) "; } else if (flag_ponder && !flag_force && game->is_running()) { s += "(pondering) "; } s += strprintf("%s (%d): ", game->get_board().get_side() == WHITE ? "White" : "Black", game->get_board().get_moveno()); s += a2; if (flag_analyze || (flag_ponder && flag_showthinking)) { s += "\n"; } return s; } void Shell::input_move(std::string input) { if (game->is_over()) { printf("Illegal move (game over): %s\n", input.c_str()); return; } else if (game->get_side() == myside) { printf("Illegal move (it's my turn): %s\n", input.c_str()); return; } Board board = game->get_board(); Move mov = board.parse_move(input); if (mov) { search->stop_thread(); user_move(mov); } else { printf("Illegal move: %s\n", input.c_str()); } } void Shell::user_move(Move mov) { Board board = game->get_board(); if (!mov.is_valid(board)) { BUG("user_move() called with invalid move: %s", mov.str().c_str()); } else if (!mov.is_legal(board)) { BUG("user_move() called with illegal move: %s", mov.str().c_str()); } std::string san = mov.san(board); GameEntry::MoveAttributes move_attr(false, false); game->make_move(mov, move_attr); if (!xboard) { printf("\n"); game->get_board().print(stdout, mov); printf("\nYour move was: %s\n\n", san.c_str()); } //game->get_board().print(stdout, mov); DBG(1, "user move: %s", san.c_str()); DBG(1, "result = %d", game->get_result()); if (game->get_result()) { print_result(); } } void Shell::engine_move() { if (!xboard) { printf("Thinking...\n"); } /* Turn back the current side's clock, so we can think the full amount * of time, even if we've switched from human to engine. */ Clock clock = game->get_clock(); clock.turn_back(); game->set_clock(clock); game->start(); Board board = game->get_board(); Move mov; bool bookmove; BookEntry bookentry; if (book && book->lookup(board, &bookentry)) { mov = bookentry.choose(); bookmove = true; if (!mov.is_valid(board)) { BUG("book returned invalid move: %s", mov.str().c_str()); } else if (!mov.is_legal(board)) { BUG("book returned illegal move: %s", mov.str().c_str()); } } else { DBG(1, "starting search..."); search->start(*game, Search::MOVE, myside); DBG(1, "search terminated"); mov = search->get_best(); bookmove = false; if (!mov.is_valid(board)) { BUG("search returned invalid move: %s", mov.str().c_str()); } else if (!mov.is_legal(board)) { BUG("search returned illegal move: %s", mov.str().c_str()); } } std::string san = mov.san(board); GameEntry::MoveAttributes move_attr(true, bookmove); game->make_move(mov, move_attr); if (xboard) { std::string str = mov.str(); atomic_printf("move %s\n", str.c_str()); } else { printf("\n"); game->get_board().print(stdout, mov); printf("\nMy move is: %s\n\n", san.c_str()); } //game->get_board().print(stdout, mov); DBG(1, "engine move: %s", san.c_str()); DBG(1, "result = %d", game->get_result()); if (game->get_result()) { print_result(); } } void Shell::print_result() { atomic_printf("%s {%s}\n", game->get_result_str().c_str(), game->get_result_comment().c_str()); } hoichess_0.10.3/src/bench.h0000640000175000017500000000244110732031250015051 0ustar oliveroliver/* $Id: bench.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/bench.h * * Copyright (C) 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef BENCH_H #define BENCH_H #include "common.h" #include "board.h" class Bench { private: typedef void (Board::* movegen_t) (Movelist *) const; private: static const char * fens[]; public: Bench(); ~Bench(); public: void bench_movegen(); void bench_evaluator(); void bench_makemove(); private: unsigned int bench_movegen(movegen_t movgen, const char * movegen_name); }; #endif // BENCH_H hoichess_0.10.3/src/common.h0000640000175000017500000000435210732031250015265 0ustar oliveroliver/* $Id: common.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/common.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef COMMON_H #define COMMON_H #include "version.h" #include "config.h" #if defined(HOICHESS) # define PROGNAME "HoiChess" #elif defined(HOIXIANGQI) # define PROGNAME "HoiXiangqi" #else # error "neither HOICHESS nor HOIXIANGQI is defined" #endif #define AUTHOR "Holger Ruckdeschel" #define AUTHOR_EMAIL "" /* Get uint64_t and friends */ # include /* * Compiler specific definitions */ #ifdef __GNUC__ # define FORCEINLINE inline __attribute__((always_inline)) #else # define FORCEINLINE inline #endif #ifdef __GNUC__ # define NORETURN __attribute__((noreturn)) #else # define NORETURN #endif #ifndef __GNUC__ # define __PRETTY_FUNCTION__ __FUNCTION__ #endif /* * Platform specific definitions */ #ifdef WIN32 #include #include #define isatty _isatty #ifndef __MINGW32__ # include "snprintf.h" #endif #include "strtok_r.h" #endif /* WIN32 */ /* * Global variables */ /* These are defined in main.cc */ extern unsigned int debug; extern unsigned int verbose; extern bool ansicolor; /* This one is defined in uint64_table.cc */ extern uint64_t uint64_table[]; extern unsigned int uint64_table_size; /* * Include some frequently used stuff */ #include "debug.h" #include "util.h" /* * Miscellaneous */ #ifdef COLLECT_STATISTICS # define STAT_INC(x) ((x)++) #else # define STAT_INC(x) #endif #endif // COMMON_H hoichess_0.10.3/src/version.h0000640000175000017500000000012210732031250015451 0ustar oliveroliver//#define VERSION "trunk" //#define VERSION "070818" #define VERSION "0.10.3" hoichess_0.10.3/src/xiangqi/0000750000175000017500000000000010732031250015257 5ustar oliveroliverhoichess_0.10.3/src/xiangqi/move.h0000640000175000017500000001212010732031250016373 0ustar oliveroliver/* $Id: move.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/move.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef MOVE_H #define MOVE_H #include "common.h" #include "board.h" #include "basic.h" #include /* Need a forward declaration here since * move.h and board.h include each other. */ class Board; #define NO_MOVE Move() class Move { public: enum { MOVE_NONE = 0x0000, MOVE_NORMAL = 0x0001, MOVE_CAPTURE = 0x0002, MOVE_NULL = 0x0020 }; private: Square mov_from; Square mov_to; Piece mov_ptype; Piece mov_cap_ptype; uint16_t mov_flags; public: FORCEINLINE Move(); private: inline Move(Square from, Square to, Piece ptype, Piece cap_ptype, uint16_t flags); public: inline Square from() const; inline Square to() const; inline Piece ptype() const; inline Piece cap_ptype() const; inline uint16_t flags() const; inline bool is_normal() const; inline bool is_capture() const; inline bool is_null() const; inline int mat_gain() const; public: inline static Move normal(Square from, Square to, Piece ptype); inline static Move capture(Square from, Square to, Piece ptype, Piece cap_ptype); inline static Move null(); public: FORCEINLINE bool operator==(const Move& m2) const; FORCEINLINE bool operator!=(const Move& m2) const; inline bool operator<(const Move& m2) const; inline operator bool() const; bool is_valid(const Board & board) const; bool is_legal(const Board & board) const; std::string str() const; std::string san(const Board & board, int nonstd = 0) const; void print() const; /* Define a strict weak ordering of Move objects. This is useful * when we want to use a std::map, like we do in * Book::group_moves(). */ class strict_weak_ordering { public: bool operator()(Move a, Move b) const { return a < b; } }; /* Hmm, Borland compiler does not grant access to Move::mov. */ friend class strict_weak_ordering; }; inline Move::Move() { mov_from = NO_SQUARE; mov_to = NO_SQUARE; mov_ptype = NO_PIECE; mov_cap_ptype = NO_PIECE; mov_flags = 0; } inline Move::Move(Square from, Square to, Piece ptype, Piece cap_ptype, uint16_t flags) { mov_from = from; mov_to = to; mov_ptype = ptype; mov_cap_ptype = cap_ptype; mov_flags = flags; } inline Square Move::from() const { return mov_from; } inline Square Move::to() const { return mov_to; } inline Piece Move::ptype() const { return mov_ptype; } inline Piece Move::cap_ptype() const { return mov_cap_ptype; } inline uint16_t Move::flags() const { return mov_flags; } inline bool Move::is_normal() const { return (flags() & MOVE_NORMAL); } inline bool Move::is_capture() const { return (flags() & MOVE_CAPTURE); } inline bool Move::is_null() const { return (flags() & MOVE_NULL); } inline int Move::mat_gain() const { int gain = 0; if (is_capture()) { gain += mat_values[cap_ptype()]; } return gain; } inline Move Move::normal(Square from, Square to, Piece ptype) { return Move(from, to, ptype, NO_PIECE, MOVE_NORMAL); } inline Move Move::capture(Square from, Square to, Piece ptype, Piece cap_ptype) { return Move(from, to, ptype, cap_ptype, MOVE_CAPTURE); } inline Move Move::null() { return Move(NO_SQUARE, NO_SQUARE, NO_PIECE, NO_PIECE, MOVE_NULL); } inline bool Move::operator==(const Move& m2) const { return (this->mov_from == m2.mov_from) && (this->mov_to == m2.mov_to) && (this->mov_ptype == m2.mov_ptype) && (this->mov_cap_ptype == m2.mov_cap_ptype) && (this->mov_flags == m2.mov_flags); } inline bool Move::operator!=(const Move& m2) const { return !operator==(m2); } inline bool Move::operator<(const Move& m2) const { if (this->mov_from < m2.mov_from) { return true; } else if (this->mov_from > m2.mov_from) { return false; } else if (this->mov_to < m2.mov_to) { return true; } else if (this->mov_to > m2.mov_to) { return false; } else if (this->mov_ptype < m2.mov_ptype) { return true; } else if (this->mov_ptype > m2.mov_ptype) { return false; } else if (this->mov_cap_ptype < m2.mov_cap_ptype) { return true; } else if (this->mov_cap_ptype > m2.mov_cap_ptype) { return false; } else if (this->mov_flags < m2.mov_flags) { return true; } else if (this->mov_flags > m2.mov_flags) { return false; } else { return false; } } inline Move::operator bool() const { return (flags() != MOVE_NONE); } #endif // MOVE_H hoichess_0.10.3/src/xiangqi/board.h0000640000175000017500000001503210732031250016521 0ustar oliveroliver/* $Id: board.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef BOARD_H #define BOARD_H #include "common.h" #include "hash.h" #include "move.h" #include "movelist.h" #include "basic.h" #include #ifdef USE_UNMAKE_MOVE /* Forward declaration */ class BoardHistory; #endif class Board { friend class Evaluator; /* Data Members */ private: Color side, opponent; int moveno; int movecnt50; Piece position_pieces[90]; Color position_colors[90]; Square king[2]; // unsigned int flags; int material[2]; unsigned int pce_movecnt[90]; Hashkey hashkey; Hashkey pawnhashkey; /* Constructors / Destructor, defined in board.cc */ public: Board(); Board(const std::string& fen); inline ~Board() {}; /* Accessors */ public: Color get_side() const { return side; } int get_moveno() const { return moveno; } int get_movecnt50() const { return movecnt50; } #if 0 unsigned int get_flags() const { return flags; } #endif Hashkey get_hashkey() const { return hashkey; } Hashkey get_pawnhashkey() const { return pawnhashkey; } inline Hashkey get_hashkey_noside() const; inline unsigned int get_pce_movecnt(Square sq) const; private: Square get_king(Color side) const { return king[side]; } /* Basic board functions, defined in board.cc */ public: void clear(); #ifdef USE_UNMAKE_MOVE BoardHistory make_move(Move mov); void unmake_move(const BoardHistory & hist); #else void make_move(Move mov); #endif bool is_valid_move(Move mov) const; bool is_legal_move(Move mov) const; inline Color color_at(Square sq) const; inline Piece piece_at(Square sq) const; private: void set_side(Color side); void switch_sides(); void place_piece(Square sq, Color side, Piece ptype); void remove_piece(Square sq, Color side, Piece ptype); void move_piece(Square from, Square to, Color side, Piece ptype); // void set_flag(unsigned int flag); // void clear_flag(unsigned int flag); public: inline bool in_check() const; inline bool is_legal() const; inline int material_difference() const; inline int get_material(Color side) const; /* Attack functions, defined in board_attack.cc */ private: unsigned int pawn_attacks(Square from, Color side, Square tos[]) const; unsigned int guard_attacks(Square from, Color side, Square tos[]) const; unsigned int elephant_attacks(Square from, Color side, Square tos[]) const; unsigned int knight_attacks(Square from, Color side, Square tos[]) const; unsigned int cannon_attacks(Square from, Color side, Square tos[]) const; unsigned int rook_attacks(Square from, Color side, Square tos[]) const; unsigned int king_attacks(Square from, Color side, Square tos[]) const; public: bool is_attacked(Square to, Color atkside) const; bool kings_facing() const; /* Move generation functions, defined in board_generate.cc */ public: void generate_moves(Movelist * movelist) const; void generate_captures(Movelist * movelist) const; void generate_noncaptures(Movelist * movelist) const; void generate_escapes(Movelist * movelist) const; /* * For compatibility with chess/board. */ inline void generate_moves(Movelist * movelist, bool allpromo) const { (void) allpromo; generate_moves(movelist); } inline void generate_captures(Movelist * movelist, bool allpromo) const { (void) allpromo; generate_captures(movelist); } private: /* Utility functions, defined in board_util.cc */ public: bool is_mate() const; bool is_stalemate() const; bool is_valid() const; bool is_material_draw() const; void print(FILE * fp = stdout, Move last_move = Move()) const; void print_small(FILE * fp = stdout) const; std::string get_fen() const; bool parse_fen(const char * s); bool parse_fen(const std::string & str); Move parse_move(const std::string & str) const; Move parse_move_1(const std::string & str) const; Move do_parse_move_1(const std::string & str) const; bool operator==(const Board & board) const; /* Static Data Members */ private: static Hashkey hashkeys[2][7][90]; static Hashkey hash_side; /* Static Member Functions */ public: static void init(); }; #ifdef USE_UNMAKE_MOVE /* * This class contains all necessary information to unmake a previous move. */ class BoardHistory { friend class Board; private: #ifdef DEBUG /* This is used by unmake_move() to verify that the board status * was correctly restored. */ Board oldboard; #endif Move move; int movecnt50; // unsigned int flags; unsigned int pce_movecnt_to; }; #endif /***************************************************************************** * * Inline functions of class board * *****************************************************************************/ inline Color Board::color_at(Square sq) const { ASSERT_DEBUG(sq >= A0 && sq <= I9); return position_colors[sq]; } inline Piece Board::piece_at(Square sq) const { ASSERT_DEBUG(sq >= A0 && sq <= I9); return position_pieces[sq]; } inline Hashkey Board::get_hashkey_noside() const { if (side == BLACK) { return hashkey ^ hash_side; } else { return hashkey; } } inline unsigned int Board::get_pce_movecnt(Square sq) const { ASSERT_DEBUG(sq >= A0 && sq <= I9); return pce_movecnt[sq]; } inline bool Board::in_check() const { return kings_facing() || is_attacked(get_king(side), opponent); } /* * Check if the position is legal, i.e. the enemy king * cannot be captured with the next move. */ inline bool Board::is_legal() const { return !kings_facing() && !is_attacked(get_king(opponent), side); } inline int Board::material_difference() const { return (material[side] - material[opponent]); } inline int Board::get_material(Color side) const { ASSERT_DEBUG(side != NO_COLOR); return material[side]; } #endif // BOARD_H hoichess_0.10.3/src/xiangqi/board_init.cc0000640000175000017500000000262410732031250017705 0ustar oliveroliver/* $Id: board_init.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board_init.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "util.h" Hashkey Board::hashkeys[2][7][90]; Hashkey Board::hash_side; void Board::init() { unsigned int k = 0; /* Generate hash keys */ for (int c=0; c<2; c++) { for (int p=0; p<7; p++) { for (int s=0; s<90; s++) { //hashkeys[c][p][s] = random64(); hashkeys[c][p][s] = uint64_table[k++]; } } } //hash_side = random64(); hash_side = uint64_table[k++]; /* uint64_table should have contained as many values as we needed */ ASSERT(k <= uint64_table_size); } hoichess_0.10.3/src/xiangqi/basic.cc0000640000175000017500000000550010732031250016650 0ustar oliveroliver/* $Id: basic.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/basic.cc * * Copyright (C) 2004-2007 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "basic.h" #if 0 const char piece_char[] = { 'P', 'G', 'E', 'N', 'C', 'R', 'K' }; #else const char piece_char[] = { 'P', 'F', 'E', 'N', 'O', 'R', 'K' }; #endif const char file_char[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' }; const char rank_char[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; const char square_str[][3] = { "a0", "b0", "c0", "d0", "e0", "f0", "g0", "h0", "i0", "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1", "i1", "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2", "i2", "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3", "i3", "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4", "i4", "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5", "i5", "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6", "i6", "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7", "i7", "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8", "i8", "a9", "b9", "c9", "d9", "e9", "f9", "g9", "h9", "i9", }; /* * Create a string with the FEN of the standard opening position. */ #define WP(p) (std::string(1, (char) toupper(piece_char[p]))) #define BP(p) (std::string(1, (char) tolower(piece_char[p]))) #define NP(n) (std::string(1, (char) ('0' + (n)))) std::string opening_fen() { std::string fen; fen += BP(ROOK) + BP(KNIGHT) + BP(ELEPHANT) + BP(GUARD) + BP(KING) + BP(GUARD) + BP(ELEPHANT) + BP(KNIGHT) + BP(ROOK) + "/" + NP(9) + "/" + NP(1) + BP(CANNON) + NP(5) + BP(CANNON) + NP(1) + "/" + BP(PAWN) + NP(1) + BP(PAWN) + NP(1) + BP(PAWN) + NP(1) + BP(PAWN) + NP(1) + BP(PAWN) + "/" + NP(9) + "/" + NP(9) + "/" + WP(PAWN) + NP(1) + WP(PAWN) + NP(1) + WP(PAWN) + NP(1) + WP(PAWN) + NP(1) + WP(PAWN) + "/" + NP(1) + WP(CANNON) + NP(5) + WP(CANNON) + NP(1) + "/" + NP(9) + "/" + WP(ROOK) + WP(KNIGHT) + WP(ELEPHANT) + WP(GUARD) + WP(KING) + WP(GUARD) + WP(ELEPHANT) + WP(KNIGHT) + WP(ROOK) + " w - - 0 1"; return fen; } #undef WP #undef BP #undef NP /* * Initialization function for basic stuff. */ void basic_init() { } hoichess_0.10.3/src/xiangqi/move.cc0000640000175000017500000000523710732031250016544 0ustar oliveroliver/* $Id: move.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/move.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "move.h" #include "basic.h" #include #include #include /* TODO Inline them. * Problem: Board::is_{valid,legal}_move() are not yet declared in * move.h due to mutual inclusion of board.h and move.h :-( */ bool Move::is_valid(const Board & board) const { return board.is_valid_move(*this); } bool Move::is_legal(const Board & board) const { return board.is_legal_move(*this); } /* * Return a string for coordinate notation, e.g. e2e4. */ std::string Move::str() const { char ss[6]; snprintf(ss, sizeof(ss), "%s%s", square_str[from()], square_str[to()]); return std::string(ss); } std::string Move::san(const Board & board, int nonstd) const { (void) nonstd; char ss[12]; const char * check = ""; Board b = board; b.make_move(*this); if (b.is_mate() || b.is_stalemate()) { check = "#"; } else if (b.in_check()) { check = "+"; } snprintf(ss, sizeof(ss), "%c%s%s%s%s", piece_char[board.piece_at(from())], square_str[from()], is_capture() ? "x" : "-", square_str[to()], check); return std::string(ss); } /* * Print the raw move data (for debugging purposes). */ void Move::print() const { if (from() >= A0 && from() <= I9) { printf("\tfrom = '%s'\n", square_str[from()]); } else { printf("\tfrom = %d\n", from()); } if (to() >= A0 && to() <= I9) { printf("\tto = '%s'\n", square_str[to()]); } else { printf("\tto = %d\n", to()); } if (ptype() >= PAWN && ptype() <= KING) { printf("\tptype = '%c'\n", piece_char[ptype()]); } else { printf("\tptype = %d\n", ptype()); } if (cap_ptype() >= PAWN && cap_ptype() <= KING) { printf("\tcap_ptype = '%c'\n", piece_char[cap_ptype()]); } else { printf("\tcap_ptype = %d\n", cap_ptype()); } printf("\tflags = 0x%x\n", flags()); } hoichess_0.10.3/src/xiangqi/board.cc0000640000175000017500000001655010732031250016665 0ustar oliveroliver/* $Id: board.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "move.h" #include "basic.h" Board::Board() { clear(); } Board::Board(const std::string& fen) { clear(); if (!parse_fen(fen)) { BUG("Constructor called with illegal FEN: %s", fen.c_str()); } } void Board::clear() { side = WHITE; opponent = BLACK; moveno = 1; movecnt50 = 0; for (Square sq = A0; sq <= I9; sq++) { position_pieces[sq] = NO_PIECE; position_colors[sq] = NO_COLOR; } king[WHITE] = NO_SQUARE; king[BLACK] = NO_SQUARE; // flags = 0; material[WHITE] = 0; material[BLACK] = 0; for (Square sq = A0; sq <= I9; sq++) { pce_movecnt[sq] = 0; } hashkey = NULLHASHKEY; pawnhashkey = NULLHASHKEY; } #ifdef USE_UNMAKE_MOVE BoardHistory Board::make_move(Move mov) #else void Board::make_move(Move mov) #endif { ASSERT_DEBUG(is_valid_move(mov)); #ifdef USE_UNMAKE_MOVE BoardHistory hist; #ifdef DEBUG hist.oldboard = *this; #endif hist.move = mov; #endif // USE_UNMAKE_MOVE /* Move pieces */ if (mov.is_capture()) { remove_piece(mov.to(), opponent, mov.cap_ptype()); move_piece(mov.from(), mov.to(), side, mov.ptype()); } else if (mov.is_normal()) { move_piece(mov.from(), mov.to(), side, mov.ptype()); } else if (mov.is_null()) { /* nothing */ } else { BUG("unknown move flags: %x", mov.flags()); } #ifdef USE_UNMAKE_MOVE hist.flags = flags; #endif /* Switch sides and update moveno */ switch_sides(); if (side == WHITE) { moveno++; } /* Update movecnt50 */ #ifdef USE_UNMAKE_MOVE hist.movecnt50 = movecnt50; #endif if ((mov.ptype() == PAWN && RNK(mov.from()) != RNK(mov.to())) || mov.is_capture()) { movecnt50 = 0; } else { movecnt50++; } /* Update pce_movecnt */ if (!mov.is_null()) { #ifdef USE_UNMAKE_MOVE hist.pce_movecnt_to = pce_movecnt[mov.to()]; #endif pce_movecnt[mov.to()] = pce_movecnt[mov.from()] + 1; pce_movecnt[mov.from()] = 0; } #ifdef USE_UNMAKE_MOVE return hist; #else return; #endif } #ifdef USE_UNMAKE_MOVE void Board::unmake_move(const BoardHistory & hist) { Move mov = hist.move; /* Restore pce_movecnt */ if (!mov.is_null()) { pce_movecnt[mov.from()] = pce_movecnt[mov.to()] - 1; pce_movecnt[mov.to()] = hist.pce_movecnt_to; } /* Restore movecnt50 */ movecnt50 = hist.movecnt50; /* Switch back sides */ if (side == WHITE) { moveno--; } switch_sides(); /* Move back pieces */ if (mov.is_capture()) { move_piece(mov.to(), mov.from(), side, mov.ptype()); place_piece(mov.to(), opponent, mov.cap_ptype()); } else if (mov.is_normal()) { move_piece(mov.to(), mov.from(), side, mov.ptype()); } else if (mov.is_null()) { /* nothing */ } else { BUG("unknown move flags: %x", mov.flags()); } ASSERT_DEBUG(memcmp(this, &hist.oldboard, sizeof(Board)) == 0); ASSERT_DEBUG(is_valid_move(mov)); } #endif /* * Check if a move is valid (= pseudo-legal) on this board. */ bool Board::is_valid_move(Move mov) const { if (mov.is_null()) { return true; } Square from = mov.from(); Square to = mov.to(); /* Check origin square. */ if (color_at(from) != get_side() || piece_at(from) != mov.ptype()) return false; /* Check destination square. */ if (mov.is_capture()) { if (color_at(to) != XSIDE(get_side())) return false; } else { if (color_at(to) != NO_COLOR) return false; } /* Check correct piece movement. */ #if 0 /* TODO */ switch (piece_at(from)) { case PAWN: if (mov.flags() & MOVE_CAPTURE || mov.flags() & MOVE_ENPASSANT) { if (!pawn_captures(from, color_at(from)).testbit(to)) return false; } else { if (!pawn_noncaptures(from, color_at(from)).testbit(to)) return false; } break; case KNIGHT: if (!knight_attacks(from).testbit(to)) return false; break; case BISHOP: if (!bishop_attacks(from).testbit(to)) return false; break; case ROOK: if (!rook_attacks(from).testbit(to)) return false; break; case QUEEN: if (!queen_attacks(from).testbit(to)) return false; break; case KING: if (!king_attacks(from).testbit(to)) return false; break; default: BUG("huh?"); } #endif /* Ok, this move is pseudo-legal. */ return true; } /* * Check if a move is legal on this board. */ bool Board::is_legal_move(Move mov) const { ASSERT_DEBUG(is_valid_move(mov)); Board tmpboard = *this; tmpboard.make_move(mov); return tmpboard.is_legal(); } void Board::set_side(Color _side) { if (side != _side) switch_sides(); } void Board::switch_sides() { side = XSIDE(side); opponent = XSIDE(opponent); hashkey ^= hash_side; pawnhashkey ^= hash_side; } void Board::place_piece(Square sq, Color side, Piece ptype) { ASSERT_DEBUG(color_at(sq) == NO_COLOR); ASSERT_DEBUG(piece_at(sq) == NO_PIECE); position_pieces[sq] = ptype; position_colors[sq] = side; if (ptype == KING) { king[side] = sq; } material[side] += mat_values[ptype]; hashkey ^= hashkeys[side][ptype][sq]; if (ptype == PAWN) { pawnhashkey ^= hashkeys[side][ptype][sq]; } } void Board::remove_piece(Square sq, Color side, Piece ptype) { ASSERT_DEBUG(color_at(sq) == side); ASSERT_DEBUG(piece_at(sq) == ptype); position_pieces[sq] = NO_PIECE; position_colors[sq] = NO_COLOR; if (ptype == KING) { king[side] = NO_SQUARE; } material[side] -= mat_values[ptype]; hashkey ^= hashkeys[side][ptype][sq]; if (ptype == PAWN) { pawnhashkey ^= hashkeys[side][ptype][sq]; } } void Board::move_piece(Square from, Square to, Color side, Piece ptype) { ASSERT_DEBUG(color_at(from) == side); ASSERT_DEBUG(piece_at(from) == ptype); ASSERT_DEBUG(color_at(to) == NO_COLOR); ASSERT_DEBUG(piece_at(to) == NO_PIECE); position_pieces[from] = NO_PIECE; position_colors[from] = NO_COLOR; position_pieces[to] = ptype; position_colors[to] = side; if (ptype == KING) { king[side] = to; } hashkey ^= hashkeys[side][ptype][from]; hashkey ^= hashkeys[side][ptype][to]; if (ptype == PAWN) { pawnhashkey ^= hashkeys[side][ptype][from]; pawnhashkey ^= hashkeys[side][ptype][to]; } } #if 0 void Board::set_flag(unsigned int flag) { if (flags & flag) return; flags |= flag; switch (flag) { case WKCASTLE: hashkey ^= hash_wk; break; case WQCASTLE: hashkey ^= hash_wq; break; case BKCASTLE: hashkey ^= hash_bk; break; case BQCASTLE: hashkey ^= hash_bq; break; } } #endif #if 0 void Board::clear_flag(unsigned int flag) { if (! (flags & flag)) return; flags &= ~flag; switch (flag) { case WKCASTLE: hashkey ^= hash_wk; break; case WQCASTLE: hashkey ^= hash_wq; break; case BKCASTLE: hashkey ^= hash_bk; break; case BQCASTLE: hashkey ^= hash_bq; break; } } #endif hoichess_0.10.3/src/xiangqi/eval.h0000640000175000017500000000500410732031250016357 0ustar oliveroliver/* $Id: eval.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/xiangqi/eval.h * * Copyright (C) 2004-2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef EVAL_H #define EVAL_H #include "common.h" #include "board.h" #include "evalcache.h" #include "pawnhash.h" /* score values */ #define INFTY 100000 #define MATE 90000 #define DRAW 0 class Evaluator { public: enum game_phase { OPENING, MIDGAME, ENDGAME }; private: static const struct score_plugin plugins[]; static const struct score_plugin plugins2[]; private: PawnHashTable * pawnhashtable; EvaluationCache * evalcache; #ifdef COLLECT_STATISTICS unsigned long stat_evals; unsigned long stat_evals_phase1; unsigned long stat_evals_phase2; #endif private: const Board * board; unsigned int phase; Color myside; PawnHashEntry pawnhashentry; //Bitboard passed_pawns[2]; //Bitboard pinned_on_king[2]; public: Evaluator(); ~Evaluator(); public: int eval(const Board & board, int alpha, int beta, Color myside); void print_eval(const Board & board, Color myside, FILE * fp = stdout); public: void reset_statistics(); void print_statistics(FILE * fp = stdout) const; void set_pawnhashtable(PawnHashTable * pawnhashtable); void set_evalcache(EvaluationCache * evalcache); void set_param(const std::string& name, const std::string& value); private: void setup(const Board * board); void finish(); public: static bool is_draw(const Board & board); static int material_balance(int mat_side, int mat_xside); static unsigned int get_phase(const Board & board); private: static const int positional_scores[7][90]; private: int score_positional(Color side); }; struct score_plugin { const char * name; int (Evaluator::* func)(Color); }; #endif // EVAL_H hoichess_0.10.3/src/xiangqi/board_util.cc0000640000175000017500000003725710732031250017731 0ustar oliveroliver/* $Id: board_util.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board_util.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "move.h" #include "basic.h" #include bool Board::is_mate() const { Movelist movelist; generate_moves(&movelist); movelist.filter_illegal(*this); return (in_check() && movelist.size() == 0); } bool Board::is_stalemate() const { Movelist movelist; generate_moves(&movelist); movelist.filter_illegal(*this); return (!in_check() && movelist.size() == 0); } bool Board::is_valid() const { #if 0 /* TODO */ /* Each side must have exactly one king. */ if (get_kings(WHITE).popcnt() != 1) return false; if (get_kings(BLACK).popcnt() != 1) return false; /* Pawns cannot be on rank 1 or rank 8. */ if ((get_pawns(WHITE) | get_pawns(BLACK)) & (Bitboard::rank[RANK1] | Bitboard::rank[RANK8])) return false; #endif /* The opponent's king must not be in check. */ if (is_attacked(get_king(opponent), side)) return false; return true; } bool Board::is_material_draw() const { if (material[WHITE] == 0 && material[BLACK] == 0) { /* only kings left -> draw */ return true; #if 0 /* TODO */ } else if (get_pawns(WHITE) || get_pawns(BLACK)) { /* there are still pawns -> no draw */ return false; } else if ((material[WHITE] < mat_values[ROOK] || (material[WHITE] == 2 * mat_values[KNIGHT] && get_knights(WHITE).popcnt() == 2)) && (material[BLACK] < mat_values[ROOK] || (material[BLACK] == 2 * mat_values[KNIGHT] && get_knights(BLACK).popcnt() == 2))) { /* both sides have only a knight or a bishop -> draw * both sides have <= 2 knights only -> draw */ return true; #endif } /* TODO more */ return false; } void Board::print(FILE * fp, Move last_move) const { Square sq; char c; for (int i=9; i>=0; i--) { fprintf(fp, "%d ", i); for (int j=0; j<=8; j++) { sq = SQUARE(i,j); if (piece_at(sq) != NO_PIECE) { ASSERT(color_at(sq) != NO_COLOR); c = piece_char[piece_at(sq)]; c = (color_at(sq) == WHITE) ? toupper(c) : tolower(c); } else { c = '+'; } if (j != 0) { fprintf(fp, "---"); } if (ansicolor && fp == stdout) { const char * a2 = ""; const char * a3 = ""; if (last_move && (sq == last_move.from() || sq == last_move.to())) { a2 = XSIDE(side) == WHITE ? "\033[31;1m" : "\033[34;1m"; a3 = "\033[7m"; } else { if (color_at(sq) == WHITE) { a2 = "\033[31;1m"; } else if (color_at(sq) == BLACK) { a2 = "\033[34;1m"; } } const char * a4 = "\033[0m"; fprintf(fp, "%s%s%c%s", a2, a3, c, a4); } else { fprintf(fp, "%c", c); } } fprintf(fp, "\n"); if (i == 9 || i == 2) { fprintf(fp, " | | | | \\ | / | | | |\n"); } else if (i == 8 || i == 1) { fprintf(fp, " | | | | / | \\ | | | |\n"); } else if (i == 5) { fprintf(fp, " | |\n"); } else if (i != 0) { fprintf(fp, " | | | | | | | | |\n"); } } fprintf(fp, "\n"); fprintf(fp, " A B C D E F G H I\n"); fprintf(fp, "\n [%d] %s\n", moveno, (side == WHITE) ? "White" : "Black"); if (last_move) { fprintf(fp, " Last move by %s: %s\n", (side == WHITE) ? "Black" : "White", last_move.str().c_str()); } } void Board::print_small(FILE * fp) const { Square sq; char c; for (int i=9; i>=0; i--) { //fprintf(fp, "%d ", i); for (int j=0; j<=7; j++) { sq = SQUARE(i,j); if (piece_at(sq) != NO_PIECE) { c = piece_char[piece_at(sq)]; if (color_at(sq) == WHITE) c = toupper(c); else c = tolower(c); } else { c = '.'; } fprintf(fp, " %c", c); } fprintf(fp, "\n"); } //fprintf(fp, "\n a b c d e f g h i\n"); fprintf(fp, "\n [%d] %s\n", moveno, (side == WHITE) ? "White" : "Black"); } std::string Board::get_fen() const { char ss[128]; char * s = ss; /* position */ Square sq; Piece pce; int empty = 0; for (int rnk = RANK9; rnk >= RANK0; rnk--) { for (int fil = FILEA; fil <= FILEI; fil++) { sq = SQUARE(rnk, fil); pce = piece_at(sq); if (pce == NO_PIECE) { empty++; } else { if (empty != 0) { *s++ = '0' + empty; empty = 0; } if (color_at(sq) == WHITE) *s++ = toupper(piece_char[pce]); else *s++ = tolower(piece_char[pce]); } if (FIL(sq) == FILEI) { if (empty != 0) { *s++ = '0' + empty; empty = 0; } if (RNK(sq) != RANK0) *s++ = '/'; } } } /* side to move */ *s++ = ' '; *s++ = (side == WHITE) ? 'w' : 'b'; /* castling flags and enpassant square (both unused), * halfmove and fullmove clocks */ int n = snprintf(s, 20, " - - %d %d", movecnt50, moveno); s += n; return std::string(ss); } bool Board::parse_fen(const char * s) { clear(); char * p; char pos[160+1]; char clr; char flg[4+1]; char ep[2+1]; int hmc; int fmc; if (sscanf(s, "%160s %c %4s %2s %d %d", pos, &clr, flg, ep, &hmc, &fmc) != 6) return false; /* position */ int rnk = RANK9, fil = FILEA; Square sq; p = pos; while (*p) { if (fil > FILEI+1 || rnk < RANK0) return false; sq = SQUARE(rnk, fil); char c = *p++; if (c >= '0' && c <= '9') { fil += (c - '0'); } else if (c == '/') { fil = FILEA; rnk--; } else { bool ok = false; for (Piece pce = PAWN; pce <= KING; pce++) { if (c == toupper(piece_char[pce])) { place_piece(sq, WHITE, pce); fil++; ok = true; break; } else if (c == tolower(piece_char[pce])) { place_piece(sq, BLACK, pce); fil++; ok = true; break; } } if (!ok) { return false; } } } /* side to move */ if (clr == 'w') set_side(WHITE); else if (clr == 'b') set_side(BLACK); else return false; /* castling flags (ignored) */ /* enpassant square (ignored) */ /* halfmove and fullmove clocks */ movecnt50 = hmc; moveno = fmc; /* validate position */ if (!is_valid() || !is_legal()) return false; return true; } bool Board::parse_fen(const std::string & str) { return parse_fen(str.c_str()); } Move Board::parse_move(const std::string & str) const { /* * Compare the input against all possible moves in coordinate * notation and SAN. */ Movelist moves; generate_moves(&moves); moves.filter_illegal(*this); for (unsigned int i=0; i= 'a' && p[0] <= 'h' && p[1] >= '1' && p[1] <= '8' && p[2] >= 'a' && p[2] <= 'h' && p[3] >= '1' && p[3] <= '8') { /* * Coordinate notation */ from_file = p[0] - 'a'; from_rank = p[1] - '1'; to_file = p[2] - 'a'; to_rank = p[3] - '1'; from = SQUARE(from_rank, from_file); to = SQUARE(to_rank, to_file); ptype = piece_at(from); cap_ptype = piece_at(to); if (ptype == KING) { /* castling? */ if (side == WHITE && (flags & WKCASTLE) && from == E1 && to == G1) { return Move::castle(E1, G1); } else if (side == WHITE && (flags & WQCASTLE) && from == E1 && to == C1) { return Move::castle(E1, C1); } else if (side == BLACK && (flags & BKCASTLE) && from == E8 && to == G8) { return Move::castle(E8, G8); } else if (side == BLACK && (flags & BQCASTLE) && from == E8 && to == C8) { return Move::castle(E8, C8); } } if (len == 5) { /* Pawn promotion */ switch (p[4]) { case 'n': promo_ptype = KNIGHT; break; case 'b': promo_ptype = BISHOP; break; case 'r': promo_ptype = ROOK; break; case 'q': promo_ptype = QUEEN; break; default: return NO_MOVE; } if (cap_ptype != NO_PIECE) { return Move::promotion_capture(from, to, promo_ptype, cap_ptype); } else { return Move::promotion(from, to, promo_ptype); } } else { if (cap_ptype != NO_PIECE) { return Move::capture(from, to, ptype, cap_ptype); } else if (to == get_epsq()) { return Move::enpassant(from, to); } else { return Move::normal(from, to, ptype); } } } /* * SAN */ if (p[0] >= 'a' && p[0] <= 'h') { /* Pawn move */ if (p[1] == 'x' && p[2] >= 'a' && p[2] <= 'h' && p[3] >= '1' && p[3] <= '8') { /* capture */ from_file = p[0] - 'a'; to_file = p[2] - 'a'; to_rank = p[3] - '1'; if (side == WHITE) { from_rank = to_rank - 1; } else { from_rank = to_rank + 1; } from = SQUARE(from_rank, from_file); to = SQUARE(to_rank, to_file); cap_ptype = piece_at(to); if (p[4] == '=') { /* promotion capture */ switch (p[5]) { case 'N': promo_ptype = KNIGHT; break; case 'B': promo_ptype = BISHOP; break; case 'R': promo_ptype = ROOK; break; case 'Q': promo_ptype = QUEEN; break; default: return NO_MOVE; } return Move::promotion_capture(from, to, promo_ptype, cap_ptype); } else { /* non-promotion capture */ if (to == get_epsq()) { return Move::enpassant(from, to); } else { return Move::capture(from, to, PAWN, cap_ptype); } } } else if (p[1] >= '1' && p[1] <= '8') { /* non-capture */ from_file = p[0] - 'a'; to_file = p[0] - 'a'; to_rank = p[1] - '1'; if (side == WHITE) { if (to_rank == 3) { if (piece_at(SQUARE(2, from_file)) == PAWN) { /* one square ahead */ from_rank = 2; } else if (piece_at(SQUARE(1, from_file) == PAWN)) { /* two squares ahead */ from_rank = 1; } else { return NO_MOVE; } } else { from_rank = to_rank - 1; } } else { if (to_rank == 4) { if (piece_at(SQUARE(5, from_file)) == PAWN) { /* one square ahead */ from_rank = 5; } else if (piece_at(SQUARE(6, from_file) == PAWN)) { /* two squares ahead */ from_rank = 6; } else { return NO_MOVE; } } else { from_rank = to_rank + 1; } } from = SQUARE(from_rank, from_file); to = SQUARE(to_rank, to_file); if (p[2] == '=') { /* promotion non-capture */ switch (p[3]) { case 'N': promo_ptype = KNIGHT; break; case 'B': promo_ptype = BISHOP; break; case 'R': promo_ptype = ROOK; break; case 'Q': promo_ptype = QUEEN; break; default: return NO_MOVE; } return Move::promotion(from, to, promo_ptype); } else { /* non-promotion non-capture */ return Move::normal(from, to, PAWN); } } else { return NO_MOVE; } } /* * SAN: Non-Pawn move */ switch (*p++) { case 'N': ptype = KNIGHT; break; case 'B': ptype = BISHOP; break; case 'R': ptype = ROOK; break; case 'Q': ptype = QUEEN; break; case 'K': ptype = KING; break; default: return NO_MOVE; } int f1 = -1, r1 = -1, f2 = -1, r2 = -1; if (*p >= 'a' && *p <= 'h') { f1 = *p - 'a'; p++; } if (*p >= '1' && *p <= '8') { r1 = *p - '1'; p++; } bool capture = false; if (*p == 'x') { capture = true; p++; } if (*p >= 'a' && *p <= 'h') { f2 = *p - 'a'; p++; } if (*p >= '1' && *p <= '8') { r2 = *p - '1'; p++; } if (f2 != -1 && r2 != -1) { from_file = f1; from_rank = r1; to_file = f2; to_rank = r2; } else if (f2 == -1 && r2 == -1) { to_file = f1; to_rank = r1; } else { return NO_MOVE; } if (to_file == -1 || to_rank == -1) { return NO_MOVE; } to = SQUARE(to_rank, to_file); if (from_rank == -1 || from_file == -1) { Bitboard from_bb; switch (ptype) { case KNIGHT: from_bb = knight_attacks(to) & get_knights(side); break; case BISHOP: from_bb = bishop_attacks(to) & get_bishops(side); break; case ROOK: from_bb = rook_attacks(to) & get_rooks(side); break; case QUEEN: from_bb = queen_attacks(to) & get_queens(side); break; case KING: from_bb = king_attacks(to) & get_kings(side); break; default: BUG("should not get here"); } if (from_rank != -1) { from_bb &= Bitboard::rank[from_rank]; } if (from_file != -1) { from_bb &= Bitboard::file[from_file]; } unsigned int n = from_bb.popcnt(); if (n == 0) { return NO_MOVE; } else if (n == 1) { from = from_bb.firstbit(); } else { Bitboard pins = pinned(get_king(side), side); Bitboard ray = Bitboard::ray_bb[to][get_king(side)]; bool ok = false; while (from_bb) { from = from_bb.firstbit(); from_bb.clearbit(from); if (pins.testbit(from) && ray.testbit(from)) { ok = true; break; } else if (!pins.testbit(from)) { ok = true; break; } } if (!ok) { return NO_MOVE; } } } else { from = SQUARE(from_rank, from_file); } if (piece_at(from) != ptype) { return NO_MOVE; } cap_ptype = piece_at(to); if (capture && cap_ptype == NO_PIECE) { return NO_MOVE; } else if (!capture && cap_ptype != NO_PIECE) { return NO_MOVE; } if (cap_ptype != NO_PIECE) { return Move::capture(from, to, ptype, cap_ptype); } else { return Move::normal(from, to, ptype); } #endif } bool Board::operator==(const Board & board) const { for (Square sq = A0; sq <= I9; sq++) { if (position_pieces[sq] != board.position_pieces[sq]) return false; if (position_colors[sq] != board.position_colors[sq]) return false; } if (side != board.side) return false; return true; } hoichess_0.10.3/src/xiangqi/board_attack.cc0000640000175000017500000002257510732031250020220 0ustar oliveroliver/* $Id: board_attack.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board_attack.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "basic.h" static Square map[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, A0, B0, C0, D0, E0, F0, G0, H0, I0, -1, -1, -1, -1, A1, B1, C1, D1, E1, F1, G1, H1, I1, -1, -1, -1, -1, A2, B2, C2, D2, E2, F2, G2, H2, I2, -1, -1, -1, -1, A3, B3, C3, D3, E3, F3, G3, H3, I3, -1, -1, -1, -1, A4, B4, C4, D4, E4, F4, G4, H4, I4, -1, -1, -1, -1, A5, B5, C5, D5, E5, F5, G5, H5, I5, -1, -1, -1, -1, A6, B6, C6, D6, E6, F6, G6, H6, I6, -1, -1, -1, -1, A7, B7, C7, D7, E7, F7, G7, H7, I7, -1, -1, -1, -1, A8, B8, C8, D8, E8, F8, G8, H8, I8, -1, -1, -1, -1, A9, B9, C9, D9, E9, F9, G9, H9, I9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; static int invmap[] = { 28, 29, 30, 31, 32, 33, 34, 35, 36, 41, 42, 43, 44, 45, 46, 47, 48, 49, 54, 55, 56, 57, 58, 59, 60, 61, 62, 67, 68, 69, 70, 71, 72, 73, 74, 75, 80, 81, 82, 83, 84, 85, 86, 87, 88, 93, 94, 95, 96, 97, 98, 99, 100, 101, 106, 107, 108, 109, 110, 111, 112, 113, 114, 119, 120, 121, 122, 123, 124, 125, 126, 127, 132, 133, 134, 135, 136, 137, 138, 139, 140, 145, 146, 147, 148, 149, 150, 151, 152, 153, }; static Square map_palace[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, D0, E0, F0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, D1, E1, F1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, D2, E2, F2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, D7, E7, F7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, D8, E8, F8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, D9, E9, F9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; static Square map_whitehalf[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, A0, B0, C0, D0, E0, F0, G0, H0, I0, -1, -1, -1, -1, A1, B1, C1, D1, E1, F1, G1, H1, I1, -1, -1, -1, -1, A2, B2, C2, D2, E2, F2, G2, H2, I2, -1, -1, -1, -1, A3, B3, C3, D3, E3, F3, G3, H3, I3, -1, -1, -1, -1, A4, B4, C4, D4, E4, F4, G4, H4, I4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; static Square map_blackhalf[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, A5, B5, C5, D5, E5, F5, G5, H5, I5, -1, -1, -1, -1, A6, B6, C6, D6, E6, F6, G6, H6, I6, -1, -1, -1, -1, A7, B7, C7, D7, E7, F7, G7, H7, I7, -1, -1, -1, -1, A8, B8, C8, D8, E8, F8, G8, H8, I8, -1, -1, -1, -1, A9, B9, C9, D9, E9, F9, G9, H9, I9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; static int dir_guard[] = { +12, +14, -12, -14 }; static int dir_elephant[] = { +24, +28, -24, -28 }; static int free_elephant[] = { +12, +14, -12, -14 }; static int dir_knight[] = { -27, -25, -11, +15, +27, +25, +11, -15 }; static int free_knight[] = { -13, -13, +1, +1, +13, +13, -1, -1 }; static int dir_cannon[] = { +1, +13, -1, -13 }; static int dir_rook[] = { +1, +13, -1, -13 }; static int dir_king[] = { +1, +13, -1, -13 }; /***************************************************************************** * * Basic attack functions. * *****************************************************************************/ #define MAP() do { \ to = map[t]; \ ok = (to != NO_SQUARE); \ } while (0) #define MAP_PALACE() do { \ to = map_palace[t]; \ ok = (to != NO_SQUARE); \ } while (0) #define MAP_WHITEHALF() do { \ to = map_whitehalf[t]; \ ok = (to != NO_SQUARE); \ } while (0) #define MAP_BLACKHALF() do { \ to = map_blackhalf[t]; \ ok = (to != NO_SQUARE); \ } while (0) #define ADD(t) do { \ *top++ = to; \ n++; \ } while (0) #define ATTACK_PROLOGUE() \ int n = 0; \ Square* top = tos; \ int f = invmap[from]; \ int t; \ Square to; \ bool ok; #define ATTACK_EPILOGUE() \ return n; unsigned int Board::pawn_attacks(Square from, Color side, Square tos[]) const { ATTACK_PROLOGUE(); if (side == WHITE) { t = f + 13; MAP(); if (ok) ADD(); if (RNK(from) >= RANK5) { t = f + 1; MAP(); if (ok) ADD(); t = f - 1; MAP(); if (ok) ADD(); } } else { t = f - 13; MAP(); if (ok) ADD(); if (RNK(from) <= RANK4) { t = f + 1; MAP(); if (ok) ADD(); t = f - 1; MAP(); if (ok) ADD(); } } ATTACK_EPILOGUE(); } unsigned int Board::guard_attacks(Square from, Color side, Square tos[]) const { (void) side; ATTACK_PROLOGUE(); for (unsigned int i=0; i<4; i++) { t = f + dir_guard[i]; MAP_PALACE(); if (ok) ADD(); } ATTACK_EPILOGUE(); } unsigned int Board::elephant_attacks(Square from, Color side, Square tos[]) const { (void) side; ATTACK_PROLOGUE(); for (unsigned int i=0; i<4; i++) { t = f + free_elephant[i]; if (side == WHITE) { MAP_WHITEHALF(); } else { MAP_BLACKHALF(); } if (!ok || color_at(to) != NO_COLOR) { continue; } t = f + dir_elephant[i]; if (side == WHITE) { MAP_WHITEHALF(); } else { MAP_BLACKHALF(); } if (ok) { ADD(); } } ATTACK_EPILOGUE(); } unsigned int Board::knight_attacks(Square from, Color side, Square tos[]) const { (void) side; ATTACK_PROLOGUE(); for (unsigned int i=0; i<8; i++) { t = f + free_knight[i]; MAP(); if (!ok || color_at(to) != NO_COLOR) { continue; } t = f + dir_knight[i]; MAP(); if (ok) { ADD(); } } ATTACK_EPILOGUE(); } unsigned int Board::cannon_attacks(Square from, Color side, Square tos[]) const { ATTACK_PROLOGUE(); for (unsigned int i=0; i<4; i++) { t = f; /* non-capture moves */ do { t += dir_cannon[i]; MAP(); if (!ok) { goto break2; } else if (color_at(to) != NO_COLOR) { break; } else { ADD(); } } while (1); /* capture move */ do { t += dir_cannon[i]; MAP(); if (!ok || color_at(to) == side) { goto break2; } else if (color_at(to) == XSIDE(side)) { ADD(); goto break2; } } while (1); break2:; } ATTACK_EPILOGUE(); } unsigned int Board::rook_attacks(Square from, Color side, Square tos[]) const { (void) side; ATTACK_PROLOGUE(); for (unsigned int i=0; i<4; i++) { t = f; do { t += dir_rook[i]; MAP(); if (ok) { ADD(); } } while (ok && color_at(to) == NO_COLOR); } ATTACK_EPILOGUE(); } unsigned int Board::king_attacks(Square from, Color side, Square tos[]) const { (void) side; ATTACK_PROLOGUE(); for (unsigned int i=0; i<4; i++) { t = f + dir_king[i]; MAP_PALACE(); if (ok) ADD(); } ATTACK_EPILOGUE(); } /***************************************************************************** * * Returns true if square 'to' is attacked by any piece of 'atkside'. * *****************************************************************************/ bool Board::is_attacked(Square to, Color atkside) const { /* TODO this is just a quick'n'dirty implementation */ Board b = *this; if (atkside != b.get_side()) { b.make_move(Move::null()); } Movelist movelist; b.generate_moves(&movelist); for (unsigned int i=0; i * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef BASIC_H #define BASIC_H #include "common.h" /* * Basic data types, macros and functions. */ typedef int Color; typedef int Piece; typedef int Square; enum colors { NO_COLOR = -1, WHITE, BLACK }; enum pieces { NO_PIECE = -1, PAWN, GUARD, ELEPHANT, KNIGHT, CANNON, ROOK, KING }; enum squares { NO_SQUARE = -1, A0, B0, C0, D0, E0, F0, G0, H0, I0, A1, B1, C1, D1, E1, F1, G1, H1, I1, A2, B2, C2, D2, E2, F2, G2, H2, I2, A3, B3, C3, D3, E3, F3, G3, H3, I3, A4, B4, C4, D4, E4, F4, G4, H4, I4, A5, B5, C5, D5, E5, F5, G5, H5, I5, A6, B6, C6, D6, E6, F6, G6, H6, I6, A7, B7, C7, D7, E7, F7, G7, H7, I7, A8, B8, C8, D8, E8, F8, G8, H8, I8, A9, B9, C9, D9, E9, F9, G9, H9, I9, }; #define BOARDSIZE 90 enum files { FILEA = 0, FILEB, FILEC, FILED, FILEE, FILEF, FILEG, FILEH, FILEI }; enum ranks { RANK0 = 0, RANK1, RANK2, RANK3, RANK4, RANK5, RANK6, RANK7, RANK8, RANK9 }; #define FIL(sq) ((sq) % 9) #define RNK(sq) ((sq) / 9) #define SQUARE(rnk,fil) ((rnk)*9 + (fil)) #define XRANK(rnk) (RANK9-(rnk)) #define XSIDE(side) (!(side)) extern const char piece_char[7]; extern const char file_char[9]; extern const char rank_char[10]; extern const char square_str[90][3]; static const int mat_values[7] = { 100, // PAWN 200, // GUARD 200, // ELEPHANT 400, // KNIGHT 450, // CANNON 900, // ROOK 0 // KING }; /* Manhattan distance between two squares. */ static inline int sq_distance(Square sq1, Square sq2) { return abs(RNK(sq1)-RNK(sq2)) + abs(FIL(sq1)-FIL(sq2)); } /* FEN of standard opening position. */ std::string opening_fen(); /* * Initialization function for basic stuff. */ extern void basic_init(); #endif // BASIC_H hoichess_0.10.3/src/xiangqi/eval.cc0000640000175000017500000001455110732031250016524 0ustar oliveroliver/* $Id: eval.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/xiangqi/eval.cc * * Copyright (C) 2004-2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "eval.h" #include "board.h" /***************************************************************************** * * Main evaluation functions. * *****************************************************************************/ /* * Advanced draw detection. * Basics are done in Search::is_draw() (repetitions, 50 move rule) * and Board::is_material_draw() (insufficient material). */ bool Evaluator::is_draw(const Board & board) { /* TODO */ (void) board; return false; } int Evaluator::material_balance(int ms, int mxs) { return ms-mxs; } /* * This is a first try to implement a material based phase * detection routine. There is a least some fine-tuning that * we must do. */ unsigned int Evaluator::get_phase(const Board & board) { const int mat = board.material[WHITE] + board.material[BLACK]; /* Starting material is 2*4800 = 9600 */ if (mat > 8600) { return OPENING; } else if (mat > 5400) { return MIDGAME; } else { return ENDGAME; } } void Evaluator::setup(const Board * board) { ASSERT_DEBUG(board != NULL); this->board = board; // const Color side = board->get_side(); // const Color xside = XSIDE(side); phase = get_phase(*board); #if 0 if (pawnhashtable) { if (pawnhashtable->probe(board->get_pawnhashkey(), &pawnhashentry)){ if (pawnhashentry.get_phase() == phase) { pawnhashtable->incr_hits2(); } } /* probe() marks entry invalid if nothing was found in * the table, so we don't need to do this here again. */ } else { pawnhashentry.set_invalid(); } #endif // pinned_on_king[side] = board->pinned(board->get_king(side), side); // pinned_on_king[xside] = board->pinned(board->get_king(xside), xside); } void Evaluator::finish() { #if 0 if (pawnhashtable) { pawnhashentry.set_hashkey(board->get_pawnhashkey()); pawnhashentry.set_phase(phase); pawnhashtable->put(pawnhashentry); } #endif } /***************************************************************************** * * Scoring plugins * *****************************************************************************/ const struct score_plugin Evaluator::plugins[] = { { "positional", &Evaluator::score_positional }, { NULL, NULL } }; const struct score_plugin Evaluator::plugins2[] = { // { "control", &Evaluator::score_control }, { NULL, NULL } }; const int Evaluator::positional_scores[][90] = { { // PAWN 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, 0,-10, 0,-10, 0,-10, 0,-10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103,105,110,110,110,110,110,105,103, 105,108,115,115,115,115,115,108,105, 100,105,110,120,120,120,110,105,100, 100,100,110,120,125,120,110,100,100, 100,100,110,120,125,120,110,100,100, }, { // GUARD 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { // ELEPHANT 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { // KNIGHT -5, -8, -2, -2, -2, -2, -2, -8, -5, -2, 0, 0, 0, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, -2, -2, 0, 5, 6, 6, 6, 5, 0, -2, -2, 5, 6, 8, 8, 8, 6, 5, -2, -2, 5, 8, 10, 10, 10, 8, 5, -2, -2, 5, 10, 0, 0, 0, 10, 5, -2, -2, 10, 0, 0, 0, 0, 0, 10, -2, -5, 10, 0, 0, 0, 0, 0, 10, -5, }, { // CANNON 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 4, 5, 4, 0, 0, 0, 8, 8, 4, 0, 0, 0, 4, 8, 8, 9, 9, 5, 0, 0, 0, 5, 9, 9, 8, 8, 4, 0, 0, 0, 4, 8, 8, }, { // ROOK -8, 0, 0, 8, 9, 8, 0, 0, -8, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 8, 0, 0, 0, 8, 8, 8, 4, 5, 4, 8, 8, 8, 9, 9, 9, 5, 5, 5, 9, 9, 9, 8, 8, 8, 4, 5, 4, 8, 8, 8, }, { // KING 0, 0, 0, 10, 20, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-10,-10,-10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, }; int Evaluator::score_positional(Color side) { int score = 0; for (Square sq=A0; sq<=I9; sq++) { if (board->color_at(sq) != side) { continue; } Piece ptype = board->piece_at(sq); /* positional score */ Square idx = (side == WHITE) ? sq : SQUARE(XRANK(RNK(sq)), FIL(sq)); score += positional_scores[ptype][idx]; /* penalize repetition during opening phase */ if (phase == OPENING) { score += - (board->get_pce_movecnt(sq)-1)*2; } } return score; } hoichess_0.10.3/src/xiangqi/board_generate.cc0000640000175000017500000001251310732031250020532 0ustar oliveroliver/* $Id: board_generate.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/board_generate.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "board.h" #include "move.h" #include "basic.h" #define ADD_IF_NONCAPTURE(movelist, from, to, ptype) do { \ if (color_at(to) == NO_COLOR) { \ (movelist)->add(Move::normal((from), (to), (ptype))); \ } \ } while (0) #define ADD_IF_CAPTURE(movelist, from, to, ptype) do { \ if (color_at(to) == opponent) { \ (movelist)->add(Move::capture((from), (to), (ptype), \ piece_at(to))); \ } \ } while (0) /* * Should we use an independent generate_moves() routine, or simply call * generate_captures() and generate_noncaptures()? */ //#define USE_INDEPENDENT_GENERATE_MOVES void Board::generate_moves(Movelist * movelist) const { #ifndef USE_INDEPENDENT_GENERATE_MOVES generate_captures(movelist); generate_noncaptures(movelist); #else /* TODO not implemented */ #endif // USE_INDEPENDENT_GENERATE_MOVES } /* * This routine generates all moves that change the material value on * the board. */ void Board::generate_captures(Movelist * movelist) const { Square tos[128]; for (Square from=A0; from<=I9; from++) { if (color_at(from) != side) { continue; } Piece ptype = piece_at(from); unsigned int n; switch (ptype) { case PAWN: n = pawn_attacks(from, side, tos); for (unsigned int i=0; i * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef BOOK_H #define BOOK_H #include "common.h" #include "board.h" #include "hash.h" #include "move.h" #include #include #include #include class BookEntry { friend class Book; static const unsigned int NR_MOVES = 4; private: /* Do not change the order or the type of those members. They are * written to the book in binary format. */ Hashkey hashkey; /* is uint64_t */ Move move[NR_MOVES]; /* is uint32_t */ uint32_t count[NR_MOVES]; public: BookEntry(); BookEntry(Hashkey _hashkey, std::vector > moves); /* Functions to convert between host and book byte order. */ static BookEntry h2b(const BookEntry& h, bool swap_byteorder); static BookEntry b2h(const BookEntry& b, bool swap_byteorder); public: Move choose() const; inline bool is_empty() const; unsigned int nr_moves() const; bool is_valid_and_legal(const Board & board) const; void print(const Board & board) const; }; inline bool BookEntry::is_empty() const { return move[0] == NO_MOVE; } class BookHeader { friend class Book; private: /* Do not change the order or the type of those members. They are * written to the book in binary format. */ uint32_t size; uint32_t magic; #if defined(HOICHESS) static const uint32_t s_magic = 0xdaabaffeL; #elif defined(HOIXIANGQI) static const uint32_t s_magic = 0x6a8dda83L; #else # error "neither HOICHESS nor HOIXIANGQI defined" #endif public: BookHeader(); /* Functions to convert between host and book byte order. */ static BookHeader h2b(const BookHeader& h, bool swap_byteorder); static BookHeader b2h(const BookHeader& b, bool swap_byteorder); }; class BookException { std::string msg; public: BookException(const std::string& msg) : msg(msg) {} public: const std::string& get_msg() { return msg; } }; class Book { private: FILE * fp; bool swap_byteorder; BookHeader header; public: Book(const char * filename); Book(const char * filename, unsigned long size); ~Book(); public: bool lookup(const Board & board, BookEntry * entry) const; bool put(const BookEntry & entry); static void create_from_pgn(const char * bookfile, const char * pgnfile, unsigned int depth, unsigned int min_move_count); private: unsigned long hashfunc(Hashkey hashkey, unsigned int i) const; static std::vector > group_moves( std::list moves, unsigned int min_move_count); void read_header(); void write_header(); BookEntry read_entry(unsigned long slot) const; void write_entry(unsigned long slot, const BookEntry & entry); }; #endif // BOOK_H hoichess_0.10.3/src/clock.cc0000640000175000017500000001256710732031250015235 0ustar oliveroliver/* $Id: clock.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/clock.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "clock.h" #include "util.h" Clock::Clock() { mode = NONE; running = false; elapsed = 0; limit = 0; hard_limit = 0; } Clock::Clock(unsigned int secs) { mode = EXACT; running = false; elapsed = 0; limit = secs * 100; hard_limit = limit; } Clock::Clock(unsigned int moves, unsigned int secs, unsigned int inc) { ASSERT(secs > 0); base_time = secs * 100; base_moves = moves; increment = inc * 100; if (moves == 0 && inc == 0) { mode = SUDDENDEATH; } else if (inc == 0) { mode = CONV; } else { mode = INCR; } remaining_time = base_time; remaining_moves = base_moves; running = false; elapsed = 0; limit = 0; hard_limit = 0; } void Clock::start() { if (running) return; gettimeofday(&start_tv, NULL); elapsed = 0; running = true; } unsigned int Clock::stop() { update(); running = false; switch (mode) { case NONE: case EXACT: break; case CONV: remaining_time -= elapsed; remaining_moves--; if (remaining_moves == 0) { remaining_time += base_time; remaining_moves = base_moves; } break; case INCR: remaining_time -= elapsed; remaining_time += increment; break; case SUDDENDEATH: remaining_time -= elapsed; break; } return elapsed; } void Clock::turn_back() { if (!running) return; gettimeofday(&start_tv, NULL); elapsed = 0; } void Clock::update() const { /* We want to update the clock status even * from const methods like print(). */ const_cast(this)->do_update(); } void Clock::do_update() { if (!running) return; struct timeval tv; gettimeofday(&tv, NULL); elapsed = (tv.tv_sec - start_tv.tv_sec) * 100 + (tv.tv_usec - start_tv.tv_usec) / 10000; } void Clock::allocate_time() { switch (mode) { case NONE: return; case EXACT: /* limit and hard_limit already set in constructor */ return; case CONV: ASSERT(remaining_moves > 0); limit = remaining_time / remaining_moves; break; case INCR: limit = remaining_time / 20 + increment; break; case SUDDENDEATH: limit = remaining_time / 40; break; } if (remaining_time <= 0) { limit = 0; hard_limit = 0; if (verbose) { atomic_printf("No time remaining!\n"); } return; } hard_limit = 2 * limit; if (hard_limit > (unsigned) remaining_time) { hard_limit = remaining_time; } check_limit(); if (verbose) { atomic_printf("Search time allocation: %.2f sec" " (max. %.2f sec)\n", (float) limit/100, (float) hard_limit/100); } } void Clock::allocate_more_time(const char * reason) { if (mode == NONE || mode == EXACT) { return; } unsigned int old_limit = limit; /* TODO Only a first try... */ limit = old_limit + (hard_limit - old_limit) / 3; check_limit(); if (verbose) { atomic_printf("Search time extended from %.2f sec" " to %.2f sec (reason: %s)\n", (float) old_limit/100, (float) limit/100, reason ? reason : "??"); } } void Clock::check_limit() { if (mode == NONE || mode == EXACT) { return; } if (limit > hard_limit) { limit = hard_limit; } /* Short on time? */ if ((float) remaining_time / base_time < 0.1f) { limit = (int) (limit * 0.8f); } /* Very short on time? */ if ((float) remaining_time / base_time < 0.05f) { limit = (int) (limit * 0.8f); } // if (limit == 0) { // limit = 1; // } } bool Clock::timeout() const { if (mode == NONE) { return false; } if (!running) { WARN("Clock::timeout() called with stopped clock"); } update(); return (elapsed >= limit); } unsigned int Clock::get_limit() const { return limit; } unsigned int Clock::get_elapsed_time() const { update(); return elapsed; } void Clock::set_remaining_time(unsigned int csecs) { remaining_time = csecs; } void Clock::print(FILE * fp) const { switch (mode) { case NONE: fprintf(fp, "Clock mode: none\n"); break; case CONV: fprintf(fp, "Clock mode: conventional\n"); fprintf(fp, "Remaining time: %.2f sec, remaining moves: %d\n", (float) remaining_time/100, remaining_moves); break; case INCR: fprintf(fp, "Clock mode: incremental\n"); fprintf(fp, "Remaining time: %.2f sec, increment: %.2fs\n", (float) remaining_time/100, (float) increment/100); break; case SUDDENDEATH: fprintf(fp, "Clock mode: sudden death\n"); fprintf(fp, "Remaining time: %.2f sec\n", (float) remaining_time/100); break; case EXACT: fprintf(fp, "Clock mode: exact\n"); fprintf(fp, "Time per move: %.2f sec\n", (float) limit/100); break; } update(); if (running) { fprintf(fp, "Clock is running, elapsed time: %.2fs\n", (float) elapsed/100); } } hoichess_0.10.3/src/search_util.cc0000640000175000017500000002343610732031250016441 0ustar oliveroliver/* $Id: search_util.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/search_util.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "clock.h" #include "search.h" #include #include /***************************************************************************** * * Search statistics. * *****************************************************************************/ void Search::print_statistics() { int csecs = clock->get_elapsed_time(); unsigned long nodes_total = nodes + nodes_quiesce; unsigned int perc_fw = nodes_total > 0 ? 100 * nodes / nodes_total : 0; unsigned int perc_quiesce = nodes_total > 0 ? 100 * nodes_quiesce / nodes_total : 0; printf("Nodes searched: %ld" " (full-width: %lu (%u%%), quiescence: %lu (%u%%))\n", nodes_total, nodes, perc_fw, nodes_quiesce, perc_quiesce); if (csecs >= 6000) { int mins = csecs / 6000; int secs = csecs % 6000 / 100; printf("Search time: %d:%02d", mins, secs); } else { printf("Search time: %.2fs", (float) csecs / 100); } printf(" (%.0fk nodes/s)\n", nodes_total / ((float) csecs / 100) / 1000); #ifdef COLLECT_STATISTICS printf("Cutoffs: beta: %ld, null: %ld, fut: %ld/%ld, razor: %ld\n", stat_cut, stat_nullcut, stat_futcut, stat_xfutcut, stat_razcut); if (stat_moves_cnt > 0) { printf("Average branching factor in full-width search: %.2f\n", (float) stat_moves_sum / stat_moves_cnt); } if (stat_moves_cnt_quiesce > 0) { printf("Average branching factor in quiescence search: %.2f\n", (float) stat_moves_sum_quiesce / stat_moves_cnt_quiesce); } #endif // COLLECT_STATISTICS if (hashtable) { hashtable->print_statistics(); } evaluator->print_statistics(); } void Search::reset_statistics() { nodes = 0; nodes_quiesce = 0; #ifdef COLLECT_STATISTICS stat_cut = 0; stat_nullcut = 0; stat_futcut = 0; stat_xfutcut = 0; stat_razcut = 0; stat_moves_sum = 0; stat_moves_cnt = 0; stat_moves_sum_quiesce = 0; stat_moves_cnt_quiesce = 0; #endif // COLLECT_STATISTICS if (hashtable) { hashtable->reset_statistics(); } evaluator->reset_statistics(); } void Search::update_overall_statistics() { ostat_knodes += (nodes + nodes_quiesce) / 1000; ostat_csecs += clock->get_elapsed_time(); if (rootdepth > 0) { ostat_depth_sum += rootdepth; ostat_depth_cnt++; } } void Search::print_overall_statistics() { if (ostat_csecs > 0) { printf("Average nps: %.0fk\n", (float) ostat_knodes / ostat_csecs * 100); } if (ostat_depth_cnt > 0) { printf("Average search depth: %d\n", ostat_depth_sum / ostat_depth_cnt); } } /***************************************************************************** * * Thinking output. * *****************************************************************************/ void Search::print_header() { printf("Depth Ply Time Score Nodes Principal-Variation\n"); } /* * Print thinking output. */ void Search::print_thinking(unsigned int depth) { unsigned long csecs = clock->get_elapsed_time(); next_update = csecs + 500; if (verbose < 3 && csecs < 300) { return; } if (shell->xboard) { print_thinking_xboard(depth); } else { print_thinking_terminal(depth); } } /* * Print thinking output to terminal: * * 9? 4.15 1109710 1. e4 (1/20) */ void Search::print_thinking_terminal(unsigned int depth) { unsigned long csecs = clock->get_elapsed_time(); int nodes_total = nodes+nodes_quiesce; int i = tree[0]->get_current_move_no(); int n = tree[0]->get_movelist_size(); Move mov = tree[0]->get_current_move(); const Board & board = tree.get_rootboard(); std::string s; char buf[128]; /* depth */ snprintf(buf, sizeof(buf), "%2d? %2d/%2d", depth, maxplyreached+1, maxplyreached_quiesce+1); s += buf; /* search time */ if (csecs >= 6000) { int mins = csecs / 6000; int secs = csecs % 6000 / 100; snprintf(buf, sizeof(buf), " %3d:%02d", mins, secs); } else { snprintf(buf, sizeof(buf), " %6.2f", (float) csecs / 100); } s += buf; /* nodes */ snprintf(buf, sizeof(buf), " %9d ", nodes_total); s += buf; /* current move */ snprintf(buf, sizeof(buf), "%d. %s%s", board.get_moveno(), board.get_side() == WHITE ? "" : "... ", mov.san(board).c_str()); s += buf; /* number of current move / total number of moves */ snprintf(buf, sizeof(buf), " (%d/%d)", i+1, n); s += buf; clear_line(); atomic_printf("%s\r", s.c_str()); fflush(stdout); } /* * In xboard mode, when analyzing, we print out the stat01 line: * * stat01: time nodes ply mvleft mvtot mvname */ void Search::print_thinking_xboard(unsigned int depth) { if (mode != ANALYZE) { return; } unsigned long csecs = clock->get_elapsed_time(); int nodes_total = nodes+nodes_quiesce; int i = tree[0]->get_current_move_no(); int n = tree[0]->get_movelist_size(); Move mov = tree[0]->get_current_move(); const Board & board = tree.get_rootboard(); atomic_printf("stat01: %d %d %d %d %d %s\n", csecs, nodes_total, depth, n - i - 1, n, mov.san(board).c_str()); } /* * Print search result. * * TODO Replace 'char c' by an enum type. */ void Search::print_result(unsigned int depth, int score, char c) { int csecs = clock->get_elapsed_time(); if (!shell->xboard && verbose < 2 && csecs < 100 && score < MATE) { return; } if (shell->xboard) { if (verbose < 2 && c == ' ') { return; } print_result_xboard(depth, score, c); } else { if (verbose < 2 && depth < 2 && c == ' ') { return; } print_result_terminal(depth, score, c); } } /* * Print search result to terminal. * * 7. 1.16 0.25 261225 1. e4 e5 2. Nf3 Nf6 3. Nxe5 Bd6 4. d4 */ void Search::print_result_terminal(unsigned int depth, int score, char c) { int csecs = clock->get_elapsed_time(); int nodes_total = nodes+nodes_quiesce; std::string s; char buf[128]; /* depth and result type */ snprintf(buf, sizeof(buf), "%2d%c %2d/%2d", depth, c, maxplyreached+1, maxplyreached_quiesce+1); s += buf; /* search time */ if (csecs >= 6000) { int mins = csecs / 6000; int secs = csecs % 6000 / 100; snprintf(buf, sizeof(buf), " %3d:%02d", mins, secs); } else { snprintf(buf, sizeof(buf), " %6.2f", (float) csecs / 100); } s += buf; /* score and nodes */ snprintf(buf, sizeof(buf), " %7.2f %9d ", (float) score / 100, nodes_total); s += buf; /* pv line */ s += get_best_line(depth, c); clear_line(); atomic_printf("%s\n", s.c_str()); fflush(stdout); } /* * Print search result in xboard mode: * * ply score time nodes pv */ void Search::print_result_xboard(unsigned int depth, int score, char c) { (void) c; int csecs = clock->get_elapsed_time(); int nodes_total = nodes+nodes_quiesce; atomic_printf("%d %d %d %d %s\n", depth, score, csecs, nodes_total, get_best_line(depth, c).c_str()); } /* * Return the line of best moves starting the root of the search tree. */ std::string Search::get_best_line(unsigned int depth, char c) const { std::ostringstream ss; Board board = tree.get_rootboard(); Move mov = tree[0]->get_best(); ss << board.get_moveno() << ". "; if (board.get_side() == BLACK) { ss << "... "; } ss << mov.san(board); if (c == '+') { ss << "!!"; } else if (c == '-') { ss << "??"; } depth--; int ply = 0; /* Get the remaining moves from the hash table. */ if (!hashtable) { return ss.str(); } while (depth-- > 0) { board.make_move(mov); HashEntry entry; if (!hashtable->probe(board, &entry)) { break; } mov = entry.get_move(); if (!mov) { break; } if (board.get_side() == WHITE) { ss << " " << board.get_moveno() << ". "; } else { ss << " "; } ss << mov.san(board); /* Limit output length to avoid xboard buffer overflow. */ if (++ply >= 30) { ss << " [...]"; break; } } return ss.str(); } void Search::clear_line() { std::string s(79, ' '); atomic_printf("\r%s\r", s.c_str()); } /***************************************************************************** * * These functions will be called by the shell to configure and control * the search. * *****************************************************************************/ void Search::set_book(Book * book) { this->book = book; } void Search::set_depthlimit(unsigned int depth) { if (depth > 0 && depth < MAXDEPTH) { maxdepth = depth; } else { maxdepth = MAXDEPTH; } } void Search::set_hashtable(HashTable * hashtable) { this->hashtable = hashtable; } void Search::set_pawnhashtable(PawnHashTable * pawnhashtable) { evaluator->set_pawnhashtable(pawnhashtable); } void Search::set_evalcache(EvaluationCache * evalcache) { evaluator->set_evalcache(evalcache); } void Search::set_showthinking(bool x) { showthinking = x; } Evaluator * Search::get_evaluator() const { return evaluator; } void Search::set_param(const std::string& name, const std::string& value) { if (name == "time") { unsigned long v; if (sscanf(value.c_str(), "%lx", &v) == 1) { param_time = v; printf("param_time = 0x%lx\n", param_time); } else { printf("Illegal argument for parameter '%s': '%s'\n", name.c_str(), value.c_str()); } } } hoichess_0.10.3/src/shell.h0000640000175000017500000000724610732031250015111 0ustar oliveroliver/* $Id: shell.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/shell.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef SHELL_H #define SHELL_H #include "common.h" #include "board.h" #include "book.h" #include "clock.h" #include "game.h" #include "hash.h" #include "search.h" #include "basic.h" #include #include #include /* forward declaration */ class Search; class Shell { private: typedef struct { std::string name; unsigned int line; FILE * fp; } source_t; public: /* Public, because also accessed from Search. */ bool xboard; private: bool flag_force; bool flag_ponder; bool flag_showthinking; bool flag_analyze; bool flag_playboth; source_t source; std::list sources; std::string myname; Game * game; Book * book; HashTable * hashtable; PawnHashTable * pawnhashtable; EvaluationCache * evalcache; Search * search; Color myside; bool quit; /* Some commands (e.g. solve and bench) call search from within a loop. * interrupt() sets this flag to abort those commands. */ bool stop; std::vector cmd_args; public: Shell(); ~Shell(); public: void main(const char * filename = NULL); void interrupt(); public: void set_book(const char * bookfile); void set_hashsize(unsigned long size); void set_pawnhashsize(unsigned long size); void set_evalcachesize(unsigned long size); void set_myname(const char * name); void set_xboard(bool x); public: void source_file(FILE * fp, const char * name); private: void input(); char * get_line(const char * prompt); char * get_line_fgets(FILE * fp, const char * prompt); #ifdef HAVE_READLINE char * get_line_readline(const char * prompt); #endif std::string get_prompt(); void input_move(std::string input); void user_move(Move mov); void engine_move(); void print_result(); private: /* FIXME this should either be const, or not static */ static struct command { const char * name; void (Shell::* func) (void); bool ignore; const char * usage; } commands[]; private: void cmd_xboard(); void cmd_protover(); void cmd_accepted(); void cmd_rejected(); void cmd_new(); void cmd_variant(); void cmd_quit(); void cmd_force(); void cmd_go(); void cmd_level(); void cmd_st(); void cmd_sd(); void cmd_time(); void cmd_otim(); void cmd_ping(); void cmd_setboard(); void cmd_bk(); void cmd_undo(); void cmd_remove(); void cmd_hard(); void cmd_easy(); void cmd_post(); void cmd_nopost(); void cmd_analyze(); void cmd_exit(); void cmd_verbose(); void cmd_debug(); void cmd_ignore(); void cmd_obey(); void cmd_help(); void cmd_source(); void cmd_echo(); void cmd_show(); void cmd_solve(); void cmd_bench(); void cmd_book(); void cmd_hash(); void cmd_pawnhash(); void cmd_evalcache(); void cmd_set(); void cmd_get(); void cmd_playboth(); void cmd_loadgame(); void cmd_savegame(); void cmd_redo(); }; #endif // SHELL_H hoichess_0.10.3/src/init.cc0000640000175000017500000000317610732031250015101 0ustar oliveroliver/* $Id: init.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/init.cc * * Copyright (C) 2004-2007 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "basic.h" #include "board.h" #include /***************************************************************************** * * This is the main initialization function. * Make sure it is called before doing anything else. * *****************************************************************************/ void init() { basic_init(); #ifdef HOICHESS Bitboard::init(); #endif Board::init(); srand(time(NULL)); #ifdef WIN32 /* Completely disable I/O buffering on WIN32 platforms. */ setbuf(stdin, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL); setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); #endif } void fini() { #ifdef STATS_MOVELIST Movelist::print_stats(); #endif } hoichess_0.10.3/src/win32/0000750000175000017500000000000010732031250014561 5ustar oliveroliverhoichess_0.10.3/src/win32/gettimeofday.cc0000640000175000017500000000112610732031250017552 0ustar oliveroliver/* $Id: gettimeofday.cc 1462 2007-12-18 20:49:56Z holger $ * * (c) Copyright 1992 Eric Backus * * This software may be used freely so long as this copyright notice is * left intact. There is no warrantee on this software. * */ #include #include int gettimeofday(struct timeval * tp, void * tzp) { (void) tzp; SYSTEMTIME systime; if (tp) { struct tm tmrec; time_t theTime = time(NULL); tmrec = *localtime(&theTime); tp->tv_sec = mktime(&tmrec); GetLocalTime(&systime); /* system time */ tp->tv_usec = systime.wMilliseconds * 1000; } return 0; } hoichess_0.10.3/src/win32/stdint.h0000640000175000017500000000062410732031250016242 0ustar oliveroliver/* $Id: stdint.h 1462 2007-12-18 20:49:56Z holger $ */ #ifndef STDINT_H #define STDINT_H typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; typedef unsigned long long uint64_t; typedef signed char int8_t; typedef signed short int16_t; typedef signed long int32_t; typedef signed long long int64_t; #endif /* STDINT_H */ hoichess_0.10.3/src/win32/bitboard_asm.h0000640000175000017500000000350110732031250017360 0ustar oliveroliver/* $Id: bitboard_asm.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/win32/bitboard_asm.h * * Copyright (C) 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ /* * x86 assembler versions of msb/lsb scan routines. * This code was originally taken from Crafty. */ #ifdef USE_ASM_LSB inline int Bitboard::lsb() const { uint32_t rt; uint32_t bitsh = ((uint32_t) (bits>>32)); uint32_t bitsl = ((uint32_t) bits); __asm { mov ebx, bitsl bsf eax, ebx jnz b mov ebx, bitsh bsf eax, ebx jnz a mov eax, -1 jmp b a: add eax, 32 b: mov rt, eax } return rt; } #endif #ifdef USE_ASM_MSB inline int Bitboard::msb() const { uint32_t rt; uint32_t bitsh = ((uint32_t) (bits>>32)); uint32_t bitsl = ((uint32_t) bits); __asm { mov ebx, bitsh bsr eax, ebx jnz a mov ebx, bitsl bsr eax, ebx jnz b mov eax, -1 jmp b a: add eax, 32 b: mov rt, eax } return rt; } #endif #ifdef USE_ASM_POPCNT #error "asm popcnt() not implemented" #endif hoichess_0.10.3/src/win32/gettimeofday.h0000640000175000017500000000012010732031250017405 0ustar oliveroliver#include extern int gettimeofday(struct timeval * tp, void * tzp); hoichess_0.10.3/src/win32/inttypes.h0000640000175000017500000000002410732031250016606 0ustar oliveroliver#include "stdint.h" hoichess_0.10.3/src/game.cc0000640000175000017500000002753610732031250015055 0ustar oliveroliver/* $Id: game.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/game.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "game.h" GameEntry::GameEntry(const Board & board, Move mov, const Clock & wclock, const Clock & bclock, const MoveAttributes & attr) { this->board = board; this->move = mov; this->clock[WHITE] = wclock; this->clock[BLACK] = bclock; this->attr = attr; } /* * Create a new game, starting from the position described by board * and assign a clock to each side. */ Game::Game(const Board & board, const Clock & wclock, const Clock & bclock) { initial_board = current_board = board; initial_clock[WHITE] = old_clock[WHITE] = current_clock[WHITE] = wclock; initial_clock[BLACK] = old_clock[BLACK] = current_clock[BLACK] = bclock; running = false; result = OPEN; nr_hashkeys = 0; } bool Game::is_over() const { return result != OPEN; } bool Game::is_running() const { return running; } int Game::get_result() const { return result; } std::string Game::get_result_str() const { return result_str; } std::string Game::get_result_comment() const { return result_comment; } Board Game::get_board() const { return current_board; } int Game::get_side() const { return current_board.get_side(); } Clock Game::get_clock() const { return current_clock[get_side()]; } Clock Game::get_clock(Color side) const { ASSERT(side == WHITE || side == BLACK); return current_clock[side]; } void Game::start() { current_clock[get_side()].start(); running = true; } void Game::make_move(Move mov, const GameEntry::MoveAttributes & move_attr) { ASSERT(mov.is_valid(current_board)); ASSERT(mov.is_legal(current_board)); /* stop clock of side that has played the current move */ current_clock[get_side()].stop(); /* make sure we don't put any running clocks in game history */ old_clock[WHITE].stop(); old_clock[BLACK].stop(); /* save current position */ GameEntry entry(current_board, mov, old_clock[WHITE], old_clock[BLACK], move_attr); entries.push_back(entry); /* update current position with new move and clocks */ current_board.make_move(mov); old_clock[WHITE] = current_clock[WHITE]; old_clock[BLACK] = current_clock[BLACK]; /* check result and start clock of side to move */ check_result(); if (!result) { current_clock[get_side()].start(); running = true; } else { running = false; } update_hashkeys(); undone_entries.clear(); } bool Game::undo_move() { if (entries.size() == 0) { running = false; return false; } /* get undo information */ const GameEntry last = entries.back(); entries.pop_back(); /* save last state */ old_clock[WHITE].stop(); old_clock[BLACK].stop(); GameEntry undone(current_board, last.get_move(), old_clock[WHITE], old_clock[BLACK], last.get_attr()); undone_entries.push_front(undone); /* load last state */ current_board = last.get_board(); old_clock[WHITE] = current_clock[WHITE] = last.get_clock(WHITE); old_clock[BLACK] = current_clock[BLACK] = last.get_clock(BLACK); current_clock[current_board.get_side()].start(); /* set result to open */ running = true; result = OPEN; update_hashkeys(); return true; } /* * FIXME This does not restore clocks correctly. */ Move Game::redo_move() { if (undone_entries.size() == 0) { return NO_MOVE; } /* get undo information */ GameEntry undone = undone_entries.front(); undone_entries.pop_front(); /* stop clock of side that has played the current move */ current_clock[get_side()].stop(); /* make sure we don't put any running clocks in game history */ old_clock[WHITE].stop(); old_clock[BLACK].stop(); /* save current position */ GameEntry entry(current_board, undone.get_move(), old_clock[WHITE], old_clock[BLACK], undone.get_attr()); entries.push_back(entry); /* update current position with new move and clocks */ current_board = undone.get_board(); current_clock[WHITE] = old_clock[WHITE] = undone.get_clock(WHITE); current_clock[BLACK] = old_clock[BLACK] = undone.get_clock(BLACK); /* check result and start clock of side to move */ check_result(); if (!result) { current_clock[get_side()].start(); running = true; } else { running = false; } update_hashkeys(); return undone.get_move(); } /* * Set up a new position based on the given board. Take the clocks as * they were at the _beginning_ of the old game. */ void Game::set_board(const Board & board) { ASSERT(board.is_valid()); ASSERT(board.is_legal()); current_board = board; old_clock[WHITE] = current_clock[WHITE] = initial_clock[WHITE]; old_clock[BLACK] = current_clock[BLACK] = initial_clock[BLACK]; entries.clear(); running = false; check_result(); update_hashkeys(); } bool Game::set_board(const std::string& fen) { Board board; if (!board.parse_fen(fen)) { entries.clear(); running = false; result = ILLEGAL; return false; } set_board(board); return true; } /* * Replace the current clock of the side to move. */ void Game::set_clock(const Clock & clock) { old_clock[get_side()] = current_clock[get_side()] = clock; if (running) { current_clock[get_side()].start(); } } void Game::set_clock(Color side, const Clock & clock) { ASSERT(side == WHITE || side == BLACK); old_clock[side] = current_clock[side] = clock; if (running) { current_clock[side].start(); } } /* * Replace the current _and_initial_ clocks of both sides by new ones. */ void Game::set_clocks(const Clock & wclock, const Clock & bclock) { initial_clock[WHITE] = old_clock[WHITE] = current_clock[WHITE] = wclock; initial_clock[BLACK] = old_clock[BLACK] = current_clock[BLACK] = bclock; if (running) { current_clock[current_board.get_side()].start(); } } /* * Count how often this board appeared in the game history, * _not_ including the current position. */ int Game::repetitions(const Board & board) const { int rep = 0; for (std::list::const_reverse_iterator it = entries.rbegin(); it != entries.rend(); it++) { if (it->get_board() == board) rep++; } return rep; } /* * Count how often this board appeared in the game history, * _not_ including the current position. * * This doesn't compare actual Board objects, but uses a list * of hash keys. This is intended to be called during search. * It is much faster than repetitions(), but might theoretically * make mistakes (due to hash key collisions). */ int Game::repetitions_search(const Board & board) const { /* We could also test if entries.empty() ... */ if (nr_hashkeys == 0) { return 0; } const Hashkey hk = board.get_hashkey(); int rep = 0; for (unsigned int i = (board.get_side() == entries.back().get_side()) ? 0 : 1; i= 2) break; } } return rep; } /* * Count the number of (full-)moves of the current player since his last * book move. If the last move was out of book, this number is 1. */ int Game::last_bookmove() const { unsigned int n = 0; for (std::list::const_reverse_iterator it = entries.rbegin(); it != entries.rend(); it++) { if (it->get_board().get_side() != get_side()) { continue; } n++; if (it->get_attr().bookmove) { break; } } #ifdef DEBUG printf("last bookmove: %d moves ago\n", n); #endif return n; } /* * Update the list of hash keys that is used by repetitions_search(). * Store max. 100 hash keys (50 move rule) and only up to an irreversible * move (pawn, capture or castling). */ void Game::update_hashkeys() { nr_hashkeys = 0; for (std::list::reverse_iterator it = entries.rbegin(); it != entries.rend(); it++) { Move mov = it->get_move(); #ifdef HOICHESS if (mov.ptype() == PAWN || mov.is_capture() || mov.is_castle()) break; #endif hashkeys[nr_hashkeys++] = it->get_board().get_hashkey(); if (nr_hashkeys == 100) break; } #ifdef DEBUG printf("positions in game history: %d\n", entries.size()); printf("hashkeys stored: %d\n", nr_hashkeys); printf("repetitions: %d/%d\n", repetitions(current_board), repetitions_search(current_board)); #endif } /* * Check if the game has ended by rule. */ void Game::check_result() { const Board & board = get_board(); if (board.is_mate()) { if (board.get_side() == WHITE) { result = BLACKMATES; result_str = "0-1"; result_comment = "Black mates"; } else { result = WHITEMATES; result_str = "1-0"; result_comment = "White mates"; } } else if (board.is_stalemate()) { #if defined(HOICHESS) result = STALEMATE; result_str = "1/2-1/2"; result_comment = "Stalemate"; #elif defined(HOIXIANGQI) if (board.get_side() == WHITE) { result = BLACKSTALEMATES; result_str = "0-1"; result_comment = "Black stalemates"; } else { result = WHITESTALEMATES; result_str = "1-0"; result_comment = "White stalemates"; } #else # error "neither HOICHESS nor HOIXIANGQI defined" #endif } else if (board.get_movecnt50() == 100) { result = RULE50; result_str = "1/2-1/2"; result_comment = "50 move rule"; } else if (repetitions(board) >= 2) { result = REPS3; result_str = "1/2-1/2"; result_comment = "3 repetitions"; } else if (board.is_material_draw()) { result = MATERIAL; result_str = "1/2-1/2"; result_comment = "Insufficient material"; } else { result = OPEN; result_str = "*"; result_comment = "Open"; } } void Game::print(FILE * fp) const { fprintf(fp, "Positions in game history: %d\n", entries.size()); for (std::list::const_iterator it = entries.begin(); it != entries.end(); it++) { fprintf(fp, "---------------------------------------------\n"); it->get_board().print_small(fp); fprintf(fp, "\n"); fprintf(fp, "White clock:\n"); it->get_clock(WHITE).print(fp); fprintf(fp, "Black clock:\n"); it->get_clock(BLACK).print(fp); fprintf(fp, "\n"); fprintf(fp, "Move played: %s\n", it->get_move().san(it->get_board()).c_str()); fprintf(fp, "Move attributes:"); if (it->get_attr().computer) fprintf(fp, " computer"); if (it->get_attr().bookmove) fprintf(fp, " bookmove"); fprintf(fp, "\n\n"); } } void Game::write_pgn(FILE * fp) const { /* standard tags (seven tag roster) */ fprintf(fp, "[Event \"unknown\"]\n"); fprintf(fp, "[Site \"unknown\"]\n"); fprintf(fp, "[Date \"unknown\"]\n"); fprintf(fp, "[Round \"unknown\"]\n"); fprintf(fp, "[White \"unknown\"]\n"); fprintf(fp, "[Black \"unknown\"]\n"); fprintf(fp, "[Result \"%s\"]\n", get_result_str().c_str()); /* additional tag: FEN if non-standard starting position */ std::string ofen = (entries.size() > 0) ? entries.begin()->get_board().get_fen() : current_board.get_fen(); if (ofen != opening_fen()) { fprintf(fp, "[FEN \"%s\"]\n", ofen.c_str()); } fprintf(fp, "\n"); /* moves */ unsigned int i = 1; unsigned int nchars = 0; for (std::list::const_iterator it = entries.begin(); it != entries.end(); it++) { std::string s = it->get_move().san(it->get_board()); if (it->get_board().get_side() == WHITE) { nchars += fprintf(fp, "%d. %s ", i, s.c_str()); } else { nchars += fprintf(fp, "%s ", s.c_str()); i++; } if (nchars > 70) { fprintf(fp, "\n"); nchars = 0; } } fprintf(fp, "\n"); /* result */ fprintf(fp, "%s {%s}\n", get_result_str().c_str(), get_result_comment().c_str()); } hoichess_0.10.3/src/pgn.h0000640000175000017500000000377410732031250014570 0ustar oliveroliver/* $Id: pgn.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/pgn.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef PGN_H #define PGN_H #include "common.h" #include "board.h" #include "move.h" #include #include #include class PGN { private: Board opening; std::map tags; std::list moves; public: PGN(); ~PGN() {}; public: Board get_opening() const { return opening; } std::list get_moves() const { return moves; } bool parse(FILE * fp); static char * get_movetext_token(FILE * fp, char * buf, size_t bufsize); static std::list parse_all(FILE * fp); static std::list parse_all(const char * filename); }; class EPD { private: std::string fen_position; std::string fen_color; std::string fen_castling; std::string fen_ep; std::map > ops; public: EPD(const std::string & s); ~EPD() {} std::string get_fen() const; std::list get(const std::string & opcode) const; std::string get1(const std::string & opcode) const; private: void parse(const char * p); const char * parse_operand(const char * p, const std::string & opcode); const char * parse_opcode(const char * p); }; #endif // PGN_H hoichess_0.10.3/src/debug_printconfig.h0000640000175000017500000000434210732031250017464 0ustar oliveroliver#define EXPTOSTRING1(x) #x #define EXPTOSTRING(x) EXPTOSTRING1(x) #ifdef DEFAULT_HASHSIZE std::cout << "\tDEFAULT_HASHSIZE " << EXPTOSTRING(DEFAULT_HASHSIZE) << "\n"; #endif #ifdef DEFAULT_PAWNHASHSIZE std::cout << "\tDEFAULT_PAWNHASHSIZE " << EXPTOSTRING(DEFAULT_PAWNHASHSIZE) << "\n"; #endif #ifdef DEFAULT_EVALCACHESIZE std::cout << "\tDEFAULT_EVALCACHESIZE " << EXPTOSTRING(DEFAULT_EVALCACHESIZE) << "\n"; #endif #ifdef DEFAULT_BOOK std::cout << "\tDEFAULT_BOOK " << EXPTOSTRING(DEFAULT_BOOK) << "\n"; #endif #ifdef USE_UNMAKE_MOVE std::cout << "\tUSE_UNMAKE_MOVE " << EXPTOSTRING(USE_UNMAKE_MOVE) << "\n"; #endif #ifdef USE_IID std::cout << "\tUSE_IID " << EXPTOSTRING(USE_IID) << "\n"; #endif #ifdef USE_PVS std::cout << "\tUSE_PVS " << EXPTOSTRING(USE_PVS) << "\n"; #endif #ifdef USE_HISTORY std::cout << "\tUSE_HISTORY " << EXPTOSTRING(USE_HISTORY) << "\n"; #endif #ifdef USE_KILLER std::cout << "\tUSE_KILLER " << EXPTOSTRING(USE_KILLER) << "\n"; #endif #ifdef USE_NULLMOVE std::cout << "\tUSE_NULLMOVE " << EXPTOSTRING(USE_NULLMOVE) << "\n"; #endif #ifdef USE_FUTILITYPRUNING std::cout << "\tUSE_FUTILITYPRUNING " << EXPTOSTRING(USE_FUTILITYPRUNING) << "\n"; #endif #ifdef USE_EXTENDED_FUTILITYPRUNING std::cout << "\tUSE_EXTENDED_FUTILITYPRUNING " << EXPTOSTRING(USE_EXTENDED_FUTILITYPRUNING) << "\n"; #endif #ifdef USE_RAZORING std::cout << "\tUSE_RAZORING " << EXPTOSTRING(USE_RAZORING) << "\n"; #endif #ifdef USE_EVALCACHE std::cout << "\tUSE_EVALCACHE " << EXPTOSTRING(USE_EVALCACHE) << "\n"; #endif #ifdef EXTEND_IN_CHECK std::cout << "\tEXTEND_IN_CHECK " << EXPTOSTRING(EXTEND_IN_CHECK) << "\n"; #endif #ifdef EXTEND_RECAPTURE std::cout << "\tEXTEND_RECAPTURE " << EXPTOSTRING(EXTEND_RECAPTURE) << "\n"; #endif #ifdef MAXDEPTH std::cout << "\tMAXDEPTH " << EXPTOSTRING(MAXDEPTH) << "\n"; #endif #ifdef MAXPLY std::cout << "\tMAXPLY " << EXPTOSTRING(MAXPLY) << "\n"; #endif #ifdef MOVELIST_MAXSIZE std::cout << "\tMOVELIST_MAXSIZE " << EXPTOSTRING(MOVELIST_MAXSIZE) << "\n"; #endif #ifdef COLLECT_STATISTICS std::cout << "\tCOLLECT_STATISTICS " << EXPTOSTRING(COLLECT_STATISTICS) << "\n"; #endif #ifdef STATS_MOVELIST std::cout << "\tSTATS_MOVELIST " << EXPTOSTRING(STATS_MOVELIST) << "\n"; #endif #undef EXPTOSTRING #undef EXPTOSTRING1 hoichess_0.10.3/src/Makefile.local0000640000175000017500000000132510732031250016352 0ustar oliveroliver# $Id: Makefile.local 1462 2007-12-18 20:49:56Z holger $ # # # NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE # # This file contains local definitions. You will most # likely want to match them to your own system. # # NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE # # Optimization flags CXXFLAGS += -O3 # Debugging flags #CXXFLAGS += -DDEBUG #CXXFLAGS += -g # Profiling flags #CXXFLAGS += -fprofile-arcs -ftest-coverage #CXXFLAGS += -pg #LDFLAGS += -pg ifeq ($(PLATFORM),unix) CXX = g++-4.1 HAVE_READLINE = 1 endif ifeq ($(PLATFORM),mingw32) CXX = i586-mingw32msvc-g++ endif ifneq ($(shell uname -m | grep i.86),) CXXFLAGS += -march=$(shell uname -m) endif hoichess_0.10.3/src/config.h0000640000175000017500000000454710732031250015250 0ustar oliveroliver/* $Id: config.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/config.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef CONFIG_H #define CONFIG_H /* Default size of main hash table */ #define DEFAULT_HASHSIZE "32M" /* Default size of pawn hash table */ #define DEFAULT_PAWNHASHSIZE "4M" /* Default size of evaluation cache */ #define DEFAULT_EVALCACHESIZE "4M" /* Default location of opening book */ #define DEFAULT_BOOK "book.dat" /* Use a single board in search tree, in connection with Board::unmake_move(). * Otherwise, the board will be copied from node to node each time a move is * made. */ //#define USE_UNMAKE_MOVE /* Use internal iterative deepening */ #define USE_IID /* Use principal variation search */ #define USE_PVS /* Use history table */ #define USE_HISTORY /* Use killer heuristic */ #define USE_KILLER /* Use null-move pruning */ #define USE_NULLMOVE /* Use futility pruning */ #define USE_FUTILITYPRUNING /* Use extended futility pruning */ #define USE_EXTENDED_FUTILITYPRUNING /* Use razoring */ //#define USE_RAZORING /* Use evaluation cache */ #define USE_EVALCACHE /* Search extensions */ #define EXTEND_IN_CHECK #define EXTEND_RECAPTURE /* Maximum depth for full-width search */ #define MAXDEPTH 900 /* Maximum search tree depth (full-width + quiescence search) */ #define MAXPLY 1024 /* Maximum size of a Movelist */ #define MOVELIST_MAXSIZE 256 /* Collect statistics, e.g. hash table hits, cutoffs during search, etc. */ #define COLLECT_STATISTICS /* Collect statistics about maximum number of moves stored in a movelist * (expensive!) */ //#define STATS_MOVELIST #endif // CONFIG_H hoichess_0.10.3/src/build/0000750000175000017500000000000010732031250014716 5ustar oliveroliverhoichess_0.10.3/src/build/mk_debug_config_h.sh0000750000175000017500000000071410732031250020670 0ustar oliveroliver#!/bin/sh # $Id: mk_debug_config_h.sh 1462 2007-12-18 20:49:56Z holger $ cat << EOF #define EXPTOSTRING1(x) #x #define EXPTOSTRING(x) EXPTOSTRING1(x) EOF grep -E '^(//)? *# *define' config.h | grep -v 'CONFIG_H' \ | sed -r -e 's/^(\/\/)? *# *define +(.*)$/\2/' \ | while read param rest; do echo "#ifdef $param" echo " std::cout << \"\t$param \" << EXPTOSTRING($param) << \"\n\";" echo "#endif" done cat << EOF #undef EXPTOSTRING #undef EXPTOSTRING1 EOF hoichess_0.10.3/src/build/compile-icc-win32.cmd0000640000175000017500000000141710732031250020533 0ustar oliveroliverrem $Id: compile-icc-win32.cmd 1462 2007-12-18 20:49:56Z holger $ rem Build script for HoiChess using Intel C compiler for Windows md .build-win32 md .build-win32\hoichess md .build-win32\hoixiangqi rem ICC options rem =========== rem rem /GX enable exceptions (?) rem /Ox optimize for maximum speed rem /QxK generate code for Pentium III rem /Qvec-report0 disable all messages from auto-vectorizer icl /D HOICHESS /D WIN32 /I win32 /I lib /I chess /I . /GX /Ox /QxK /Qvec-report0 /Fe.build-win32\hoichess.exe /Fo.build-win32\hoichess\ *.cc chess\*.cc lib\*.cc win32\*.cc icl /D HOIXIANGQI /D WIN32 /I win32 /I lib /I xiangqi /I . /GX /Ox /QxK /Qvec-report0 /Fe.build-win32\hoixiangqi.exe /Fo.build-win32\hoixiangqi\ *.cc xiangqi\*.cc lib\*.cc win32\*.cc hoichess_0.10.3/src/eval.cc0000640000175000017500000001300410732031250015054 0ustar oliveroliver/* $Id: eval.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/eval.cc * * Copyright (C) 2004-2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "eval.h" #include "board.h" Evaluator::Evaluator() { pawnhashtable = NULL; evalcache = NULL; reset_statistics(); } Evaluator::~Evaluator() { } /***************************************************************************** * * Main evaluation functions. * *****************************************************************************/ /* TODO * - This could be different for Chess and Xiangqi... * - This should be configurable on runtime, because test tourneys have * shown that it depends on available search time. */ #define EVAL_CUTOFF_MATERIAL 150 #define EVAL_CUTOFF_PHASE1 5 #define EVAL_ENABLE_PHASE2 int Evaluator::eval(const Board & board, int alpha, int beta, Color _myside) { myside = _myside; int score; /* TODO is_draw() still empty */ #if 0 if (is_draw(board)) return DRAW; #endif const Color side = board.get_side(); const Color xside = XSIDE(side); STAT_INC(stat_evals); /* * material */ score = material_balance(board.get_material(side), board.get_material(xside)); if (score >= beta + EVAL_CUTOFF_MATERIAL || score <= alpha - EVAL_CUTOFF_MATERIAL) { return score; } /* * do normal evaluation */ #ifdef USE_EVALCACHE if (evalcache && evalcache->probe(board, &score)) { return score; } #endif setup(&board); /* * phase 1 */ { STAT_INC(stat_evals_phase1); /* call plugins */ int score1 = 0; for (int i=0; plugins[i].name != NULL; i++) { ASSERT_DEBUG(plugins[i].func != NULL); score1 += (this->*plugins[i].func)(side) - (this->*plugins[i].func)(xside); } score += score1; #ifdef EVAL_CUTOFF_PHASE1 if (score1 > EVAL_CUTOFF_PHASE1 || score1 < -EVAL_CUTOFF_PHASE1) { goto done; } #endif } #ifdef EVAL_ENABLE_PHASE2 /* * phase 2 */ { STAT_INC(stat_evals_phase2); /* call plugins2 */ int score2 = 0; for (int i=0; plugins2[i].name != NULL; i++) { ASSERT_DEBUG(plugins2[i].func != NULL); score2 += (this->*plugins2[i].func)(side) - (this->*plugins2[i].func)(xside); } score += score2; } #endif /* * done */ goto done; // avoid warning about unused label done: finish(); #ifdef USE_EVALCACHE if (evalcache) { evalcache->put(board, score); } #endif return score; } void Evaluator::print_eval(const Board & board, Color _myside, FILE * fp) { myside = _myside; setup(&board); fprintf(fp, "material: %d/%d\n", board.material[WHITE], board.material[BLACK]); fprintf(fp, "material difference: %d\n", board.material[WHITE] - board.material[BLACK]); fprintf(fp, "material balance: %d\n", material_balance(board.material[WHITE], board.material[BLACK])); fprintf(fp, "phase: %u\n", phase); fprintf(fp, "draw: %s\n", is_draw(board) ? "yes" : "no"); fprintf(fp, "myside: %s\n", (myside == WHITE ? "white" : (myside == BLACK ? "black" : "none"))); fprintf(fp, "scoring plugins:\n"); for (int i=0; plugins[i].name != NULL; i++) { ASSERT(plugins[i].func != NULL); fprintf(fp, "\t%s: %d/%d\n", plugins[i].name, (this->*plugins[i].func)(WHITE), (this->*plugins[i].func)(BLACK)); } fprintf(fp, "scoring plugins2:\n"); for (int i=0; plugins2[i].name != NULL; i++) { ASSERT(plugins2[i].func != NULL); fprintf(fp, "\t%s: %d/%d\n", plugins2[i].name, (this->*plugins2[i].func)(WHITE), (this->*plugins2[i].func)(BLACK)); } } /***************************************************************************** * * Utility functions. * *****************************************************************************/ void Evaluator::reset_statistics() { #ifdef COLLECT_STATISTICS stat_evals = 0; stat_evals_phase1 = 0; stat_evals_phase2 = 0; #endif if (pawnhashtable) { pawnhashtable->reset_statistics(); } #ifdef USE_EVALCACHE if (evalcache) { evalcache->reset_statistics(); } #endif } void Evaluator::print_statistics(FILE * fp) const { #ifdef COLLECT_STATISTICS fprintf(fp, "Evaluations: %lu/%lu/%lu\n", stat_evals, stat_evals_phase1, stat_evals_phase2); #endif // COLLECT_STATISTICS if (pawnhashtable) { pawnhashtable->print_statistics(fp); } #ifdef USE_EVALCACHE if (evalcache) { evalcache->print_statistics(fp); } #endif } void Evaluator::set_pawnhashtable(PawnHashTable * pawnhashtable) { this->pawnhashtable = pawnhashtable; } void Evaluator::set_evalcache(EvaluationCache * evalcache) { #ifdef USE_EVALCACHE this->evalcache = evalcache; #else (void) evalcache; WARN("This version of %s has been compiled without" " evaluation cache support.\n", PROGNAME); #endif } void Evaluator::set_param(const std::string& name, const std::string& value) { /* avoid compiler warning about unused parameter */ (void) name; (void) value; /* TODO ... */ } hoichess_0.10.3/src/tree.h0000640000175000017500000001205510732031250014733 0ustar oliveroliver/* $Id: tree.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/tree.h * * Copyright (C) 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef TREE_H #define TREE_H #include "common.h" #include "board.h" #include "historytable.h" /* forward declaration */ class Tree; class Node { friend class Tree; public: enum node_type { UNKNOWN, ROOT, FULLWIDTH, QUIESCE }; private: enum node_state { GEN_CAPTURES, SCORE_CAPTURES, CAPTURES, GEN_NONCAPTURES, SCORE_NONCAPTURES, NONCAPTURES, GEN_ESCAPES, SCORE_ESCAPES, ESCAPES, SCORE_ALL, ALL, DONE }; private: Tree * tree; #ifdef USE_UNMAKE_MOVE BoardHistory hist; #else Board board; #endif Hashkey hashkey; bool incheck; int material; Movelist movelist; bool captures_generated; bool noncaptures_generated; bool escapes_generated; int current_move_no; enum node_type type; enum node_state state; Move best; Move hashmv; Move killer1; Move killer2; HistoryTable * historytable; Move played_move; public: Node(); public: Move first(); Move next(); Move pick(); void score_moves(); inline Hashkey get_hashkey() const; inline bool in_check() const; inline int material_balance() const; inline unsigned int get_movelist_size() const; inline unsigned int get_current_move_no() const; inline Move get_current_move() const; inline void set_current_score(int score); inline enum node_type get_type() const; inline void set_type(enum node_type t); inline Move get_best() const; inline void set_best(Move mov); inline Move get_hashmv() const; inline void set_hashmv(Move mov); inline void set_historytable(HistoryTable * ht); inline void add_killer(Move mov); inline Move get_played_move() const; }; class Tree { private: #ifdef USE_UNMAKE_MOVE Board board; Board rootboard; #endif Node * nodes; unsigned int current_ply; public: Tree(); ~Tree(); public: void clear_killer(); void set_root(const Board & board); Node * make_move(Move mov); void unmake_move(); inline Node * operator[](unsigned int ply); inline const Node * operator[](unsigned int ply) const; inline const Board & get_board() const; inline Board get_rootboard() const; inline unsigned int get_current_ply() const; }; /***************************************************************************** * * Inline functions of class Node * *****************************************************************************/ inline Hashkey Node::get_hashkey() const { return hashkey; } inline bool Node::in_check() const { return incheck; } inline int Node::material_balance() const { return material; } inline unsigned int Node::get_movelist_size() const { return movelist.size(); } inline unsigned int Node::get_current_move_no() const { return current_move_no; } inline Move Node::get_current_move() const { return movelist[current_move_no]; } inline void Node::set_current_score(int score) { movelist.set_score(current_move_no, score); } inline enum Node::node_type Node::get_type() const { return type; } inline void Node::set_type(enum Node::node_type t) { type = t; } inline Move Node::get_best() const { return best; } inline void Node::set_best(Move mov) { best = mov; } inline Move Node::get_hashmv() const { return hashmv; } inline void Node::set_hashmv(Move mov) { hashmv = mov; } inline void Node::set_historytable(HistoryTable * ht) { historytable = ht; } inline void Node::add_killer(Move mov) { if (killer1 == NO_MOVE) { killer1 = mov; } else if (killer2 != killer1) { killer2 = mov; } } inline Move Node::get_played_move() const { return played_move; } /***************************************************************************** * * Inline functions of class Tree * *****************************************************************************/ inline Node * Tree::operator[](unsigned int ply) { ASSERT_DEBUG(ply <= current_ply); return &nodes[ply]; } inline const Node * Tree::operator[](unsigned int ply) const { ASSERT_DEBUG(ply <= current_ply); return &nodes[ply]; } inline const Board & Tree::get_board() const { #ifdef USE_UNMAKE_MOVE return board; #else return nodes[current_ply].board; #endif } inline Board Tree::get_rootboard() const { #ifdef USE_UNMAKE_MOVE return rootboard; #else return nodes[0].board; #endif } inline unsigned int Tree::get_current_ply() const { return current_ply; } #endif // TREE_H hoichess_0.10.3/src/pgn.cc0000640000175000017500000002146710732031250014725 0ustar oliveroliver/* $Id: pgn.cc 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/pgn.cc * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "common.h" #include "game.h" #include "pgn.h" #include "util.h" #include #include #include #include //#define DEBUG_PGN_PARSE_1 //#define DEBUG_PGN_PARSE_2 PGN::PGN() { } bool PGN::parse(FILE * fp) { ASSERT(fp != NULL); char buf[1024]; char * strtok_r_buf; /* First, dischard everything up to the next tag */ while (!feof(fp)) { if (fgets(buf, sizeof(buf), fp) == NULL) { return false; } if (buf[0] == '[') { break; } } /* Read all tags until the next empty line. * One tag line is already in buf. */ while (!feof(fp)) { #ifdef DEBUG_PGN_PARSE_1 printf("%s", buf); #endif char * p = buf; /* skip whitespace */ while (*p && *p == ' ') { p++; } if (buf[0] != '[') { break; } /* skip '[' */ p++; /* skip whitespace */ while (*p && *p == ' ') { p++; } char * q; q = strtok_r(p, " \"]\n\r", &strtok_r_buf); #ifdef DEBUG_PGN_PARSE_1 printf("q = '%s'\n", q); #endif if (!q) { return false; } std::string tag = q; q = strtok_r(NULL, "\"\n\r", &strtok_r_buf); #ifdef DEBUG_PGN_PARSE_1 printf("q = '%s'\n", q); #endif if (!q) { return false; } std::string val = q; #ifdef DEBUG_PGN_PARSE_2 printf("tag: '%s', value '%s'\n", tag.c_str(), val.c_str()); #endif tags[tag] = val; /* Read next tag line */ if (fgets(buf, sizeof(buf), fp) == NULL) { return false; } } if (tags["FEN"] != "") { if (!opening.parse_fen(tags["FEN"])) { return false; } } else { if (!opening.parse_fen(opening_fen())) { BUG("Failed to set up standard opening position"); } } /* * Now read the list of moves, make them on board and put them * into this->moves. */ Board board = opening; std::string tok; while (!feof(fp)) { char * p = get_movetext_token(fp, buf, sizeof(buf)); if (!p || !*p) { continue; } tok = p; if (tok[tok.length()-1] == '.') { /* move number */ #ifdef DEBUG_PGN_PARSE_2 printf("move number: %s\n", tok.c_str()); #endif } else if (tok[0] == '{') { /* comment */ std::string comment = tok; #ifdef DEBUG_PGN_PARSE_2 printf("comment: %s\n", comment.c_str()); #endif } else if (tok[0] == '$') { /* `numeric annotation glyph' */ #ifdef DEBUG_PGN_PARSE_2 printf("nag: %s\n", tok.c_str()); #endif } else if (tok == "1-0" || tok == "0-1" || tok == "1/2-1/2" || tok == "*") { /* result */ #ifdef DEBUG_PGN_PARSE_2 printf("result: %s\n", tok.c_str()); #endif /* PGN finished, just read rest of line */ //strm.getline(buf, sizeof(buf)); #ifdef DEBUG_PGN_PARSE_1 printf("%s\n", buf); #endif return true; } else { /* move */ #ifdef DEBUG_PGN_PARSE_2 printf("move: %s\n", tok.c_str()); #endif Move mov = board.parse_move_1(tok); if (!mov) { if (debug) { /* TODO Perhaps we should print some * more information here (e.g. tags) */ printf("Invalid or illegal move in" " PGN: %s\n", tok.c_str()); } return false; } moves.push_back(mov); board.make_move(mov); } } return true; } char * PGN::get_movetext_token(FILE * fp, char * buf, size_t bufsize) { ASSERT(fp != NULL); char * p = buf; bool comment = false; while (!feof(fp) && p != buf + bufsize-1) { int c = fgetc(fp); if (c == EOF) { break; } else if (c == '\n' || c == '\r') { c = ' '; } if (comment) { *p++ = c; if (c == '}') { break; } } else { if (c == '{') { *p++ = c; comment = true; } else if (c == '.') { *p++ = c; break; } else if (c == ' ') { break; } else { *p++ = c; } } } *p = '\0'; return buf; } std::list PGN::parse_all(FILE * fp) { ASSERT(fp != NULL); std::list ret; while (feof(fp)) { PGN pgn; if (!pgn.parse(fp)) break; ret.push_back(pgn); } return ret; } std::list PGN::parse_all(const char * filename) { FILE * fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "cannot open %s for reading: %s\n", filename, strerror(errno)); exit(EXIT_FAILURE); } return parse_all(fp); } /****************************************************************************** * * Methods of class EPD * *****************************************************************************/ /* * TODO We need some error handling if parsing failes. */ EPD::EPD(const std::string & _s) { char * s = new char[_s.size()+1]; strcpy(s, _s.c_str()); if (s[strlen(s)-1] == '\n') s[strlen(s)-1] = '\0'; const char * p = s; parse(p); delete s; } /* * Return an FEN representation for this EPD. If halfmove or fullmove * numbers are not specified, we just use 0 resp. 1. */ std::string EPD::get_fen() const { std::string fmvn, hmvn; if ((hmvn = get1("hmvn")) == "") hmvn = "0"; if ((fmvn = get1("fmvn")) == "") fmvn = "1"; std::stringstream ss; ss << fen_position << " " << fen_color << " " << fen_castling << " " << fen_ep << " " << hmvn << " " << fmvn; return ss.str(); } /* * Get a list of all operands for an the opcode. */ std::list EPD::get(const std::string & opcode) const { std::list ret; /* ops[opcode] does not work here, because operator[] is not const. */ std::map >::const_iterator it = ops.find(opcode); if (it != ops.end()) ret = it->second; return ret; } /* * Get only one operand. To make things simpler, use this method for * opcodes that normally have only one operand, like id or hmvn. */ std::string EPD::get1(const std::string & opcode) const { std::list tmp = get(opcode); if (tmp.size() == 0) { #ifdef DEBUG WARN("get1(): no operand for '%s', returning empty string", opcode.c_str()); #endif return std::string(""); } else if (tmp.size() > 1) { WARN("get1(): returning only 1st operand out of %d for '%s'", tmp.size(), opcode.c_str()); } return tmp.front(); } /***************************************************************************** * EPD parsing functions. This is good code (TM). *****************************************************************************/ void EPD::parse(const char * p) { /* First the FEN */ enum foo { S_POSITION, S_COLOR, S_CASTLING, S_EP, S_DONE }; int state = S_POSITION; while (*p) { if (*p == ' ') { state++; p++; if (state == S_DONE) break; continue; } switch (state) { case S_POSITION: fen_position += *p; break; case S_COLOR: fen_color += *p; break; case S_CASTLING: fen_castling += *p; break; case S_EP: fen_ep += *p; break; default: BUG("illegal state"); } p++; } /* Now the opcodes with their operands */ while (*p) { switch (*p) { case ' ': break; default: p = parse_opcode(p); } p++; } } const char * EPD::parse_opcode(const char * p) { std::string opcode; std::list operands; while (*p) { switch (*p) { case ';': #ifdef DEBUG printf("opcode = '%s', no operands\n", opcode.c_str()); #endif ops[opcode] = operands; return p; case ' ': #ifdef DEBUG printf("opcode = '%s', operands follow\n", opcode.c_str()); #endif ops[opcode] = operands; p++; while (*p) { p = parse_operand(p, opcode); if (*p != ' ') break; p++; } #ifdef DEBUG printf("opcode '%s' finished, had %d operands\n", opcode.c_str(), ops[opcode].size()); #endif return p; default: opcode += *p; } p++; } return p; } const char * EPD::parse_operand(const char * p, const std::string & opcode) { std::string operand; while (*p) { switch (*p) { case '"': /* A quoted string. Put everything up to * the next `"' into operand. */ p++; while (*p) { if (*p == '"') { break; } else { operand += *p++; } } break; case ';': #ifdef DEBUG printf("\toperand = '%s' (last)\n", operand.c_str()); #endif ops[opcode].push_back(operand); return p; case ' ': #ifdef DEBUG printf("\toperand = '%s'\n", operand.c_str()); #endif ops[opcode].push_back(operand); return p; default: operand += *p; } p++; } return p; } hoichess_0.10.3/src/search.h0000640000175000017500000001023010732031250015232 0ustar oliveroliver/* $Id: search.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/search.h * * Copyright (C) 2004-2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef SEARCH_H #define SEARCH_H #include "common.h" #include "board.h" #include "book.h" #include "clock.h" #include "eval.h" #include "game.h" #include "hash.h" #include "historytable.h" #include "move.h" #include "movelist.h" #include "shell.h" #include "thread.h" #include "tree.h" /* forward declaration */ class Shell; class Search { public: enum search_modes_e { MOVE, ANALYZE, PONDER }; enum params_time_e { PARAM_TIME_FL = 0x01, PARAM_TIME_IC = 0x02, PARAM_TIME_NB = 0x04, PARAM_TIME_FH = 0x08 }; private: Shell * shell; /* external data structures */ Evaluator * evaluator; HashTable * hashtable; HistoryTable * histtable[2]; Book * book; /* information about game */ const Game * game; Clock * clock; /* tree */ Tree tree; int rootdepth; int maxdepth; unsigned int maxplyreached; unsigned int maxplyreached_quiesce; /* search mode */ int mode; Color myside; /* parameters */ unsigned long param_time; /* thread/control stuff */ Mutex start_mutex; Mutex main_mutex; Thread * thread; bool stop; /* required for time control and basic statistics */ unsigned long nodes; unsigned long nodes_quiesce; unsigned long next_timecheck; unsigned long next_update; #ifdef COLLECT_STATISTICS /* extended statistics */ unsigned long stat_cut; unsigned long stat_nullcut; unsigned long stat_futcut; unsigned long stat_xfutcut; unsigned long stat_razcut; unsigned long stat_moves_sum; unsigned long stat_moves_cnt; unsigned long stat_moves_sum_quiesce; unsigned long stat_moves_cnt_quiesce; #endif /* overall statistics */ unsigned long ostat_knodes; unsigned long ostat_csecs; unsigned int ostat_depth_sum; unsigned int ostat_depth_cnt; /* flags */ bool showthinking; public: Search(Shell * shell); ~Search(); public: void start(Game game, int mode, Color myside = NO_COLOR); void start(const Board & board, const Clock & clock, int mode); void start_thread(Game game, int mode, Color myside = NO_COLOR); void stop_thread(); static void * thread_main(void * arg); void interrupt(); Move get_best(); void set_book(Book * book); void set_depthlimit(unsigned int depth); void set_hashtable(HashTable * hashtable); void set_pawnhashtable(PawnHashTable * pawnhashtable); void set_evalcache(EvaluationCache * evalcache); void set_showthinking(bool x); Evaluator * get_evaluator() const; void set_param(const std::string& name, const std::string& value); private: void main(); void iterate(); int search_root(unsigned int ply, int depth, int alpha, int beta); int search(unsigned int ply, int depth, int extend, int alpha, int beta); int quiescence_search(unsigned int ply, int alpha, int beta); bool is_draw(); private: void check_time(); void reset_statistics(); void print_statistics(); void update_overall_statistics(); void print_overall_statistics(); void print_header(); void print_thinking(unsigned int depth); void print_thinking_terminal(unsigned int depth); void print_thinking_xboard(unsigned int depth); void print_result(unsigned int depth, int score, char c); void print_result_terminal(unsigned int depth, int score, char c); void print_result_xboard(unsigned int depth, int score, char c); std::string get_best_line(unsigned int depth, char c) const; void clear_line(); }; #endif // SEARCH_H hoichess_0.10.3/src/clock.h0000640000175000017500000000364010732031250015067 0ustar oliveroliver/* $Id: clock.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/clock.h * * Copyright (C) 2004, 2005 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef CLOCK_H #define CLOCK_H #include "common.h" #ifdef WIN32 # include "gettimeofday.h" #else # include #endif class Clock { private: enum clock_mode { NONE, CONV, INCR, SUDDENDEATH, EXACT } mode; bool running; struct timeval start_tv; unsigned int elapsed; unsigned int limit; unsigned int hard_limit; int remaining_time; unsigned int remaining_moves; unsigned int base_time; unsigned int base_moves; unsigned int increment; public: Clock(); Clock(unsigned int secs); Clock(unsigned int moves, unsigned int secs, unsigned int inc); ~Clock() {} public: void start(); unsigned int stop(); void turn_back(); private: void update() const; void do_update(); public: void allocate_time(); void allocate_more_time(const char * reason = NULL); private: void check_limit(); public: bool timeout() const; unsigned int get_limit() const; unsigned int get_elapsed_time() const; void set_remaining_time(unsigned int csecs); void print(FILE * fp = stdout) const; }; #endif // CLOCK_H hoichess_0.10.3/src/pawnhash.h0000640000175000017500000000723510732031250015611 0ustar oliveroliver/* $Id: pawnhash.h 1462 2007-12-18 20:49:56Z holger $ * * HoiChess/pawnhash.h * * Copyright (C) 2004-2006 Holger Ruckdeschel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef PAWNHASH_H #define PAWNHASH_H #include "common.h" #include "board.h" #include "hash.h" #include "move.h" #include "util.h" /***************************************************************************** * * Class PawnHashEntry * *****************************************************************************/ class PawnHashEntry { friend class PawnHashTable; private: Hashkey hashkey; int phase; int score[2]; #ifdef HOICHESS Bitboard passed[2]; #endif // HOICHESS public: FORCEINLINE PawnHashEntry(); FORCEINLINE ~PawnHashEntry() {} public: inline bool is_valid() const; inline void set_invalid(); inline Hashkey get_hashkey() const; inline void set_hashkey(Hashkey hashkey); inline unsigned int get_phase() const; inline void set_phase(unsigned int phase); inline int get_score(Color side) const; inline void set_score(Color side, int score); #ifdef HOICHESS inline Bitboard get_passed(Color side) const; inline void set_passed(Color side, Bitboard bb); #endif // HOICHESS }; inline PawnHashEntry::PawnHashEntry() { phase = -1; } inline bool PawnHashEntry::is_valid() const { return (phase != -1); } inline void PawnHashEntry::set_invalid() { phase = -1; } inline Hashkey PawnHashEntry::get_hashkey() const { return hashkey; } inline void PawnHashEntry::set_hashkey(Hashkey hashkey) { this->hashkey = hashkey; } inline unsigned int PawnHashEntry::get_phase() const { ASSERT_DEBUG(phase >= 0); return phase; } inline void PawnHashEntry::set_phase(unsigned int phase) { this->phase = phase; } inline int PawnHashEntry::get_score(Color side) const { return score[side]; } inline void PawnHashEntry::set_score(Color side, int score) { this->score[side] = score; } #ifdef HOICHESS inline Bitboard PawnHashEntry::get_passed(Color side) const { return passed[side]; } inline void PawnHashEntry::set_passed(Color side, Bitboard bb) { this->passed[side] = bb; } #endif // HOICHESS /***************************************************************************** * * Class PawnHashTable * *****************************************************************************/ class PawnHashTable { private: unsigned long table_size; PawnHashEntry * table; unsigned long entries; #ifdef COLLECT_STATISTICS unsigned long stat_probes; unsigned long stat_hits; unsigned long stat_hits2; unsigned long stat_collisions; #endif // COLLECT_STATISTICS public: PawnHashTable(unsigned long size); ~PawnHashTable(); public: void clear(); bool put(const PawnHashEntry & entry); bool probe(Hashkey hashkey, PawnHashEntry * entry); inline void incr_hits2(); void print_info(FILE * fp = stdout) const; void print_statistics(FILE * fp = stdout) const; void reset_statistics(); }; inline void PawnHashTable::incr_hits2() { STAT_INC(stat_hits2); } #endif // HASHPAWN_H hoichess_0.10.3/README0000640000175000017500000000425110732031250013713 0ustar oliveroliver=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= | | | HoiChess | | | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= HoiChess is an xboard compatible chess engine. It is written in C++ for GNU/Linux, but should work on most other Unix like systems. Since version 0.2.4, HoiChess also fully supports Win32 platforms. HoiChess was written by Holger Ruckdeschel , with some contributions by other people (see "Acknowledgments" below). See http://www.hoicher.de/hoichess for more information and new releases. Acknowledgments --------------- Special thanks go to Jim Ablett and Dann Corbit for their contributions and help in connection with the Win32 support. Special thanks also to Leo Dijksman, for his bug reports and help in testing HoiChess in hard tournament life. Documentation ------------- Currently, the only existing documentation is a Unix man page, which is included in the source distribution of HoiChess. This man page is also available in HTML format as hoichess.6.html in both the source and the Win32 distributions. Copyright --------- Copyright (C) 2004-2006 Holger Ruckdeschel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Please report any bugs and suggestions to . hoichess_0.10.3/hoichess.6.html0000640000175000017500000003541510732031250015700 0ustar oliveroliver HoiChess


NAME

hoichess - xboard compatible chess engine

hoixiangqi - xiangqi engine


SYNOPSIS

hoichess [options]

hoixiangqi [options]


DESCRIPTION

hoichess is a chess playing program. It implements major parts of the xboard/winboard chess engine protocol.

hoichess uses many of the standard techniques found in modern chess programs, like rotated bitboards, principal variation search, quiescence search, transposition table and iterative deepening.

See xboard(6) for instructions about how to use hoichess through xboard. To start up quickly, you just need the command: xboard -fcp hoichess.

hoixiangqi is a xiangqi (``Chinese chess'') playing program. Currently, it also uses the xboard/winboard protocol. However, there is no user interface that supports this protocol. In the future, a different protocol might be used.

hoichess and hoixiangqi are built from the same code base, so nearly all commands and options, as well as the text based user interface, are the same for both programs.

If run hoichess or hoixiangqi at the command line, the help command gives you a brief summary of available commands. See section COMMANDS for more details about those commands.


OPTIONS

-h, --help

Display usage information.

-V, --version

Display version information.

-v, --verbose[=n]

Increase verbosity. Multiple -v options may be given. --verbose=n sets verbosity level n.

-d, --debug[=n]

Increase debug level. Multiple -d options may be given. --debug=n sets debug level n.

-L filename, --logfile filename

Specify file name for logging. The log will be appended to this file. Note: Logging is not yet implemented in the current version of HoiChess, so the log will be empty.

-x, --xboard[=arg]

Start in xboard compatible mode. This turns off the input prompt and alters the output format to meet the requirements of the xboard protocol. Normally, this option should not be necessary because hoichess automatically detects when it is started under xboard.

The optional argument can be one of:

off

Force non-xboard mode.

on

Force xboard mode.

auto

Automatically enable xboard mode when stdout is not a terminal, which is the case when HoiChess is started under xboard.

This is the default.

--book filename

Set location of opening book.

--nobook

Disable opening book.

--hashsize arg

Set the size of the main hash table (transposition table). The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively.

A size of 0 disables the hash table.

--pawnhashsize arg

Set the size of the pawn hash table. The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively.

A size of 0 disables the pawn hash table.

--evalcache arg

Set the size of the evaluation cache. The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively.

A size of 0 disables the evaluation cache.

--name name

Set engine's name to name.

--rcfile filename

Before accepting input from stdin, first read commands (and probably moves) from filename.

--color arg

Control usage of ANSI color control sequences, e.g. when displaying the chess board.

arg can be one of:

off

Never use ANSI color sequences.

on

Always use ANSI color sequences.

auto

Automatically use ANSI color sequences when stdout is a terminal.

On Unix platforms, the default is auto. On Windows platforms, the default is off, because the Windows terminal is normally not ANSI capable.


COMMANDS

hoichess supports most commands of the XBoard protocol. Those commands are described in detail at http://www.tim-mann.org/xboard/engine-intf.html. Furthermore, the following special commands are also available:

help

Give a brief summary about available commands.

bench movegen

Run move generator benchmark.

bench evaluator

Run evaluator benchmark.

bench makemove

Run benchmark for make_move and unmake_move routines.

book open bookfile

Use opening book bookfile.

book close

Disable opening book.

book create bookfile pgnfile depth min_move_count

Create a new opening book, from the games in pgnfile. The new book will be written to bookfile.

The parameter depth specifies how many moves (half-moves, ply) of each game will be included in the opening book. If depth is 0, there is no depth limit, i.e. all moves of all games will be put into the book.

The parameter min_move_count specifies how many times a move must be played until it is added to the opening book.

debug level

Set debug level to level.

If level is omitted, the current debug level is printed.

evalcache clear

Clear evaluation cache.

evalcache size arg

Set the size of the evaluation cache. The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively.

A size of 0 disables the evaluation cache.

evalcache off

Disable evaluation cache.

evalcache info

Print information about evaluation cache.

evalcache stats

Print evaluation cache statistics.

hash clear

Clear hash table.

hash size arg

Set the size of the main hash table (transposition table). The size is given in bytes, the suffixes 'K' and 'M' (e.g. '32M') may be used to specify size in kilobytes or megabytes, respectively.

A size of 0 disables the hash table.

hash off

Disable hash table.

hash info

Print information about hash table.

hash stats

Print hash table statistics.

hash replace scheme

Set hash table replacement scheme. Currently available schemes are:

  • always

    Always replace existing entries by new entries.

  • depth

    Replace existing entries only by entries with same or higher search depth.

ignore command

From now on, ignore the command command. This is basically intended for debugging.

See also command obey.

obey command

Do not ignore the command command anymore.

See also command ignore.

pawnhash ...

Configure the pawn hash table. The available options are the same as for the main hash table (see command hash), with the exception that pawnhash replace is not available, because the pawn hash table always uses the ``always replace'' strategy.

verbose level

Set verbosity level to level.

If level is omitted, the current verbosity level is printed.

source file

Read commands from file, just like command line option --rcfile does.

show board

Display the chess board.

show fen

Print the current position's FEN.

show moves|captures|noncaptures|escapes

Show all legal moves, captures, non-captures or escapes.

show eval

Evaluate current position and print result.

show clocks

Show both players' clocks.

show game

Show information about entire game, e.g. past positions, moves played, etc..

solve epdfile

Run search on all positions in epdfile (testsuite mode).


SEE ALSO

http://www.hoicher.de/hoichess

xboard(6)


AUTHOR

hoichess was written by Holger Ruckdeschel <holger@hoicher.de>.

This manual page was generated with pod2man(1).

hoichess_0.10.3/BUGS0000640000175000017500000000017410732031250013516 0ustar oliveroliver=-=-=-=-=-=-=-=-=-=-=-=-=-= | Open Bugs in HoiChess | =-=-=-=-=-=-=-=-=-=-=-=-=-= No important bugs known at the moment.