hoichess-0.22.0/0000750000175000017500000000000013276601731012723 5ustar holgerholgerhoichess-0.22.0/README0000640000175000017500000000424613276601731013612 0ustar holgerholger=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= | | | 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 binary distributions. Copyright --------- Copyright (C) 2004-2008 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.22.0/bin/0000750000175000017500000000000013276601731013473 5ustar holgerholgerhoichess-0.22.0/bin/builddir-wrapper0000750000175000017500000000051013276601731016671 0ustar holgerholger#!/bin/sh set -e name=`basename "$0"` if [ "$name" = "builddir-wrapper" ]; then # called as "builddir-wrapper progname args" name="$1" shift dir=`dirname "$0"` else # called via symlink to builddir-wrapper me=`readlink -f "$0"` dir=`dirname "$me"` fi arch=`gcc -dumpmachine` exec "$dir"/../build/"$arch"/"$name" "$@" hoichess-0.22.0/utils/0000750000175000017500000000000013276601731014063 5ustar holgerholgerhoichess-0.22.0/utils/logstats.pl0000750000175000017500000000064313276601731016266 0ustar holgerholger#!/usr/bin/perl # # Read HoiChess log file and print some statistics. use warnings; use strict; my $sum_nodes = 0; my $sum_nps = 0; my $num_nps = 0; while (<>) { if (/^Info: nodes_total=(\d+) /) { $sum_nodes += $1; } elsif (/^Info: searchtime=\d+.\d+ nps=(\d+)/) { $sum_nps += $1; $num_nps++; } } my $avg_nps = $num_nps != 0 ? int($sum_nps / $num_nps) : 0; print("sum_nodes=$sum_nodes avg_nps=$avg_nps\n") hoichess-0.22.0/utils/solvelog2html.pl0000750000175000017500000000320213276601731017221 0ustar holgerholger#!/usr/bin/perl # # This is a simple script that reads the results of a testsuite run # (command 'solve') from a HoiChess log file and generates a nice # html table. # # Usage: hoichess -L logfile # (run 'solve' command) # solvelog2html.pl logfile > results.html use warnings; use strict; my $positions_per_row = 10; my $i = 0; print_prolog("xyz"); while (<>) { chomp; #if (s/^solve: (.*)$/$1/) { # $i = 0; # next; #} els if (/^SOLVE\s+(\d+)\s+(\d+)\s+(.*)\s+([01])\s+(.*)/) { my ($total, $right, $move, $correct, $pos) = ($1, $2, $3, $4, $5); print_result($pos, $move, $correct); } elsif (/^SOLVE_DONE\s+(\d+)\s+(\d+)/) { my ($total, $right) = ($1, $2); print_epilog($total, $right); } } ############################################################################### sub print_prolog { my ($testsuite) = @_; print("

Testsuite: $testsuite

"); print(''); print(''); for (my $j=1; $j<=$positions_per_row; $j++) { print(""); } print("\n"); } sub print_result { my ($pos, $move, $correct) = @_; if ($i % $positions_per_row == 0) { print(''); print(""); } print(''); if ($i % $positions_per_row == $positions_per_row-1) { print("\n"); } $i++; } sub print_epilog { my ($total, $correct) = @_; print('
+$j
$i'); print("$pos
"); if ($correct) { print(''); } else { print(''); } print("$move"); print('
'); printf("

Correct: %d of %d (%d%%)

", $correct, $total, $total != 0 ? $correct/$total*100 : 0); } hoichess-0.22.0/src/0000750000175000017500000000000013276601731013512 5ustar holgerholgerhoichess-0.22.0/src/uint64_table.cc0000640000175000017500000012464413276601731016335 0ustar holgerholger#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.22.0/src/common.h0000640000175000017500000000450413276601731015157 0ustar holgerholger/* 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" #ifndef PROGNAME # if defined(HOICHESS) # define PROGNAME "HoiChess" # elif defined(HOIXIANGQI) # define PROGNAME "HoiXiangqi" # else # error "neither HOICHESS nor HOIXIANGQI is defined" # endif #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 #endif /* WIN32 */ #ifdef __leonbare__ # include "sparc32/leon/printf.h" # include "sparc32/leon/usleep.h" #endif /* * Include own versions of library functions is required */ #ifndef HAVE_SNPRINTF # include "lib/snprintf.h" #endif #ifndef HAVE_STRTOK_R # include "lib/strtok_r.h" #endif /* * 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 */ #define INFO_PRFX "Info: " #endif // COMMON_H hoichess-0.22.0/src/spinlock.cc0000640000175000017500000000236313276601731015650 0ustar holgerholger/* Copyright (C) 2005-2017 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 "spinlock.h" Spinlock::Spinlock() { #if defined(HAVE_PTHREAD) int res = pthread_spin_init(&lck, PTHREAD_PROCESS_PRIVATE); ASSERT(res == 0); #elif defined(WIN32) BOOL res = InitializeCriticalSectionAndSpinCount(&cs, (DWORD) -1); ASSERT(res); #endif } Spinlock::~Spinlock() { #if defined(HAVE_PTHREAD) int res = pthread_spin_destroy(&lck); ASSERT(res == 0); #elif defined(WIN32) DeleteCriticalSection(&cs); /* void */ #endif } hoichess-0.22.0/src/common/0000750000175000017500000000000013276601731015002 5ustar holgerholgerhoichess-0.22.0/src/common/shell.cc0000640000175000017500000003504613276601731016431 0ustar holgerholger/* Copyright (C) 2004-2008 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 "shell.h" #include #ifdef HAVE_READLINE # include # include #endif #include #include #include Shell::Shell() { xboard = false; flag_force = false; flag_ponder = false; flag_showthinking = false; flag_analyze = false; flag_playboth = false; source.name = "(stdin)"; source.line = 0; source.fp = stdin; register_commands(shell_commands); register_option("verbose", (int *) &verbose, verbose); register_option("debug", (int *) &debug, debug); #define SHELL_DEFINE_OPTION SHELL_REGISTER_OPTION # include "shell_option_defs.h" #undef SHELL_DEFINE_OPTION register_option("echo", &echo, echo); set_myname(NULL); Clock clock(5); game = new Game(Board(), clock, clock); book = NULL; #ifdef WITH_THREAD parallel = 0; #endif search = new Search(this); maxdepth = MAXDEPTH; last_status_line_length = 0; } Shell::~Shell() { delete search; delete book; delete game; } int Shell::main() { cmd_new(); if (!isatty(1)) { /* probably output is redirected to a log file, so * don't print lines with \r that will be overwritten */ print_search_output_terminal_newline = true; } if (!xboard && (source.fp != stdin || !isatty(0))) { printf("Reading %s\n", source.name.c_str()); } 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()) { /* let engine search in background */ engine_ponder(); } else if (flag_analyze) { /* let engine search in background */ engine_analyze(); } if (input() != SHELL_CMD_OK) { return EXIT_FAILURE; } } stop_search(); printf("\n"); for (std::list >::iterator it = atexit_commands.begin(); it != atexit_commands.end(); it++) { exec_command(*it); } return EXIT_SUCCESS; } /* * 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) { delete book; bool ok; book = new Book(bookfile, &ok); if (!ok) { /* Yuck! Under xboard, we must not print messages * containing things like 'no such file' because this * will cause an immediate abort. * Because when trying to open the default book * xboard mode has not yet been set, we also check * if stdout is a tty, supposing xboard mode if not. */ if (xboard || !isatty(1)) { printf("Failed to open opening book `%s'.\n", bookfile); } else { printf("Failed to open opening book `%s': %s\n", bookfile, strerror(errno)); } book = NULL; } else { printf("Opening book: %s\n", bookfile); } } else { delete book; book = NULL; } } /* * Set the size of the hash table in bytes. 0 disables hash table. */ void Shell::set_hash_size(size_t bytes) { stop_search(); search->set_hash_size(bytes); /* save value so that cmd_cores() has it available when * re-creating search */ hashsize = bytes; } size_t Shell::get_hash_size() const { return hashsize; } /* * Set the size of the pawn hash table in bytes. 0 disables pawn hash table. */ void Shell::set_pawnhash_size(size_t bytes) { stop_search(); search->set_pawnhash_size(bytes); /* save value so that cmd_cores() has it available when * re-creating search */ pawnhashsize = bytes; } size_t Shell::get_pawnhash_size() const { return pawnhashsize; } /* * Set the size of the evaluation cache in bytes. 0 disables evaluation cache. */ void Shell::set_evalcache_size(size_t bytes) { stop_search(); search->set_evalcache_size(bytes); /* save value so that cmd_cores() has it available when * re-creating search */ evalcachesize = bytes; } size_t Shell::get_evalcache_size() const { return evalcachesize; } /* * Set the engine's name. */ void Shell::set_myname(const char * name) { if (name) { myname = name; } else { myname = PROGNAME + std::string(" ") + VERSION; } } /* * Get the engine's name. */ const char * Shell::get_myname() const { return myname.c_str(); } /* * Set/unset xboard mode. */ void Shell::set_xboard(bool x) { xboard = x; if (xboard) { setbuf(stdout, NULL); } } 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; } int Shell::exec_command(const char * s) { /* Need s writable for strtok. */ char * s1 = strdup(s); ASSERT(s1 != NULL); /* Tokenize the input. */ std::vector args; const char * delim = " \t\n"; char * strtok_r_buf; for (char * p = strtok_r(s1, delim, &strtok_r_buf); p != NULL; p = strtok_r(NULL, delim, &strtok_r_buf)) { args.push_back(p); } free(s1); /* Ignore empty commands and comments. */ if (args.size() == 0 || args[0][0] == '#') { return SHELL_CMD_OK; } return exec_command(args); } int Shell::exec_command(const std::vector& args) { cmd_args = args; #ifdef WIN32 const char * vbegin_delim = "$%"; #else const char * vbegin_delim = "$"; #endif /* this allows variable names to start with a number, but we can * live with that */ const char * varchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz0123456789_"; /* Environment variable substitution. Currently only $VAR syntax, * not ${VAR}. On Windows, also accept %VAR%. */ for (std::vector::iterator it = cmd_args.begin(); it != cmd_args.end(); it++) { size_t pos = 0; size_t vbegin, vend; while ((vbegin = it->find_first_of(vbegin_delim, pos)) != std::string::npos) { size_t len; if ((*it)[vbegin] == '%') { vend = it->find_first_of("%", vbegin + 1); len = vend - vbegin + 1; if (vend == std::string::npos) { break; } } else { vend = it->find_first_not_of(varchars, vbegin + 1); len = vend - vbegin; } std::string var = it->substr(vbegin + 1, vend - vbegin - 1); const char * tmp = getenv(var.c_str()); if (tmp != NULL) { std::string val = tmp; it->replace(vbegin, len, val); pos = vbegin + val.length(); } else { pos += len; } } } if (echo) { printf("#"); for (std::vector::const_iterator it = cmd_args.begin(); it != cmd_args.end(); it++) { printf(" %s", it->c_str()); } printf("\n"); } /* Walk through the list of registered commands. */ for (std::list::iterator it = commands.begin(); it != commands.end(); it++) { if (cmd_args[0] != it->name) continue; /* If a function is registered, call it. */ if (it->func != NULL) { return (this->*it->func)(); } else { printf("Error (command not implemented): %s\n", cmd_args[0].c_str()); return SHELL_CMD_FAIL; } } /* The input wasn't recognized as a command, * so check if it is a move. */ if (cmd_args.size() == 1) { if (input_move(cmd_args[0])) { return SHELL_CMD_OK; } } printf("Error (unknown command): %s\n", cmd_args[0].c_str()); return SHELL_CMD_FAIL; } void Shell::register_commands(const struct Shell::command* cmds) { for (int i=0; cmds[i].name != NULL; i++) { commands.push_back(cmds[i]); } } void Shell::register_option(const char * name, int * varptr, int defval) { struct option opt; opt.name = name; opt.varptr = varptr; option_list.push_back(opt); *varptr = defval; } int Shell::input() { char * line = get_line(get_prompt().c_str()); if (line == NULL) { quit = true; return SHELL_CMD_OK; } /* Strip trailing \n and \r */ while (line[strlen(line)-1] == '\n' || line[strlen(line)-1] == '\r') { line[strlen(line)-1] = '\0'; } /* When command from script fails, exit */ int ret = exec_command(line); if (ret != SHELL_CMD_OK && (source.fp != stdin || !isatty(0))) { return SHELL_CMD_FAIL; } free(line); return SHELL_CMD_OK; } char * Shell::get_line(const char * prompt) { again: char * line; if (source.fp == NULL) { return NULL; } int fd = fileno(source.fp); if (xboard) { line = get_line_fgets(source.fp, NULL); } else if (fd == 0 && isatty(fd)) { #ifdef HAVE_READLINE line = get_line_readline(prompt); #else line = get_line_fgets(stdin, 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(); if (!xboard && (source.fp != stdin || !isatty(0))) { printf("Reading %s\n", source.name.c_str()); } 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()); if (game->is_running() && !flag_analyze) { const Clock * clock = game->get_clock(); Clock::val_t elapsed = clock->get_elapsed_time(); if (!clock->is_exact()) { Clock::val_t remaining = clock->get_remaining_time(); s += strprintf(" (%.2f/%.2f sec)", Clock::to_s_f(elapsed), Clock::to_s_f(remaining));; } else { s += strprintf(" (%.2f sec)", Clock::to_s_f(elapsed)); } } s += ": "; s += a2; if (flag_analyze || (flag_ponder && flag_showthinking)) { s += "\n"; } return s; } bool Shell::input_move(std::string input) { if (game->is_over()) { printf("Illegal move (game over): %s\n", input.c_str()); return false; } else if (game->get_side() == myside) { printf("Illegal move (it's my turn): %s\n", input.c_str()); return false; } Board board = game->get_board(); Move mov = board.parse_move(input); if (mov) { stop_search(); user_move(mov); return true; } else { printf("Illegal move: %s\n", input.c_str()); return false; } } 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); game->make_move(mov, 0); 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(2, "user move: %s", san.c_str()); DBG(2, "result = %d", game->get_result()); if (game->get_result()) { print_result(); } } void Shell::engine_move() { if (!xboard) { printf("Thinking...\n"); } game->start(); Board board = game->get_board(); Movelist movelist; board.generate_moves(&movelist); movelist.filter_illegal(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 if (movelist.size() == 1) { /* If there is only one move, don't waste any time * searching it. */ mov = movelist[0]; bookmove = false; } else { DBG(1, "starting search..."); mov = search->start(game, game->get_clock(), Search::MOVE, myside, maxdepth); DBG(1, "search terminated"); 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()); } } if (verbose >= 1) { printf(INFO_PRFX "bookmove=%d\n", bookmove); } std::string san = mov.san(board); game->make_move(mov, GameEntry::FLAG_COMPUTER | (bookmove ? GameEntry::FLAG_BOOKMOVE : 0)); 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(2, "engine move: %s", san.c_str()); DBG(2, "result = %d", game->get_result()); if (game->get_result()) { print_result(); } } void Shell::engine_analyze() { #ifdef WITH_THREAD DBG(1, "starting background search..."); search->start_thread(game, NULL, Search::ANALYZE, NO_COLOR, maxdepth); #else BUG("no thread support compiled in"); #endif } void Shell::engine_ponder() { #ifdef WITH_THREAD DBG(1, "starting background search..."); search->start_thread(game, NULL, Search::PONDER, myside, maxdepth); #else BUG("no thread support compiled in"); #endif } void Shell::stop_search() { #ifdef WITH_THREAD search->stop_thread(); #endif } void Shell::print_result() { atomic_printf("%s {%s}\n", game->get_result_str().c_str(), game->get_result_comment().c_str()); } hoichess-0.22.0/src/common/hash.h0000640000175000017500000001173213276601731016103 0ustar holgerholger/* 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 "node.h" #include "util.h" #include "spinlock.h" /***************************************************************************** * * Class HashEntry * *****************************************************************************/ class HashEntry { friend class HashTable; public: enum hashentry_type { NONE, EXACT, ALPHA, BETA }; private: Hashkey hashkey; unsigned short type; unsigned short depth; int score; Move move; public: FORCEINLINE HashEntry(); inline 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 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; } 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 HashEntryPV * *****************************************************************************/ #define HASHENTRYPV_MAXMOVES 8 class HashEntryPV { friend class HashTable; private: Move moves[HASHENTRYPV_MAXMOVES]; unsigned int len; public: FORCEINLINE HashEntryPV(); FORCEINLINE ~HashEntryPV() {} }; inline HashEntryPV::HashEntryPV() { len = 0; } /***************************************************************************** * * Class HashTable * *****************************************************************************/ /* To reduce the average time that threads need to wait for the lock, devide * the table into multiple domains, each with its own lock. If the number of * lock domains is sufficiently large, the probability that a thread needs to * access a table entry of an already locked domain should be rather low. * (The extreme case would be one lock per table entry, but that is * infeasible of course.) * For efficiency, we start with a constant power of two here and see how * it works. The lock domain is determined from the table key by a simple * modulo division. */ #define HASHTABLE_LOCK_DOMAINS 64 class HashTable { private: unsigned long table_size; HashEntry * table; HashEntryPV * pvtable; Spinlock spinlock[HASHTABLE_LOCK_DOMAINS]; Spinlock stats_spinlock; unsigned long stat_probes; unsigned long stat_hits; unsigned long stat_collisions2; public: HashTable(size_t bytes, bool enable_pvline = false); ~HashTable(); public: void clear(); bool put(const HashEntry & entry, const struct Node::pvline * pvline = NULL); bool probe(const Board & board, HashEntry * entry, struct Node::pvline * pvline = NULL); void print_info(FILE * fp = stdout) const; void print_statistics(FILE * fp = stdout) const; void reset_statistics(); private: inline void lock(unsigned long long key); inline void unlock(unsigned long long key); inline void lock_stats(); inline void unlock_stats(); }; inline void HashTable::lock(unsigned long long key) { /* Unconditionally use the lock. We assume that spinlock * implementation is so efficient that an extra check if * this is a shared hash table is not worth or even increases * overhead. */ unsigned int domain = key % HASHTABLE_LOCK_DOMAINS; spinlock[domain].lock(); } inline void HashTable::unlock(unsigned long long key) { unsigned int domain = key % HASHTABLE_LOCK_DOMAINS; spinlock[domain].unlock(); } inline void HashTable::lock_stats() { /* Unconditionally use the lock. We assume that spinlock * implementation is so efficient that an extra check if * this is a shared hash table is not worth or even increases * overhead. */ stats_spinlock.lock(); } inline void HashTable::unlock_stats() { stats_spinlock.unlock(); } #endif // HASH_H hoichess-0.22.0/src/common/parallelsearch.cc0000640000175000017500000004346413276601731020307 0ustar holgerholger/* Copyright (C) 2015 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 "parallelsearch.h" #include "shell.h" #include #include #include #define SHOPT(x) (shell->get_option_##x()) /***************************************************************************** * * Constructor / Destructor * *****************************************************************************/ ParallelSearch::ParallelSearch(Shell * shell, unsigned int nthreads) : Search(shell) { for (unsigned int i=0; iinterrupt(); slaves[i].search->stop_slave_thread(); /* get statistics from slave */ get_slave_statistics(i); /* free the slave */ slaves[i].node->free(); slaves[i].free = true; } ready_queue.clear(); } void ParallelSearch::get_slave_statistics(unsigned int id) { unsigned long long tmp; tmp = slaves[id].search->get_nodes_fullwidth(); nodes_fullwidth += tmp - slaves[id].last_nodes_fullwidth; slaves[id].last_nodes_fullwidth = tmp; tmp = slaves[id].search->get_nodes_quiesce(); nodes_quiesce += tmp - slaves[id].last_nodes_quiesce; slaves[id].last_nodes_quiesce = tmp; unsigned int tmp2; tmp2 = slaves[id].search->get_maxplyreached_fullwidth(); if (tmp2 > maxplyreached_fullwidth) { maxplyreached_fullwidth = tmp2; } tmp2 = slaves[id].search->get_maxplyreached_quiesce(); if (tmp2 > maxplyreached_quiesce) { maxplyreached_quiesce = tmp2; } } /***************************************************************************** * * Callbacks from slave. * These are called within slave thread context. * *****************************************************************************/ void ParallelSearch::slave_ready(const Search * me) { /* The ready_queue stores the slave index, so look up the slave * pointer within slaves[]. * Doing it here (i.e. in slave thread context) saves a tiny little bit * of computation time in the master thread, and the slave thread * won't get new work anyway as long as the master is busy. */ for (unsigned int i=0; iget_option_search_failsoft()) int ParallelSearch::search(Node * node, unsigned int ply, int depth, int extend, int alpha, int beta) { /* * For shallow depth, don't do any parallel search. Instead, * call one slave for the whole current node. * The other slaves can catch up through shared hash table * and the like. */ if (depth < SHOPT(search_parallel_min_depth)) { return nonparallel_search(node, ply, depth, extend, alpha, beta); } /* * If there are only very few (legal) moves, it is not worth * searching in parallel, so we go back to normal search for * this node. */ node->generate_all_moves(); unsigned int nmoves = node->get_movelist_size(); unsigned int minmoves = SHOPT(search_parallel_min_move_ratio) * slaves.size(); if (nmoves < minmoves) { return Search::search(node, ply, depth, extend, alpha, beta); } /* * Search the node in parallel. */ return parallel_search(node, ply, depth, extend, alpha, beta); } int ParallelSearch::parallel_search(Node * node, unsigned int ply, int depth, int extend, int alpha, int beta) { /* We do not support quiescence search. */ ASSERT(depth > 0); int drawscore; if (is_draw(node, ply, &drawscore)) { if (failsoft) { return drawscore; } else { /* strict fail hard */ return bound_score(drawscore, alpha, beta); } } int save_alpha = alpha; /* need old value to save in hash table */ int score; int bestscore = -INFTY; int moves = 0; nodes_fullwidth++; if (ply > maxplyreached_fullwidth) { maxplyreached_fullwidth = ply; } if (depth > 0 && probe_hashtable(node, depth, alpha, beta, &score)) { return score; } /* Null-move forward pruning */ bool null_ok = !(node->get_parent()->get_played_move().is_null()) && !(Evaluator::get_phase(node->get_board()) == Evaluator::ENDGAME); if (!node->in_check() && null_ok) { Node * child = node->make_move(Move::null(), &nodealloc); score = -search(child, ply+1, depth-2-1, 0, -beta, -beta+1); child->free(); if (score >= beta) { stat_nullcut++; if (failsoft) { return score; } else { return beta; /* fail hard */ } } } /* * 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_pvmove() && !node->get_hashmv() && depth > 2) { search(node, ply, depth-2, 0, alpha, beta); node->set_hashmv(node->get_best_move()); } node->set_type(Node::FULLWIDTH); node->set_historytable(histtable[node->get_board().get_side()]); /* * Search the first move by its own using a recursive call * of the master search. The remaining moves are searched * in parallel by the available slaves. * The same will happen for the first move one ply deeper, * and so on. */ Move mov = node->first(); Node * child = node->make_move(mov, &nodealloc); if (!child->get_board().is_legal()) { BUG("illegal move at parallel node: %s", mov.str().c_str()); } moves++; score = -search(child, ply+1, depth-1, extend, -beta, -alpha); if (!failsoft && (score < alpha || score > beta) && !stop) { printf("parallel_search(first): fail hard condition violated:" " score=%d alpha=%d beta=%d\n", score, alpha, beta); } check_time(true, false); if (stop) { child->free(); /* We don't get any useful result after canceling the * alpha-beta search, so iterate() must return the * result of the previous (completed) iteration. * For that reason, we can return an arbitrary value * here, because iterate() won't use it anyway. */ return INT_MIN; } if (score > bestscore) { bestscore = score; node->set_best(mov, child); } child->free(); if (score > alpha) { alpha = score; } if (score >= beta) { if (!failsoft) { score = beta; /* fail hard */ } goto done; } /* Parallel search of remaining moves. */ mov = node->next(); int id; /* slave ID */ while (1) { /* first, give all free slaves a legal move to search */ for (; mov && (id = find_free_slave()) >= 0; mov = node->next()) { Node * child = node->make_move(mov, slaves[id].nodealloc); if (!child->get_board().is_legal()) { BUG("illegal move at parallel node: %s", mov.str().c_str()); //child->free(); //continue; } moves++; /* The slave has its own hash table, but also probe * the master's table. Maybe we can provide the slave * a PV found earlier by another slave. As we do not * use the score, the valus for alpha and beta are * not important. */ probe_hashtable(child, depth-1, -beta, -alpha, &score); /* principal variation search */ bool nullwin = (SHOPT(search_parallel_pvs_mode) == 1) /* this is never the first move here */ || (SHOPT(search_parallel_pvs_mode) == 2 && alpha > save_alpha); /* start the slave */ DBG(1, "start slave %d\n", id); ASSERT(slaves[id].free); slaves[id].free = false; slaves[id].node = child; if (nullwin) { slaves[id].pvs_nullwin = true; slaves[id].search->start_slave_thread(this, game, clock, mode, myside, child, ply+1, depth-1, extend, -alpha-1, -alpha); } else { slaves[id].pvs_nullwin = false; slaves[id].search->start_slave_thread(this, game, clock, mode, myside, child, ply+1, depth-1, extend, -beta, -alpha); } slaves[id].calls++; } /* if now all slaves are free, there were no more moves * left to be assigned, so we're done */ if (all_slaves_free()) { break; } /* if time is over (or we're stopped by other means), * terminate all slaves and return */ check_time(true, false); if (stop) { DBG(1, "time over, abort all slaves\n"); abort_all_slaves(); /* We don't get any useful result after canceling the * alpha-beta search, so iterate() must return the * result of the previous (completed) iteration. * For that reason, we can return an arbitrary value * here, because iterate() won't use it anyway. */ return INT_MIN; } /* wait until the next slave gets ready */ DBG(1, "wait for slave ready\n"); id = wait_slave_ready(); DBG(1, "slave %d ready\n", id); /* get result from slave */ score = -slaves[id].search->stop_slave_thread(); Move slave_mov = slaves[id].node->get_played_move(); /* get statistics from slave */ get_slave_statistics(id); /* if the PVS assumption failed, restart slave search for the * same node, but this time with full alpha-beta window */ if (slaves[id].pvs_nullwin && score > alpha && score < beta) { DBG(1, "start slave %d again\n", id); slaves[id].pvs_nullwin = false; slaves[id].search->start_slave_thread(this, game, clock, mode, myside, slaves[id].node, ply+1, depth-1, extend, -beta, -alpha); slaves[id].calls++; continue; } /* check for alpha not possible because alpha may have been * improved since the slave was started */ if (!failsoft && score > beta && !stop) { printf("parallel_search(): fail hard condition violated:" " score=%d alpha=%d beta=%d\n", score, alpha, beta); } if (score > bestscore) { bestscore = score; node->set_best(slave_mov, slaves[id].node); } /* see above call to probe_hashtable() */ store_hashtable(slaves[id].node, depth-1, -beta, -save_alpha, score); /* free the slave */ slaves[id].node->free(); slaves[id].free = true; if (score > alpha) { alpha = score; } if (score >= beta) { if (!failsoft) { score = beta; /* fail hard */ } /* alpha has already been updated */ DBG(1, "cutoff, abort all slaves\n"); abort_all_slaves(); break; } } done: /* Test for checkmate or stalemate */ if (moves == 0) { #if defined(HOICHESS) int matescore = node->in_check() ? (-INFTY + ply) : DRAW; #elif defined(HOIXIANGQI) int matescore = -INFTY + ply; #else # error "neither HOICHESS nor HOIXIANGQI is defined" #endif if (failsoft) { bestscore = matescore; } else { /* strict fail hard */ alpha = bound_score(matescore, alpha, beta); } } /* Save search result in hash table. */ if (failsoft) { store_hashtable(node, depth, save_alpha, beta, bestscore); } else { store_hashtable(node, depth, save_alpha, beta, alpha); } add_history(node); add_killer(node); stat_moves_sum += moves; stat_moves_cnt++; if (failsoft) { return bestscore; } else { return alpha; } } int ParallelSearch::nonparallel_search(Node * node, unsigned int ply, int depth, int extend, int alpha, int beta) { int drawscore; if (depth > 0 && is_draw(node, ply, &drawscore)) { if (failsoft) { return drawscore; } else { /* strict fail hard */ return bound_score(drawscore, alpha, beta); } } int score; /* Probe hash table. Although the slave has its own hash table, * we can possibly provide a PV (TODO) or even avoid calling the slave * at all. */ if (depth > 0 && probe_hashtable(node, depth, alpha, beta, &score)) { return score; } /* start the slave */ int id = find_free_slave(); ASSERT(id >= 0); DBG(1, "start slave %d\n", id); slaves[id].free = false; slaves[id].node = node; slaves[id].search->start_slave_thread(this, game, clock, mode, myside, node, ply, depth, extend, alpha, beta); slaves[id].calls++; /* wait until the slave gets ready */ int id1 = wait_slave_ready(); ASSERT(id1 == id); /* get result from slave */ score = slaves[id].search->stop_slave_thread(); DBG(1, "slave %d finished\n", id); /* slave may have terminated due to time limit, so check time also * in master so that the stop flag can get set */ check_time(true, false); if (!failsoft && (score < alpha || score > beta) && !stop) { printf("nonparallel_search(): fail hard condition violated:" " score=%d alpha=%d beta=%d\n", score, alpha, beta); } /* get statistics from slave */ get_slave_statistics(id); /* free the slave */ slaves[id].free = true; /* Save search result in hash table. */ store_hashtable(node, depth, alpha, beta, score); return score; } /***************************************************************************** * * These functions will be called by the shell to configure and control * the search. * *****************************************************************************/ void ParallelSearch::interrupt() { DBG(2, "interrupt"); stop = true; unsigned int nslaves = slaves.size(); for (unsigned int i=0; iinterrupt(); } } void ParallelSearch::set_hash_size(size_t bytes) { /* We distribute the given size equally among all slaves * and the master. */ unsigned int nslaves = slaves.size(); size_t bytes_master = bytes / (nslaves + 1); size_t bytes_slave = bytes_master; size_t bytes_slave_shared = bytes - bytes_master; /* master */ if (SHOPT(search_parallel_hash_pvtable)) { Search::set_hash_size_pvline(bytes_master); } else { Search::set_hash_size(bytes_master); } /* slaves */ if (SHOPT(search_parallel_shared_hash)) { delete shared_hashtable; shared_hashtable = new HashTable(bytes_slave_shared); for (unsigned int i=0; iset_hash_table(shared_hashtable); } } else { delete shared_hashtable; shared_hashtable = NULL; for (unsigned int i=0; iset_hash_size(bytes_slave); } } } void ParallelSearch::clear_hash() { Search::clear_hash(); unsigned int nslaves = slaves.size(); for (unsigned int i=0; iclear_hash(); } } void ParallelSearch::set_pawnhash_size(size_t bytes) { /* We distribute the given size equally among all slaves. * Of course, the master does not get a pawn hash. */ unsigned int nslaves = slaves.size(); size_t bytes1 = bytes / nslaves; for (unsigned int i=0; iset_pawnhash_size(bytes1); } } void ParallelSearch::clear_pawnhash() { unsigned int nslaves = slaves.size(); for (unsigned int i=0; iclear_pawnhash(); } } void ParallelSearch::set_evalcache_size(size_t bytes) { /* We distribute the given size equally among all slaves. * Of course, the master does not get an evaluation cache. */ unsigned int nslaves = slaves.size(); size_t bytes1 = bytes / nslaves; for (unsigned int i=0; iset_evalcache_size(bytes1); } } void ParallelSearch::clear_evalcache() { unsigned int nslaves = slaves.size(); for (unsigned int i=0; iclear_evalcache(); } } /***************************************************************************** * * Search statistics. * *****************************************************************************/ void ParallelSearch::print_statistics() { printf(INFO_PRFX "=== parallel search statistics ===\n"); printf(INFO_PRFX "--- master ---\n"); Search::print_statistics(); for (unsigned int i=0; iprint_statistics(); } } printf(INFO_PRFX "==================================\n"); } void ParallelSearch::reset_statistics() { Search::reset_statistics(); for (unsigned int i=0; ireset_statistics(); slaves[i].calls = 0; slaves[i].last_nodes_fullwidth = 0; slaves[i].last_nodes_quiesce = 0; } } hoichess-0.22.0/src/common/epd.cc0000640000175000017500000001221513276601731016063 0ustar holgerholger/* Copyright (C) 2004-2008 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 "epd.h" #include "game.h" #include "util.h" #include #include #include #include /* * 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(); } /* * Get a list of all operands for an the 'bm' opcode converted to Moves. */ std::list EPD::get_bm() const { std::list bms_str = get("bm"); Board board(get_fen().c_str()); std::list bms; for (std::list::iterator it = bms_str.begin(); it != bms_str.end(); it++) { Move m = board.parse_move(*it); if (!m) { WARN("get_bm(): illegal move: %s", it->c_str()); continue; } bms.push_back(m); } return bms; } /***************************************************************************** * * EPD parsing functions. * *****************************************************************************/ 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.22.0/src/common/search_util.cc0000640000175000017500000001446513276601731017626 0ustar holgerholger/* Copyright (C) 2004-2008 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 "shell.h" #include /***************************************************************************** * * Search statistics. * *****************************************************************************/ void Search::print_statistics() { /* If print_statistics() is called before the first search has * been started, there is no clock yet. This can happen e.g. * during parallel search when a slave is never started due to * small search tree. We don't want to hide this problem, so * just check and expect the caller to handle it. */ ASSERT(clock != NULL); int csecs = Clock::to_cs(clock->get_elapsed_time()); unsigned long long nodes_total = nodes_fullwidth + nodes_quiesce; printf(INFO_PRFX "nodes_total=%llu nodes_fullwidth=%llu" " nodes_quiesce=%llu\n", nodes_total, nodes_fullwidth, nodes_quiesce); printf(INFO_PRFX "searchtime=%.2f nps=%.0f\n", (float) csecs / 100, nodes_total / ((float) csecs / 100) ); printf(INFO_PRFX "cuts_beta=%ld cuts_null=%ld cuts_fut=%ld" " cuts_xfut=%ld cuts_razor=%ld\n", stat_cut, stat_nullcut, stat_futcut, stat_xfutcut, stat_razcut); printf(INFO_PRFX "avg_branchfactor_fullwidth=%.2f" " avg_branchfactor_quiesce=%.2f\n", (float) stat_moves_sum / stat_moves_cnt, (float) stat_moves_sum_quiesce / stat_moves_cnt_quiesce); if (hashtable) { hashtable->print_statistics(); } evaluator->print_statistics(); } void Search::reset_statistics() { nodes_fullwidth = 0; nodes_quiesce = 0; /* maxplyreached_fullwidth and maxplyreached_quiesce are reset * in iterate() so they can be tracked for each iteration * separately (matter of taste) */ 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; if (hashtable) { hashtable->reset_statistics(); } evaluator->reset_statistics(); } unsigned long long Search::get_nodes_fullwidth() const { return nodes_fullwidth; } unsigned long long Search::get_nodes_quiesce() const { return nodes_quiesce; } unsigned int Search::get_maxplyreached_fullwidth() const { return maxplyreached_fullwidth; } unsigned int Search::get_maxplyreached_quiesce() const { return maxplyreached_quiesce; } /***************************************************************************** * * Thinking output. * *****************************************************************************/ void Search::print_header() { shell->print_search_header(); } /* * Print thinking output. */ void Search::print_thinking(unsigned int depth) { unsigned long csecs = Clock::to_cs(clock->get_elapsed_time()); /* pack all information into structure that is passed to shell */ struct searchinfo si; si.depth = depth; si.csecs = csecs; si.csecs_alloc = Clock::to_cs(clock->get_limit()); si.nodes_total = nodes_fullwidth + nodes_quiesce; si.maxplyreached_fullwidth = maxplyreached_fullwidth; si.maxplyreached_quiesce = maxplyreached_quiesce; get_root_progress(&si.n, &si.i, &si.mov); si.board = rootnode->get_board(); /* call shell for actual output */ shell->print_search_info(&si); } /* * Print search result. */ void Search::print_result(unsigned int depth, int score, enum searchresult::resulttype type, const struct Node::pvline& pvline) { int csecs = Clock::to_cs(clock->get_elapsed_time()); /* pack all information into structure that is passed to shell */ struct searchresult sr; sr.type = type; sr.depth = depth; sr.score = score; sr.csecs = csecs; sr.csecs_alloc = Clock::to_cs(clock->get_limit()); sr.nodes_total = nodes_fullwidth + nodes_quiesce; sr.best_line = Node::pvline2str(pvline, rootnode->get_board(), true); sr.maxplyreached_fullwidth = maxplyreached_fullwidth; sr.maxplyreached_quiesce = maxplyreached_quiesce; /* call shell for actual output */ shell->print_search_result(&sr); } void Search::get_root_progress(unsigned int * moves_total, unsigned int * current_move_no, Move * current_move) const { if (moves_total != NULL) { *moves_total = rootnode->get_movelist_size(); } if (current_move_no != NULL) { *current_move_no = rootnode->get_current_move_no(); } if (current_move != NULL) { *current_move = rootnode->get_current_move(); } } /***************************************************************************** * * These functions will be called by the shell to configure and control * the search. * *****************************************************************************/ void Search::set_hash_size(size_t bytes) { if (!shared_hashtable) { delete hashtable; } if (bytes > 0) { hashtable = new HashTable(bytes); hashtable->print_info(); } else { hashtable = NULL; } shared_hashtable = false; } void Search::set_hash_size_pvline(size_t bytes) { if (!shared_hashtable) { delete hashtable; } if (bytes > 0) { hashtable = new HashTable(bytes, true); hashtable->print_info(); } else { hashtable = NULL; } shared_hashtable = false; } void Search::set_hash_table(HashTable * table) { if (!shared_hashtable) { delete hashtable; } hashtable = table; hashtable->print_info(); shared_hashtable = true; } void Search::clear_hash() { if (hashtable) { hashtable->clear(); } } void Search::set_pawnhash_size(size_t bytes) { evaluator->set_pawnhash_size(bytes); } void Search::clear_pawnhash() { evaluator->clear_pawnhash(); } void Search::set_evalcache_size(size_t bytes) { evaluator->set_evalcache_size(bytes); } void Search::clear_evalcache() { evaluator->clear_evalcache(); } hoichess-0.22.0/src/common/eval.cc0000640000175000017500000001464413276601731016252 0ustar holgerholger/* Copyright (C) 2004-2008 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() { delete pawnhashtable; delete evalcache; } /***************************************************************************** * * 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_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 */ if (evalcache && evalcache->probe(board, &score)) { return score; } setup(&board); /* * phase 1 */ { 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_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(); if (evalcache) { evalcache->put(board, score); } return score; } void Evaluator::print_eval(const Board & board, Color _myside, FILE * fp) { myside = _myside; setup(&board); #if 0 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"))); #else fprintf(fp, INFO_PRFX "eval_material_white=%d" " eval_material_black=%d\n", board.material[WHITE], board.material[BLACK]); fprintf(fp, INFO_PRFX "eval_material_difference=%d\n", board.material[WHITE] - board.material[BLACK]); fprintf(fp, INFO_PRFX "eval_material_balance=%d\n", material_balance(board.material[WHITE], board.material[BLACK])); fprintf(fp, INFO_PRFX "eval_phase=%u eval_isdraw=%d\n", phase, is_draw(board)); #endif #if 0 fprintf(fp, "scoring plugins:\n"); #endif for (int i=0; plugins[i].name != NULL; i++) { ASSERT(plugins[i].func != NULL); int score_white = (this->*plugins[i].func)(WHITE); int score_black = (this->*plugins[i].func)(BLACK); #if 0 fprintf(fp, "\t%s: %d/%d\n", plugins[i].name, score_white, score_black); #endif fprintf(fp, INFO_PRFX "eval_plugin_%s_white=%d" " eval_plugin_%s_black=%d\n", plugins[i].name, score_white, plugins[i].name, score_black); } #if 0 fprintf(fp, "scoring plugins2:\n"); #endif for (int i=0; plugins2[i].name != NULL; i++) { ASSERT(plugins2[i].func != NULL); int score_white = (this->*plugins2[i].func)(WHITE); int score_black = (this->*plugins2[i].func)(BLACK); #if 0 fprintf(fp, "\t%s: %d/%d\n", plugins2[i].name, score_white, score_black); #endif fprintf(fp, INFO_PRFX "eval_plugin2_%s_white=%d" " eval_plugin2_%s_black=%d\n", plugins2[i].name, score_white, plugins2[i].name, score_black); } } /***************************************************************************** * * Utility functions. * *****************************************************************************/ void Evaluator::reset_statistics() { stat_evals = 0; stat_evals_phase1 = 0; stat_evals_phase2 = 0; if (pawnhashtable) { pawnhashtable->reset_statistics(); } if (evalcache) { evalcache->reset_statistics(); } } void Evaluator::print_statistics(FILE * fp) const { #if 0 fprintf(fp, "Evaluations: %lu/%lu/%lu\n", stat_evals, stat_evals_phase1, stat_evals_phase2); #else fprintf(fp, INFO_PRFX "evals=%lu evals_phase1=%lu evals_phase2=%lu\n", stat_evals, stat_evals_phase1, stat_evals_phase2); #endif if (pawnhashtable) { pawnhashtable->print_statistics(fp); } if (evalcache) { evalcache->print_statistics(fp); } } void Evaluator::set_pawnhash_size(size_t bytes) { if (bytes > 0) { delete pawnhashtable; pawnhashtable = new PawnHashTable(bytes); pawnhashtable->print_info(); } else { delete pawnhashtable; pawnhashtable = NULL; } } void Evaluator::clear_pawnhash() { if (pawnhashtable) { pawnhashtable->clear(); } } void Evaluator::set_evalcache_size(size_t bytes) { if (bytes > 0) { delete evalcache; evalcache = new EvaluationCache(bytes); evalcache->print_info(); } else { delete evalcache; evalcache = NULL; } } void Evaluator::clear_evalcache() { if (evalcache) { evalcache->clear(); } } hoichess-0.22.0/src/common/epd.h0000640000175000017500000000277613276601731015740 0ustar holgerholger/* Copyright (C) 2004-2008 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 EPD_H #define EPD_H #include "common.h" #include "board.h" #include "move.h" #include #include #include 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; std::list get_bm() 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 // EPD_H hoichess-0.22.0/src/common/node.h0000640000175000017500000001375713276601731016116 0ustar holgerholger/* Copyright (C) 2005-2012 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 NODE_H #define NODE_H #include "common.h" #include "board.h" #include "historytable.h" class Node; class NodeAllocator { private: Node* pool; Node* next; Node* end; /* points 1 beyond last Node in pool */ public: NodeAllocator(unsigned long count); ~NodeAllocator(); public: inline Node* alloc(); static void free(Node* node); }; #define NODE_PVLINE_MAXMOVES MAXPLY class Node { friend class NodeAllocator; public: enum node_type { UNKNOWN, ROOT, FULLWIDTH, QUIESCE }; /* To collect the PV as described at * http://www.brucemo.com/compchess/programming/pv.htm */ struct pvline { unsigned int nmoves; Move moves[NODE_PVLINE_MAXMOVES]; }; private: NodeAllocator * _allocator; /* managed by class NodeAllocator */ /* tree structure */ const Node * parent; const Node * root; /* the board */ #ifdef USE_UNMAKE_MOVE BoardHistory hist; #else Board board; #endif /* caches to avoid recomputation when needed multiple times */ bool incheck; int material; /* movelist and move generator state */ Movelist movelist; int current_move_no; /* node parameters, move ordering, ... */ enum node_type type; struct pvline pvline; Move hashmv; Move killer1; Move killer2; HistoryTable * historytable; /* search result */ struct pvline best_line; /* the move that led to this node, i.e. was played at parent node */ Move played_move; public: Node(); Node(const Board& board); public: void init_root(); Node* make_move(Move mov, NodeAllocator * allocator) const; Node* copy(NodeAllocator * allocator) const; inline void free(); Move first(); Move next(); Move pick(); void score_moves(); void generate_all_moves(); inline const Node* get_parent() const; inline const Node* get_root() const; bool is_root() const; inline const Board& get_board() 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_move() const; inline const struct pvline& get_best_line() const; std::string get_best_line_str() const; void set_best(Move mov, const Node* child); void set_best_line(const struct pvline& best_line); inline Move get_hashmv() const; inline void set_hashmv(Move mov); inline Move get_pvmove() const; const struct pvline& get_pvline() const; std::string get_pvline_str() const; void set_pvline(const struct pvline & pvline); inline void set_historytable(HistoryTable * ht); inline void add_killer(Move mov); inline Move get_played_move() const; public: static std::string pvline2str(const struct Node::pvline& pvline, const Board& board, bool pretty); }; /***************************************************************************** * * Inline functions of class Node * *****************************************************************************/ inline void Node::free() { NodeAllocator::free(this); } inline const Node* Node::get_parent() const { return parent; } inline const Node* Node::get_root() const { return root; } inline bool Node::is_root() const { return (this == root); } inline const Board& Node::get_board() const { return board; } 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_move() const { if (best_line.nmoves == 0) { return NO_MOVE; } else { return best_line.moves[0]; } } inline const struct Node::pvline& Node::get_best_line() const { return best_line; } inline Move Node::get_hashmv() const { return hashmv; } inline void Node::set_hashmv(Move mov) { hashmv = mov; } inline Move Node::get_pvmove() const { if (pvline.nmoves == 0) { return NO_MOVE; } else { return pvline.moves[0]; } } 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 NodeAllocator * *****************************************************************************/ inline Node* NodeAllocator::alloc() { if (next == end) { return NULL; } Node * node = next++; node->_allocator = this; return node; } inline void NodeAllocator::free(Node* node) /* static */ { ASSERT_DEBUG(node->_allocator != NULL); ASSERT_DEBUG(node->_allocator->next - 1 == node); node->_allocator->next--; } #endif // NODE_H hoichess-0.22.0/src/common/movelist.h0000640000175000017500000000465213276601731017025 0ustar holgerholger/* 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" class Movelist { private: Move move[MOVELIST_MAXSIZE]; int score[MOVELIST_MAXSIZE]; unsigned int nextin; 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 HOICHESS void filter_illegal_castling(const Board & board); #endif bool operator==(const Movelist & ml2) const; bool operator!=(const Movelist & ml2) const; }; inline unsigned int Movelist::size() const { return nextin; } inline void Movelist::clear() { nextin = 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.22.0/src/common/movelist.cc0000640000175000017500000000354313276601731017161 0ustar holgerholger/* 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; } Movelist::~Movelist() {} void Movelist::filter_illegal(const Board & board) { 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 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); }; #endif // PGN_H hoichess-0.22.0/src/common/historytable.h0000640000175000017500000000331713276601731017671 0ustar holgerholger/* 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.22.0/src/common/pawnhash.cc0000640000175000017500000000455713276601731017136 0ustar holgerholger/* 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(size_t bytes) { ASSERT(bytes > 0); table_size = bytes / sizeof(PawnHashEntry); if (table_size == 0) { table_size = 1; } table = new PawnHashEntry[table_size]; reset_statistics(); } PawnHashTable::~PawnHashTable() { delete[] table; } void PawnHashTable::clear() { delete[] table; table = new PawnHashEntry[table_size]; reset_statistics(); } bool PawnHashTable::put(const PawnHashEntry & entry) { const unsigned long key = entry.hashkey % table_size; table[key] = entry; return true; } bool PawnHashTable::probe(Hashkey hashkey, PawnHashEntry * entry) { 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_hits++; return true; } void PawnHashTable::print_info(FILE * fp) const { fprintf(fp, INFO_PRFX "pawnhash_size_entries=%lu" " pawnhash_size_bytes=%lu\n", table_size, (unsigned long) (table_size * sizeof(PawnHashEntry))); } void PawnHashTable::print_statistics(FILE * fp) const { fprintf(fp, INFO_PRFX "pawnhash_probes=%lu" " pawnhash_hits=%lu pawnhash_hits2=%lu\n", stat_probes, stat_hits, stat_hits2); } void PawnHashTable::reset_statistics() { stat_probes = 0; stat_hits = 0; stat_hits2 = 0; } hoichess-0.22.0/src/common/shell_cmd.cc0000640000175000017500000006065313276601731017256 0ustar holgerholger/* 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" #ifdef WITH_THREAD # include "parallelsearch.h" #endif #include "epd.h" #include "pgn.h" #include #include #include #include #include const struct Shell::command Shell::shell_commands[] = { /* xboard protocol commands */ { "xboard", &Shell::cmd_xboard, "" }, { "protover", &Shell::cmd_protover, "" }, { "accepted", &Shell::cmd_accepted, "" }, { "rejected", &Shell::cmd_rejected, "" }, { "new", &Shell::cmd_new, "Start a new game" }, { "variant", &Shell::cmd_variant, "" }, { "quit", &Shell::cmd_quit, "Quit" }, { "random", &Shell::cmd_null, "" }, { "force", &Shell::cmd_force, "Let engine make no moves at all" }, { "go", &Shell::cmd_go, "Switch sides, let computer make next move" }, { "playother", NULL, "" }, { "white", NULL, "" }, { "black", NULL, "" }, { "level", &Shell::cmd_level, "" }, { "st", &Shell::cmd_st, "" }, { "sd", &Shell::cmd_sd, "" }, { "time", &Shell::cmd_time, "" }, { "otim", &Shell::cmd_otim, "" }, { "usermove", &Shell::cmd_usermove, "" }, { "?", &Shell::cmd_null, "" }, { "ping", &Shell::cmd_ping, "" }, { "draw", &Shell::cmd_null, "" }, { "result", &Shell::cmd_null, "" }, { "setboard", &Shell::cmd_setboard, "" }, { "edit", NULL, "" }, { "hint", NULL, "" }, { "bk", &Shell::cmd_bk, "" }, { "undo", &Shell::cmd_undo, "" }, { "remove", &Shell::cmd_remove, "" }, #ifdef WITH_THREAD { "hard", &Shell::cmd_hard, "Turn on pondering (thinking on opponent's time)" }, { "easy", &Shell::cmd_easy, "Turn off pondering" }, #else { "hard", &Shell::cmd_null, "Ignored (feature not compiled in)" }, { "easy", &Shell::cmd_null, "Ignored (feature not compiled in)" }, #endif { "post", &Shell::cmd_post, "Show thinking output" }, { "nopost", &Shell::cmd_nopost, "Hide thinking output" }, #ifdef WITH_THREAD { "analyze", &Shell::cmd_analyze, "Enter analysis mode" }, { "exit", &Shell::cmd_exit, "Leave analysis mode" }, #endif { "name", &Shell::cmd_null, "" }, { "rating", &Shell::cmd_null, "" }, { "ics", NULL, "" }, { "computer", &Shell::cmd_null, "" }, { "pause", NULL, "" }, { "resume", NULL, "" }, { ".", &Shell::cmd_null, "" }, #ifdef WITH_THREAD { "cores", &Shell::cmd_cores, "" }, #endif { "option", &Shell::cmd_option, "" }, /* own commands */ { "verbose", &Shell::cmd_verbose, "" }, { "debug", &Shell::cmd_debug, "" }, { "help", &Shell::cmd_help, "" }, { "source", &Shell::cmd_source, "" }, { "echo", &Shell::cmd_echo, "" }, { "noxboard", &Shell::cmd_noxboard, "" }, { "show", &Shell::cmd_show, "" }, { "solve", &Shell::cmd_solve, "" }, { "book", &Shell::cmd_book, "" }, { "hash", &Shell::cmd_hash, "" }, { "pawnhash", &Shell::cmd_pawnhash, "" }, { "evalcache", &Shell::cmd_evalcache, "" }, { "set", &Shell::cmd_set, "" }, { "get", &Shell::cmd_get, "" }, { "playboth", &Shell::cmd_playboth, "" }, { "loadgame", &Shell::cmd_loadgame, "" }, { "savegame", &Shell::cmd_savegame, "" }, { "redo", &Shell::cmd_redo, "" }, { "options", &Shell::cmd_options, "List all options and their current values" }, { "atexit", &Shell::cmd_atexit, "" }, { NULL, NULL, NULL } }; int Shell::cmd_null() { return SHELL_CMD_OK; } int Shell::cmd_xboard() { set_xboard(true); printf("\n"); return SHELL_CMD_OK; } int Shell::cmd_protover() { SHELL_CMD_REQUIRE_ARGS(1); std::ostringstream ss; ss << "feature"; /* replace " by ' and \ by / in myname */ std::string myname_sanitized = myname; for (size_t i = 0; i::iterator it = option_list.begin(); it != option_list.end(); it++) { ss << " option=\"" << it->name << " -spin " << *it->varptr << " " << INT_MIN << " " << INT_MAX << "\""; } ss << " done=1\n"; atomic_printf("%s", ss.str().c_str()); return SHELL_CMD_OK; } int Shell::cmd_accepted() { /* no reaction */ return SHELL_CMD_OK; } int Shell::cmd_rejected() { SHELL_CMD_REQUIRE_ARGS(1); printf("tellusererror Feature `%s' was rejected, expect problems\n", cmd_args[1].c_str()); return SHELL_CMD_OK; } int Shell::cmd_new() { stop_search(); if (!game->set_board(opening_fen())) { BUG("Failed to set up standard opening position"); } if (!flag_analyze) { flag_force = false; myside = BLACK; } return SHELL_CMD_OK; } int Shell::cmd_variant() { SHELL_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()); return SHELL_CMD_FAIL; } return SHELL_CMD_OK; } int Shell::cmd_quit() { quit = true; return SHELL_CMD_OK; } int Shell::cmd_force() { stop_search(); flag_force = true; flag_playboth = false; myside = NO_COLOR; return SHELL_CMD_OK; } int Shell::cmd_go() { stop_search(); flag_force = false; flag_playboth = false; myside = game->get_side(); /* Turn back the current side's clock, so we can think the full amount * of time, even though we've switched from human to engine. */ game->turn_back_clock(); return SHELL_CMD_OK; } int Shell::cmd_level() { SHELL_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 SHELL_CMD_FAIL; } Clock clock(moves, secs, inc); game->set_clocks(clock, clock); return SHELL_CMD_OK; } int Shell::cmd_st() { SHELL_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"); return SHELL_CMD_FAIL; } return SHELL_CMD_OK; } int Shell::cmd_sd() { SHELL_CMD_REQUIRE_ARGS(1); unsigned int depth = atoi(cmd_args[1].c_str()); if (depth == 0 || depth > MAXDEPTH) { maxdepth = MAXDEPTH; } else { maxdepth = depth; } printf("Search depth limited to %u ply.\n", maxdepth); return SHELL_CMD_OK; } int Shell::cmd_time() { SHELL_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 SHELL_CMD_FAIL; } if (myside != NO_COLOR) { game->set_remaining_time(myside, csecs); } return SHELL_CMD_OK; } int Shell::cmd_otim() { SHELL_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 SHELL_CMD_FAIL; } if (myside != NO_COLOR) { game->set_remaining_time(XSIDE(myside), csecs); } return SHELL_CMD_OK; } int Shell::cmd_usermove() { SHELL_CMD_REQUIRE_ARGS(1); if (input_move(cmd_args[1])) { return SHELL_CMD_OK; } else { return SHELL_CMD_FAIL; } } int Shell::cmd_ping() { SHELL_CMD_REQUIRE_ARGS(1); atomic_printf("pong %s\n", cmd_args[1].c_str()); return SHELL_CMD_OK; } int Shell::cmd_setboard() { stop_search(); #if defined(HOICHESS) SHELL_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]; #elif defined(HOIXIANGQI) SHELL_CMD_REQUIRE_ARGS(4); std::string fen = cmd_args[1] + " " + cmd_args[2] + " " + cmd_args[3] + " " + cmd_args[4]; #endif 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 SHELL_CMD_FAIL; } if (verbose) { print_result(); } return SHELL_CMD_OK; } int 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"); return SHELL_CMD_OK; } int Shell::cmd_undo() { stop_search(); 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"); } } } return SHELL_CMD_OK; } int Shell::cmd_remove() { stop_search(); game->undo_move(); game->undo_move(); return SHELL_CMD_OK; } int Shell::cmd_hard() { flag_ponder = true; return SHELL_CMD_OK; } int Shell::cmd_easy() { stop_search(); flag_ponder = false; return SHELL_CMD_OK; } int Shell::cmd_post() { flag_showthinking = true; return SHELL_CMD_OK; } int Shell::cmd_nopost() { flag_showthinking = false; return SHELL_CMD_OK; } #ifdef WITH_THREAD int Shell::cmd_analyze() { stop_search(); cmd_force(); cmd_post(); flag_analyze = true; return SHELL_CMD_OK; } int Shell::cmd_exit() { stop_search(); flag_analyze = false; return SHELL_CMD_OK; } #endif // WITH_THREAD #ifdef WITH_THREAD /* * cores 1 activates standard search * cores N, N>=2 activates parallel search with N threads * cores 0 activates parallel search with 1 thread (for testing) */ int Shell::cmd_cores() { unsigned int was_parallel = parallel; if (cmd_args.size() == 2) { unsigned int tmp = 0; if (sscanf(cmd_args[1].c_str(), "%u", &tmp) == 1) { if (tmp == 0) { parallel = 1; } else if (tmp == 1) { parallel = 0; } else { parallel = tmp; } } else { fprintf(stderr, "Illegal argument: %s\n", cmd_args[1].c_str()); return SHELL_CMD_FAIL; } } if (parallel == was_parallel) { /* no change */ return SHELL_CMD_OK; } if (parallel) { printf("Switching to parallel search with %u thread%s\n", parallel, (parallel==1 ? "" : "s")); stop_search(); delete search; search = new ParallelSearch(this, parallel); } else { printf("Switching to non-parallel search\n"); stop_search(); delete search; search = new Search(this); } /* restore hash size etc. */ search->set_hash_size(hashsize); search->set_pawnhash_size(pawnhashsize); search->set_evalcache_size(evalcachesize); return SHELL_CMD_OK; } #endif // WITH_THREAD int Shell::cmd_option() { SHELL_CMD_REQUIRE_ARGS(1); const std::string& tmp = cmd_args[1]; size_t i = tmp.find("="); if (i == std::string::npos) { printf("Illegal argument: %s\n", tmp.c_str()); return SHELL_CMD_FAIL; } std::string name = tmp.substr(0, i); std::string val = tmp.substr(i+1, tmp.length()); for (std::list::iterator it = option_list.begin(); it != option_list.end(); it++) { if (it->name == name) { int tmp; if (sscanf(val.c_str(), "%d", &tmp) != 1) { printf("Illegal value: %s\n", val.c_str()); return SHELL_CMD_FAIL; } *it->varptr = tmp; return SHELL_CMD_OK; } } printf("Illegal option: %s\n", name.c_str()); return SHELL_CMD_FAIL; } int 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); } return SHELL_CMD_OK; } int 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); } return SHELL_CMD_OK; } int Shell::cmd_help() { printf("Available commands:\n"); printf("\t\t\tPlay move (coordinate notation or SAN)\n"); for (std::list::iterator it = commands.begin(); it != commands.end(); it++) { if (it->func == NULL) continue; printf("\t%s\t\t%s\n", it->name, it->usage); } return SHELL_CMD_OK; } int Shell::cmd_source() { SHELL_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)); return SHELL_CMD_FAIL; } source_file(fp, filename); return SHELL_CMD_OK; } int 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()); return SHELL_CMD_OK; } int Shell::cmd_noxboard() { set_xboard(false); return SHELL_CMD_OK; } int Shell::cmd_show() { SHELL_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"); } return SHELL_CMD_OK; } int Shell::cmd_solve() { stop_search(); SHELL_CMD_REQUIRE_ARGS(1); const char * filename = cmd_args[1].c_str(); FILE * fp; bool close_fp; if (strcmp(filename, "-") == 0) { fp = stdin; close_fp = false; } else { fp = fopen(filename, "r"); if (fp == NULL) { printf("Cannot open %s: %s\n", filename, strerror(errno)); return SHELL_CMD_FAIL; } close_fp = true; } int right = 0; int wrong = 0; int total = 0; int skipped = 0; char buf[1024]; while (fgets(buf, sizeof(buf), fp) != NULL) { /* Strip trailing \n and \r */ while (buf[strlen(buf)-1] == '\n' || buf[strlen(buf)-1] == '\r') { buf[strlen(buf)-1] = '\0'; } if (strcmp(buf, ".") == 0) { break; } printf("--------------------------------------------------\n"); /* Parse EPD, print FEN */ EPD epd(buf); Board board(epd.get_fen().c_str()); printf("[%s] %s\n", epd.get1("id").c_str(), epd.get_fen().c_str()); /* Get the list of best moves */ std::list bms = epd.get_bm(); if (bms.size() == 0) { printf("No best move associated to this position," " skipping.\n"); skipped++; continue; } /* Print the list of best moves */ printf("[%s] best move:", epd.get1("id").c_str()); for (std::list::const_iterator it = bms.begin(); it != bms.end(); it++) { printf(" %s", it->san(board).c_str()); } printf("\n"); /* Reset search stuff */ search->clear_hash(); search->clear_pawnhash(); search->clear_evalcache(); /* Must copy the clock from the game because this is set * to the desired time limit. If a previous search was * interrupted, we might get here with a running clock, * so restart its copy. */ Clock clock = *game->get_clock(); clock.stop(); clock.turn_back(); clock.start(); /* Start search */ printf("\n"); board.print_small(); printf("\n"); printf("Thinking...\n"); Move mov = search->start(board, clock, Search::MOVE, maxdepth); if (!mov) { printf("Warning: search returned NO_MOVE" ", excluding position from result\n"); continue; } /* Look if our move is among the best. */ bool correct = false; std::list::const_iterator it; for (it = bms.begin(); it != bms.end(); it++) { if (*it == mov) { 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"); total = right + wrong; printf("Correct: %d of %d (%d%%), skipped: %d\n", right, total, 100 * right / total, skipped); printf("SOLVE %u %u %s %u %s\n", total, right, mov.san(board).c_str(), correct, epd.get1("id").c_str()); if (stop) { break; } } printf("SOLVE_DONE %u %u\n", total, right); if (close_fp) { fclose(fp); } return SHELL_CMD_OK; } int Shell::cmd_book() { SHELL_CMD_REQUIRE_ARGS(1); const std::string param = cmd_args[1]; if (param == "close" || param == "off") { delete book; book = NULL; } else if (param == "open") { SHELL_CMD_REQUIRE_ARGS(2); const char * file = cmd_args[2].c_str(); set_book(file); } else if (param == "create") { SHELL_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 SHELL_CMD_FAIL; } 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 SHELL_CMD_FAIL; } 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"); } return SHELL_CMD_OK; } int Shell::cmd_hash() { SHELL_CMD_REQUIRE_ARGS(1); const std::string param = cmd_args[1]; if (param == "clear") { search->clear_hash(); } else if (param == "size") { SHELL_CMD_REQUIRE_ARGS(2); const std::string& s = cmd_args[2]; ssize_t size; if (s == "-") { size = get_hash_size(); } else if (!parse_size(s.c_str(), &size) || size < 0) { printf("Illegal value for hash table size: %s\n", s.c_str()); return SHELL_CMD_FAIL; } stop_search(); set_hash_size((size_t) size); } else if (param == "off") { stop_search(); set_hash_size(0); } else { printf("Usage: hash clear\n"); printf(" hash size \n"); printf(" hash off\n"); } return SHELL_CMD_OK; } int Shell::cmd_pawnhash() { SHELL_CMD_REQUIRE_ARGS(1); const std::string param = cmd_args[1]; if (param == "clear") { search->clear_pawnhash(); } else if (param == "size") { SHELL_CMD_REQUIRE_ARGS(2); const char * s = cmd_args[2].c_str(); ssize_t size; if (!parse_size(s, &size) || size < 0) { printf("Illegal value for pawn hash table size: %s\n", s); return SHELL_CMD_FAIL; } stop_search(); set_pawnhash_size((size_t) size); } else if (param == "off") { stop_search(); set_pawnhash_size(0); } else { printf("Usage: pawnhash clear\n"); printf(" pawnhash size \n"); printf(" pawnhash off\n"); } return SHELL_CMD_OK; } int Shell::cmd_evalcache() { SHELL_CMD_REQUIRE_ARGS(1); const std::string param = cmd_args[1]; if (param == "clear") { search->clear_evalcache(); } else if (param == "size") { SHELL_CMD_REQUIRE_ARGS(2); const char * s = cmd_args[2].c_str(); ssize_t size; if (!parse_size(s, &size) || size < 0) { printf("Illegal value for evaluation cache size: %s\n", s); return SHELL_CMD_FAIL; } stop_search(); set_evalcache_size((size_t) size); } else if (param == "off") { stop_search(); set_evalcache_size(0); } else { printf("Usage: evalcache clear\n"); printf(" evalcache size \n"); printf(" evalcache off\n"); } return SHELL_CMD_OK; } int Shell::cmd_set() { SHELL_CMD_REQUIRE_ARGS(1); if (cmd_args[1] == "myname") { SHELL_CMD_REQUIRE_ARGS(2); std::string tmp; for (unsigned int i=2; i 2) { tmp += " "; } tmp += cmd_args[i]; } set_myname(tmp.c_str()); printf("myname set to \"%s\"\n", tmp.c_str()); } else { printf("Illegal argument to command 'set': '%s'\n", cmd_args[1].c_str()); return SHELL_CMD_FAIL; } return SHELL_CMD_OK; } int Shell::cmd_get() { SHELL_CMD_REQUIRE_ARGS(1); if (cmd_args[1] == "myname") { printf("myname = %s\n", myname.c_str()); } else { printf("Illegal argument to command 'get': '%s'\n", cmd_args[1].c_str()); return SHELL_CMD_FAIL; } return SHELL_CMD_OK; } int Shell::cmd_playboth() { stop_search(); flag_playboth = true; flag_force = false; return SHELL_CMD_OK; } int Shell::cmd_loadgame() { SHELL_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 SHELL_CMD_FAIL; } PGN pgn; pgn.parse(fp); fclose(fp); Game g(pgn, Clock(), Clock()); printf("--- begin read game ---\n"); g.write_pgn(stdout); printf("--- end read game ---\n"); stop_search(); *game = g; return SHELL_CMD_OK; } int Shell::cmd_savegame() { SHELL_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 SHELL_CMD_FAIL; } game->write_pgn(fp); fclose(fp); return SHELL_CMD_OK; } int Shell::cmd_redo() { stop_search(); 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 SHELL_CMD_OK; } } else { mov = game->redo_move(); if (!mov) { if (!xboard) { printf("No move to be redone.\n"); } return SHELL_CMD_OK; } } if (!xboard) { game->get_board().print(stdout, mov); if (game->get_result()) { print_result(); } } return SHELL_CMD_OK; } int Shell::cmd_options() { for (std::list::iterator it = option_list.begin(); it != option_list.end(); it++) { printf("%s = %d\n", it->name, *it->varptr); } return SHELL_CMD_OK; } int Shell::cmd_atexit() { SHELL_CMD_REQUIRE_ARGS(1); std::vector tmp = cmd_args; tmp.erase(tmp.begin()); atexit_commands.push_back(tmp); return SHELL_CMD_OK; } hoichess-0.22.0/src/common/pawnhash.h0000640000175000017500000000667213276601731017000 0ustar holgerholger/* 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 "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 stat_probes; unsigned long stat_hits; unsigned long stat_hits2; public: PawnHashTable(size_t bytes); ~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_hits2++; } #endif // HASHPAWN_H hoichess-0.22.0/src/common/hash.cc0000640000175000017500000001041113276601731016232 0ustar holgerholger/* 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 HashTable. * *****************************************************************************/ HashTable::HashTable(size_t bytes, bool enable_pvline) { ASSERT(bytes > 0); if (enable_pvline) { table_size = bytes / (sizeof(HashEntry) + sizeof(HashEntryPV)); } else { table_size = bytes / sizeof(HashEntry); } if (table_size == 0) { table_size = 1; } table = new HashEntry[table_size]; if (enable_pvline) { pvtable = new HashEntryPV[table_size]; } else { pvtable = NULL; } reset_statistics(); } HashTable::~HashTable() { delete[] table; delete[] pvtable; } void HashTable::clear() { delete[] table; table = new HashEntry[table_size]; /* pvtable does not need to be cleared, because its contents are * only used in combination with a normal table entry */ reset_statistics(); } bool HashTable::put(const HashEntry & entry, const struct Node::pvline * pvline) { const unsigned long long key = entry.hashkey % table_size; lock(key); table[key] = entry; /* An optimization would be to store the first move of pvline in * the normal table entry. However due to alignment, reducing * HASHENTRYPV_MAXMOVES by 1 might not save space anyway, so we * start without this optimization to keep the code simple. */ if (pvtable != NULL && pvline != NULL && pvline->nmoves > 0) { unsigned int n = MIN(pvline->nmoves, HASHENTRYPV_MAXMOVES); pvtable[key].len = n; memcpy(pvtable[key].moves, pvline->moves, n * sizeof(Move)); } else if (pvtable != NULL) { pvtable[key].len = 0; } unlock(key); return true; } bool HashTable::probe(const Board & board, HashEntry * entry, struct Node::pvline * pvline) { const unsigned long long key = board.get_hashkey() % table_size; lock_stats(); stat_probes++; unlock_stats(); lock(key); { /* For efficiency, first use a reference and copy only if * it is a hit. */ const HashEntry & e = table[key]; if (e.type == HashEntry::NONE || e.hashkey != board.get_hashkey()) { unlock(key); return false; } if (pvtable != NULL && pvline != NULL) { unsigned int n = MIN(pvtable[key].len, NODE_PVLINE_MAXMOVES); memcpy(pvline->moves, pvtable[key].moves, n * sizeof(Move)); pvline->nmoves = n; } else if (pvline != NULL) { pvline->nmoves = 0; } *entry = e; } /* end of scope of e */ unlock(key); /* If this entry has a move, make sure it is * valid for the given board position. */ if (entry->move) { if (!entry->move.is_valid(board)) { lock_stats(); stat_collisions2++; unlock_stats(); return false; } if (!entry->move.is_legal(board)) { WARN("illegal move in hash table"); return false; } } lock_stats(); stat_hits++; unlock_stats(); return true; } void HashTable::print_info(FILE * fp) const { size_t bytes; if (pvtable) { bytes = table_size * (sizeof(HashEntry) + sizeof(HashEntryPV)); } else { bytes = table_size * sizeof(HashEntry); } fprintf(fp, INFO_PRFX "hash_size_entries=%lu hash_size_bytes=%lu" " hash_pvtable=%d\n", table_size, (unsigned long) bytes, pvtable ? 1 : 0); } void HashTable::print_statistics(FILE * fp) const { fprintf(fp, INFO_PRFX "hash_probes=%lu hash_hits=%lu" " hash_collisions2=%lu\n", stat_probes, stat_hits, stat_collisions2); } void HashTable::reset_statistics() { stat_probes = 0; stat_hits = 0; stat_collisions2 = 0; } hoichess-0.22.0/src/common/evalcache.cc0000640000175000017500000000505113276601731017226 0ustar holgerholger/* 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(size_t bytes) { ASSERT(bytes > 0); cache_size = bytes / sizeof(struct cacheentry); if (cache_size == 0) { cache_size = 1; } cache = new struct cacheentry[cache_size]; for (unsigned long i = 0; i < cache_size; i++) { cache[i].score = INT_MIN; } 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; } reset_statistics(); } bool EvaluationCache::put(const Board & board, int score) { const Hashkey hashkey = board.get_hashkey_noside(); const unsigned long key = hashkey % cache_size; 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_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_hits++; return true; } void EvaluationCache::print_info(FILE * fp) const { fprintf(fp, INFO_PRFX "evalcache_size_entries=%lu" " evalcache_size_bytes=%lu\n", cache_size, (unsigned long) (cache_size * sizeof(cacheentry))); } void EvaluationCache::print_statistics(FILE * fp) const { fprintf(fp, INFO_PRFX "evalcache_probes=%lu evalcache_hits=%lu\n", stat_probes, stat_hits); } void EvaluationCache::reset_statistics() { stat_probes = 0; stat_hits = 0; } hoichess-0.22.0/src/common/node.cc0000640000175000017500000001771613276601731016253 0ustar holgerholger/* Copyright (C) 2005-2012 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 "node.h" #include #ifdef USE_UNMAKE_MOVE #error "USE_UNMAKE_MOVE currently not supported" #endif /***************************************************************************** * * Functions of class Node * *****************************************************************************/ Node::Node() { parent = NULL; root = NULL; historytable = NULL; pvline.nmoves = 0; best_line.nmoves = 0; } Node::Node(const Board& _board) { parent = NULL; root = NULL; board = _board; historytable = NULL; pvline.nmoves = 0; best_line.nmoves = 0; } void Node::init_root() { root = this; incheck = board.in_check(); material = board.material_difference(); movelist.clear(); generate_all_moves(); ASSERT(movelist.size() > 0); set_type(Node::ROOT); pvline.nmoves = 0; set_hashmv(NO_MOVE); killer1 = NO_MOVE; killer2 = NO_MOVE; /* Assign one legal move as best, in case search terminates without * choosing a move. */ best_line.moves[0] = movelist[0]; best_line.nmoves = 1; played_move = NO_MOVE; } Node * Node::make_move(Move mov, NodeAllocator * allocator) const { Node * child = allocator->alloc(); /* sets this->_allocator */ if (child == NULL) { BUG("Node alloc failed. MAXPLY reached?"); } child->parent = this; child->root = this->root; child->board = this->board; child->board.make_move(mov); child->incheck = child->board.in_check(); child->material = child->board.material_difference(); child->movelist.clear(); child->set_type(Node::UNKNOWN); /* if the PV move has been made, copy the rest of the pvline * to the child */ if (pvline.nmoves > 1 && pvline.moves[0] == mov) { memcpy(child->pvline.moves, pvline.moves+1, (pvline.nmoves-1)*sizeof(Move)); child->pvline.nmoves = pvline.nmoves - 1; } else { child->pvline.nmoves = 0; } child->set_hashmv(NO_MOVE); child->killer1 = NO_MOVE; child->killer2 = NO_MOVE; child->best_line.nmoves = 0; child->played_move = mov; return child; } Node * Node::copy(NodeAllocator * allocator) const { ASSERT(allocator != this->_allocator); Node * node1 = allocator->alloc(); /* sets this->_allocator */ if (node1 == NULL) { BUG("Node alloc failed. MAXPLY reached?"); } node1->parent = this->parent; node1->root = this->root; node1->board = this->board; node1->incheck = this->incheck; node1->material = this->material; node1->movelist = this->movelist; node1->current_move_no = this->current_move_no; node1->type = this->type; node1->pvline = this->pvline; node1->hashmv = this->hashmv; node1->killer1 = this->killer1; node1->killer2 = this->killer2; node1->historytable = NULL; /* TODO copy */ node1->best_line = this->best_line; node1->played_move = this->played_move; return node1; } Move Node::first() { current_move_no = -1; switch (type) { case ROOT: /* For the root node, all moves have been generated in * Node::init_root(). Scores were assigned by search_root() * using set_current_score(). So we can just start returning * moves. */ ASSERT(movelist.size() != 0); break; case FULLWIDTH: if (movelist.size() != 0) { /* Moves have already been generated * due to internal iterative deepening. */ } else if (in_check()) { board.generate_escapes(&movelist); } else { board.generate_moves(&movelist, false); } break; case QUIESCE: /* For some strange reason, movelist is not always * empty here...? */ movelist.clear(); if (in_check()) { board.generate_escapes(&movelist); } else { board.generate_captures(&movelist, false); } break; default: BUG("node type is bad: %d", type); } score_moves(); return pick(); } Move Node::next() { return pick(); } 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; i 0 && mov == pvline.moves[0]) { /* PV move */ score = 1000000; } else if (mov == hashmv) { /* hash move */ score = 900000; } else if (mov.is_capture() #ifdef HOICHESS || mov.is_promotion() || mov.is_enpassant() #endif ) { /* captures */ unsigned int mat_atk = mat_values[mov.ptype()]; unsigned int mat_vic = mat_values[mov.cap_ptype()]; #ifdef HOICHESS if (mov.is_promotion()) { mat_vic += mat_values[mov.promote_to()]; } #endif if (mat_vic > mat_atk) { /* winning capture */ score = 800000 + mat_vic - mat_atk; } else if (mat_vic < mat_atk) { /* losing capture */ score = 10000 + mat_vic - mat_atk; } else { /* equal capture */ score = 500000; } } else { /* non-captures */ if (mov == killer1 || mov == killer2) { score = 700000; } if (historytable) { score += MIN(historytable->get(mov), 100000); } } movelist.set_score(i, score); } } void Node::generate_all_moves() { /* TODO This could be optimized by looking which moves * have already been generated, e.g. due to IID. */ movelist.clear(); board.generate_moves(&movelist, false); movelist.filter_illegal(board); } std::string Node::get_best_line_str() const { return pvline2str(best_line, board, false); } void Node::set_best(Move mov, const Node* child) { best_line.moves[0] = mov; unsigned int n = MIN(child->best_line.nmoves, NODE_PVLINE_MAXMOVES-1); memcpy(best_line.moves+1, child->best_line.moves, n*sizeof(Move)); best_line.nmoves = n + 1; } void Node::set_best_line(const struct pvline& best_line) { this->best_line = best_line; } const struct Node::pvline& Node::get_pvline() const { return this->pvline; } std::string Node::get_pvline_str() const { return pvline2str(pvline, board, false); } void Node::set_pvline(const struct pvline & pvline) { this->pvline = pvline; } std::string Node::pvline2str(const struct Node::pvline& pvline, const Board& board, bool pretty) { std::ostringstream ss; Board tmpboard = board; for (unsigned int ply=0; ply 0) { ss << " "; } if (pretty) { if (tmpboard.get_side() == WHITE) { ss << tmpboard.get_moveno() << ". "; } else if (ply == 0) { /* && BLACK */ ss << tmpboard.get_moveno() << ". ... "; } } ss << mov.san(tmpboard); /* Limit output length to avoid xboard buffer overflow. */ if (ply >= 30) { ss << " [...]"; break; } tmpboard.make_move(mov); } return ss.str(); } /***************************************************************************** * * Functions of class NodeAllocator * *****************************************************************************/ NodeAllocator::NodeAllocator(unsigned long count) { pool = new Node[count]; next = pool; end = pool + count; } NodeAllocator::~NodeAllocator() { delete[] pool; } hoichess-0.22.0/src/common/parallelsearch.h0000640000175000017500000000467413276601731020151 0ustar holgerholger/* Copyright (C) 2015 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 PARALLELSEARCH_H #define PARALLELSEARCH_H #include "common.h" #include "search.h" #include "queue.h" #include class ParallelSearch : public Search { public: struct slave { Search * search; bool free; NodeAllocator * nodealloc; Node * node; bool pvs_nullwin; unsigned int calls; unsigned long long last_nodes_fullwidth; unsigned long long last_nodes_quiesce; }; protected: std::vector slaves; private: HashTable * shared_hashtable; private: Queue ready_queue; /* stores slave index */ public: ParallelSearch(Shell * shell, unsigned int nthreads); public: virtual ~ParallelSearch(); protected: void add_slave(Search * slave_search); int find_free_slave() const; bool all_slaves_free() const; unsigned int wait_slave_ready(); void abort_all_slaves(); void get_slave_statistics(unsigned int id); public: void slave_ready(const Search * me); protected: virtual int search(Node * node, unsigned int ply, int depth, int extend, int alpha, int beta); private: int parallel_search(Node * node, unsigned int ply, int depth, int extend, int alpha, int beta); int nonparallel_search(Node * node, unsigned int ply, int depth, int extend, int alpha, int beta); public: virtual void interrupt(); virtual void set_hash_size(size_t bytes); virtual void clear_hash(); virtual void set_pawnhash_size(size_t bytes); virtual void clear_pawnhash(); virtual void set_evalcache_size(size_t bytes); virtual void clear_evalcache(); public: virtual void print_statistics(); virtual void reset_statistics(); }; #endif // PARALLELSEARCH_H hoichess-0.22.0/src/common/shell_util.cc0000640000175000017500000002317113276601731017462 0ustar holgerholger/* Copyright (C) 2004-2008 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 "search.h" #include #include #include #include #include /***************************************************************************** * * Thinking output. * *****************************************************************************/ void Shell::print_search_header() { if (!flag_showthinking) { return; } if (!xboard) { printf("Depth Ply Time/Alloc Score Nodes Principal-Variation\n"); } } /* * Print thinking output. */ void Shell::print_search_info(struct Search::searchinfo * si) { if (!flag_showthinking) { return; } unsigned long csecs = si->csecs; if (xboard) { if (verbose >= 3 || (flag_analyze && csecs > 100) || csecs > 500) { print_search_info_xboard(si); } } else { if (verbose >= 3 || (isatty(1) && csecs > 1000)) { print_search_info_terminal(si); } } } /* * Print search result. */ void Shell::print_search_result(struct Search::searchresult * sr) { if (!flag_showthinking) { return; } unsigned long csecs = sr->csecs; enum Search::searchresult::resulttype type = sr->type; if (xboard) { if (type != Search::searchresult::INTERMEDIATE) { print_search_result_xboard(sr); } } else { if (verbose >= 2 || csecs > 500 || type != Search::searchresult::INTERMEDIATE) { print_search_result_terminal(sr); } } } /* * Print thinking output to terminal: * * 9? 4.15/10.00 1109710 1. e4 (1/20) [267k nps] */ void Shell::print_search_info_terminal(struct Search::searchinfo * si) { /* extract information from structure passed by search */ unsigned int depth = si->depth; unsigned long csecs = si->csecs; unsigned long csecs_alloc = si->csecs_alloc; unsigned long long nodes_total = si->nodes_total; unsigned int i = si->i; unsigned int n = si->n; Move mov = si->mov; const Board & board = si->board; unsigned int maxplyreached_fullwidth = si->maxplyreached_fullwidth; unsigned int maxplyreached_quiesce = si->maxplyreached_quiesce; std::string s; char buf[128]; /* depth */ snprintf(buf, sizeof(buf), "%2u? %2u/%2u", depth, maxplyreached_fullwidth+1, maxplyreached_quiesce+1); s += buf; /* elapsed search time */ if (csecs >= 6000) { unsigned int mins = csecs / 6000; unsigned int secs = csecs % 6000 / 100; snprintf(buf, sizeof(buf), " %2u:%02u", mins, secs); } else { snprintf(buf, sizeof(buf), " %5.2f", (float) csecs / 100); } s += buf; /* allocated search time */ if (csecs_alloc >= 6000) { unsigned int mins = csecs_alloc / 6000; unsigned int secs = csecs_alloc % 6000 / 100; snprintf(buf, sizeof(buf), "/%2u:%02u", mins, secs); } else { snprintf(buf, sizeof(buf), "/%5.2f", (float) csecs_alloc / 100); } s += buf; /* nodes */ if (nodes_total > (int)1E9) { snprintf(buf, sizeof(buf), " %8lluM ", nodes_total/(int)1E6); } else if (nodes_total > (int)10E6) { snprintf(buf, sizeof(buf), " %8lluk ", nodes_total/(int)1E3); } else { snprintf(buf, sizeof(buf), " %9llu ", nodes_total); } s += buf; /* current move */ if (mov) { 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 */ if (n != 0) { snprintf(buf, sizeof(buf), " (%u/%u)", i+1, n); s += buf; } /* nodes/s */ unsigned int nps = (csecs > 0) ? (nodes_total / csecs * 100) : 0; snprintf(buf, sizeof(buf), " [%uk nps]", nps/1000); s += buf; /* fill with spaces up to length of last partial line */ unsigned int len = s.length(); if (len < last_status_line_length) { s += std::string(last_status_line_length - len, ' '); } if (print_search_output_terminal_newline) { atomic_printf("%s\n", s.c_str()); last_status_line_length = 0; /* because we end this line with \n */ } else { atomic_printf("\r%s", s.c_str()); last_status_line_length = len; /* because we print a partial line that will be overwritten */ } fflush(stdout); } /* Whether we end every status line with \n or * have them overwritten by the next line. */ bool Shell::print_search_output_terminal_newline = false; /* * In xboard mode, when analyzing, we print out the stat01 line: * * stat01: time nodes ply mvleft mvtot mvname * * Note: The xboard protocol defines that the stat01 line is printed * as a response to the '.' command. However, we print the line freely, * but that obviously works well with xboard/winboard. */ void Shell::print_search_info_xboard(struct Search::searchinfo * si) { /* extract information from structure passed by search */ unsigned int depth = si->depth; unsigned long csecs = si->csecs; unsigned long long nodes_total = si->nodes_total; unsigned int i = si->i; unsigned int n = si->n; Move mov = si->mov; const Board & board = si->board; //unsigned int maxplyreached_fullwidth = si->maxplyreached_fullwidth; //unsigned int maxplyreached_quiesce = si->maxplyreached_quiesce; atomic_printf("stat01: %lu %llu %u %u %u %s\n", csecs, nodes_total, depth, n - i - 1, n, mov ? (mov.san(board).c_str()) : "(no move)"); } /* * Print search result to terminal. * * 7. 1.16/10.00 0.25 261225 1. e4 e5 2. Nf3 Nf6 3. Nxe5 Bd6 4. d4 */ void Shell::print_search_result_terminal(struct Search::searchresult * sr) { /* extract information from structure passed by search */ enum Search::searchresult::resulttype type = sr->type; unsigned int depth = sr->depth; int score = sr->score; unsigned long csecs = sr->csecs; unsigned long csecs_alloc = sr->csecs_alloc; unsigned long long nodes_total = sr->nodes_total; const std::string& best_line = sr->best_line; unsigned int maxplyreached_fullwidth = sr->maxplyreached_fullwidth; unsigned int maxplyreached_quiesce = sr->maxplyreached_quiesce; std::string s; char buf[128]; /* depth and result type */ char c; switch (type) { case Search::searchresult::INTERMEDIATE: c = ' '; break; case Search::searchresult::DEPTH: c = '.'; break; case Search::searchresult::FAILLOW: c = '-'; break; case Search::searchresult::FAILHIGH: c = '+'; break; case Search::searchresult::FINAL: c = ':'; break; default: BUG("illegal type: ", type); } snprintf(buf, sizeof(buf), "%2u%c %2u/%2u", depth, c, maxplyreached_fullwidth+1, maxplyreached_quiesce+1); s += buf; /* elapsed search time */ if (csecs >= 6000) { unsigned int mins = csecs / 6000; unsigned int secs = csecs % 6000 / 100; snprintf(buf, sizeof(buf), " %2u:%02u", mins, secs); } else { snprintf(buf, sizeof(buf), " %5.2f", (float) csecs / 100); } s += buf; /* allocated search time */ if (csecs_alloc >= 6000) { unsigned int mins = csecs_alloc / 6000; unsigned int secs = csecs_alloc % 6000 / 100; snprintf(buf, sizeof(buf), "/%2u:%02u", mins, secs); } else { snprintf(buf, sizeof(buf), "/%5.2f", (float) csecs_alloc / 100); } s += buf; /* score */ if (score >= MATE) { snprintf(buf, sizeof(buf), " Mat%2d", INFTY-score); } else if (score <= -MATE) { snprintf(buf, sizeof(buf), " -Mat%2d", score+INFTY); } else { snprintf(buf, sizeof(buf), " %7.2f", (float) score / 100); } s += buf; /* nodes */ if (nodes_total > (int)1E9) { snprintf(buf, sizeof(buf), " %8lluM ", nodes_total/(int)1E6); } else if (nodes_total > (int)10E6) { snprintf(buf, sizeof(buf), " %8lluk ", nodes_total/(int)1E3); } else { snprintf(buf, sizeof(buf), " %9llu ", nodes_total); } s += buf; /* pv line */ s += best_line; /* fill with spaces up to length of last partial line */ unsigned int len = s.length(); if (len < last_status_line_length) { s += std::string(last_status_line_length - len, ' '); } last_status_line_length = 0; /* because we end this line with \n */ if (print_search_output_terminal_newline) { atomic_printf("%s\n", s.c_str()); } else { atomic_printf("\r%s\n", s.c_str()); } fflush(stdout); } /* * Print search result in xboard mode: * * ply score time nodes pv */ void Shell::print_search_result_xboard(struct Search::searchresult * sr) { /* extract information from structure passed by search */ //enum Search::searchresult::resulttype type = sr->type; unsigned int depth = sr->depth; int score = sr->score; unsigned long csecs = sr->csecs; unsigned long long nodes_total = sr->nodes_total; const std::string& best_line = sr->best_line; //unsigned int maxplyreached_fullwidth = sr->maxplyreached_fullwidth; //unsigned int maxplyreached_quiesce = sr->maxplyreached_quiesce; const char * note = ""; switch (sr->type) { case Search::searchresult::FAILLOW: note = "(-) "; break; case Search::searchresult::FAILHIGH: note = "(+) "; break; case Search::searchresult::INTERMEDIATE: note = "(.) "; break; default: note = ""; break; } atomic_printf("%u %d %lu %llu %s%s\n", depth, score, csecs, nodes_total, note, best_line.c_str()); } hoichess-0.22.0/src/common/game.h0000640000175000017500000000710613276601731016071 0ustar holgerholger/* Copyright (C) 2004-2008 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 "pgn.h" #include class GameEntry { public: enum flags { FLAG_COMPUTER = 0x1, FLAG_BOOKMOVE = 0x2, }; private: Board board; /* position */ Move move; /* move that was played in this position */ Clock clock[2]; /* clocks at beginning */ unsigned int flags; /* more information about this->move */ public: GameEntry(const Board & board, Move mov, const Clock & wclock, const Clock & bclock, unsigned int flags); ~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]; } unsigned int get_flags() const { return flags; } }; 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; int result; std::string result_str; std::string result_comment; public: Game(const Board & board, const Clock & wclock, const Clock & bclock); Game(const PGN & pgn, const Clock & wclock, const Clock & bclock); ~Game() {} private: void construct(const Board & board, const Clock & wclock, const Clock & bclock); 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; const Clock* get_clock() const; Clock* get_clock(); const Clock* get_clock(Color side) const; const Board& get_opening() const; const std::list& get_entries() const; void start(); void make_move(Move mov, unsigned int flags); bool undo_move(); Move redo_move(); bool set_board(const std::string& fen); void set_board(const Board & board); void set_clocks(const Clock & wclock, const Clock & bclock); void turn_back_clock(); void set_remaining_time(Color side, unsigned int csecs); int repetitions(const Board & board) const; int last_bookmove() const; private: void check_result(); public: void print(FILE * fp = stdout) const; void write_pgn(FILE * fp = stdout) const; }; #endif // GAME_H hoichess-0.22.0/src/common/search.h0000640000175000017500000001724013276601731016425 0ustar holgerholger/* Copyright (C) 2004-2008 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 "clock.h" #include "eval.h" #include "game.h" #include "historytable.h" #include "move.h" #include "movelist.h" //#include "shell.h" #ifdef WITH_THREAD # include "mutex.h" # include "thread.h" #endif #include "node.h" /* forward declarations */ class Shell; class ParallelSearch; class HashTable; class Search { public: enum search_modes_e { MOVE, ANALYZE, PONDER }; struct searchinfo { unsigned int depth; // search depth unsigned long csecs; // elapsed time unsigned long csecs_alloc; // allocated search time unsigned long long nodes_total; // total nodes searched unsigned int maxplyreached_fullwidth; // maximum ply reached unsigned int maxplyreached_quiesce; // ... during q.s. unsigned int i; // number of current move unsigned int n; // total number of moves Move mov; // current move Board board; // current position (tree root) }; struct searchresult { enum resulttype { INTERMEDIATE, DEPTH, FAILLOW, FAILHIGH, FINAL } type; unsigned int depth; // search depth int score; // score unsigned long csecs; // elapsed time unsigned long csecs_alloc; // allocated search time unsigned long long nodes_total; // total nodes searched std::string best_line; // line of best moves unsigned int maxplyreached_fullwidth; // maximum ply reached unsigned int maxplyreached_quiesce; // ... during q.s. }; #ifdef WITH_THREAD protected: struct thread_args { Search * self; const Game * game; Clock * clock; int mode; Color myside; unsigned int maxdepth; /* Return values: We return by output parameters so we * don't need to manage a separate return data structure * to pass from the thread back to the caller. Instead, * the thread just returns its own argument. */ Move best; }; struct slave_search_args { Node * node; unsigned int ply; int depth; int extend; int alpha; int beta; }; struct slave_thread_args { Search * self; ParallelSearch * master; const Game * game; Clock * clock; int mode; Color myside; struct slave_search_args search_args; /* Return values: We return by output parameters so we * don't need to manage a separate return data structure * to pass from the thread back to the caller. Instead, * the thread just returns its own argument. */ int score; }; #endif protected: Shell * shell; protected: NodeAllocator nodealloc; Evaluator * evaluator; HashTable * hashtable; bool shared_hashtable; HistoryTable * histtable[2]; /* information about game */ protected: const Game * game; Clock * clock; protected: Node * rootnode; private: unsigned int rootdepth; /* search mode */ protected: int mode; bool slave; Color myside; private: int maxdepth; #ifdef WITH_THREAD /* thread+mutexes */ Mutex start_mutex; Mutex main_mutex; Thread * thread; #endif /* control variable to stop running search */ protected: volatile bool stop; bool stop_iteration; /* basic statistics */ protected: unsigned long long nodes_fullwidth; unsigned long long nodes_quiesce; unsigned int maxplyreached_fullwidth; unsigned int maxplyreached_quiesce; /* time check and thinking output interval */ private: unsigned long long next_timecheck_nodes; unsigned long next_update_csecs; unsigned long last_timecheck_csecs; unsigned long timecheck_interval_nodes; unsigned long iteration_start_csecs; protected: /* 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; private: /* For each ply-1 node, stores the PV of the previous iteration, * starting from that node. This allows us to provide a PV line * for move ordering for every ply-1 move, rather than just the * first. */ std::map ply1_pvline_map; /* see comment in probe_hashtable() */ struct Node::pvline _probe_hashtable_pvline; public: Search(Shell * shell); virtual ~Search(); public: Move start(const Game * game, Clock * clock, int mode, Color myside, unsigned int maxdepth); Move start(const Board & board, const Clock & clock, int mode, unsigned int maxdepth); #ifdef WITH_THREAD void start_thread(const Game * game, Clock * clock, int mode, Color myside, unsigned int maxdepth); void start_slave_thread(ParallelSearch * master, const Game * game, Clock * clock, int mode, Color myside, Node * node, unsigned int ply, int depth, int extend, int alpha, int beta); void stop_thread(); int stop_slave_thread(); private: static void * thread_main(void * arg); static void * slave_thread_main(void * arg); #endif public: virtual void interrupt(); virtual void set_hash_size(size_t bytes); virtual void set_hash_size_pvline(size_t bytes); virtual void set_hash_table(HashTable * table); virtual void clear_hash(); virtual void set_pawnhash_size(size_t bytes); virtual void clear_pawnhash(); virtual void set_evalcache_size(size_t bytes); virtual void clear_evalcache(); protected: virtual Move main(); #ifdef WITH_THREAD virtual int slave_main(const struct slave_search_args& search_args); #endif virtual Move iterate(unsigned int depth); virtual int search_root(Node * node, unsigned int ply, int depth, int alpha, int beta); virtual int search(Node * node, unsigned int ply, int depth, int extend, int alpha, int beta); virtual int quiescence_search(Node * node, unsigned int ply, int alpha, int beta); bool is_draw(const Node * node, unsigned int ply, int * score); bool is_repetition(const Node * node, unsigned int ply, int * score); bool probe_hashtable(Node * node, int depth, int alpha, int beta, int * score); void store_hashtable(Node * node, int depth, int alpha, int beta, int score); void add_history(Node * node); void add_killer(Node * node); int bound_score(int score, int alpha, int beta); protected: void check_time(bool force_check, bool force_update); private: void adjust_timecheck_interval(unsigned long elapsed_csecs); void extend_time_iteration(); bool time_for_new_iteration(); public: virtual void print_statistics(); virtual void reset_statistics(); unsigned long long get_nodes_fullwidth() const; unsigned long long get_nodes_quiesce() const; unsigned int get_maxplyreached_fullwidth() const; unsigned int get_maxplyreached_quiesce() const; private: void print_header(); void print_thinking(unsigned int depth); void print_result(unsigned int depth, int score, enum searchresult::resulttype type, const struct Node::pvline& pvline); protected: virtual void get_root_progress(unsigned int * moves_total, unsigned int * current_move_no, Move * current_move) const; }; #endif // SEARCH_H hoichess-0.22.0/src/common/book.h0000640000175000017500000000640313276601731016111 0ustar holgerholger/* 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 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 Book { private: FILE * fp; bool swap_byteorder; BookHeader header; public: Book(const char * filename, bool * ret); 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.22.0/src/common/book.cc0000640000175000017500000003671013276601731016253 0ustar holgerholger/* 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 #include #include #include #include #include #include #include #include #include "common.h" #include "book.h" #include "pgn.h" /***************************************************************************** * * 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; 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); } bool show_progress = (isatty(1) == 1); /* * 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; if (!show_progress) { printf("Reading PGN...\n"); } 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 (show_progress && ((read+skipped) % 1000 == 0)) { printf("Reading PGN: %lu games read, " "%lu games skipped due to errors\r", read, skipped); fflush(stdout); } } fclose(fp); printf("Reading PGN: %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. */ if (!show_progress) { printf("Sorting and filtering book contents...\n"); } /* 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 (show_progress && ((nr_entries_total >= 100 && (nr_entries % (nr_entries_total/100) == 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); if (!show_progress) { printf("Writing book to file...\n"); } 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 (show_progress && ((booksize >= 100 && (total % (booksize/100) == 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.22.0/src/common/shell.h0000640000175000017500000001375713276601731016300 0ustar holgerholger/* Copyright (C) 2004-2008 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 #define SHELL_STRUCT_OPTION(name, defval) \ private: int option_##name; \ public: inline int get_option_##name() const { return option_##name; } #define SHELL_REGISTER_OPTION(name, defval) \ register_option(#name, &option_##name, defval) class Shell { private: typedef struct { std::string name; unsigned int line; FILE * fp; } source_t; protected: struct command { const char * name; int (Shell::* func) (void); const char * usage; }; #define SHELL_DEFINE_OPTION SHELL_STRUCT_OPTION # include "shell_option_defs.h" #undef SHELL_DEFINE_OPTION private: struct option { const char * name; int * varptr; }; protected: 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::list > atexit_commands; int echo; std::string myname; unsigned long hashsize; unsigned long pawnhashsize; unsigned long evalcachesize; protected: Game * game; private: Book * book; #ifdef WITH_THREAD unsigned int parallel; #endif /* print_search_info_terminal() prints partial lines that will be * overwritten by the next output of print_search_info_terminal() * or print_search_result_terminal(). We must remember the length * of the last output to be able to overwrite excess characters * with spaces. */ unsigned int last_status_line_length; protected: Search * search; private: Color myside; unsigned int maxdepth; bool quit; /* Some commands (e.g. solve) call search from within a loop. * interrupt() sets this flag to abort those commands. */ bool stop; std::list commands; std::list option_list; protected: /* FIXME remove, add as argument to all cmd_ functions */ std::vector cmd_args; public: Shell(); virtual ~Shell(); public: int main(); void interrupt(); public: void set_book(const char * bookfile); void set_hash_size(size_t bytes); size_t get_hash_size() const; void set_pawnhash_size(size_t bytes); size_t get_pawnhash_size() const; void set_evalcache_size(size_t bytes); size_t get_evalcache_size() const; void set_myname(const char * name); const char * get_myname() const; void set_xboard(bool x); public: void source_file(FILE * fp, const char * name); int exec_command(const char * s); int exec_command(const std::vector& args); protected: void register_commands(const struct command* cmds); void register_option(const char * name, int * varptr, int defval); private: int 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(); bool input_move(std::string input); void user_move(Move mov); void engine_move(); void engine_analyze(); void engine_ponder(); protected: void stop_search(); private: void print_result(); public: void print_search_header(); void print_search_info(struct Search::searchinfo * si); void print_search_result(struct Search::searchresult * sr); private: void print_search_info_terminal(struct Search::searchinfo * si); void print_search_info_xboard(struct Search::searchinfo * si); void print_search_result_terminal(struct Search::searchresult * sr); void print_search_result_xboard(struct Search::searchresult * sr); public: static bool print_search_output_terminal_newline; private: static const struct command shell_commands[]; protected: int cmd_null(); int cmd_xboard(); int cmd_protover(); int cmd_accepted(); int cmd_rejected(); int cmd_new(); int cmd_variant(); int cmd_quit(); int cmd_force(); int cmd_go(); int cmd_level(); int cmd_st(); int cmd_sd(); int cmd_time(); int cmd_otim(); int cmd_usermove(); int cmd_ping(); int cmd_setboard(); int cmd_bk(); int cmd_undo(); int cmd_remove(); int cmd_hard(); int cmd_easy(); int cmd_post(); int cmd_nopost(); #ifdef WITH_THREAD int cmd_analyze(); int cmd_exit(); virtual int cmd_cores(); #endif int cmd_option(); int cmd_verbose(); int cmd_debug(); int cmd_help(); int cmd_source(); int cmd_echo(); int cmd_noxboard(); virtual int cmd_show(); int cmd_solve(); int cmd_book(); int cmd_hash(); int cmd_pawnhash(); int cmd_evalcache(); int cmd_set(); int cmd_get(); int cmd_playboth(); int cmd_loadgame(); int cmd_savegame(); int cmd_redo(); int cmd_options(); int cmd_atexit(); }; #define SHELL_CMD_REQUIRE_ARGS(n) do { \ if (cmd_args.size() < (n)+1) { \ printf("Error (command requires %d argument%s): %s\n", \ (n), ((n) == 1 ? "" : "s"), \ cmd_args[0].c_str()); \ return SHELL_CMD_FAIL; \ } \ } while(0) #define SHELL_CMD_DEPRECATED() do { \ printf("Warning: command %s is deprecated\n", \ cmd_args[0].c_str()); \ } while (0) #define SHELL_CMD_OK 1 #define SHELL_CMD_FAIL 0 #endif // SHELL_H hoichess-0.22.0/src/common/game.cc0000640000175000017500000002626013276601731016231 0ustar holgerholger/* Copyright (C) 2004-2008 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, unsigned int flags) { this->board = board; this->move = mov; this->clock[WHITE] = wclock; this->clock[BLACK] = bclock; this->flags = flags; } /* * 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) { construct(board, wclock, bclock); } /* * Create a new game by loading a PGN. */ Game::Game(const PGN & pgn, const Clock & wclock, const Clock & bclock) { construct(pgn.get_opening(), wclock, bclock); /* make moves */ std::list moves = pgn.get_moves(); for (std::list::const_iterator it = moves.begin(); it != moves.end(); it++) { make_move(*it, 0); } } /* * Common code for all constructors. * Remember that a constructor cannot call another constructor on 'this', * so we need a helper function... */ void Game::construct(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; } 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(); } const Clock* Game::get_clock() const { return ¤t_clock[get_side()]; } Clock* Game::get_clock() { return ¤t_clock[get_side()]; } const Clock* Game::get_clock(Color side) const { ASSERT(side == WHITE || side == BLACK); return ¤t_clock[side]; } const Board& Game::get_opening() const { return initial_board; } const std::list& Game::get_entries() const { return entries; } void Game::start() { current_clock[get_side()].start(); running = true; } void Game::make_move(Move mov, unsigned int flags) { 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 */ ASSERT(!current_clock[WHITE].is_running()); ASSERT(!current_clock[BLACK].is_running()); ASSERT(!old_clock[WHITE].is_running()); ASSERT(!old_clock[BLACK].is_running()); /* save current position */ GameEntry entry(current_board, mov, old_clock[WHITE], old_clock[BLACK], flags); 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; } 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_flags()); 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; 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_flags()); 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; } 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()); initial_board = 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(); } 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 _and_initial_ clocks of both sides by new ones. */ void Game::set_clocks(const Clock & wclock, const Clock & bclock) { ASSERT(!wclock.is_running()); ASSERT(!bclock.is_running()); 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(); } } void Game::turn_back_clock() { current_clock[get_side()].turn_back(); } void Game::set_remaining_time(Color side, unsigned int csecs) { ASSERT(side == WHITE || side == BLACK); current_clock[side].set_remaining_time(Clock::from_cs(csecs)); } /* * 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 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. * If no move was played out of book at all, return 0. */ 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_flags() & GameEntry::FLAG_BOOKMOVE) { #ifdef DEBUG printf("last bookmove: %d moves ago\n", n); #endif return n; } } #ifdef DEBUG printf("last bookmove: not found\n"); #endif return 0; } /* * 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", (int) 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 flags:"); if (it->get_flags() & GameEntry::FLAG_COMPUTER) { fprintf(fp, " computer"); } if (it->get_flags() & GameEntry::FLAG_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.22.0/src/common/shell_option_defs.h0000640000175000017500000000172613276601731020662 0ustar holgerholger/* long names... */ SHELL_DEFINE_OPTION(search_update_interval_csecs, 500); SHELL_DEFINE_OPTION(search_timecheck_interval_csecs_min, 2); SHELL_DEFINE_OPTION(search_timecheck_interval_csecs_max, 5); SHELL_DEFINE_OPTION(search_extend_time_iteration_enable, 1); SHELL_DEFINE_OPTION(search_extend_time_iteration_min_percent_done, 75); SHELL_DEFINE_OPTION(search_extend_time_iteration_expect_safety_factor_tenth, 11); SHELL_DEFINE_OPTION(search_extend_time_iteration_extend_safety_factor_tenth, 10); SHELL_DEFINE_OPTION(search_time_for_new_iteration_enable, 1); SHELL_DEFINE_OPTION(search_time_for_new_iteration_expect_factor_tenth, 15); SHELL_DEFINE_OPTION(search_parallel_min_depth, 6); SHELL_DEFINE_OPTION(search_parallel_min_move_ratio, 2); SHELL_DEFINE_OPTION(search_parallel_hash_pvtable, 0); SHELL_DEFINE_OPTION(search_parallel_shared_hash, 0); SHELL_DEFINE_OPTION(search_parallel_pvs_mode, 1); SHELL_DEFINE_OPTION(search_failsoft, 0); SHELL_DEFINE_OPTION(search_pvs_mode, 1); hoichess-0.22.0/src/common/clock.cc0000640000175000017500000001560713276601731016416 0ustar holgerholger/* 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; limit = 0; hard_limit = 0; over_time = 0; lost_time = 0; } Clock::Clock(unsigned int secs) { mode = EXACT; running = false; limit = from_s(secs); hard_limit = limit; over_time = 0; lost_time = 0; } Clock::Clock(unsigned int moves, unsigned int base_secs, unsigned int inc_secs) { ASSERT(base_secs > 0); base_time = from_s(base_secs); base_moves = moves; increment = from_s(inc_secs); if (moves == 0 && inc_secs == 0) { mode = SUDDENDEATH; } else if (inc_secs == 0) { mode = CONV; } else { mode = INCR; } remaining_time = base_time; remaining_moves = base_moves; running = false; limit = 0; hard_limit = 0; over_time = 0; lost_time = 0; } void Clock::start() { if (running) return; start_time = get_realtime_us(); running = true; } void Clock::stop() { if (!running) return; stop_time = get_realtime_us(); running = false; val_t elapsed = get_elapsed_time(); update_remaining(elapsed); /* determine how much search has exceeded its time limit */ if (mode != NONE && elapsed > limit) { over_time = elapsed - limit; } else { over_time = 0; } DBG(1, "elapsed=%lu over_time=%lu\n", (unsigned long) elapsed, (unsigned long) over_time); if (mode == EXACT && elapsed > limit * 1.1) { WARN("time exeeded in exact clock mode:" " elapsed=%lu limit=%lu\n", (unsigned long) elapsed, (unsigned long) limit); } } void Clock::turn_back() { /* This function is supposed to be called when switching one side * from human to engine, e.g. through command 'go'. The saved delays * must be reset, otherwise over_time could contain the human's * thinking time etc.. */ over_time = 0; lost_time = 0; if (!running) return; start_time = get_realtime_us(); } void Clock::allocate_time() { if (mode == NONE || mode == EXACT) { /* For EXACT, limit and hard_limit already set in * constructor. For NONE, there is no limit. */ return; } DBG(1, "over_time=%lu lost_time=%lu\n", (unsigned long) over_time, (unsigned long) lost_time); /* Safety margin for remaining time. Always add 1 second reserve * so can be sure we never exceed the game's time limit. */ val_t remaining_safe = remaining_time - 2*lost_time - from_s(1); if (remaining_safe <= 0) { limit = 0; hard_limit = 0; if (verbose) { atomic_printf("No time remaining!\n"); } return; } DBG(1, "remaining_time=%lu remaining_safe=%lu\n", (unsigned long) remaining_time, (unsigned long) remaining_safe); /* determine search time limit */ val_t limit_tmp; switch (mode) { case CONV: ASSERT(remaining_moves > 0); limit_tmp = remaining_safe / remaining_moves; break; case INCR: limit_tmp = remaining_safe / 20 + increment; break; case SUDDENDEATH: limit_tmp = remaining_safe / 40; break; default: BUG("should not get here"); } DBG(1, "limit_tmp=%lu\n", (unsigned long) limit_tmp); /* safety margin for limit */ if (limit_tmp < 2*over_time) { limit = 0; } else { limit = limit_tmp - 2*over_time; } DBG(1, "limit=%lu\n", (unsigned long) limit); /* set hard limit */ hard_limit = 2 * limit; if (hard_limit > remaining_safe) { hard_limit = remaining_safe; limit = hard_limit; } DBG(1, "limit=%lu hard_limit=%lu\n", (unsigned long) limit, (unsigned long) hard_limit); if (verbose) { atomic_printf(INFO_PRFX "searchtime_alloc=%.2f" " searchtime_alloc_max=%.2f\n", to_s_f(limit), to_s_f(hard_limit)); } } bool Clock::allocate_more_time(val_t t) { if (mode == NONE || mode == EXACT) { return false; } limit += t; if (limit > hard_limit) { limit = hard_limit; } if (verbose) { atomic_printf(INFO_PRFX "searchtime_alloc=%.2f" " searchtime_alloc_max=%.2f\n", to_s_f(limit), to_s_f(hard_limit)); } return true; } void Clock::update_remaining(val_t elapsed) { 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; } } bool Clock::timeout() const { if (mode == NONE) { return false; } if (!running) { WARN("Clock::timeout() called with stopped clock"); } val_t elapsed = get_elapsed_time(); return (elapsed >= limit); } bool Clock::is_exact() const { return (mode == EXACT); } bool Clock::is_running() const { return running; } Clock::val_t Clock::get_limit() const { return limit; } Clock::val_t Clock::get_elapsed_time() const { val_t elapsed; if (!running) { elapsed = (stop_time - start_time) / 1000; } else { unsigned long long now = get_realtime_us(); elapsed = (now - start_time) / 1000; } return elapsed; } Clock::val_t Clock::get_remaining_time() const { return remaining_time; } void Clock::set_remaining_time(val_t t) { /* Due to external delay, the remaining time may be less than * the stored value, so track this difference to tune safety margin * for time allocation accordingly. */ if (t < remaining_time) { lost_time = remaining_time - t; } else { lost_time = 0; } DBG(1, "lost_time=%lu\n", (unsigned long) lost_time); remaining_time = t; } 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", to_s_f(remaining_time), remaining_moves); break; case INCR: fprintf(fp, "Clock mode: incremental\n"); fprintf(fp, "Remaining time: %.2f sec, increment: %.2fs\n", to_s_f(remaining_time), to_s_f(increment)); break; case SUDDENDEATH: fprintf(fp, "Clock mode: sudden death\n"); fprintf(fp, "Remaining time: %.2f sec\n", to_s_f(remaining_time)); break; case EXACT: fprintf(fp, "Clock mode: exact\n"); fprintf(fp, "Time per move: %.2f sec\n", to_s_f(limit)); break; } val_t elapsed = get_elapsed_time(); if (running) { fprintf(fp, "Clock is running, elapsed time: %.2fs\n", to_s_f(elapsed)); } } hoichess-0.22.0/src/common/pgn.cc0000640000175000017500000001143213276601731016077 0ustar holgerholger/* Copyright (C) 2004-2008 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); } hoichess-0.22.0/src/common/search.cc0000640000175000017500000010156713276601731016571 0ustar holgerholger/* Copyright (C) 2004-2008 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 "shell.h" #ifdef WITH_THREAD # include "parallelsearch.h" #endif #include #include #include #define SHOPT(x) (shell->get_option_##x()) /***************************************************************************** * * Constructor / Destructor * *****************************************************************************/ Search::Search(Shell * shell) : nodealloc(MAXPLY) { this->shell = shell; evaluator = new Evaluator(); hashtable = NULL; shared_hashtable = false; histtable[WHITE] = new HistoryTable(); histtable[BLACK] = new HistoryTable(); game = NULL; clock = NULL; rootnode = NULL; maxdepth = MAXDEPTH; #ifdef WITH_THREAD thread = NULL; #endif stop = false; timecheck_interval_nodes = 100; } Search::~Search() { delete evaluator; if (!shared_hashtable) { delete hashtable; } delete histtable[WHITE]; delete histtable[BLACK]; } /***************************************************************************** * * These functions will be called by the shell * to set up and control the search. * *****************************************************************************/ Move Search::start(const Game * _game, Clock * _clock, int _mode, Color _myside, unsigned int _maxdepth) { #ifdef WITH_THREAD DBG(2, "locking start_mutex"); start_mutex.lock(); DBG(2, "locked start_mutex"); ASSERT(!thread); #endif ASSERT(game == NULL); game = _game; clock = _clock; mode = _mode; myside = _myside; maxdepth = _maxdepth; stop = false; Move best = main(); game = NULL; clock = NULL; #ifdef WITH_THREAD DBG(2, "unlocking start_mutex"); start_mutex.unlock(); DBG(2, "unlocked start_mutex"); #endif return best; } Move Search::start(const Board & board, const Clock & clock, int mode, unsigned int maxdepth) { Game game(board, clock, clock); game.start(); return start(&game, game.get_clock(), mode, NO_COLOR, maxdepth); } #ifdef WITH_THREAD void Search::start_thread(const Game * _game, Clock * _clock, int _mode, Color _myside, unsigned int _maxdepth) { DBG(2, "locking start_mutex"); start_mutex.lock(); DBG(2, "locked start_mutex"); if (!thread) { DBG(2, "starting thread"); /* args will be freed again by stop_thread() */ struct thread_args * args = new struct thread_args; args->self = this; args->game = _game; args->clock = _clock; args->mode = _mode; args->myside = _myside; args->maxdepth = _maxdepth; stop = false; thread = new Thread(thread_main); thread->start((void *) args); /* thread_main() will return args again so that * stop_thread() can get output variables from there * and free it afterwards */ } else { DBG(2, "thread already running"); } DBG(2, "unlocking start_mutex"); start_mutex.unlock(); DBG(2, "unlocked start_mutex"); } void Search::start_slave_thread(ParallelSearch * master, const Game * game, Clock * clock, int mode, Color myside, Node * node, unsigned int ply, int depth, int extend, int alpha, int beta) { DBG(2, "locking start_mutex"); start_mutex.lock(); DBG(2, "locked start_mutex"); if (!thread) { DBG(2, "starting thread"); /* args will be freed again by stop_slave_thread() */ struct slave_thread_args * args = new struct slave_thread_args; args->self = this; args->master = master; args->game = game; args->clock = clock; args->mode = mode; args->myside = myside; args->search_args.node = node; args->search_args.ply = ply; args->search_args.depth = depth; args->search_args.extend = extend; args->search_args.alpha = alpha; args->search_args.beta = beta; stop = false; thread = new Thread(slave_thread_main); thread->start((void *) args); /* slave_thread_main() will return args again so that * stop_slave_thread() can get output variables from there * and free it afterwards */ } 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"); struct thread_args * args = (struct thread_args *) thread->wait(); DBG(2, "thread has terminated"); delete thread; thread = NULL; //Move best = args->best; delete args; } else { DBG(2, "thread not running"); } DBG(2, "unlocking start_mutex"); start_mutex.unlock(); DBG(2, "unlocked start_mutex"); } int Search::stop_slave_thread() { DBG(2, "locking start_mutex"); start_mutex.lock(); DBG(2, "locked start_mutex"); int score; if (thread) { interrupt(); DBG(2, "waiting for thread to terminate"); struct slave_thread_args * args = (struct slave_thread_args *) thread->wait(); DBG(2, "thread has terminated"); delete thread; thread = NULL; score = args->score; delete args; } else { BUG("thread not running"); } DBG(2, "unlocking start_mutex"); start_mutex.unlock(); DBG(2, "unlocked start_mutex"); return score; } void * Search::thread_main(void * arg) { struct thread_args * args = (struct thread_args *) arg; Search * self = args->self; ASSERT(self->game == NULL); self->game = args->game; self->clock = args->clock; self->mode = args->mode; self->myside = args->myside; self->maxdepth = args->maxdepth; args->best = self->main(); self->game = NULL; self->clock = NULL; return args; } void * Search::slave_thread_main(void * arg) { struct slave_thread_args * args = (struct slave_thread_args *) arg; Search * self = args->self; ASSERT(self->game == NULL); self->game = args->game; self->clock = args->clock; self->mode = args->mode; self->myside = args->myside; args->score = self->slave_main(args->search_args); self->game = NULL; /* must not set self->clock = NULL, because clock is required * by print_statistics() which is called by master when slave * search is not running anymore */ args->master->slave_ready(self); return args; } #endif // WITH_THREAD void Search::interrupt() { DBG(2, "interrupt"); stop = true; } /***************************************************************************** * * Main search function. Initialize everything and start * iterative deepening search. * *****************************************************************************/ Move Search::main() { #ifdef WITH_THREAD DBG(2, "locking main_mutex"); main_mutex.lock(); DBG(2, "locked main_mutex"); #endif slave = false; last_timecheck_csecs = 0; next_timecheck_nodes = timecheck_interval_nodes; next_update_csecs = 0; reset_statistics(); histtable[WHITE]->reset(); histtable[BLACK]->reset(); /* Convert the game entries into a list of node. The * last one will be the root node of the search tree. */ const std::list& gameentries = game->get_entries(); NodeAllocator gamenodealloc(gameentries.size() + 1); Node openingnode(game->get_opening()); Node * node = &openingnode; for (std::list::const_iterator it = gameentries.begin(); it != gameentries.end(); it++) { node = node->make_move(it->get_move(), &gamenodealloc); } rootnode = node; /* Initialize the root node. init_root() already assigns one legal * move as best, in case search terminates without choosing a move. */ ASSERT(rootnode->get_board() == game->get_board()); rootnode->init_root(); rootdepth = 0; /* If we're not supplied with a clock, create a local one just for * measuring elapsed time. */ Clock tmp_clock; if (clock == NULL) { ASSERT(mode == ANALYZE || mode == PONDER); tmp_clock.start(); clock = &tmp_clock; } if (verbose >= 2) { clock->print(); } /* Allocate search time. */ if (mode == MOVE) { ASSERT(clock->is_running()); clock->allocate_time(); } print_header(); Move best = iterate(maxdepth); if (verbose) { print_statistics(); } rootnode = NULL; #ifdef WITH_THREAD DBG(2, "unlocking main_mutex"); main_mutex.unlock(); DBG(2, "unlocked main_mutex"); #endif return best; } /***************************************************************************** * * Main function of slave search. Initialize everything and start * full-width search. * *****************************************************************************/ #ifdef WITH_THREAD int Search::slave_main(const struct slave_search_args& search_args) { DBG(2, "locking main_mutex"); main_mutex.lock(); DBG(2, "locked main_mutex"); slave = true; /* clock is passed from master and set by slave_thread_main */ last_timecheck_csecs = 0; next_timecheck_nodes = timecheck_interval_nodes; next_update_csecs = 0; /* statistics are reset by ParallelSearch::reset_statistics() */ /* for non-parallel and master search, these are reset in * iterate(), so for slaves, it must be done here */ maxplyreached_fullwidth = 0; maxplyreached_quiesce = 0; histtable[WHITE]->reset(); histtable[BLACK]->reset(); /* There is no direct root node for a slave search. */ rootnode = NULL; rootdepth = 0; int score = search(search_args.node, search_args.ply, search_args.depth, search_args.extend, search_args.alpha, search_args.beta); DBG(2, "unlocking main_mutex"); main_mutex.unlock(); DBG(2, "unlocked main_mutex"); return score; } #endif /* WITH_THREAD */ /***************************************************************************** * * Tree Search Functions. * *****************************************************************************/ /* Aspiration window for iterative deepening */ #define WINDOW 50 /* Shortcut */ #define failsoft (shell->get_option_search_failsoft()) Move Search::iterate(unsigned int depth) { Move best = rootnode->get_best_move(); /* set by Node::init_root() */ int score = 0; int alpha = -INFTY; int beta = INFTY; /* stop search after current iteration, even in case of fail-low */ stop_iteration = false; ply1_pvline_map.clear(); for (rootdepth = 1; rootdepth <= depth; rootdepth++) { again: maxplyreached_fullwidth = 0; maxplyreached_quiesce = 0; iteration_start_csecs = Clock::to_cs(clock->get_elapsed_time()); score = search_root(rootnode, 0, rootdepth, alpha, beta); if (!failsoft && (score < alpha || score > beta) && !stop) { printf("iterate(): fail hard condition violated:" " score=%d alpha=%d beta=%d\n", score, alpha, beta); } check_time(true, true); if (stop) { unsigned int moves_total; unsigned int moves_done; get_root_progress(&moves_total, &moves_done, NULL); unsigned long csecs_wasted = Clock::to_cs(clock->get_elapsed_time()) - iteration_start_csecs; printf("\nIteration aborted after %u/%u moves (%u%%)" ", %.2f s wasted\n", moves_done, moves_total, 100 * moves_done / moves_total, (float) csecs_wasted / 100); break; } /* If search failed low or high, re-search with a wider * window. Best move is not updated in this case. * Otherwise adjust window for next iteration. * When a mate is detected, we can stop immediately. */ if (score <= alpha && score > -MATE) { print_result(rootdepth, score, searchresult::FAILLOW, rootnode->get_best_line()); if (stop_iteration) { break; } alpha = -INFTY; //beta = beta; goto again; } else if (score >= beta && score < MATE) { print_result(rootdepth, score, searchresult::FAILHIGH, rootnode->get_best_line()); if (stop_iteration) { break; } //alpha = alpha; beta = INFTY; goto again; } else { Move mov = rootnode->get_best_move(); if (mov) { best = mov; } print_result(rootdepth, score, searchresult::DEPTH, rootnode->get_best_line()); if (stop_iteration) { break; } else if (score >= MATE || score <= -MATE) { break; } alpha = score - WINDOW; beta = score + WINDOW; } /* Decide if time is sufficient to start a new iteration. */ if (mode == MOVE && !clock->is_exact() && SHOPT(search_time_for_new_iteration_enable) && !time_for_new_iteration()) { printf("No time for another iteration.\n"); break; } } return best; } int Search::search_root(Node * node, unsigned int ply, int depth, int alpha, int beta) { ASSERT_DEBUG(ply == 0); // DBG(3, "depth=%d, alpha=%d, beta=%d\n", depth, alpha, beta); int save_alpha = alpha; int score; int bestscore = -INFTY; int moves = 0; bool first = true; for (Move mov = node->first(); mov; mov = node->next()) { /* make move */ Node * child = node->make_move(mov, &nodealloc); if (!child->get_board().is_legal()) { BUG("illegal move at root node: %s", mov.str().c_str()); } moves++; /* Get the child node's PV of the previous iteration. */ std::map::iterator mit = ply1_pvline_map.find(mov); if (mit != ply1_pvline_map.end()) { child->set_pvline(mit->second); } check_time(true, true); /* Search the current move. We use a standard * principal variation search here. */ bool nullwin = (SHOPT(search_pvs_mode) == 1 && !first) || (SHOPT(search_pvs_mode) == 2 && alpha > save_alpha); if (nullwin) { score = -search(child, ply+1, depth-1, 0, -alpha-1, -alpha); if (score > alpha && score < beta) { score = -search(child, ply+1, depth-1, 0, -beta, -alpha); } } else { score = -search(child, ply+1, depth-1, 0, -beta, -alpha); } first = false; if (!failsoft && (score < alpha || score > beta) && !stop) { printf("search_root(): fail hard condition violated:" " score=%d alpha=%d beta=%d\n", score, alpha, beta); } ply1_pvline_map[mov] = child->get_best_line(); if (stop) { child->free(); /* We don't get any useful result after canceling the * alpha-beta search, so iterate() must return the * result of the previous (completed) iteration. * For that reason, we can return an arbitrary value * here, because iterate() won't use it anyway. */ return INT_MIN; } /* this is taken for move ordering at the next iteration */ node->set_current_score(score); if (score > bestscore) { bestscore = score; node->set_best(mov, child); print_result(depth, score, searchresult::INTERMEDIATE, node->get_best_line()); } child->free(); if (score > alpha) { alpha = score; } if (score >= beta) { if (!failsoft) { score = beta; /* fail hard */ } stat_cut++; break; } } add_history(node); stat_moves_sum += moves; stat_moves_cnt++; if (failsoft) { return bestscore; } else { return alpha; } } int Search::search(Node * node, unsigned int ply, int depth, int extend, int alpha, int beta) { /* If maximum search depth is reached, begin quiescence search. */ if (depth <= 0) { return quiescence_search(node, ply, alpha, beta); } int drawscore; if (is_draw(node, ply, &drawscore)) { if (failsoft) { return drawscore; } else { /* strict fail hard */ return bound_score(drawscore, alpha, beta); } } int save_alpha = alpha; /* need old value to save in hash table */ int score; int bestscore = -INFTY; int moves = 0; bool first = true; nodes_fullwidth++; if (ply > maxplyreached_fullwidth) { maxplyreached_fullwidth = ply; } if (probe_hashtable(node, depth, alpha, beta, &score)) { return score; } /* Null-move forward pruning */ bool null_ok = !(node->get_parent()->get_played_move().is_null()) && !(Evaluator::get_phase(node->get_board()) == Evaluator::ENDGAME); if (!node->in_check() && null_ok) { Node * child = node->make_move(Move::null(), &nodealloc); score = -search(child, ply+1, depth-2-1, 0, -beta, -beta+1); child->free(); if (score >= beta) { stat_nullcut++; if (failsoft) { return score; } else { return beta; /* fail hard */ } } } /* * 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_pvmove() && !node->get_hashmv() && depth > 2) { search(node, ply, depth-2, 0, alpha, beta); node->set_hashmv(node->get_best_move()); } node->set_type(Node::FULLWIDTH); node->set_historytable(histtable[node->get_board().get_side()]); /* * Futility pruning, extended futility pruning, and razoring. */ if (depth == 3 && (node->material_balance() + 900 <= alpha)) { /* razoring */ stat_razcut++; depth--; } bool fprune = false; if (depth == 1 && (node->material_balance() + 300 <= alpha)) { /* futility pruning */ fprune = true; } else if (depth == 2 && (node->material_balance() + 500 <= alpha)) { /* extended futility pruning */ stat_xfutcut++; fprune = true; depth--; } /* * Search all successor moves. */ for (Move mov = node->first(); mov; mov = node->next()) { Node * child = node->make_move(mov, &nodealloc); if (!child->get_board().is_legal()) { child->free(); continue; } moves++; /* Futility pruning */ if (fprune && !node->in_check() && !child->in_check() && !mov.is_capture() #ifdef HOICHESS && !mov.is_enpassant() && !mov.is_promotion() #endif // HOICHESS ) { stat_futcut++; child->free(); continue; } /* Search the current move. We use a standard * principal variation search here. */ bool nullwin = (SHOPT(search_pvs_mode) == 1 && !first) || (SHOPT(search_pvs_mode) == 2 && alpha > save_alpha); if (nullwin) { score = -search(child, ply+1, depth-1, extend, -alpha-1, -alpha); if (score > alpha && score < beta) { score = -search(child, ply+1, depth-1, extend, -beta, -alpha); } } else { score = -search(child, ply+1, depth-1, extend, -beta, -alpha); } first = false; if (!failsoft && (score < alpha || score > beta) && !stop) { printf("search(): fail hard condition violated:" " score=%d alpha=%d beta=%d\n", score, alpha, beta); } check_time(false, false); if (stop) { child->free(); /* We don't get any useful result after canceling the * alpha-beta search, so iterate() must return the * result of the previous (completed) iteration. * For that reason, we can return an arbitrary value * here, because iterate() won't use it anyway. */ return INT_MIN; } if (score > bestscore) { bestscore = score; node->set_best(mov, child); } child->free(); if (score > alpha) { alpha = score; } if (score >= beta) { if (!failsoft) { score = beta; /* fail hard */ } stat_cut++; break; } } /* Test for checkmate or stalemate */ if (moves == 0) { #if defined(HOICHESS) int matescore = node->in_check() ? (-INFTY + ply) : DRAW; #elif defined(HOIXIANGQI) int matescore = -INFTY + ply; #else # error "neither HOICHESS nor HOIXIANGQI is defined" #endif if (failsoft) { bestscore = matescore; } else { /* strict fail hard */ alpha = bound_score(matescore, alpha, beta); } } /* Save search result in hash table. */ if (failsoft) { store_hashtable(node, depth, save_alpha, beta, bestscore); } else { store_hashtable(node, depth, save_alpha, beta, alpha); } add_history(node); add_killer(node); stat_moves_sum += moves; stat_moves_cnt++; if (failsoft) { return bestscore; } else { return alpha; } } int Search::quiescence_search(Node * node, unsigned int ply, int alpha, int beta) { int save_alpha = alpha; /* need old value to save in hash table */ int score = 0; /* initialized only to avoid compiler warning */ int bestscore = -INFTY; int moves = 0; nodes_quiesce++; if (ply > maxplyreached_quiesce) { maxplyreached_quiesce = ply; } if (probe_hashtable(node, 0, alpha, beta, &score)) { return score; } /* * Evaluate board position. * * This score will be returned if none * of the moves is better than alpha. */ score = evaluator->eval(node->get_board(), alpha, beta, myside); if (score >= beta) { if (failsoft) { return score; } else { return beta; /* fail hard */ } } if (score > alpha) { alpha = score; } if (failsoft) { bestscore = 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()) { Node * child = node->make_move(mov, &nodealloc); if (!child->get_board().is_legal()) { child->free(); continue; } moves++; score = -quiescence_search(child, ply+1, -beta, -alpha); if (!failsoft && (score < alpha || score > beta) && !stop) { printf("q_search(): fail hard condition violated:" " score=%d alpha=%d beta=%d\n", score, alpha, beta); } check_time(false, false); if (stop) { child->free(); /* We don't get any useful result after canceling the * alpha-beta search, so iterate() must return the * result of the previous (completed) iteration. * For that reason, we can return an arbitrary value * here, because iterate() won't use it anyway. */ return INT_MIN; } if (score > bestscore) { bestscore = score; node->set_best(mov, child); } child->free(); if (score > alpha) { alpha = score; } if (score >= beta) { if (!failsoft) { score = beta; /* fail hard */ } stat_cut++; break; } } /* Test for checkmate */ if (moves == 0 && node->in_check()) { int matescore = -INFTY + ply; if (failsoft) { bestscore = matescore; } else { /* strict fail hard */ alpha = bound_score(matescore, alpha, beta); } } /* Save search result in hash table. */ if (failsoft) { store_hashtable(node, 0, save_alpha, beta, bestscore); } else { store_hashtable(node, 0, save_alpha, beta, alpha); } stat_moves_sum_quiesce += moves; stat_moves_cnt_quiesce++; if (failsoft) { return bestscore; } else { return alpha; } } /* * Return true if the current position is a draw by rule. The score assigned * to the draw is returned by the score output parameter. * This is because the code also handles perpetual check for xiangqi, in which * case a mate score is assigned. It could also be used for chess to assign * different draw scores in different situations. */ bool Search::is_draw(const Node * node, unsigned int ply, int * score) { const Board & board = node->get_board(); /* 50 move rule */ if (board.get_movecnt50() >= 100) { *score = DRAW; return true; } /* Draw due to insufficient material */ if (board.is_material_draw()) { *score = DRAW; return true; } /* Look for repetitions */ if (is_repetition(node, ply, score)) { return true; } return false; } /* * Return true if the current position is a repetition. The score assigned * to the repetition is returned by the score output parameter. * * For xiangqi, this also handled perpetual check: If between the repeating * positions, one side always checks but the other side does not, a mate * score is returned. */ bool Search::is_repetition(const Node * node, unsigned int ply, int * score) { #ifndef HOIXIANGQI (void) ply; #endif /* Count repetitions until next irreversible move. */ int rep = 0; #ifdef HOIXIANGQI unsigned int moves[2] = {0, 0}; /* [0] is side */ unsigned int checks[2] = {0, 0}; /* [0] is side */ /* in the current position, xside has moved last */ unsigned int side = 1; #endif for (const Node * p = node; p != NULL; p = p->get_parent()) { if (p->get_played_move().is_irreversible()) { break; } if (p != node && p->get_board().get_hashkey() == node->get_board().get_hashkey()) { rep++; } #ifdef HOIXIANGQI moves[side]++; if (p->in_check()) { checks[side]++; } side = 1 - side; #endif if (rep) { break; } } if (rep) { #ifdef HOIXIANGQI if (moves[0] > 0 && checks[0] == moves[0] && moves[1] > 0 && checks[1] == moves[1]) { *score = DRAW; printf("perpetual both, %u/%u\n", checks[0], checks[1]); } else if (moves[0] > 0 && checks[0] == moves[0]) { *score = -INFTY + ply; printf("perpetual side, %u/%u\n", checks[0], checks[1]); } else if (moves[1] > 0 && checks[1] == moves[1]) { *score = INFTY - ply; printf("perpetual xside, %u/%u\n", checks[0],checks[1]); } else { *score = DRAW; } #else *score = DRAW; #endif return true; } else { *score = INT_MIN; /* never used */ return false; } } /* Returns true if the probe result can be directly used as search * return value. */ bool Search::probe_hashtable(Node * node, int depth, int alpha, int beta, int * score) { if (!hashtable) { return false; } /* Constructor of Node::pvline is expensive as it contains a * quite large array of Move elements. So we add a pvline as * class member to avoid construction each time probe_hashtable() * runs. */ //struct Node::pvline pvline; struct Node::pvline & pvline = _probe_hashtable_pvline; HashEntry entry; if (!hashtable->probe(node->get_board(), &entry, &pvline)) { return false; } node->set_hashmv(entry.get_move()); /* Overwrite the node's existing PV line only if the line in the * hash table is longer. */ if (pvline.nmoves > node->get_pvline().nmoves) { node->set_pvline(pvline); } if (entry.get_depth() >= (unsigned) depth) { int s = entry.get_score(); switch (entry.get_type()) { case HashEntry::EXACT: if (failsoft) { *score = s; } else { /* strict fail hard */ *score = bound_score(s, alpha, beta); } return true; case HashEntry::ALPHA: if (s <= alpha) { if (failsoft) { *score = s; } else { /* strict fail hard */ *score = bound_score(s, alpha, beta); } return true; } break; case HashEntry::BETA: if (s >= beta) { if (failsoft) { *score = s; } else { /* strict fail hard */ *score = bound_score(s, alpha, beta); } return true; } break; } } return false; } void Search::store_hashtable(Node * node, int depth, int alpha, int beta, int score) { if (!hashtable) { return; } /* Translate ply-dependent mate scores into ply-independent * mate scores. * See also http://www.brucemo.com/compchess/programming/matehash.htm. * FIXME The cases "fail-low at mate" (alpha >= score >= MATE) * and "fail-high at being mated" (-MATE >= score >= beta) are * not yet handled, because they seem to be always triggered * during PVS null window search. And I don't understand all * this yet. */ int scoretype; if (score >= MATE) { scoretype = HashEntry::BETA; score = MATE; } else if (score <= -MATE) { scoretype = HashEntry::ALPHA; score = -MATE; } else if (score >= beta) { scoretype = HashEntry::BETA; } else if (score <= alpha) { scoretype = HashEntry::ALPHA; } else { scoretype = HashEntry::EXACT; } HashEntry hashentry(node->get_board(), score, node->get_best_move(), depth, scoretype); const struct Node::pvline & best_line = node->get_best_line(); hashtable->put(hashentry, &best_line); } void Search::add_history(Node * node) { if (node->get_best_move()) { histtable[node->get_board().get_side()]->add(node->get_best_move()); } } void Search::add_killer(Node * node) { if (node->get_best_move() != node->get_hashmv() && !(node->get_best_move().is_capture()) #ifdef HOICHESS && !(node->get_best_move().is_enpassant()) && !(node->get_best_move().is_promotion()) #endif // HOICHESS ) { node->add_killer(node->get_best_move()); } } int Search::bound_score(int score, int alpha, int beta) { if (score > beta) { return beta; } else if (score < alpha) { return alpha; } else { return score; } } void Search::check_time(bool force_check, bool force_update) { /* check time only after a certain number of nodes to reduce * system call overhead */ unsigned long long nodes = nodes_fullwidth + nodes_quiesce; if (nodes < next_timecheck_nodes && !force_check) { return; } /* check time */ if (clock->timeout()) { stop = true; return; } unsigned long elapsed_csecs = Clock::to_cs(clock->get_elapsed_time()); /* update and adjust time check interval */ if (!force_check) { adjust_timecheck_interval(elapsed_csecs); } last_timecheck_csecs = elapsed_csecs; next_timecheck_nodes = nodes + timecheck_interval_nodes; /* thinking output (not in slave mode) */ if (!slave && (elapsed_csecs >= next_update_csecs || force_update)) { next_update_csecs = elapsed_csecs + SHOPT(search_update_interval_csecs); print_thinking(rootdepth); } /* time extensions (not in slave mode) */ if (mode == MOVE && !slave && !clock->is_exact() && SHOPT(search_extend_time_iteration_enable)) { extend_time_iteration(); } } /* * Adjust timecheck_interval_nodes based on time since last check. */ void Search::adjust_timecheck_interval(unsigned long elapsed_csecs) { unsigned long diff = elapsed_csecs - last_timecheck_csecs; unsigned long dmin = SHOPT(search_timecheck_interval_csecs_min); unsigned long dmax = SHOPT(search_timecheck_interval_csecs_max); if (dmax == 0) { timecheck_interval_nodes = 1; DBG(1, "elapsed_csecs=%u last_timecheck_csecs=%lu diff=%u" " timecheck_interval_nodes=%lu\n", elapsed_csecs, last_timecheck_csecs, diff, timecheck_interval_nodes); } else if (diff < dmin && timecheck_interval_nodes < ULONG_MAX/2) { timecheck_interval_nodes *= 2; DBG(1, "elapsed_csecs=%u last_timecheck_csecs=%lu diff=%u" " timecheck_interval_nodes=%lu\n", elapsed_csecs, last_timecheck_csecs, diff, timecheck_interval_nodes); } else if (diff > dmax && timecheck_interval_nodes > 1) { timecheck_interval_nodes /= 2; DBG(1, "elapsed_csecs=%u last_timecheck_csecs=%lu diff=%u" " timecheck_interval_nodes=%lu\n", elapsed_csecs, last_timecheck_csecs, diff, timecheck_interval_nodes); } DBG(2, "elapsed_csecs=%u last_timecheck_csecs=%lu diff=%u" " timecheck_interval_nodes=%lu\n", elapsed_csecs, last_timecheck_csecs, diff, timecheck_interval_nodes); } /* * Extend search time when remaining time is expected to be * slightly too short to finish current iteration. */ void Search::extend_time_iteration() { unsigned int rootmoves_total; unsigned int rootmoves_done; get_root_progress(&rootmoves_total, &rootmoves_done, NULL); unsigned int elapsed_csecs = Clock::to_cs(clock->get_elapsed_time()); const unsigned int min_percent_done = SHOPT(search_extend_time_iteration_min_percent_done); const float expect_safety_factor = (float) SHOPT(search_extend_time_iteration_expect_safety_factor_tenth) / 10; const float extend_safety_factor = (float) SHOPT(search_extend_time_iteration_extend_safety_factor_tenth) / 10; // ontop of expect_safety_factor if (100 * rootmoves_done / rootmoves_total >= min_percent_done) { /* Assuming that each of the remaining moves will take the * average time spent on the completed moves (plus safety * margin), check if the remaining time would be sufficient * to complete the iteration. If not, extend by the difference * between expected time required for remaining moves and * remaining time. */ unsigned long csecs_avg = (elapsed_csecs - iteration_start_csecs) / rootmoves_done; unsigned long csecs_expect = csecs_avg * (rootmoves_total - rootmoves_done) * expect_safety_factor; /* NOTE that this can be negative! */ long csecs_remain = Clock::to_cs(clock->get_limit()) - elapsed_csecs; if (csecs_remain < (signed long) csecs_expect && !stop_iteration) { unsigned long csecs_extend = (csecs_expect - csecs_remain) * extend_safety_factor; #if 0 printf("\nextend_time_iteration:" " %u/%u done, avg=%.2f, expect=%.2f" ", remain=%.2f, diff=%.2f" ", extend=%.2f\n", rootmoves_done, rootmoves_total, (float) csecs_avg / 100, (float) csecs_expect / 100, (float) csecs_remain / 100, (float) csecs_remain / 100 - (float) csecs_expect / 100, (float) csecs_extend / 100); #endif if (clock->allocate_more_time( Clock::from_cs(csecs_extend))) { /* do not start a new iteration anymore */ stop_iteration = true; } } } } /* Decide if time is likely sufficient to start a new iteration. */ bool Search::time_for_new_iteration() { unsigned long elapsed_csecs = Clock::to_cs(clock->get_elapsed_time()); unsigned long iteration_csecs = elapsed_csecs - iteration_start_csecs; /* NOTE that this can be negative! */ long remain_csecs = Clock::to_cs(clock->get_limit()) - elapsed_csecs; const float f = (float) SHOPT(search_time_for_new_iteration_expect_factor_tenth) / 10; unsigned long expected_csecs = iteration_csecs * f; #if 0 printf("time_for_new_iteration:" " last=%.2f, remain=%.2f, expect=%.2f\n", (float) iteration_csecs / 100, (float) remain_csecs / 100, (float) expected_csecs / 100); #endif return (remain_csecs >= (signed long) expected_csecs); } hoichess-0.22.0/src/common/clock.h0000640000175000017500000000525413276601731016255 0ustar holgerholger/* 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" #include class Clock { public: typedef long val_t; /* milliseconds */ static const val_t VAL_T_MAX = LONG_MAX; private: enum clock_mode { NONE, CONV, INCR, SUDDENDEATH, EXACT } mode; bool running; unsigned long long start_time; unsigned long long stop_time; val_t limit; val_t hard_limit; val_t remaining_time; unsigned int remaining_moves; val_t base_time; unsigned int base_moves; val_t increment; /* how much the elapsed time exceeds the limit when clock is stopped */ val_t over_time; /* lost time because set_remaining_time() set a lower value than * remaining_time had before */ val_t lost_time; public: Clock(); Clock(unsigned int secs); Clock(unsigned int moves, unsigned int base_secs, unsigned int inc_secs); ~Clock() {} public: void start(); void stop(); void turn_back(); public: void allocate_time(); bool allocate_more_time(val_t t); private: void update_remaining(val_t elapsed); public: bool timeout() const; bool is_exact() const; bool is_running() const; val_t get_limit() const; val_t get_elapsed_time() const; val_t get_remaining_time() const; void set_remaining_time(val_t t); void print(FILE * fp = stdout) const; public: static inline long to_s(val_t v); static inline float to_s_f(val_t v); static inline long to_cs(val_t v); static inline long long to_us(val_t v); static inline val_t from_s(long s); static inline val_t from_cs(long cs); }; inline long Clock::to_s(val_t v) { return v / 1000; } inline float Clock::to_s_f(val_t v) { return (float) v / 1000; } inline long Clock::to_cs(val_t v) { return v / 10; } inline long long Clock::to_us(val_t v) { return v * 1000; } inline Clock::val_t Clock::from_s(long s) { return s * 1000; } inline Clock::val_t Clock::from_cs(long cs) { return cs * 10; } #endif // CLOCK_H hoichess-0.22.0/src/common/evalcache.h0000640000175000017500000000272513276601731017075 0ustar holgerholger/* 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 "common.h" #include "board.h" class EvaluationCache { private: /* A cache slot is empty if score == INT_MIN. */ struct cacheentry { Hashkey hashkey; int score; }; private: unsigned long cache_size; struct cacheentry * cache; unsigned long stat_probes; unsigned long stat_hits; public: EvaluationCache(size_t bytes); ~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.22.0/src/util.cc0000640000175000017500000001050113276601731014774 0ustar holgerholger/* 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" #ifdef WITH_THREAD # include "mutex.h" # include "thread.h" #endif #include #include #include #include #ifndef WIN32 # include # include #endif #include #include #ifdef WITH_THREAD 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; } #endif // WITH_THREAD /* * 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, ssize_t * 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; } } /* Returns real time (wall clock) in microseconds since an undefined point * in the past. Use for time measurement. */ unsigned long long get_realtime_us() { unsigned long long t; #ifdef WIN32 FILETIME ft; GetSystemTimeAsFileTime(&ft); /* resolution is 100 ns */ uint64_t tmp = ((uint64_t) ft.dwHighDateTime << 32) | ft.dwLowDateTime; t = tmp / 10; #else struct timeval tv; if (gettimeofday(&tv, NULL) == -1) { perror("gettimeofday() failed"); exit(EXIT_FAILURE); } t = (unsigned long long) tv.tv_sec * (int)1E6 + tv.tv_usec; #endif return t; } #if !defined(WIN32) && !defined(__leonbare__) /* FIXME assumes that sysconf() never fails */ static long sc_clk_tck = sysconf(_SC_CLK_TCK); #endif /* Returns CPU time (user time) in microseconds since an undefined point * in the past. Use for time measurement. */ unsigned long long get_cputime_us() { unsigned long long t; #if defined(WIN32) FILETIME ct, et, kt, ut; BOOL ok = GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut); ASSERT(ok); /* resolution is 100 ns */ uint64_t tmp = ((uint64_t) ut.dwHighDateTime << 32) | ut.dwLowDateTime; t = tmp / 10; #elif defined(__leonbare__) t = get_realtime_us(); #else struct tms tmp; if (times(&tmp) == -1) { perror("times() failed"); exit(EXIT_FAILURE); } t = (int)1E6 * (unsigned long long) (tmp.tms_utime + tmp.tms_cutime) / sc_clk_tck; #endif return t; } unsigned long long _timing_trace_us_start; unsigned long long _timing_trace_us_last; hoichess-0.22.0/src/thread.h0000640000175000017500000000317613276601731015142 0ustar holgerholger/* Copyright (C) 2005-2008 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 #endif class Thread { private: #if defined(HAVE_PTHREAD) pthread_t threadid; #elif defined(WIN32) HANDLE hndl; #endif void * (*startfunc)(void *); #if defined(WIN32) /* because for win32, the thread main function is declared * differently than for pthread, we need to use a wrapper * function (win32_startfunc_wrapper) and pass argument * and return value of startfunc through the Thread object */ void * startfunc_arg; void * startfunc_ret; #endif public: Thread(void * (*startfunc)(void *)); ~Thread(); public: void start(void * arg); void* wait(); private: #if defined(WIN32) static DWORD WINAPI win32_startfunc_wrapper(LPVOID arg); #endif }; #endif // THREAD_H hoichess-0.22.0/src/mutex.cc0000640000175000017500000000312513276601731015165 0ustar holgerholger/* Copyright (C) 2005-2015 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 "mutex.h" Mutex::Mutex() { #if defined(HAVE_PTHREAD) int res = pthread_mutex_init(&mtx, NULL); ASSERT(res == 0); #elif defined(WIN32) hndl = CreateMutex(NULL, FALSE, NULL); ASSERT(hndl != NULL); #endif } Mutex::~Mutex() { #if defined(HAVE_PTHREAD) int res = pthread_mutex_destroy(&mtx); ASSERT(res == 0); #elif defined(WIN32) BOOL res = CloseHandle(hndl); ASSERT(res); #endif } void Mutex::lock() { #if defined(HAVE_PTHREAD) int res = pthread_mutex_lock(&mtx); ASSERT(res == 0); #elif defined(WIN32) DWORD res = WaitForSingleObject(hndl, INFINITE); ASSERT(res == WAIT_OBJECT_0); #endif } void Mutex::unlock() { #if defined(HAVE_PTHREAD) int res = pthread_mutex_unlock(&mtx); ASSERT(res == 0); #elif defined(WIN32) BOOL res = ReleaseMutex(hndl); ASSERT(res); #endif } hoichess-0.22.0/src/version.cc0000640000175000017500000000017413276601731015511 0ustar holgerholgerconst char * version = VERSION; /* disabled for reproducible build */ //const char * compile_date = __DATE__ " " __TIME__; hoichess-0.22.0/src/lib/0000750000175000017500000000000013276601731014260 5ustar holgerholgerhoichess-0.22.0/src/lib/snprintf.h0000640000175000017500000000077613276601731016307 0ustar holgerholger#ifndef SNPRINTF_H #define SNPRINTF_H #include #include #include extern "C" { extern 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, ...); extern int pg_sprintf(char *str, const char *fmt, ...); extern int pg_fprintf(FILE *stream, const char *fmt, ...); extern int pg_printf(const char *fmt, ...); } #define vsnprintf pg_vsnprintf #define snprintf pg_snprintf #endif // SNPRINTF_H hoichess-0.22.0/src/lib/my_getopt.cc0000640000175000017500000002625713276601731016613 0ustar holgerholger/* * 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.22.0/src/lib/strtok_r.cc0000640000175000017500000000423013276601731016436 0ustar holgerholger/* 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.22.0/src/lib/strtok_r.h0000640000175000017500000000010413276601731016274 0ustar holgerholgerextern char *strtok_r(char *s, const char *delim, char **save_ptr); hoichess-0.22.0/src/lib/snprintf.cc0000640000175000017500000004606213276601731016443 0ustar holgerholger/* * 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. */ extern "C" { #ifdef WIN32 #include #else #include #endif #include #include #include #include #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(const 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(const 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(const 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(const 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; } } } /* extern "C" */ hoichess-0.22.0/src/lib/my_getopt_wrapper.h0000640000175000017500000000323613276601731020205 0ustar holgerholger/* * 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.22.0/src/lib/my_getopt.h0000640000175000017500000000424013276601731016441 0ustar holgerholger/* * 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.22.0/src/xiangqi/0000750000175000017500000000000013276601731015152 5ustar holgerholgerhoichess-0.22.0/src/xiangqi/move.h0000640000175000017500000001227013276601731016274 0ustar holgerholger/* 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 bool is_irreversible() 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 bool Move::is_irreversible() const { return ((ptype() == PAWN && RNK(from()) != RNK(to())) // P forward move || is_capture()); } 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.22.0/src/xiangqi/board_util.cc0000640000175000017500000003621013276601731017610 0ustar holgerholger/* 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(XSIDE(side)), side)) return false; return true; } /* * Detect draw by insufficient material. * Only draw by rule is reported here. Positions that do have a * mate that is very unlikely or cannot be forced are not reported as draw. */ bool Board::is_material_draw() const { if (material[WHITE] == 0 && material[BLACK] == 0) { /* both sides have only their king -> draw */ return true; } /* TODO */ 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'; /* 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; int hmc; int fmc; if (sscanf(s, "%160s %c %d %d", pos, &clr, &hmc, &fmc) != 4) 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; /* 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, bool pseudolegal) const { /* * Compare the input against all possible moves in coordinate * notation and SAN. */ Movelist moves; generate_moves(&moves); if (! pseudolegal) { 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.22.0/src/xiangqi/eval.cc0000640000175000017500000001442313276601731016415 0ustar holgerholger/* Copyright (C) 2004-2008 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, 20, 20, 20, 20, 20, 20, 20, 20, 20, 25, 30, 40, 50, 50, 50, 40, 30, 25, 20, 35, 40, 50, 50, 50, 40, 35, 20, 15, 30, 35, 45, 45, 45, 35, 30, 15, 0, 15, 30, 40, 40, 40, 30, 15, 0, }, { // 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(XRNK(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.22.0/src/xiangqi/board.h0000640000175000017500000001505213276601731016416 0ustar holgerholger/* 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 "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; 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, bool pseudolegal = false) 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; inline bool operator!=(const Board & board) const { return !operator==(board); } /* 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), XSIDE(side)); } /* * 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(XSIDE(side)), side); } inline int Board::material_difference() const { return (material[side] - material[XSIDE(side)]); } inline int Board::get_material(Color side) const { ASSERT_DEBUG(side != NO_COLOR); return material[side]; } #endif // BOARD_H hoichess-0.22.0/src/xiangqi/eval.h0000640000175000017500000000454213276601731016260 0ustar holgerholger/* Copyright (C) 2004-2008 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; unsigned long stat_evals; unsigned long stat_evals_phase1; unsigned long stat_evals_phase2; 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_pawnhash_size(size_t bytes); void clear_pawnhash(); void set_evalcache_size(size_t bytes); void clear_evalcache(); 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.22.0/src/xiangqi/board_init.cc0000640000175000017500000000247313276601731017602 0ustar holgerholger/* 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.22.0/src/xiangqi/basic.h0000640000175000017500000000461713276601731016415 0ustar holgerholger/* 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, 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 XRNK(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(); typedef uint64_t Hashkey; #define NULLHASHKEY ((uint64_t) 0) #endif // BASIC_H hoichess-0.22.0/src/xiangqi/board_generate.cc0000640000175000017500000001234613276601731020431 0ustar holgerholger/* 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) == XSIDE(side)) { \ (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; ifilter_illegal(*this); } hoichess-0.22.0/src/xiangqi/board_attack.cc0000640000175000017500000002244013276601731020102 0ustar holgerholger/* 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. * */ #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.22.0/src/xiangqi/basic.cc0000640000175000017500000000526113276601731016547 0ustar holgerholger/* 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', 'A', 'E', 'H', 'C', 'R', 'K' }; // for xboard #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 hoichess-0.22.0/src/xiangqi/board.cc0000640000175000017500000001636613276601731016565 0ustar holgerholger/* 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; 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(), XSIDE(side), 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(), XSIDE(side), 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); 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.22.0/src/queue.cc0000640000175000017500000000236013276601731015147 0ustar holgerholger/* Copyright (C) 2005-2015 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" #if 0 #include "queue.h" #include "thread.h" static void * thread_main(void * arg) { Queue* q = (Queue*) arg; while (1) { int i = q->get(); printf("get %d\n", i); if (i == 9) { break; } } return NULL; } void test_queue() { Queue q; Thread t(thread_main); t.start((void*) &q); for (unsigned int i=0; i<10; i++) { printf("put %d\n",i ); q.put(i); printf("put %d done\n",i ); } t.wait(); } #endif hoichess-0.22.0/src/version.h0000640000175000017500000000022613276601731015351 0ustar holgerholger#ifndef VERSION_H #define VERSION_H extern const char * version; /* disabled for reproducible build */ //extern const char * compile_date; #endif hoichess-0.22.0/src/sparc32/0000750000175000017500000000000013276601731014767 5ustar holgerholgerhoichess-0.22.0/src/sparc32/leon/0000750000175000017500000000000013276601731015724 5ustar holgerholgerhoichess-0.22.0/src/sparc32/leon/inttypes.h0000640000175000017500000000002413276601731017751 0ustar holgerholger#include "stdint.h" hoichess-0.22.0/src/sparc32/leon/usleep.h0000640000175000017500000000003513276601731017371 0ustar holgerholgerextern int usleep(int usec); hoichess-0.22.0/src/sparc32/leon/usleep.cc0000640000175000017500000000067613276601731017542 0ustar holgerholger#include int usleep(int usec) { struct timeval tv; unsigned long long start, now; if (gettimeofday(&tv, NULL) == -1) { return -1; } start = (unsigned long long) tv.tv_sec * 1000000 + (unsigned long long) tv.tv_usec; now = start; while (now < start+usec) { if (gettimeofday(&tv, NULL) == -1) { return -1; } now = (unsigned long long) tv.tv_sec * 1000000 + (unsigned long long) tv.tv_usec; } return 0; } hoichess-0.22.0/src/sparc32/leon/pthread.h0000640000175000017500000000005413276601731017524 0ustar holgerholger#define SOLARIS_NP #include hoichess-0.22.0/src/sparc32/leon/printf.h0000640000175000017500000000033213276601731017376 0ustar holgerholger/* leonbare functions do not support %llx etc., so always use pg_ versions */ #define sprintf pg_sprintf #define fprintf pg_fprintf #define printf pg_printf #define vsnprintf pg_vsnprintf #define snprintf pg_snprintf hoichess-0.22.0/src/sparc32/leon/stdio.cc0000640000175000017500000000074713276601731017366 0ustar holgerholger#include #include /* fgets() of leonbare seems to be somehow broken.. */ char* fgets(char* buf, int n, FILE* fp) { int fd = fileno(fp); if (fd == -1) { return NULL; } char * p; for (p = buf; p < buf+n-1; p++) { if (read(fd, p, 1) != 1) { return NULL; } if (*p == '\n' || *p == '\r') { putc('\r', stdout); putc('\n', stdout); *p = '\n'; // replace \r by \n break; } else { putc(*p, stdout); } } *(p+1) = '\0'; return buf; } hoichess-0.22.0/src/sparc32/leon/arpa/0000750000175000017500000000000013276601731016647 5ustar holgerholgerhoichess-0.22.0/src/sparc32/leon/arpa/inet.h0000640000175000017500000000021013276601731017751 0ustar holgerholger#ifndef INET_H #define INET_H #define ntohl(x) (x) #define ntohs(x) (x) #define htonl(x) (x) #define htons(x) (x) #endif /* INET_H */ hoichess-0.22.0/src/debug.cc0000640000175000017500000000477313276601731015123 0ustar holgerholger/* 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" #ifdef WITH_THREAD # include "mutex.h" # include "thread.h" #endif #include "eval.h" /* for debug_print_storagesizes() */ #include "node.h" /* for debug_print_storagesizes() */ #include "util.h" #include #include #include #include #include #include void __debug_helper::__dbg(unsigned int level, const char * fmt, ...) { if (debug < level) { return; } #ifdef WITH_THREAD if (mutex) { mutex->lock(); } #endif /* 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"); } #ifdef WITH_THREAD if (mutex) { mutex->unlock(); } #endif } void __debug_helper::__warn(const char * fmt, ...) { #ifdef WITH_THREAD if (mutex) { mutex->lock(); } #endif /* 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"); } #ifdef WITH_THREAD if (mutex) { mutex->unlock(); } #endif } void __debug_helper::__bug(const char * fmt, ...) { #ifdef WITH_THREAD if (mutex) { mutex->lock(); } #endif /* 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); #ifdef WITH_THREAD if (mutex) { mutex->unlock(); } #endif raise(SIGABRT); exit(EXIT_FAILURE); } hoichess-0.22.0/src/win32/0000750000175000017500000000000013276601731014454 5ustar holgerholgerhoichess-0.22.0/src/spinlock.h0000640000175000017500000000306413276601731015511 0ustar holgerholger/* Copyright (C) 2005-2017 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 SPINLOCK_H #define SPINLOCK_H #include "common.h" #if defined(HAVE_PTHREAD) # include #elif defined(WIN32) # include #endif class Spinlock { private: #if defined(HAVE_PTHREAD) pthread_spinlock_t lck; #elif defined(WIN32) CRITICAL_SECTION cs; #endif public: Spinlock(); ~Spinlock(); public: inline void lock(); inline void unlock(); }; inline void Spinlock::lock() { #if defined(HAVE_PTHREAD) int res = pthread_spin_lock(&lck); ASSERT(res == 0); #elif defined(WIN32) EnterCriticalSection(&cs); /* void */ #endif } inline void Spinlock::unlock() { #if defined(HAVE_PTHREAD) int res = pthread_spin_unlock(&lck); ASSERT(res == 0); #elif defined(WIN32) LeaveCriticalSection(&cs); /* void */ #endif } #endif // SPINLOCK_H hoichess-0.22.0/src/queue.h0000640000175000017500000001116013276601731015007 0ustar holgerholger/* Copyright (C) 2005-2015 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 QUEUE_H #define QUEUE_H #include "common.h" #include #if defined(HAVE_PTHREAD) # include # include # include #elif defined(WIN32) # include #else # error no thread support is available #endif template class Queue { private: #if defined(HAVE_PTHREAD) pthread_mutex_t mtx; pthread_cond_t cv; #elif defined(WIN32) CRITICAL_SECTION cs; HANDLE sem; #endif std::list queue; public: Queue(); ~Queue(); public: void put(const T& elem); T get(); bool wait(unsigned long long timeout_us); void clear(); }; template Queue::Queue() { #if defined(HAVE_PTHREAD) int res = pthread_mutex_init(&mtx, NULL); ASSERT(res == 0); res = pthread_cond_init(&cv, NULL); ASSERT(res == 0); #elif defined(WIN32) InitializeCriticalSection(&cs); /* void */ sem = CreateSemaphore(NULL, 0, INT_MAX, NULL); ASSERT(sem != NULL); #endif } template Queue::~Queue() { #if defined(HAVE_PTHREAD) int res = pthread_mutex_destroy(&mtx); ASSERT(res == 0); res = pthread_cond_destroy(&cv); ASSERT(res == 0); #elif defined(WIN32) DeleteCriticalSection(&cs); /* void */ BOOL res = CloseHandle(sem); ASSERT(res); #endif } template void Queue::put(const T& elem) { #if defined(HAVE_PTHREAD) int res = pthread_mutex_lock(&mtx); ASSERT(res == 0); queue.push_back(elem); res = pthread_cond_signal(&cv); ASSERT(res == 0); res = pthread_mutex_unlock(&mtx); ASSERT(res == 0); #elif defined(WIN32) EnterCriticalSection(&cs); /* void */ queue.push_back(elem); BOOL res = ReleaseSemaphore(sem, 1, NULL); ASSERT(res); LeaveCriticalSection(&cs); /* void */ #endif } template T Queue::get() { #if defined(HAVE_PTHREAD) int res = pthread_mutex_lock(&mtx); ASSERT(res == 0); while (queue.empty()) { res = pthread_cond_wait(&cv, &mtx); ASSERT(res == 0); } T elem = queue.front(); queue.pop_front(); res = pthread_mutex_unlock(&mtx); ASSERT(res == 0); return elem; #elif defined(WIN32) DWORD res = WaitForSingleObject(sem, INFINITE); ASSERT(res == WAIT_OBJECT_0); EnterCriticalSection(&cs); /* void */ ASSERT(!queue.empty()); T elem = queue.front(); queue.pop_front(); LeaveCriticalSection(&cs); /* void */ return elem; #endif } template bool Queue::wait(unsigned long long timeout_us) { #if defined(HAVE_PTHREAD) /* Ugh. pthread_cond_timedwait() needs absolute time. */ struct timeval now; struct timespec timeout; int res = gettimeofday(&now, NULL); ASSERT(res == 0); unsigned long long us_tmp = now.tv_usec + timeout_us; timeout.tv_nsec = us_tmp % (int) 1E6 * 1000; timeout.tv_sec = now.tv_sec + us_tmp / (int) 1E6; res = pthread_mutex_lock(&mtx); ASSERT(res == 0); bool ret = true; while (queue.empty()) { res = pthread_cond_timedwait(&cv, &mtx, &timeout); if (res == ETIMEDOUT) { ret = false; break; } ASSERT(res == 0); } res = pthread_mutex_unlock(&mtx); ASSERT(res == 0); return ret; #elif defined(WIN32) DWORD res = WaitForSingleObject(sem, timeout_us / (int) 1E3); if (res == WAIT_TIMEOUT) { return false; } ASSERT(res == WAIT_OBJECT_0); return true; #endif } template void Queue::clear() { #if defined(HAVE_PTHREAD) int res = pthread_mutex_lock(&mtx); ASSERT(res == 0); queue.erase(queue.begin(), queue.end()); res = pthread_mutex_unlock(&mtx); ASSERT(res == 0); #elif defined(WIN32) EnterCriticalSection(&cs); /* void */ /* There seems to be no way to simply set the semaphore to zero, * thus we cannot just clear the queue. Instead we remove each * element individually, decrementing the semaphore each time * (like the normal get() procedure does). */ while (queue.size() != 0) { DWORD res = WaitForSingleObject(sem, INFINITE); ASSERT(res == WAIT_OBJECT_0); queue.pop_front(); } LeaveCriticalSection(&cs); /* void */ #endif } #endif // QUEUE_H hoichess-0.22.0/src/main.cc0000640000175000017500000002226413276601731014754 0ustar holgerholger/* Copyright (C) 2004-2014 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 #ifndef WIN32 # include #endif #include #include #include #include #include #include #include "common.h" #include "shell.h" #ifdef VHDLCHESS # include "vhdlchessshell.h" #endif #include "util.h" #ifdef HAVE_GETOPT # include #else /* Must include this last or there will be conflicts * with getopt() from unistd.h. */ # include "lib/my_getopt_wrapper.h" #endif /* Global variables, declared in common.h. */ unsigned int debug = 0; unsigned int verbose = 0; bool ansicolor = false; /* Shell must be global because we need it in the signal handler. */ static Shell * shell; #ifndef WIN32 static void sigint_handler(int sig) { (void) sig; shell->interrupt(); } #endif extern void init(); extern const char * builtin_initcmds[]; static void print_version() { printf("%s %s\n", PROGNAME, version); } static void print_copyright() { printf("Copyright (C) 2004-2017 %s %s\n", AUTHOR, AUTHOR_EMAIL); #ifndef VHDLCHESS printf( "This program is free software and comes with ABSOLUTELY NO WARRANTY.\n" "See the GNU General Public License for more details.\n"); #endif } 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(" -x | --xboard Start in xboard mode\n"); printf(" --source 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); } struct opts { const char * xboard; std::list source_files; std::list initcmds; bool norc; const char * color; }; static int parse_commandline(int argc, char ** argv, struct opts * opts) { /* defaults */ opts->xboard = "false"; // opts->source_files is the empty list // opts->initcmds is the empty list opts->norc = false; opts->color = "auto"; /* option definitions */ const char * short_opts = "hVvdx::"; struct option long_options[] = { { "help", 0, 0, 'h' }, { "version", 0, 0, 'V' }, { "verbose", 2, 0, 'v' }, { "debug", 2, 0, 'd' }, { "xboard", 2, 0, 'x' }, { "source", 1, 0, 132 }, { "color", 1, 0, 133 }, { "initcmd", 1, 0, 136 }, { "norc", 0, 0, 137 }, { 0, 0, 0, 0 } }; /* parse arguments */ 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 'x': /* --xboard */ if (optarg) { opts->xboard = optarg; } else { opts->xboard = "true"; } break; case 132: /* --source */ opts->source_files.push_back(optarg); break; case 133: /* --color */ opts->color = optarg; break; case 136: /* --initcmd */ opts->initcmds.push_back(optarg); break; case 137: /* --norc */ opts->norc = true; break; case '?': usage(argv[0]); exit(1); default: BUG("getopt_long() returned %d", c); } } return 0; } #define IS_OPTION_TRUE(s) (strcmp((s), "yes" ) == 0 \ || strcmp((s), "on" ) == 0 \ || strcmp((s), "true") == 0) #define IS_OPTION_FALSE(s) (strcmp((s), "no" ) == 0 \ || strcmp((s), "off" ) == 0 \ || strcmp((s), "false") == 0) #define IS_OPTION_AUTO(s) (strcmp((s), "auto" ) == 0 \ || strcmp((s), "default") == 0) static void setup(struct opts * opts) { /* decide about ANSI color */ if (opts->color) { if (IS_OPTION_TRUE(opts->color)) { ansicolor = true; } else if (IS_OPTION_FALSE(opts->color)) { ansicolor = false; } else if (IS_OPTION_AUTO(opts->color)) { /* Most Unix platforms have color terminals. But on * Win32 systems, ANSI color is normally not available. */ #ifdef WIN32 ansicolor = false; #else if (isatty(1)) { ansicolor = true; } else { ansicolor = false; } #endif } else { fprintf(stderr, "Illegal argument to option --color: %s\n", opts->color); exit(EXIT_FAILURE); } } if (ansicolor) { verbose && printf("Enabled ANSI color terminal.\n"); } } static void setup_shell(struct opts * opts) { /* decide about xboard mode */ bool xboard_mode = false; if (opts->xboard) { if (IS_OPTION_TRUE(opts->xboard)) { xboard_mode = true; } else if (IS_OPTION_FALSE(opts->xboard)) { xboard_mode = false; } else { fprintf(stderr, "Illegal argument to option --xboard: %s\n", opts->xboard); exit(EXIT_FAILURE); } } /* xboard mode */ shell->set_xboard(xboard_mode); /* if there are no --initcmd options given, use builtin commands */ if (opts->initcmds.size() == 0) { for (const char ** p = builtin_initcmds; *p != NULL; p++) { opts->initcmds.push_back(*p); } } /* read --source files given on command line; note that they are * passed in reverse order to shell, because the last opened source * is read as first */ for (std::list::reverse_iterator it = opts->source_files.rbegin(); it != opts->source_files.rend(); it++) { FILE * fp = fopen(*it, "r"); if (fp == NULL) { fprintf(stderr, "Cannot open %s for reading: %s\n", *it, strerror(errno)); exit(EXIT_FAILURE); } shell->source_file(fp, *it); } /* read hoichess.rc; note that commands here are executed _before_ * commands in --source files, because the last opened source is * read as first */ if (!opts->norc) { #if defined(HOICHESS) const char * rcfile_base = "hoichess.rc"; #elif defined(HOIXIANGQI) const char * rcfile_base = "hoixiangqi.rc"; #endif /* we try several locations and open only the first found */ std::list rcfiles; /* current directory */ rcfiles.push_back(std::string("./") + rcfile_base); /* $HOME/.hoichess */ const char * home = getenv("HOME"); if (home != NULL) { rcfiles.push_back(home + std::string("/.hoichess/") + rcfile_base); } #ifdef WIN32 /* $USERPROFILE/.hoichess */ const char * profile = getenv("USERPROFILE"); if (profile != NULL) { rcfiles.push_back(profile + std::string("/.hoichess/") + rcfile_base); } #endif #ifdef DATA_DIR /* installation dependent default location */ rcfiles.push_back(DATA_DIR + std::string("/") + rcfile_base); #endif /* read the first file that was found */ for (std::list::iterator it = rcfiles.begin(); it != rcfiles.end(); it++) { FILE * fp = fopen(it->c_str(), "r"); if (fp != NULL) { shell->source_file(fp, it->c_str()); break; } } } } static int run_shell(struct opts * opts) { /* execute initial commands */ for (std::list::iterator it = opts->initcmds.begin(); it != opts->initcmds.end(); it++) { int ret = shell->exec_command(*it); if (ret != SHELL_CMD_OK) { return EXIT_FAILURE; } } /* run the shell (starting with commands from sourced files) */ return shell->main(); } int main(int argc, char ** argv) { struct opts opts; parse_commandline(argc, argv, &opts); if (IS_OPTION_TRUE(opts.xboard)) { /* xboard has a timeout of 2 seconds after 'protover', and * falls back to protocol version 1 if it does not receive the * 'feature' reply within that time. * To prevent this in case our initialization takes too long, * we send a 'feature' line now if we're running under xboard, * as suggested by the xboard protocol spec. */ printf("feature done=0\n"); } print_version(); print_copyright(); printf("\n"); if (verbose || debug) { printf("Verbosity set to %u.\n", verbose); printf("Debug level set to %u.\n", debug); printf("\n"); } setup(&opts); init(); #ifdef VHDLCHESS shell = new VHDLChessShell(); #else shell = new Shell(); #endif setup_shell(&opts); #ifndef WIN32 signal(SIGINT, sigint_handler); #endif int ret = run_shell(&opts); #ifndef WIN32 signal(SIGINT, SIG_IGN); #endif delete shell; return ret; } hoichess-0.22.0/src/mutex.h0000640000175000017500000000223213276601731015025 0ustar holgerholger/* Copyright (C) 2005-2015 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 MUTEX_H #define MUTEX_H #include "common.h" #if defined(HAVE_PTHREAD) # include #elif defined(WIN32) # include #endif class Mutex { private: #if defined(HAVE_PTHREAD) pthread_mutex_t mtx; #elif defined(WIN32) HANDLE hndl; #endif public: Mutex(); ~Mutex(); public: void lock(); void unlock(); }; #endif // MUTEX_H hoichess-0.22.0/src/chess/0000750000175000017500000000000013276601731014617 5ustar holgerholgerhoichess-0.22.0/src/chess/move.h0000640000175000017500000001454513276601731015750 0ustar holgerholger/* 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 bool is_irreversible() 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(); static Move autoselect(const Board& board, Square from, Square to, Piece promote_to); 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 str2(const Board & board) 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 bool Move::is_irreversible() const { return (ptype() == PAWN || is_capture() || is_castle()); } 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.22.0/src/chess/board_util.cc0000640000175000017500000004245013276601731017260 0ustar holgerholger/* 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(XSIDE(side)), side)) return false; return true; } /* * Detect draw by insufficient material. * Only draw by rule is reported here. Positions (e.g. KNKN) that do have a * mate that is very unlikely or cannot be forced are not reported as draw. */ bool Board::is_material_draw() const { /* shortcuts */ Bitboard wn = get_knights(WHITE); Bitboard bn = get_knights(BLACK); Bitboard wb = get_bishops(WHITE); Bitboard bb = get_bishops(BLACK); Bitboard wbl = wb & LIGHTBITBOARD; Bitboard wbd = wb & DARKBITBOARD; Bitboard bbl = bb & LIGHTBITBOARD; Bitboard bbd = bb & DARKBITBOARD; if (material[WHITE] == 0 && material[BLACK] == 0) { /* both sides have only their king -> draw */ return true; } else if (get_pawns(WHITE) || get_pawns(BLACK) || get_rooks(WHITE) || get_rooks(BLACK) || get_queens(WHITE) || get_queens(BLACK)) { /* at least one side has a pawn, rook or queen -> no draw */ return false; } else if ((wn | bn).popcnt() == 1 && !wb && !bb) { /* KNK -> draw */ return true; } else if ((wb | bb).popcnt() == 1 && !wn && !bn) { /* KBK -> draw */ return true; } else if (!wn && !bn && (!(wbl | bbl) || !(wbd | bbd))) { /* KBKB with all bishops of same color -> draw */ return true; } else { 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[46m"; 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, bool pseudolegal) const { /* * Compare the input against all possible moves in coordinate * notation and SAN. */ Movelist moves; generate_moves(&moves); if (! pseudolegal) { 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.22.0/src/chess/eval.cc0000640000175000017500000004556013276601731016070 0ustar holgerholger/* Copyright (C) 2004-2008 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 "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(XRNK(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_EARLYROOKADVANCE -10 #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 rank1 = (side == WHITE) ? RANK1 : RANK8; 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 #ifdef EVAL_EARLYROOKADVANCE /* Keep rooks on back rank until endgame */ if (phase != ENDGAME) { if (RNK(sq) != rank1) { score += EVAL_EARLYROOKADVANCE; } } #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_KINGPAWNSHIELD 8 //#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_KINGPAWNSHIELD /* Pawn shield */ if (phase != ENDGAME) { static const Bitboard kingmask[2] = { /* A1,B1,C1,F1,G1,H1 A8,B8,C8,F8,G8,H8 */ 0x00000000000000e7ULL, 0xe700000000000000ULL }; static const Bitboard pawnmask[2] = { /* A2,B2,C2,F2,G2,H2 A7,B7,C7,F7,G7,H7 */ 0x000000000000e700ULL, 0x00e7000000000000ULL }; if (board->get_kings(side) & kingmask[side]) { Bitboard pawnshield = board->king_attacks(kingsq) & pawnmask[side] & board->get_pawns(side); score += pawnshield.popcnt() * EVAL_KINGPAWNSHIELD; } } #endif // EVAL_KINGPAWNSHIELD #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 // EVAL_SQAROUNDKINGATKD 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.22.0/src/chess/board.h0000640000175000017500000002237613276601731016072 0ustar holgerholger/* 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 "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; // TODO pack into flags 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]; // TODO remove? unsigned int flags; Square epsq; int material[2]; bool has_castled[2]; // TODO pack into flags unsigned int pce_movecnt[64]; // TODO replace by Bitboard? Hashkey hashkey; Hashkey pawnhashkey; /* Constructors / Destructor, defined in board.cc */ public: Board(); Board(const std::string& fen); Board(const Piece pieces[], const Color colors[], Color side, Square epsq, unsigned int flags, unsigned int moveno, unsigned int movecnt50); 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_move(Movelist * movelist, Square from, Square to, bool allpromo) 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, bool pseudolegal = false) 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; inline bool operator!=(const Board & board) const { return !operator==(board); } /* 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), XSIDE(side)); } /* * 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(XSIDE(side)), side); } inline int Board::material_difference() const { return (material[side] - material[XSIDE(side)]); } 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.22.0/src/chess/eval.h0000640000175000017500000000556313276601731015731 0ustar holgerholger/* Copyright (C) 2004-2008 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; unsigned long stat_evals; unsigned long stat_evals_phase1; unsigned long stat_evals_phase2; 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_pawnhash_size(size_t bytes); void clear_pawnhash(); void set_evalcache_size(size_t bytes); void clear_evalcache(); 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.22.0/src/chess/i386/0000750000175000017500000000000013276601731015310 5ustar holgerholgerhoichess-0.22.0/src/chess/i386/bitboard_asm.h0000640000175000017500000000616713276601731020122 0ustar holgerholger/* 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.22.0/src/chess/x86_64/0000750000175000017500000000000013276601731015555 5ustar holgerholgerhoichess-0.22.0/src/chess/x86_64/bitboard_asm.h0000640000175000017500000000317213276601731020360 0ustar holgerholger/* Copyright (C) 2005-2011 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_64 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 { uint64_t dummy1, dummy2; asm(" bsfq %1, %0" "\n\t" " jnz 1f" "\n\t" " movq $-1, %0" "\n\t" "1:" : "=&r" (dummy1), "=&r" (dummy2) : "1" ((uint64_t) (bits)) : "cc"); return (dummy1); } #endif #ifdef USE_ASM_MSB inline int Bitboard::msb() const { uint64_t dummy1, dummy2; asm(" bsrq %1, %0" "\n\t" " jnz 1f" "\n\t" " movq $-1, %0" "\n\t" "1:" : "=&r" (dummy1), "=&r" (dummy2) : "1" ((uint64_t) (bits)) : "cc"); return (dummy1); } #endif #ifdef USE_ASM_POPCNT #error "asm popcnt() not implemented" #endif hoichess-0.22.0/src/chess/board_init.cc0000640000175000017500000000336213276601731017245 0ustar holgerholger/* 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.22.0/src/chess/bitboard_rotated.cc0000640000175000017500000001621713276601731020446 0ustar holgerholger/* Copyright (C) 2004-2008 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" /***************************************************************************** * * Stuff needed for rotated bitboards. * *****************************************************************************/ const unsigned 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 unsigned 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 unsigned int 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 unsigned 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 unsigned 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 unsigned int 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 unsigned 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 unsigned 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 unsigned int Bitboard::_diagmask_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 unsigned 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 unsigned int 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 unsigned 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 unsigned 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 unsigned int Bitboard::_diagmask_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; unsigned 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. * */ #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 XRNK(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(); typedef uint64_t Hashkey; #define NULLHASHKEY ((uint64_t) 0) #endif // BASIC_H hoichess-0.22.0/src/chess/bitboard.cc0000640000175000017500000002102713276601731016717 0ustar holgerholger/* Copyright (C) 2004-2008 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" /***************************************************************************** * * Bitboard utility functions. * *****************************************************************************/ void Bitboard::print() const { for (int r=0; r<8; r++) { printf("%2d..%2d ", r*8, r*8+7); 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() { init_luts(); init_attack_bb(); init_pawn_capt_bb(); init_ray_bb(); init_masks(); init_rot_atk(); } void Bitboard::init_luts() { 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)]; } } hoichess-0.22.0/src/chess/bitboard.h0000640000175000017500000001073713276601731016567 0ustar holgerholger/* Copyright (C) 2004-2008 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 (Bitboard(0ULL)) #define LIGHTBITBOARD (Bitboard(0x55aa55aa55aa55aaULL)) #define DARKBITBOARD (Bitboard(0xaa55aa55aa55aa55ULL)) 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]; private: static int8_t lsb_lut[65536]; static int8_t msb_lut[65536]; static int8_t popcnt_lut[65536]; static const unsigned int _map_l90[64]; static const unsigned int _map_l45[64]; static const unsigned int _map_r45[64]; static const unsigned int _inv_map_l90[64]; static const unsigned int _inv_map_l45[64]; static const unsigned int _inv_map_r45[64]; static const unsigned int _shift_0[64]; static const unsigned int _shift_l90[64]; static const unsigned int _shift_l45[64]; static const unsigned int _shift_r45[64]; static const unsigned int _diaglen_l45[64]; static const unsigned int _diaglen_r45[64]; static const unsigned int _diagmask_l45[64]; static const unsigned int _diagmask_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_luts(); 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(); public: static inline unsigned int map_l90(unsigned int a); static inline unsigned int map_l45(unsigned int a); static inline unsigned int map_r45(unsigned int a); static inline unsigned int inv_map_l90(unsigned int b); static inline unsigned int inv_map_l45(unsigned int b); static inline unsigned int inv_map_r45(unsigned int b); static inline unsigned int shift_0(unsigned int a); static inline unsigned int shift_l90(unsigned int a); static inline unsigned int shift_l45(unsigned int a); static inline unsigned int shift_r45(unsigned int a); static inline unsigned int diaglen_l45(unsigned int a); static inline unsigned int diaglen_r45(unsigned int a); static inline unsigned int diagmask_l45(unsigned int a); static inline unsigned int diagmask_r45(unsigned int a); }; #include "bitboard_inlines.h" #endif // BITBOARD_H hoichess-0.22.0/src/chess/board_generate.cc0000640000175000017500000004106613276601731020077 0ustar holgerholger/* 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(XSIDE(side)); 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(XSIDE(side)).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(XSIDE(side)).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(XSIDE(side)).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(XSIDE(side)).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(XSIDE(side)).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(XSIDE(side)); 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(XSIDE(side)); 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(XSIDE(side)); 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(XSIDE(side)); 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(XSIDE(side)); 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(XSIDE(side)); 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)); } } #if 0 This code help in finding a bug in generate_escapes(), so we leave it, just in case. void Board::generate_escapes(Movelist * movelist) const { ASSERT(movelist->size() == 0); do_generate_escapes(movelist); movelist->filter_illegal(*this); Movelist movelist2; generate_moves(&movelist2, false); movelist2.filter_illegal(*this); bool failed = false; if (movelist->size() != movelist2.size()) { failed = true; } else { for (unsigned int i=0; isize(); i++) { bool found = false; for (unsigned int j=0; j>>>>>>>>>>>>>>>>>>\n"); this->print(); printf("%s\n", this->get_fen().c_str()); printf("generate_escapes():"); for (unsigned int i=0; isize(); i++) { printf(" %s", (*movelist)[i].str().c_str()); } printf("\n"); printf("generate_moves():"); for (unsigned int i=0; iadd(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, false); } /* Also try enpassant capture. */ if (checker == get_eppawn()) { from_bb = pawn_captures(epsq, XSIDE(side)) & 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) & ~get_pawns(side) // would be captures, not blocks & ~get_kings(side); // already considered above /* 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, false); } } } /* * 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 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, bool allpromo) const { ASSERT_DEBUG(to != get_king(XSIDE(side))); Piece ptype = piece_at(from); if (ptype == PAWN && to == epsq) { movelist->add(Move::enpassant(from, to)); } else if (get_pieces(XSIDE(side)).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)); if (allpromo) { 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)); if (allpromo) { movelist->add(Move::promotion(from, to,BISHOP)); movelist->add(Move::promotion(from, to,ROOK)); } } else { movelist->add(Move::normal(from, to, ptype)); } } } hoichess-0.22.0/src/chess/board_attack.cc0000640000175000017500000000703713276601731017554 0ustar holgerholger/* 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 { /* 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; /* pawns */ if (pawn_captures(to, !atkside) & get_pawns(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.22.0/src/chess/move.cc0000640000175000017500000001474113276601731016104 0ustar holgerholger/* 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 Move Move::autoselect(const Board& board, Square from, Square to, Piece promote_to) { Move mov; Piece ptype = board.piece_at(from); Color pside = board.color_at(from); Piece cap_ptype = board.piece_at(to); switch (ptype) { case PAWN: if (to == board.get_epsq()) { mov = Move::enpassant(from, to); } else if ((pside == WHITE && RNK(to) == RANK8) || (pside == BLACK && RNK(to) == RANK1)) { if (cap_ptype != NO_PIECE) { mov = Move::promotion_capture(from, to, promote_to, cap_ptype); } else { mov = Move::promotion(from, to, promote_to); } } else if (cap_ptype != NO_PIECE) { mov = Move::capture(from, to, ptype, cap_ptype); } else { mov = Move::normal(from, to, ptype); } break; case KING: if ((from == E1 && (to == C1 || to == G1)) || (from == E8 && (to == C8 || to == G8))) { mov = Move::castle(from, to); break; } /* fall through case */ default: if (cap_ptype != NO_PIECE) { mov = Move::capture(from, to, ptype, cap_ptype); } else { mov = Move::normal(from, to, ptype); } break; } ASSERT_DEBUG(mov.is_valid(board)); return mov; } /* 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()], is_promotion() ? tolower(piece_char[promote_to()]) : '\0' ); return std::string(ss); } /* * Return a string for a move verbose coordinate notation, e.g. * Qe2xe4, Pe7-e8=Q, Ke1xg1 (white king-side castling). */ std::string Move::str2(const Board & board) const { char ss[16]; snprintf(ss, sizeof(ss), "%c%s%c%s%c%c", piece_char[ptype()], square_str[from()], (board.piece_at(to()) != NO_PIECE ? 'x' : '-'), square_str[to()], is_promotion() ? '=' : '\0', is_promotion() ? toupper(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.22.0/src/chess/win32/0000750000175000017500000000000013276601731015561 5ustar holgerholgerhoichess-0.22.0/src/chess/win32/bitboard_asm.h0000640000175000017500000000334013276601731020361 0ustar holgerholger/* 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.22.0/src/chess/basic.cc0000640000175000017500000000422013276601731016206 0ustar holgerholger/* 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 hoichess-0.22.0/src/chess/board.cc0000640000175000017500000003770713276601731016234 0ustar holgerholger/* 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()); } } Board::Board(const Piece pieces[], const Color colors[], Color side, Square epsq, unsigned int flags, unsigned int moveno, unsigned int movecnt50) { clear(); for (int i=0; i<64; i++) { if (pieces[i] != NO_PIECE) { place_piece(i, colors[i], pieces[i]); } } set_side(side); if (epsq != NO_SQUARE) { set_epsq(epsq); } else { clear_epsq(); } if (flags & WKCASTLE) { set_flag(WKCASTLE); } if (flags & WQCASTLE) { set_flag(WQCASTLE); } if (flags & BKCASTLE) { set_flag(BKCASTLE); } if (flags & BQCASTLE) { set_flag(BQCASTLE); } /* TODO no functions to set moveno and movecnt50 */ this->moveno = moveno; this->movecnt50 = movecnt50; } void Board::clear() { side = WHITE; 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_capture()) { if (mov.is_promotion()) { remove_piece(mov.from(), side, PAWN); remove_piece(mov.to(), XSIDE(side), mov.cap_ptype()); place_piece(mov.to(), side, mov.promote_to()); } else { remove_piece(mov.to(), XSIDE(side), 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_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(), XSIDE(side), PAWN); } 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_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.is_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.is_enpassant()) { ASSERT_DEBUG(mov.to() == epsq); move_piece(mov.to(), mov.from(), side, PAWN); place_piece(get_eppawn(), XSIDE(side), PAWN); } else if (mov.is_capture()) { if (mov.is_promotion()) { remove_piece(mov.to(), side, mov.promote_to()); place_piece(mov.to(), XSIDE(side), mov.cap_ptype()); place_piece(mov.from(), side, PAWN); } else { move_piece(mov.to(), mov.from(), side, mov.ptype()); place_piece(mov.to(), XSIDE(side), mov.cap_ptype()); } } else if (mov.is_normal()) { if (mov.is_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.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 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); 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]; /* Alternative (also for remove_piece() and move_piece()): * To avoid the 'if', create a second table of hash keys that * contains 0 for all pieces except pawn. Then we can always do * the xor, since xor-ing with 0 for non-pawns has no effect. * * Status: * This did not speed up (nor slow down) on a Pentium-M, even not if * the two tables were stored interleaved (hashkeys[side][ptype][sq][0] * for normal, hashkeys[side][ptype][sq][1] for pawn hash keys) * to make use of burst memory access as we always need both keys in * sequence. So the old code remains here because it is clearer. * Maybe try again on a 64-bit machine? */ 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]; /* See place_piece() for a comment */ 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; } /* A quick implementation of a pre-computed table * with all from-to-pairs to reduce computation here * did not show a significant speed benefit. */ hashkey ^= hashkeys[side][ptype][from]; hashkey ^= hashkeys[side][ptype][to]; /* See place_piece() for a comment */ 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.22.0/src/chess/bitboard_inlines.h0000640000175000017500000001564013276601731020306 0ustar holgerholger/* Copyright (C) 2004-2008 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_INLINES_H #define BITBOARD_INLINES_H #include "common.h" #include "bitboard.h" #if defined(USE_ASM) && defined(__GNUC__) && defined(__i386__) # define USE_ASM_LSB # define USE_ASM_MSB //# define USE_ASM_POPCNT // LUT version is faster # define USE_LUT_POPCNT # include "i386/bitboard_asm.h" # define BITBOARD_FIRSTBIT msb #elif defined(USE_ASM) && defined(__GNUC__) && defined(__x86_64__) # define USE_ASM_LSB # define USE_ASM_MSB //# define USE_ASM_POPCNT // not implemented # define USE_LUT_POPCNT # include "x86_64/bitboard_asm.h" # define BITBOARD_FIRSTBIT msb #elif defined(USE_ASM) && defined(__WIN32__) && !defined(__WIN64__) # define USE_ASM_LSB # define USE_ASM_MSB //# define USE_ASM_POPCNT // not implemented # define USE_LUT_POPCNT # include "win32/bitboard_asm.h" # define BITBOARD_FIRSTBIT msb #elif defined(__GNUC__) # define USE_BUILTIN_LSB # define USE_BUILTIN_MSB //# define USE_BUILTIN_POPCNT // LUT version is faster // (at least on i386 and amd64: +12% nps) # define USE_LUT_POPCNT # define BITBOARD_FIRSTBIT lsb #else # define USE_LUT_LSB # define USE_LUT_MSB # define USE_LUT_POPCNT # define BITBOARD_FIRSTBIT msb #endif /***************************************************************************** * Static Functions. */ inline unsigned int Bitboard::map_l90(unsigned int a) { unsigned int b = (((7-a)&0x07)<<3) | ((a&0x38)>>3); ASSERT_DEBUG(b == _map_l90[a]); return b; //return _map_l90[a]; } inline unsigned int Bitboard::map_l45(unsigned int a) { return _map_l45[a]; } inline unsigned int Bitboard::map_r45(unsigned int a) { return _map_r45[a]; } inline unsigned int Bitboard::inv_map_l90(unsigned int b) { unsigned int a = ((b&0x07)<<3) | (7-((b&0x38)>>3)); ASSERT_DEBUG(a == _inv_map_l90[b]); return a; //return _inv_map_l90[b]; } inline unsigned int Bitboard::inv_map_l45(unsigned int b) { return _inv_map_l45[b]; } inline unsigned int Bitboard::inv_map_r45(unsigned int b) { return _inv_map_r45[b]; } inline unsigned int Bitboard::shift_0(unsigned int a) { unsigned int s = (a&0x38); ASSERT_DEBUG(s == _shift_0[a]); return s; //return _shift_0[a]; } inline unsigned int Bitboard::shift_l90(unsigned int a) { unsigned int s = (((7-a)&0x07)<<3); ASSERT_DEBUG(s == _shift_l90[a]); return s; //return _shift_l90[a]; } inline unsigned int Bitboard::shift_l45(unsigned int a) { return _shift_l45[a]; } inline unsigned int Bitboard::shift_r45(unsigned int a) { return _shift_r45[a]; } inline unsigned int Bitboard::diaglen_l45(unsigned int a) { return _diaglen_l45[a]; } inline unsigned int Bitboard::diaglen_r45(unsigned int a) { return _diaglen_r45[a]; } inline unsigned int Bitboard::diagmask_l45(unsigned int a) { return _diagmask_l45[a]; } inline unsigned int Bitboard::diagmask_r45(unsigned int a) { return _diagmask_r45[a]; } /***************************************************************************** * Non-static Functions. */ 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 { return BITBOARD_FIRSTBIT(); } /* * Lookup table version of msb/lsb scan routines. * This code was taken from GNU Chess. */ #ifdef USE_LUT_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 #ifdef USE_LUT_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. */ #ifdef USE_LUT_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 #ifdef USE_BUILTIN_LSB inline int Bitboard::lsb() const { if (bits) { return __builtin_ctzll(bits); } else { return -1; } } #endif #ifdef USE_BUILTIN_MSB inline int Bitboard::msb() const { if (bits) { return 63 - __builtin_clzll(bits); } else { return -1; } } #endif #ifdef USE_BUILTIN_POPCNT inline int Bitboard::popcnt() const { return __builtin_popcountll(bits); } #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)) & diagmask_l45(from)]; } inline Bitboard Bitboard::atkr45(Square from) const { return rot_atk_r45[from][(bits >> shift_r45(from)) & diagmask_r45(from)]; } #endif // BITBOARD_INLINES_H hoichess-0.22.0/src/build/0000750000175000017500000000000013276601731014611 5ustar holgerholgerhoichess-0.22.0/src/build/print_version_str0000750000175000017500000000100413276601731020323 0ustar holgerholger#!/bin/sh if [ -n "$1" ]; then basedir="$1" else mydir=`dirname "$0"` basedir="$mydir"/.. fi svn info "$basedir" >/dev/null 2>&1 if [ $? -eq 0 ]; then # determine branch name path=`svn info "$basedir" | awk '/^URL:/ {print $2}'` branch=`basename "$path"` # determine revision (replace ':' because this breaks makefile syntax) rev=`svnversion "$basedir" | sed -e 's/:/_/g'` version_str="$branch-$rev-svn" else version_str=`awk '/^Version/ {print $2; exit}' "$basedir/ChangeLog"` fi echo "$version_str" hoichess-0.22.0/src/build/configure.sh0000750000175000017500000000066613276601731017141 0ustar holgerholger#!/bin/sh mydir=`dirname "$0"` if [ -z "$1" ]; then echo "Usage: $0 " >&2 exit 1 fi outputdir="$1" cat > "$outputdir"/config.mk < "$outputdir"/config.log <&2 exit 2 elif ! $CXX --version >/dev/null 2>&1; then echo "CXX not working" >&2 exit 2 fi tmpdir=`mktemp -d` || exit 2 cat > "$tmpdir"/test.cc < int main(int argc, char ** argv) { char buf[64]; snprintf(buf, sizeof(buf), "foo%d", 1); va_list args; snprintf(buf, sizeof(buf), "foo%d", args); return 0; } EOF $CXX $CXXFLAGS -o "$tmpdir"/test "$tmpdir"/test.cc >> "$config_log" 2>&1 ret=$? rm -rf "$tmpdir" if [ $ret -eq 0 ]; then echo "yes" | tee -a "$config_log" echo "HAVE_SNPRINTF = 1" >> "$config_mk" exit 0 else echo "no" | tee -a "$config_log" echo "HAVE_SNPRINTF = 0" >> "$config_mk" exit 0 fi hoichess-0.22.0/src/build/configure.d/check-getopt.sh0000750000175000017500000000147613276601731021740 0ustar holgerholger#!/bin/sh config_mk="$1" config_log="$2" echo -n "Checking if getopt_long is available..." | tee -a "$config_log" if [ -z "$CXX" ]; then echo "CXX not defined" >&2 exit 2 elif ! $CXX --version >/dev/null 2>&1; then echo "CXX not working" >&2 exit 2 fi tmpdir=`mktemp -d` || exit 2 cat > "$tmpdir"/test.cc < int main(int argc, char ** argv) { const char * short_opts = ""; struct option long_options[] = { { 0, 0, 0, 0 } }; getopt_long(argc, argv, short_opts, long_options, 0); return 0; } EOF $CXX $CXXFLAGS -o "$tmpdir"/test "$tmpdir"/test.cc >> "$config_log" 2>&1 ret=$? rm -rf "$tmpdir" if [ $ret -eq 0 ]; then echo "yes" | tee -a "$config_log" echo "HAVE_GETOPT = 1" >> "$config_mk" exit 0 else echo "no" | tee -a "$config_log" echo "HAVE_GETOPT = 0" >> "$config_mk" exit 0 fi hoichess-0.22.0/src/build/configure.d/check-readline.sh0000750000175000017500000000146613276601731022220 0ustar holgerholger#!/bin/sh config_mk="$1" config_log="$2" echo -n "Checking if readline is available..." | tee -a "$config_log" if [ -z "$CXX" ]; then echo "CXX not defined" >&2 exit 2 elif ! $CXX --version >/dev/null 2>&1; then echo "CXX not working" >&2 exit 2 fi tmpdir=`mktemp -d` || exit 2 cat > "$tmpdir"/test.cc < #include #include int main() { char * line = readline(">"); add_history(line); fputs(line, stdout); return 0; } EOF $CXX $CXXFLAGS -lreadline -o "$tmpdir"/test "$tmpdir"/test.cc >/dev/null >> "$config_log" 2>&1 ret=$? rm -rf "$tmpdir" if [ $ret -eq 0 ]; then echo "yes" | tee -a "$config_log" echo "HAVE_READLINE = 1" >> "$config_mk" exit 0 else echo "no" | tee -a "$config_log" echo "HAVE_READLINE = 0" >> "$config_mk" exit 0 fi hoichess-0.22.0/src/build/configure.d/check-strtok_r.sh0000750000175000017500000000133213276601731022274 0ustar holgerholger#!/bin/sh config_mk="$1" config_log="$2" echo -n "Checking if strtok_r is available..." | tee -a "$config_log" if [ -z "$CXX" ]; then echo "CXX not defined" >&2 exit 2 elif ! $CXX --version >/dev/null 2>&1; then echo "CXX not working" >&2 exit 2 fi tmpdir=`mktemp -d` || exit 2 cat > "$tmpdir"/test.cc < int main(int argc, char ** argv) { char * p; strtok_r(argv[0], " ", &p); return 0; } EOF $CXX $CXXFLAGS -o "$tmpdir"/test "$tmpdir"/test.cc >> "$config_log" 2>&1 ret=$? rm -rf "$tmpdir" if [ $ret -eq 0 ]; then echo "yes" | tee -a "$config_log" echo "HAVE_STRTOK_R = 1" >> "$config_mk" exit 0 else echo "no" | tee -a "$config_log" echo "HAVE_STRTOK_R = 0" >> "$config_mk" exit 0 fi hoichess-0.22.0/src/build/configure.d/check-pthread.sh0000750000175000017500000000161013276601731022053 0ustar holgerholger#!/bin/sh config_mk="$1" config_log="$2" echo -n "Checking if pthread is available..." | tee -a "$config_log" if [ -z "$CXX" ]; then echo "CXX not defined" >&2 exit 2 elif ! $CXX --version >/dev/null 2>&1; then echo "CXX not working" >&2 exit 2 fi tmpdir=`mktemp -d` || exit 2 cat > "$tmpdir"/test.cc < #else # include #endif void * tmain(void * arg) { return arg; } int main() { pthread_t t; pthread_create(&t, NULL, tmain, NULL); pthread_mutex_t m; pthread_mutex_init(&m, NULL); return 0; } EOF $CXX $CXXFLAGS -o "$tmpdir"/test "$tmpdir"/test.cc -lpthread >> "$config_log" 2>&1 ret=$? rm -rf "$tmpdir" if [ $ret -eq 0 ]; then echo "yes" | tee -a "$config_log" echo "HAVE_PTHREAD = 1" >> "$config_mk" exit 0 else echo "no" | tee -a "$config_log" echo "HAVE_PTHREAD = 0" >> "$config_mk" exit 0 fi hoichess-0.22.0/src/config.h0000640000175000017500000000245313276601731015135 0ustar holgerholger/* Copyright (C) 2004-2008 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 /* Use assembler code where supported */ #define USE_ASM /* 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 /* 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 #endif // CONFIG_H hoichess-0.22.0/src/thread.cc0000640000175000017500000000372513276601731015300 0ustar holgerholger/* Copyright (C) 2005-2008 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 "thread.h" Thread::Thread(void * (*_startfunc)(void *)) { startfunc = _startfunc; #if defined(HAVE_PTHREAD) #elif defined(WIN32) #endif } Thread::~Thread() { #if defined(HAVE_PTHREAD) #elif defined(WIN32) #endif } void Thread::start(void * arg) { #if defined(HAVE_PTHREAD) int res = pthread_create(&threadid, NULL, startfunc, arg); ASSERT(res == 0); #elif defined(WIN32) startfunc_arg = arg; startfunc_ret = NULL; DWORD dwThreadId; hndl = CreateThread(0, 0, win32_startfunc_wrapper, (LPVOID) this, 0, &dwThreadId); ASSERT(hndl != NULL); #else (void) arg; #endif } void* Thread::wait() { void * retval; #if defined(HAVE_PTHREAD) int res = pthread_join(threadid, &retval); ASSERT(res == 0); threadid = 0; #elif defined(WIN32) DWORD res = WaitForSingleObject(hndl, INFINITE); ASSERT(res == WAIT_OBJECT_0); BOOL res2 = CloseHandle(hndl); ASSERT(res2); hndl = INVALID_HANDLE_VALUE; retval = startfunc_ret; #else retval = NULL; #endif return retval; } #if defined(WIN32) DWORD WINAPI Thread::win32_startfunc_wrapper(LPVOID arg) { Thread * self = (Thread *) arg; self->startfunc_ret = (*(self->startfunc))(self->startfunc_arg); return 0; } #endif hoichess-0.22.0/src/Makefile0000640000175000017500000001073013276601731015154 0ustar holgerholgerCROSS_COMPILE = CXX = $(CROSS_COMPILE)g++ CPP = $(CXX) -E INSTALL = /usr/bin/install LIBPATH = CXXFLAGS = -W -Wall -O3 -fno-exceptions $(ADD_CXXFLAGS) LDFLAGS = ############################################################################### ifneq (,$(findstring s,$(MAKEFLAGS))) SILENT = 1 endif VERSION := $(shell build/print_version_str ..) TARGET := $(shell $(CXX) -dumpmachine) ifeq ($(TARGET),) $(error Unable to determine compiler target) endif BUILDDIR = ../build/$(TARGET) ifeq (,$(findstring clean,$(MAKECMDGOALS))) -include $(BUILDDIR)/config.mk endif ifneq (,$(findstring mingw32,$(TARGET))) WITH_THREAD = 1 else ifeq ($(HAVE_PTHREAD),1) WITH_THREAD = 1 endif # # define PROGS # PROGS = hoichess hoixiangqi # # define SOURCES, CXXFLAGS, INCLUDE, etc. # (ADD_SOURCES can optionally be set at make command line) # SOURCES = \ debug.cc \ init.cc \ main.cc \ uint64_table.cc \ util.cc \ version.cc \ common/book.cc \ common/clock.cc \ common/epd.cc \ common/eval.cc \ common/evalcache.cc \ common/game.cc \ common/hash.cc \ common/movelist.cc \ common/node.cc \ common/pawnhash.cc \ common/pgn.cc \ common/search.cc \ common/search_util.cc \ common/shell.cc \ common/shell_cmd.cc \ common/shell_util.cc ifeq ($(WITH_THREAD),1) SOURCES += \ mutex.cc \ queue.cc \ spinlock.cc \ thread.cc \ common/parallelsearch.cc endif hoichess_SOURCES = $(SOURCES) \ chess/basic.cc \ chess/bitboard.cc \ chess/bitboard_rotated.cc \ chess/board.cc \ chess/board_attack.cc \ chess/board_generate.cc \ chess/board_init.cc \ chess/board_util.cc \ chess/eval.cc \ chess/move.cc hoixiangqi_SOURCES = $(SOURCES) \ xiangqi/basic.cc \ xiangqi/board.cc \ xiangqi/board_attack.cc \ xiangqi/board_generate.cc \ xiangqi/board_init.cc \ xiangqi/board_util.cc \ xiangqi/eval.cc \ xiangqi/move.cc INCLUDE = -I. -Icommon all-hoichess: override CXXFLAGS += -DHOICHESS all-hoichess: override INCLUDE += -Ichess all-hoixiangqi: override CXXFLAGS += -DHOIXIANGQI all-hoixiangqi: override INCLUDE += -Ixiangqi ifneq (,$(findstring mingw32,$(TARGET))) override INCLUDE += -Iwin32 override CXXFLAGS += -DWITH_THREAD override LDFLAGS += -static-libgcc -static-libstdc++ BIN_SUFFIX = .exe else BIN_SUFFIX = endif ifneq (,$(shell echo '' | $(CXX) -E -dM - | grep __leonbare__)) SOURCES += \ sparc32/leon/stdio.cc \ sparc32/leon/usleep.cc override INCLUDE += -Isparc32/leon endif ifeq ($(HAVE_READLINE),1) override CXXFLAGS += -DHAVE_READLINE LIBS += -lreadline endif ifeq ($(HAVE_PTHREAD),1) override CXXFLAGS += -DHAVE_PTHREAD -DWITH_THREAD LIBS += -lpthread endif ifeq ($(HAVE_GETOPT),1) override CXXFLAGS += -DHAVE_GETOPT else SOURCES += lib/my_getopt.cc endif ifeq ($(HAVE_SNPRINTF),1) override CXXFLAGS += -DHAVE_SNPRINTF else SOURCES += lib/snprintf.cc endif ifeq ($(HAVE_STRTOK_R),1) override CXXFLAGS += -DHAVE_STRTOK_R else SOURCES += lib/strtok_r.cc endif ifneq ($(datadir),) override CXXFLAGS += -DDATA_DIR='"$(datadir)"' endif ifeq ($(wildcard vhdlchess/),vhdlchess/) include vhdlchess/Makefile.inc endif $(foreach p,$(PROGS),all-$(p)): override CXXFLAGS += -DVERSION='"$(VERSION)"' ############################################################################### .DEFAULT_GOAL = all .PHONY: all all: $(foreach p,$(PROGS),all-$(p)) .PHONY: install install: $(foreach p,$(PROGS),install-$(p)) .PHONY: clean clean: rm -rf ../build .PHONY: maintainer-clean maintainer-clean: clean # auto configuration $(BUILDDIR)/config.mk: mkdir -p $(dir $@) CXX="$(CXX)" CXXFLAGS="$(CXXFLAGS)" build/configure.sh $(BUILDDIR) $(if $(SILENT),>/dev/null) # # building targets # define gen_prog_rules # object files for program $(1)_OBJS = $$(patsubst %.cc,$$(BUILDDIR)/build-$(1)/%.o,$$($(1)_SOURCES)) # all- target .PHONY: all-$(1) all-$(1): $$(BUILDDIR)/$(1)$(BIN_SUFFIX) # compile sources $$(BUILDDIR)/build-$(1)/%.o: %.cc @mkdir -p $$(dir $$@) $$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(INCLUDE) -MT $$@ -MD -MF $$(patsubst %.o,%.d,$$@) -c -o $$@ $$< # link binary $$(BUILDDIR)/$(1)$(BIN_SUFFIX): $$($(1)_OBJS) @mkdir -p $$(dir $$@) $$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) -c -o $$(BUILDDIR)/build-$(1)/version.o version.cc $$(CXX) $$(CXXFLAGS) $$(LDFLAGS) -o $$@ $$^ $$(LIBPATH) $$(LIBS) # include dependencies -include $$(patsubst %.o,%.d,$$($(1)_OBJS)) # install- target .PHONY: install-$(1) install-$(1): all-$(1) $$(INSTALL) -m 755 -D $$(BUILDDIR)/$(1)$(BIN_SUFFIX) $(DESTDIR)$(install_bindir)/$$(notdir $$(BUILDDIR)/$(1)$(BIN_SUFFIX)) endef $(foreach p,$(PROGS),$(eval $(call gen_prog_rules,$(p)))) hoichess-0.22.0/src/util.h0000640000175000017500000000577213276601731014654 0ustar holgerholger/* 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 #ifdef WITH_THREAD extern Mutex stdout_mutex; extern int atomic_printf(const char * fmt, ...); extern int atomic_fprintf(FILE * fp, Mutex * mutex, const char * fmt, ...); #else // !WITH_THREAD #define atomic_printf printf #define atomic_fprintf fprintf #endif // !WITH_THREAD extern uint64_t random64(); extern std::string strprintf(const char * fmt, ...); extern bool parse_size(const char * s, ssize_t * n); extern unsigned long long get_realtime_us(); extern unsigned long long get_cputime_us(); #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 extern unsigned long long _timing_trace_us_start; extern unsigned long long _timing_trace_us_last; #define TIMING_TRACE_INIT() do { \ struct timeval tv; \ gettimeofday(&tv, NULL); \ _timing_trace_us_start = (unsigned long long) tv.tv_sec * (int)1E6 + tv.tv_usec; \ _timing_trace_us_last = _timing_trace_us_start; \ printf("%s:%d(%s) @%llu us +%llu us\n", \ __FILE__, __LINE__, __func__, \ 0ULL, 0ULL); \ } while (0) #define TIMING_TRACE() do { \ struct timeval tv; \ gettimeofday(&tv, NULL); \ unsigned long long us = (unsigned long long) tv.tv_sec * (int)1E6 + tv.tv_usec; \ printf("%s:%d(%s) @%llu us +%llu us\n", \ __FILE__, __LINE__, __func__, \ us-_timing_trace_us_start, us-_timing_trace_us_last); \ _timing_trace_us_last = us; \ } while (0) #endif // UTIL_H hoichess-0.22.0/src/init.cc0000640000175000017500000000426313276601731014772 0ustar holgerholger/* 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 #ifdef __leonbare__ extern "C" { # include # define SOLARIS_NP # include } #endif /***************************************************************************** * * This is the main initialization function. * Make sure it is called before doing anything else. * *****************************************************************************/ void init() { #ifdef __leonbare__ //leonbare_init_ticks(); pthread_init(); #endif #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 } /***************************************************************************** * * Default builtin initial commands. * Declared with weak linkage so that they can be overridden at build * time. * * This is for embedded systems where command line arguments (e.g. --initcmd) * or script files are not available. * *****************************************************************************/ const char * builtin_initcmds[] #ifndef WIN32 __attribute__((weak)) #endif = { NULL }; /* { "echo default builtin initcmd", NULL };*/ hoichess-0.22.0/src/debug.h0000640000175000017500000000572413276601731014762 0ustar holgerholger/* 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 #ifdef WITH_THREAD /* 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; #endif /* * 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; #ifdef WITH_THREAD Mutex * mutex; #endif const char * file; int line; const char * function; public: inline __debug_helper(FILE * fp, #ifdef WITH_THREAD Mutex * mutex, #endif const char * file, int line, const char * function) : fp(fp), #ifdef WITH_THREAD mutex(mutex), #endif 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; }; #ifdef WITH_THREAD #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 #else // !WITH_THREAD #define DBG __debug_helper(stdout, \ __FILE__, __LINE__, __PRETTY_FUNCTION__).__dbg #define WARN __debug_helper(stdout, \ __FILE__, __LINE__, __PRETTY_FUNCTION__).__warn #define BUG __debug_helper(stderr, \ __FILE__, __LINE__, __PRETTY_FUNCTION__).__bug #endif // !WITH_THREAD #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 #endif // DEBUG_H hoichess-0.22.0/lib/0000750000175000017500000000000013276601731013471 5ustar holgerholgerhoichess-0.22.0/BUGS0000640000175000017500000000017413276601731013411 0ustar holgerholger=-=-=-=-=-=-=-=-=-=-=-=-=-= | Open Bugs in HoiChess | =-=-=-=-=-=-=-=-=-=-=-=-=-= No important bugs known at the moment. hoichess-0.22.0/hoichess.rc.m40000640000175000017500000000012513276601731015374 0ustar holgerholgerhash size 32M pawnhash size 4M evalcache size 4M book open DATADIR/hoichess-book.dat hoichess-0.22.0/hoixiangqi.rc.m40000640000175000017500000000012713276601731015731 0ustar holgerholgerhash size 32M pawnhash size 4M evalcache size 4M book open DATADIR/hoixiangqi-book.dat hoichess-0.22.0/LICENSE0000640000175000017500000004311013276601731013730 0ustar holgerholger 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.22.0/book/0000750000175000017500000000000013276601731013655 5ustar holgerholgerhoichess-0.22.0/book/download-gnuchess-book0000750000175000017500000000062413276601731020161 0ustar holgerholger#!/bin/sh file="book_1.02.pgn.gz" url="http://ftp.gnu.org/pub/gnu/chess/$file" md5sum="e382f5774f050efc79a08baa083eba79" outfile="hoichess-book.pgn" wget "$url" -O "$file".tmp echo "$md5sum $file.tmp" | md5sum -c || exit mv "$file".tmp "$file" if [ -e "$outfile" ]; then echo "Error: $outfile already exists, won't overwrite" >&2 exit 1 fi gzip -dc < "$file" > "$outfile" echo "Created $outfile" hoichess-0.22.0/book/Makefile0000640000175000017500000000207313276601731015320 0ustar holgerholger# To build the book, we need a binary for the host architecture. # Even when not cross-compiling the main binary (i.e. CXX=HOST_CXX), # we build this "host binary" in a separate directory to avoid any # conflicts. # (Or call 'make HOST_HOICHESS=/usr/games/hoichess' if already installed.) HOST_CXX = g++ HOST_CXXFLAGS = -W -Wall -O2 HOST_HOICHESS = ../build/host/hoichess INSTALL = /usr/bin/install # TODO xiangqi BOOKS = $(patsubst %.pgn,%.dat,$(wildcard *.pgn)) BOOK_DEPTH = 0 BOOK_MINMOVECOUNT = 5 .PHONY: all all: $(BOOKS) .PHONY: clean clean: rm -f $(BOOKS) .PHONY: install install: all $(INSTALL) -d $(DESTDIR)$(install_datadir) ifneq ($(BOOKS),) $(INSTALL) -m 644 $(BOOKS) $(DESTDIR)$(install_datadir) endif # # build book # $(BOOKS): %.dat: %.pgn $(HOST_HOICHESS) echo "book create $@ $< $(BOOK_DEPTH) $(BOOK_MINMOVECOUNT)" | $(HOST_HOICHESS) --norc # # build host binary required to create opening book # $(HOST_HOICHESS): @# BUILDDIR is relative to src/! $(MAKE) -C ../src CXX="$(HOST_CXX)" CXXFLAGS="$(HOST_CXXFLAGS)" BUILDDIR="$(dir $@)" all-hoichess hoichess-0.22.0/ChangeLog0000640000175000017500000005665113276601731014513 0ustar holgerholgerVersion 0.22.0 (2018-05-15) * Shared hash table for parallel search. (Experimental - currently disabled by default, but can be enabled through shell option.) * Removed hash replacement scheme selection. This was never complete and tested. Default is now to always replace hash entries. * Removed some useless hash table statistics to optimize speed. * Removed configuration defines COLLECT_STATISTICS, USE_FUTILITYPRUNING, USE_EXTENDED_FUTILITYPRUNING and USE_RAZORING to clean up code. These features are now always enabled. * Minor fixes and code cleanups. Version 0.21.0 (2017-03-03) * Do zero window principal variation search only after a move better than alpha has been found. * Do null move also in parallel search. * Speed optimization in Search::probe_hashtable(). * Compilation fix for leonbare. * Added simple installer for Windows. * Added binary build script for Windows (mingw32). * On Windows, also accept %VAR% syntax for environment variable substitution. Version 0.20.0 (2017-02-01) * Bugfix: Fix lost on time in parallel search. * Bugfix: Fix division by zero when generating very small opening books. * Bugfix: Moved leonbare specific stdint.h and inttypes.h from sparc32 into sparc32/leon directory to fix compilation failure on sparc64. * [xiangqi] Handle perpetual checks. * [xiangqi] Improved pawn evaluation. * Included reproducible-build patch from Debian package hoichess_0.19.0-3. * Fail soft search. (Experimental - currently disabled by default, but can be enabled through shell option.) * No time extensions in exact clock mode. * New abstraction layer for time functions. Removed gettimeofday() wrapper for Win32. * Added command 'atexit' to register commands that shall be executed upon shell exit. * Use own versions of snprintf() and strtok_r() only if these functions are not provided by the system. * Cleaned up some platform/compiler specific stuff. * Minor fixes and code cleanups. Version 0.19.0 (2016-08-08) * Strict fail hard search. (Temporary - to reduce search instabilities to help discovering bugs. In the future, fail soft search will be implemented as an option.) * Store normalized mate scores in hash table. Version 0.18.0 (2016-06-07) * Bugfix: Ignore 'draw', 'rating' and '?' commands instead of aborting with error. * Bugfix: In exact clock mode, do not check if remaining time is enough for new iteration. * Bugfix: Keep values of verbose, debug and echo when registering them as shell options. * Some bugfixes in parallel search. * Reworked iterative deepening code. * Return PV during search through class Node instead of search functions in order to simplify code. * Rewrote move ordering in class Node: - Generate all moves at once. - New scoring. - Include PV move from previous iteration. - Losing captures last. * In parallel search, store PV line in master's hash table to provide a better move ordering for slaves. (Experimental - currently disabled by default, but can be enabled through shell option.) * Rewrote time allocation code to be more safe and not exceed remaining time. Track externally lost time to adapt safety margin to system speed. (Try) * Changed time unit from centiseconds to milliseconds internally to increase precision of time measurement and calculations. * Rewrote timecheck interval computation code. Added shell options to specify minimum and maximum intervals. * Various code improvements related to clock handling. * Removed configuration defines USE_PVS, USE_IID, USE_NULLMOVE, USE_HISTORY and USE_KILLER to clean up code. These features are now always enabled. * Removed commands 'dumppgn' and 'show tree' as well as output switches of command 'show moves'. They were only used for testing. * Minor code cleanups. Version 0.17.0 (2016-01-19) * Improved parallel search algorithm: Search first move recursively, then remaining moves in parallel. * Parallel search: Master hash table * Extend search time when remaining time is expected to be slightly too short to finish current iteration. * Do not start a new iteration if remaining time is very likely not sufficient. * [chess] Bugfix in draw by material detection. * Support xboard 'option' command, available since xboard 4.4.x. * Support multiple --source and --initcmd arguments. * Search for hoichess.rc in current, home and installation data directory; added new option --norc to disable this. * Install default hoichess.rc in data directory. * Substitute environment variables in shell. * Avoid xboard timeout between 'protover' and 'feature' if engine initialization takes long. * Removed old time extension code. It has never been fully tested. * Removed search depth extensions. They have never been fully tested and probably not even understood. * Removed commands 'set/get search_param' because they are superseded by the new 'option' command. * Removed commands 'ignore' and 'obey' because they have never been used. * Removed configuration defines USE_BOOK, USE_PGN, USE_HASH, USE_PAWNHASH and USE_EVALCACHE to clean up code. These features are now always enabled. * Removed command line options --book, --nobook, --hashsize, --pawnhashsize, --evalcache, --name, --append-name and corresponding defaults in config.h. Defaults are now supposed to be in hoichess.rc. * Support pthread on leonbare (buggy). * Support parallel search on Win32 (Queue). * Fixed compilation failures without thread support. * Bugfix in parallel search statistics. * Removed some other unused code. * Minor code cleanups and fixes. Version 0.16.1 (2015-07-23) * Testsuite solver: Tolerate non-standard bm values in EPD. * Re-create hash, pawn hash and evaluation cache with same total sizes when switching number of cores. Version 0.16.0 (2015-05-21) * Initial implementation of parallel search. (ALPHA) * Removed log file mechanism because it has never been used. * Included most fixes from Debian package hoichess_0.10.3-6.1. Version 0.15.0 (2015-02-02) * New command 'show tree'. * Use own versions of *printf for leonbare in order to support %llu etc. * Use the defaults for book, hash size, pawn hash size and evaluation cache size only if there is no user command script. In that case all configuration is expected there. * Added command line option --initcmd. If not set, read builtin initial commands, with weak linkage. * First preparations for implementation of parallel search. * Removed benchmarking and movelist statistics code. * [win32] Get return value from thread. * Minor code cleanups and fixes. Version 0.14.0 (2014-10-07) * Fixes for latest gcc/glibc: added missing #includes * Fixes for leonbare: - Added own implementation of htonl, htons, ntohl, ntohs and usleep because they are not available on current leonbare. - Bugfix in own fgets. - Fixed format strings. * Minor fixes in build system. Version 0.13.0 (2014-02-02) * x86_64 assembler versions of msb and lsb routines. * Implemented command 'usermove'. * [chess] Do not reset movecnt50 after a castling move. * Support LEON processor with leonbare. * Collect PV during search. * Command 'solve': Allow reading positions from stdin (-). * Command 'show moves': Added options -pseudolegal and -nosan and -no-pseudolegal-castling. * Bugfix in command 'solve': Reset clock before starting search. * Fixed getopt include problems. * Allow compilation without main hash table support. * Rewrote src/Makefile once again. Added automatic check for getopt_long, pthread and readline availabiliy. * Statically link libstdc++ and libgcc on mingw32. * Support use of GCC builtins for bitscan and population count. Select the fastest implementation (own asm, LUT, GCC builtin) depending on CPU. * Code cleanup and restructuring: - Moved management of hash/pawnhash/evalcache from class Shell into Search and Evaluator. - Rewrote tree implementation again; removed class Tree in favour of new class NodeAllocator. - Other minor things. * Fixed bug in iterate() that could result in calling search with beta > INFTY or alpha < -INFTY. * Improved thinking output. * Build book. (No source PGN included yet, but script to download GNU Chess book.) * Take SVN branch/revision as program version. * Removed dist-src target from top-level Makefile. * VHDLChess (changes not listed here) Version 0.12.1 (2009-01-25) * Fixed Xiangqi FEN parsing for latest xboard version. Version 0.12.0 (2008-08-15) * [chess] Fixed long-existing bug in generate_escapes(), and use it. * [chess] Evaluation: - Score Pawn shield in front of king. - Keep rook on back rank until endgame. * Compile with USE_ASM by default. (New option added with 0.11.1, but disabled by accident.) * Reformatted most informational output for easier parsing by scripts. * Some improvements to build system to ease multiple-platform build. Version 0.11.1 (2008-07-28) * Do not use assembler code for WIN64 (x86_64-pc-mingw32). Version 0.11.0 (2008-07-27) * Book: Do not use exception in constructor. Now we can compile with -fno-exceptions to reduce code size. * Enable compilation without support for opening book, PGN parser, pawn hash table, evaluation cache, background thread (pondering/analysis). * Code cleanup/restructuring: - Moved search output from class Search into class Shell. - Moved most common source files into subdirectory src/common. * [chess] Minor optimizations: - Bitboard code: Use computation instead of lookup tables in some functions related to rotated bitboards. - others... * Dynamically adjust time check interval during search to work on slower processors without source code change. * Some improvements to build system. * Various minor changes and improvements. Version 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.22.0/dist/0000750000175000017500000000000013276601731013666 5ustar holgerholgerhoichess-0.22.0/dist/windows/0000750000175000017500000000000013276601731015360 5ustar holgerholgerhoichess-0.22.0/dist/windows/install.cmd0000640000175000017500000000146613276601731017523 0ustar holgerholger@echo off set install_dir="%USERPROFILE%\.hoichess" echo ---------------------------------------------------------------------- echo HoiChess Installer for Windows echo ---------------------------------------------------------------------- echo. echo This will install HoiChess into echo %install_dir% echo. rem choice /C yn /M "Continue? [y/n] " rem if errorlevel 2 exit /b set /P ANS="Continue? [y/n] " if /I "%ANS%"=="y" goto continue exit /b :continue mkdir %install_dir% copy bin\* %install_dir% copy doc\* %install_dir% copy share\* %install_dir% echo. echo ---------------------------------------------------------------------- echo HoiChess has been installed into echo %install_dir% echo To uninstall, simply delete that directory. echo ---------------------------------------------------------------------- hoichess-0.22.0/dist/windows/Makefile0000640000175000017500000000276113276601731017027 0ustar holgerholgerTOPDIR = ../.. VERSION := $(shell $(TOPDIR)/src/build/print_version_str) .PHONY: all all: hoichess-$(VERSION)-win32.zip hoichess-$(VERSION)-win64.zip \ hoichess-$(VERSION)-win32-pthread.zip hoichess-$(VERSION)-win64-pthread.zip .PHONY: clean clean: rm -rf build-* rm -f hoichess-*.zip BUILDFLAGS := prefix= bindir=/bin docdir=/doc mandir=/man datadir="%USERPROFILE%/.hoichess" install_datadir=/share hoichess-$(VERSION)-win32.zip: CXX=i686-w64-mingw32-g++ hoichess-$(VERSION)-win32.zip: LDFLAGS=-static hoichess-$(VERSION)-win32.zip: BUILDFLAGS+=HAVE_PTHREAD=0 hoichess-$(VERSION)-win64.zip: CXX=x86_64-w64-mingw32-g++ hoichess-$(VERSION)-win64.zip: LDFLAGS=-static hoichess-$(VERSION)-win64.zip: BUILDFLAGS+=HAVE_PTHREAD=0 hoichess-$(VERSION)-win32-pthread.zip: CXX=i686-w64-mingw32-g++ hoichess-$(VERSION)-win32-pthread.zip: LDFLAGS=-static hoichess-$(VERSION)-win64-pthread.zip: CXX=x86_64-w64-mingw32-g++ hoichess-$(VERSION)-win64-pthread.zip: LDFLAGS=-static hoichess-$(VERSION)-%.zip: mkdir build-$(VERSION)-$* $(MAKE) -s -C $(TOPDIR) BUILDDIR=$(CURDIR)/build-$(VERSION)-$* CXX=$(CXX) LDFLAGS="$(LDFLAGS)" $(BUILDFLAGS) $(MAKE) -s -C $(TOPDIR) BUILDDIR=$(CURDIR)/build-$(VERSION)-$* CXX=$(CXX) install $(BUILDFLAGS) \ DESTDIR=$(CURDIR)/build-$(VERSION)-$*/hoichess-$(VERSION)-$* cp install.cmd build-$(VERSION)-$*/hoichess-$(VERSION)-$*/install.cmd cd build-$(VERSION)-$* && zip -q -9 -r hoichess-$(VERSION)-$*.zip hoichess-$(VERSION)-$* mv build-$(VERSION)-$*/hoichess-$(VERSION)-$*.zip $@ hoichess-0.22.0/hoichess.6.pod0000640000175000017500000000646613276601731015415 0ustar holgerholger=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. Recent versions of xboard also support xiangqi: B. 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. At program start, a default startup file is read. This file is called I or I, respectively. It is searched for in the following directories, in order: current directory, I<$HOME/.hoichess>, I<$USERPROFILE/.hoichess> (only on Windows), I. Only the first found file is read. The I is installation dependent, commonly I. =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<-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. =back =item B<--source> I Before accepting input from stdin, first read commands (and probably moves) from I. Can be given multiple times. =item B<--initcmd> I Execute I at startup. The command is executed before reading script files given by the B<--source> option. Can be given multiple times. =item B<--norc> Do not read default startup file I or 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 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.22.0/AUTHORS0000640000175000017500000000004713276601731013775 0ustar holgerholgerHolger Ruckdeschel hoichess-0.22.0/Makefile0000640000175000017500000000355113276601731014370 0ustar holgerholgerprefix = /usr # Make these variables also available to sub-makes. export bindir = $(prefix)/games export docdir = $(prefix)/share/doc/hoichess export mandir = $(prefix)/share/man export datadir = $(prefix)/share/games/hoichess export install_bindir = $(bindir) export install_docdir = $(docdir) export install_mandir = $(mandir) export install_datadir = $(datadir) VERSION := $(shell grep '^Version' ChangeLog | head -n 1 | awk '{ print $$2; }') TARGET := $(shell $(CXX) -dumpmachine) ifeq ($(TARGET),) $(error Unable to determine compiler target) endif # # Build # .PHONY: all all: compile book doc cfg .PHONY: compile compile: $(MAKE) -C src all .PHONY: book book: $(MAKE) -C book .PHONY: doc doc: hoichess.6 hoichess.6.html hoichess.6: hoichess.6.pod pod2man -n hoichess -s 6 -r "hoichess-$(VERSION)" -c Games $< $@ hoichess.6.html: hoichess.6.pod pod2html --title "HoiChess" $< > $@ .PHONY: cfg cfg: hoichess.rc hoixiangqi.rc hoichess.rc hoixiangqi.rc: %: %.m4 m4 -D DATADIR=$(datadir) $< > $@ # # Install # .PHONY: install install: install-bin INSTALL_BIN_DOCS = AUTHORS BUGS ChangeLog LICENSE README hoichess.6.html INSTALL_BIN_DATA = hoichess.rc hoixiangqi.rc .PHONY: install-bin install-bin: all $(MAKE) -C src install DESTDIR="$(DESTDIR)" install -m 644 -D hoichess.6 $(DESTDIR)$(install_mandir)/man6/hoichess.6 install -m 755 -d $(DESTDIR)$(install_docdir) install -m 644 $(INSTALL_BIN_DOCS) $(DESTDIR)$(install_docdir) install -m 755 -d $(DESTDIR)$(install_datadir) install -m 644 $(INSTALL_BIN_DATA) $(DESTDIR)$(install_datadir) $(MAKE) -C book install DESTDIR="$(DESTDIR)" # # Clean # .PHONY: clean clean: $(MAKE) -C src clean rm -f hoichess.6 hoichess.6.html pod2htmd.tmp pod2htmi.tmp rm -f hoichess.rc hoixiangqi.rc $(MAKE) -C book clean rm -rf $(DIST_OUTDIR) .PHONY: maintainer-clean maintainer-clean: clean $(MAKE) -C src maintainer-clean