Delete stockfish-8-linux
Browse files- stockfish-8-linux/.travis.yml +0 -55
- stockfish-8-linux/AUTHORS +0 -98
- stockfish-8-linux/Copying.txt +0 -674
- stockfish-8-linux/Linux/stockfish_8_x64 +0 -3
- stockfish-8-linux/Linux/stockfish_8_x64_bmi2 +0 -3
- stockfish-8-linux/Linux/stockfish_8_x64_modern +0 -3
- stockfish-8-linux/Readme.md +0 -115
- stockfish-8-linux/appveyor.yml +0 -45
- stockfish-8-linux/src/Makefile +0 -545
- stockfish-8-linux/src/benchmark.cpp +0 -183
- stockfish-8-linux/src/bitbase.cpp +0 -180
- stockfish-8-linux/src/bitboard.cpp +0 -333
- stockfish-8-linux/src/bitboard.h +0 -338
- stockfish-8-linux/src/endgame.cpp +0 -845
- stockfish-8-linux/src/endgame.h +0 -125
- stockfish-8-linux/src/evaluate.cpp +0 -927
- stockfish-8-linux/src/evaluate.h +0 -40
- stockfish-8-linux/src/main.cpp +0 -54
- stockfish-8-linux/src/material.cpp +0 -225
- stockfish-8-linux/src/material.h +0 -73
- stockfish-8-linux/src/misc.cpp +0 -187
- stockfish-8-linux/src/misc.h +0 -100
- stockfish-8-linux/src/movegen.cpp +0 -420
- stockfish-8-linux/src/movegen.h +0 -70
- stockfish-8-linux/src/movepick.cpp +0 -350
- stockfish-8-linux/src/movepick.h +0 -123
- stockfish-8-linux/src/pawns.cpp +0 -291
- stockfish-8-linux/src/pawns.h +0 -88
- stockfish-8-linux/src/position.cpp +0 -1168
- stockfish-8-linux/src/position.h +0 -414
- stockfish-8-linux/src/psqt.cpp +0 -126
- stockfish-8-linux/src/search.cpp +0 -1656
- stockfish-8-linux/src/search.h +0 -111
- stockfish-8-linux/src/syzygy/tbcore.cpp +0 -1378
- stockfish-8-linux/src/syzygy/tbcore.h +0 -169
- stockfish-8-linux/src/syzygy/tbprobe.cpp +0 -824
- stockfish-8-linux/src/syzygy/tbprobe.h +0 -19
- stockfish-8-linux/src/thread.cpp +0 -223
- stockfish-8-linux/src/thread.h +0 -111
- stockfish-8-linux/src/thread_win32.h +0 -70
- stockfish-8-linux/src/timeman.cpp +0 -132
- stockfish-8-linux/src/timeman.h +0 -48
- stockfish-8-linux/src/tt.cpp +0 -117
- stockfish-8-linux/src/tt.h +0 -121
- stockfish-8-linux/src/types.h +0 -435
- stockfish-8-linux/src/uci.cpp +0 -289
- stockfish-8-linux/src/uci.h +0 -80
- stockfish-8-linux/src/ucioption.cpp +0 -163
stockfish-8-linux/.travis.yml
DELETED
|
@@ -1,55 +0,0 @@
|
|
| 1 |
-
language: cpp
|
| 2 |
-
sudo: required
|
| 3 |
-
dist: trusty
|
| 4 |
-
|
| 5 |
-
matrix:
|
| 6 |
-
include:
|
| 7 |
-
- os: linux
|
| 8 |
-
compiler: gcc
|
| 9 |
-
addons:
|
| 10 |
-
apt:
|
| 11 |
-
sources: ['ubuntu-toolchain-r-test']
|
| 12 |
-
packages: ['g++-6', 'g++-6-multilib', 'g++-multilib', 'valgrind']
|
| 13 |
-
env:
|
| 14 |
-
- COMPILER=g++-6
|
| 15 |
-
- COMP=gcc
|
| 16 |
-
|
| 17 |
-
- os: linux
|
| 18 |
-
compiler: clang
|
| 19 |
-
addons:
|
| 20 |
-
apt:
|
| 21 |
-
sources: ['ubuntu-toolchain-r-test']
|
| 22 |
-
packages: ['clang', 'g++-multilib', 'valgrind']
|
| 23 |
-
env:
|
| 24 |
-
- COMPILER=clang++
|
| 25 |
-
- COMP=clang
|
| 26 |
-
|
| 27 |
-
- os: osx
|
| 28 |
-
compiler: gcc
|
| 29 |
-
env:
|
| 30 |
-
- COMPILER=g++
|
| 31 |
-
- COMP=gcc
|
| 32 |
-
|
| 33 |
-
- os: osx
|
| 34 |
-
compiler: clang
|
| 35 |
-
env:
|
| 36 |
-
- COMPILER=clang++ V='Apple LLVM 6.0' # Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
|
| 37 |
-
- COMP=clang
|
| 38 |
-
|
| 39 |
-
branches:
|
| 40 |
-
only:
|
| 41 |
-
- master
|
| 42 |
-
|
| 43 |
-
before_script:
|
| 44 |
-
- cd src
|
| 45 |
-
|
| 46 |
-
script:
|
| 47 |
-
- make clean && make build ARCH=x86-64 && ./stockfish bench 2>&1 >/dev/null | grep 'Nodes searched' | tee bench1
|
| 48 |
-
- make clean && make build ARCH=x86-32 && ./stockfish bench 2>&1 >/dev/null | grep 'Nodes searched' | tee bench2
|
| 49 |
-
- echo "Checking for same bench numbers..."
|
| 50 |
-
- diff bench1 bench2 > result
|
| 51 |
-
- test ! -s result
|
| 52 |
-
# if valgrind is available check the build is without error, reduce depth to speedup testing, but not too shallow to catch more cases.
|
| 53 |
-
- if [ -x "$(command -v valgrind )" ] ; then make clean && make ARCH=x86-64 debug=yes build && valgrind --error-exitcode=42 ./stockfish bench 128 1 10 default depth 1>/dev/null ; fi
|
| 54 |
-
# use g++-6 as a proxy for having sanitizers ... might need revision as they become available for more recent versions of clang/gcc than trusty provides
|
| 55 |
-
- if [[ "$COMPILER" == "g++-6" ]]; then make clean && make ARCH=x86-64 sanitize=yes build && ! ./stockfish bench 2>&1 | grep "runtime error:" ; fi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/AUTHORS
DELETED
|
@@ -1,98 +0,0 @@
|
|
| 1 |
-
# Generated with git shortlog -sn | cut -c8-', which sorts by commits (manually ordered the first four authors)
|
| 2 |
-
|
| 3 |
-
Tord Romstad
|
| 4 |
-
Marco Costalba
|
| 5 |
-
Joona Kiiski
|
| 6 |
-
Gary Linscott
|
| 7 |
-
lucasart
|
| 8 |
-
mstembera
|
| 9 |
-
Lucas Braesch
|
| 10 |
-
Stefan Geschwentner
|
| 11 |
-
Reuven Peleg
|
| 12 |
-
Chris Caino
|
| 13 |
-
joergoster
|
| 14 |
-
VoyagerOne
|
| 15 |
-
Jean-Francois Romang
|
| 16 |
-
homoSapiensSapiens
|
| 17 |
-
Alain SAVARD
|
| 18 |
-
Arjun Temurnikar
|
| 19 |
-
Stéphane Nicolet
|
| 20 |
-
Uri Blass
|
| 21 |
-
jundery
|
| 22 |
-
Ralph Stößer
|
| 23 |
-
Ajith
|
| 24 |
-
Leonid Pechenik
|
| 25 |
-
Stefano80
|
| 26 |
-
Tom Vijlbrief
|
| 27 |
-
hxim
|
| 28 |
-
snicolet
|
| 29 |
-
Daylen Yang
|
| 30 |
-
Henri Wiechers
|
| 31 |
-
Jonathan Calovski
|
| 32 |
-
mbootsector
|
| 33 |
-
David Zar
|
| 34 |
-
Eelco de Groot
|
| 35 |
-
Jerry Donald
|
| 36 |
-
Joerg Oster
|
| 37 |
-
Jörg Oster
|
| 38 |
-
Ryan Schmitt
|
| 39 |
-
mcostalba
|
| 40 |
-
Alexander Kure
|
| 41 |
-
Dan Schmidt
|
| 42 |
-
H. Felix Wittmann
|
| 43 |
-
Joseph R. Prostko
|
| 44 |
-
Justin Blanchard
|
| 45 |
-
Linus Arver
|
| 46 |
-
NicklasPersson
|
| 47 |
-
Rodrigo Exterckötter Tjäder
|
| 48 |
-
Ron Britvich
|
| 49 |
-
Ronald de Man
|
| 50 |
-
RyanTaker
|
| 51 |
-
Vince Negri
|
| 52 |
-
ceebo
|
| 53 |
-
jhellis3
|
| 54 |
-
ppigazzini
|
| 55 |
-
shane31
|
| 56 |
-
Andy Duplain
|
| 57 |
-
Auguste Pop
|
| 58 |
-
Balint Pfliegel
|
| 59 |
-
Chris Cain
|
| 60 |
-
DU-jdto
|
| 61 |
-
Dariusz Orzechowski
|
| 62 |
-
DiscanX
|
| 63 |
-
Ernesto Gatti
|
| 64 |
-
Gregor Cramer
|
| 65 |
-
Guenther Demetz
|
| 66 |
-
Hiraoka Takuya
|
| 67 |
-
Hongzhi Cheng
|
| 68 |
-
Joseph Hellis
|
| 69 |
-
Kelly Wilson
|
| 70 |
-
Ken T Takusagawa
|
| 71 |
-
Kojirion
|
| 72 |
-
Luca Brivio
|
| 73 |
-
Matt Sullivan
|
| 74 |
-
Matthew Lai
|
| 75 |
-
Matthew Sullivan
|
| 76 |
-
Michel Van den Bergh
|
| 77 |
-
Mysseno
|
| 78 |
-
Oskar Werkelin Ahlin
|
| 79 |
-
Pablo Vazquez
|
| 80 |
-
Pascal Romaret
|
| 81 |
-
Ralph Stoesser
|
| 82 |
-
Ralph St��er
|
| 83 |
-
Raminder Singh
|
| 84 |
-
Richard Lloyd
|
| 85 |
-
Ryan Takker
|
| 86 |
-
Stephane Nicolet
|
| 87 |
-
Thanar2
|
| 88 |
-
absimaldata
|
| 89 |
-
braich
|
| 90 |
-
gguliash
|
| 91 |
-
kinderchocolate
|
| 92 |
-
loco-loco
|
| 93 |
-
pellanda
|
| 94 |
-
renouve
|
| 95 |
-
sf-x
|
| 96 |
-
thaspel
|
| 97 |
-
unknown
|
| 98 |
-
uriblass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/Copying.txt
DELETED
|
@@ -1,674 +0,0 @@
|
|
| 1 |
-
GNU GENERAL PUBLIC LICENSE
|
| 2 |
-
Version 3, 29 June 2007
|
| 3 |
-
|
| 4 |
-
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
| 5 |
-
Everyone is permitted to copy and distribute verbatim copies
|
| 6 |
-
of this license document, but changing it is not allowed.
|
| 7 |
-
|
| 8 |
-
Preamble
|
| 9 |
-
|
| 10 |
-
The GNU General Public License is a free, copyleft license for
|
| 11 |
-
software and other kinds of works.
|
| 12 |
-
|
| 13 |
-
The licenses for most software and other practical works are designed
|
| 14 |
-
to take away your freedom to share and change the works. By contrast,
|
| 15 |
-
the GNU General Public License is intended to guarantee your freedom to
|
| 16 |
-
share and change all versions of a program--to make sure it remains free
|
| 17 |
-
software for all its users. We, the Free Software Foundation, use the
|
| 18 |
-
GNU General Public License for most of our software; it applies also to
|
| 19 |
-
any other work released this way by its authors. You can apply it to
|
| 20 |
-
your programs, too.
|
| 21 |
-
|
| 22 |
-
When we speak of free software, we are referring to freedom, not
|
| 23 |
-
price. Our General Public Licenses are designed to make sure that you
|
| 24 |
-
have the freedom to distribute copies of free software (and charge for
|
| 25 |
-
them if you wish), that you receive source code or can get it if you
|
| 26 |
-
want it, that you can change the software or use pieces of it in new
|
| 27 |
-
free programs, and that you know you can do these things.
|
| 28 |
-
|
| 29 |
-
To protect your rights, we need to prevent others from denying you
|
| 30 |
-
these rights or asking you to surrender the rights. Therefore, you have
|
| 31 |
-
certain responsibilities if you distribute copies of the software, or if
|
| 32 |
-
you modify it: responsibilities to respect the freedom of others.
|
| 33 |
-
|
| 34 |
-
For example, if you distribute copies of such a program, whether
|
| 35 |
-
gratis or for a fee, you must pass on to the recipients the same
|
| 36 |
-
freedoms that you received. You must make sure that they, too, receive
|
| 37 |
-
or can get the source code. And you must show them these terms so they
|
| 38 |
-
know their rights.
|
| 39 |
-
|
| 40 |
-
Developers that use the GNU GPL protect your rights with two steps:
|
| 41 |
-
(1) assert copyright on the software, and (2) offer you this License
|
| 42 |
-
giving you legal permission to copy, distribute and/or modify it.
|
| 43 |
-
|
| 44 |
-
For the developers' and authors' protection, the GPL clearly explains
|
| 45 |
-
that there is no warranty for this free software. For both users' and
|
| 46 |
-
authors' sake, the GPL requires that modified versions be marked as
|
| 47 |
-
changed, so that their problems will not be attributed erroneously to
|
| 48 |
-
authors of previous versions.
|
| 49 |
-
|
| 50 |
-
Some devices are designed to deny users access to install or run
|
| 51 |
-
modified versions of the software inside them, although the manufacturer
|
| 52 |
-
can do so. This is fundamentally incompatible with the aim of
|
| 53 |
-
protecting users' freedom to change the software. The systematic
|
| 54 |
-
pattern of such abuse occurs in the area of products for individuals to
|
| 55 |
-
use, which is precisely where it is most unacceptable. Therefore, we
|
| 56 |
-
have designed this version of the GPL to prohibit the practice for those
|
| 57 |
-
products. If such problems arise substantially in other domains, we
|
| 58 |
-
stand ready to extend this provision to those domains in future versions
|
| 59 |
-
of the GPL, as needed to protect the freedom of users.
|
| 60 |
-
|
| 61 |
-
Finally, every program is threatened constantly by software patents.
|
| 62 |
-
States should not allow patents to restrict development and use of
|
| 63 |
-
software on general-purpose computers, but in those that do, we wish to
|
| 64 |
-
avoid the special danger that patents applied to a free program could
|
| 65 |
-
make it effectively proprietary. To prevent this, the GPL assures that
|
| 66 |
-
patents cannot be used to render the program non-free.
|
| 67 |
-
|
| 68 |
-
The precise terms and conditions for copying, distribution and
|
| 69 |
-
modification follow.
|
| 70 |
-
|
| 71 |
-
TERMS AND CONDITIONS
|
| 72 |
-
|
| 73 |
-
0. Definitions.
|
| 74 |
-
|
| 75 |
-
"This License" refers to version 3 of the GNU General Public License.
|
| 76 |
-
|
| 77 |
-
"Copyright" also means copyright-like laws that apply to other kinds of
|
| 78 |
-
works, such as semiconductor masks.
|
| 79 |
-
|
| 80 |
-
"The Program" refers to any copyrightable work licensed under this
|
| 81 |
-
License. Each licensee is addressed as "you". "Licensees" and
|
| 82 |
-
"recipients" may be individuals or organizations.
|
| 83 |
-
|
| 84 |
-
To "modify" a work means to copy from or adapt all or part of the work
|
| 85 |
-
in a fashion requiring copyright permission, other than the making of an
|
| 86 |
-
exact copy. The resulting work is called a "modified version" of the
|
| 87 |
-
earlier work or a work "based on" the earlier work.
|
| 88 |
-
|
| 89 |
-
A "covered work" means either the unmodified Program or a work based
|
| 90 |
-
on the Program.
|
| 91 |
-
|
| 92 |
-
To "propagate" a work means to do anything with it that, without
|
| 93 |
-
permission, would make you directly or secondarily liable for
|
| 94 |
-
infringement under applicable copyright law, except executing it on a
|
| 95 |
-
computer or modifying a private copy. Propagation includes copying,
|
| 96 |
-
distribution (with or without modification), making available to the
|
| 97 |
-
public, and in some countries other activities as well.
|
| 98 |
-
|
| 99 |
-
To "convey" a work means any kind of propagation that enables other
|
| 100 |
-
parties to make or receive copies. Mere interaction with a user through
|
| 101 |
-
a computer network, with no transfer of a copy, is not conveying.
|
| 102 |
-
|
| 103 |
-
An interactive user interface displays "Appropriate Legal Notices"
|
| 104 |
-
to the extent that it includes a convenient and prominently visible
|
| 105 |
-
feature that (1) displays an appropriate copyright notice, and (2)
|
| 106 |
-
tells the user that there is no warranty for the work (except to the
|
| 107 |
-
extent that warranties are provided), that licensees may convey the
|
| 108 |
-
work under this License, and how to view a copy of this License. If
|
| 109 |
-
the interface presents a list of user commands or options, such as a
|
| 110 |
-
menu, a prominent item in the list meets this criterion.
|
| 111 |
-
|
| 112 |
-
1. Source Code.
|
| 113 |
-
|
| 114 |
-
The "source code" for a work means the preferred form of the work
|
| 115 |
-
for making modifications to it. "Object code" means any non-source
|
| 116 |
-
form of a work.
|
| 117 |
-
|
| 118 |
-
A "Standard Interface" means an interface that either is an official
|
| 119 |
-
standard defined by a recognized standards body, or, in the case of
|
| 120 |
-
interfaces specified for a particular programming language, one that
|
| 121 |
-
is widely used among developers working in that language.
|
| 122 |
-
|
| 123 |
-
The "System Libraries" of an executable work include anything, other
|
| 124 |
-
than the work as a whole, that (a) is included in the normal form of
|
| 125 |
-
packaging a Major Component, but which is not part of that Major
|
| 126 |
-
Component, and (b) serves only to enable use of the work with that
|
| 127 |
-
Major Component, or to implement a Standard Interface for which an
|
| 128 |
-
implementation is available to the public in source code form. A
|
| 129 |
-
"Major Component", in this context, means a major essential component
|
| 130 |
-
(kernel, window system, and so on) of the specific operating system
|
| 131 |
-
(if any) on which the executable work runs, or a compiler used to
|
| 132 |
-
produce the work, or an object code interpreter used to run it.
|
| 133 |
-
|
| 134 |
-
The "Corresponding Source" for a work in object code form means all
|
| 135 |
-
the source code needed to generate, install, and (for an executable
|
| 136 |
-
work) run the object code and to modify the work, including scripts to
|
| 137 |
-
control those activities. However, it does not include the work's
|
| 138 |
-
System Libraries, or general-purpose tools or generally available free
|
| 139 |
-
programs which are used unmodified in performing those activities but
|
| 140 |
-
which are not part of the work. For example, Corresponding Source
|
| 141 |
-
includes interface definition files associated with source files for
|
| 142 |
-
the work, and the source code for shared libraries and dynamically
|
| 143 |
-
linked subprograms that the work is specifically designed to require,
|
| 144 |
-
such as by intimate data communication or control flow between those
|
| 145 |
-
subprograms and other parts of the work.
|
| 146 |
-
|
| 147 |
-
The Corresponding Source need not include anything that users
|
| 148 |
-
can regenerate automatically from other parts of the Corresponding
|
| 149 |
-
Source.
|
| 150 |
-
|
| 151 |
-
The Corresponding Source for a work in source code form is that
|
| 152 |
-
same work.
|
| 153 |
-
|
| 154 |
-
2. Basic Permissions.
|
| 155 |
-
|
| 156 |
-
All rights granted under this License are granted for the term of
|
| 157 |
-
copyright on the Program, and are irrevocable provided the stated
|
| 158 |
-
conditions are met. This License explicitly affirms your unlimited
|
| 159 |
-
permission to run the unmodified Program. The output from running a
|
| 160 |
-
covered work is covered by this License only if the output, given its
|
| 161 |
-
content, constitutes a covered work. This License acknowledges your
|
| 162 |
-
rights of fair use or other equivalent, as provided by copyright law.
|
| 163 |
-
|
| 164 |
-
You may make, run and propagate covered works that you do not
|
| 165 |
-
convey, without conditions so long as your license otherwise remains
|
| 166 |
-
in force. You may convey covered works to others for the sole purpose
|
| 167 |
-
of having them make modifications exclusively for you, or provide you
|
| 168 |
-
with facilities for running those works, provided that you comply with
|
| 169 |
-
the terms of this License in conveying all material for which you do
|
| 170 |
-
not control copyright. Those thus making or running the covered works
|
| 171 |
-
for you must do so exclusively on your behalf, under your direction
|
| 172 |
-
and control, on terms that prohibit them from making any copies of
|
| 173 |
-
your copyrighted material outside their relationship with you.
|
| 174 |
-
|
| 175 |
-
Conveying under any other circumstances is permitted solely under
|
| 176 |
-
the conditions stated below. Sublicensing is not allowed; section 10
|
| 177 |
-
makes it unnecessary.
|
| 178 |
-
|
| 179 |
-
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
| 180 |
-
|
| 181 |
-
No covered work shall be deemed part of an effective technological
|
| 182 |
-
measure under any applicable law fulfilling obligations under article
|
| 183 |
-
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
| 184 |
-
similar laws prohibiting or restricting circumvention of such
|
| 185 |
-
measures.
|
| 186 |
-
|
| 187 |
-
When you convey a covered work, you waive any legal power to forbid
|
| 188 |
-
circumvention of technological measures to the extent such circumvention
|
| 189 |
-
is effected by exercising rights under this License with respect to
|
| 190 |
-
the covered work, and you disclaim any intention to limit operation or
|
| 191 |
-
modification of the work as a means of enforcing, against the work's
|
| 192 |
-
users, your or third parties' legal rights to forbid circumvention of
|
| 193 |
-
technological measures.
|
| 194 |
-
|
| 195 |
-
4. Conveying Verbatim Copies.
|
| 196 |
-
|
| 197 |
-
You may convey verbatim copies of the Program's source code as you
|
| 198 |
-
receive it, in any medium, provided that you conspicuously and
|
| 199 |
-
appropriately publish on each copy an appropriate copyright notice;
|
| 200 |
-
keep intact all notices stating that this License and any
|
| 201 |
-
non-permissive terms added in accord with section 7 apply to the code;
|
| 202 |
-
keep intact all notices of the absence of any warranty; and give all
|
| 203 |
-
recipients a copy of this License along with the Program.
|
| 204 |
-
|
| 205 |
-
You may charge any price or no price for each copy that you convey,
|
| 206 |
-
and you may offer support or warranty protection for a fee.
|
| 207 |
-
|
| 208 |
-
5. Conveying Modified Source Versions.
|
| 209 |
-
|
| 210 |
-
You may convey a work based on the Program, or the modifications to
|
| 211 |
-
produce it from the Program, in the form of source code under the
|
| 212 |
-
terms of section 4, provided that you also meet all of these conditions:
|
| 213 |
-
|
| 214 |
-
a) The work must carry prominent notices stating that you modified
|
| 215 |
-
it, and giving a relevant date.
|
| 216 |
-
|
| 217 |
-
b) The work must carry prominent notices stating that it is
|
| 218 |
-
released under this License and any conditions added under section
|
| 219 |
-
7. This requirement modifies the requirement in section 4 to
|
| 220 |
-
"keep intact all notices".
|
| 221 |
-
|
| 222 |
-
c) You must license the entire work, as a whole, under this
|
| 223 |
-
License to anyone who comes into possession of a copy. This
|
| 224 |
-
License will therefore apply, along with any applicable section 7
|
| 225 |
-
additional terms, to the whole of the work, and all its parts,
|
| 226 |
-
regardless of how they are packaged. This License gives no
|
| 227 |
-
permission to license the work in any other way, but it does not
|
| 228 |
-
invalidate such permission if you have separately received it.
|
| 229 |
-
|
| 230 |
-
d) If the work has interactive user interfaces, each must display
|
| 231 |
-
Appropriate Legal Notices; however, if the Program has interactive
|
| 232 |
-
interfaces that do not display Appropriate Legal Notices, your
|
| 233 |
-
work need not make them do so.
|
| 234 |
-
|
| 235 |
-
A compilation of a covered work with other separate and independent
|
| 236 |
-
works, which are not by their nature extensions of the covered work,
|
| 237 |
-
and which are not combined with it such as to form a larger program,
|
| 238 |
-
in or on a volume of a storage or distribution medium, is called an
|
| 239 |
-
"aggregate" if the compilation and its resulting copyright are not
|
| 240 |
-
used to limit the access or legal rights of the compilation's users
|
| 241 |
-
beyond what the individual works permit. Inclusion of a covered work
|
| 242 |
-
in an aggregate does not cause this License to apply to the other
|
| 243 |
-
parts of the aggregate.
|
| 244 |
-
|
| 245 |
-
6. Conveying Non-Source Forms.
|
| 246 |
-
|
| 247 |
-
You may convey a covered work in object code form under the terms
|
| 248 |
-
of sections 4 and 5, provided that you also convey the
|
| 249 |
-
machine-readable Corresponding Source under the terms of this License,
|
| 250 |
-
in one of these ways:
|
| 251 |
-
|
| 252 |
-
a) Convey the object code in, or embodied in, a physical product
|
| 253 |
-
(including a physical distribution medium), accompanied by the
|
| 254 |
-
Corresponding Source fixed on a durable physical medium
|
| 255 |
-
customarily used for software interchange.
|
| 256 |
-
|
| 257 |
-
b) Convey the object code in, or embodied in, a physical product
|
| 258 |
-
(including a physical distribution medium), accompanied by a
|
| 259 |
-
written offer, valid for at least three years and valid for as
|
| 260 |
-
long as you offer spare parts or customer support for that product
|
| 261 |
-
model, to give anyone who possesses the object code either (1) a
|
| 262 |
-
copy of the Corresponding Source for all the software in the
|
| 263 |
-
product that is covered by this License, on a durable physical
|
| 264 |
-
medium customarily used for software interchange, for a price no
|
| 265 |
-
more than your reasonable cost of physically performing this
|
| 266 |
-
conveying of source, or (2) access to copy the
|
| 267 |
-
Corresponding Source from a network server at no charge.
|
| 268 |
-
|
| 269 |
-
c) Convey individual copies of the object code with a copy of the
|
| 270 |
-
written offer to provide the Corresponding Source. This
|
| 271 |
-
alternative is allowed only occasionally and noncommercially, and
|
| 272 |
-
only if you received the object code with such an offer, in accord
|
| 273 |
-
with subsection 6b.
|
| 274 |
-
|
| 275 |
-
d) Convey the object code by offering access from a designated
|
| 276 |
-
place (gratis or for a charge), and offer equivalent access to the
|
| 277 |
-
Corresponding Source in the same way through the same place at no
|
| 278 |
-
further charge. You need not require recipients to copy the
|
| 279 |
-
Corresponding Source along with the object code. If the place to
|
| 280 |
-
copy the object code is a network server, the Corresponding Source
|
| 281 |
-
may be on a different server (operated by you or a third party)
|
| 282 |
-
that supports equivalent copying facilities, provided you maintain
|
| 283 |
-
clear directions next to the object code saying where to find the
|
| 284 |
-
Corresponding Source. Regardless of what server hosts the
|
| 285 |
-
Corresponding Source, you remain obligated to ensure that it is
|
| 286 |
-
available for as long as needed to satisfy these requirements.
|
| 287 |
-
|
| 288 |
-
e) Convey the object code using peer-to-peer transmission, provided
|
| 289 |
-
you inform other peers where the object code and Corresponding
|
| 290 |
-
Source of the work are being offered to the general public at no
|
| 291 |
-
charge under subsection 6d.
|
| 292 |
-
|
| 293 |
-
A separable portion of the object code, whose source code is excluded
|
| 294 |
-
from the Corresponding Source as a System Library, need not be
|
| 295 |
-
included in conveying the object code work.
|
| 296 |
-
|
| 297 |
-
A "User Product" is either (1) a "consumer product", which means any
|
| 298 |
-
tangible personal property which is normally used for personal, family,
|
| 299 |
-
or household purposes, or (2) anything designed or sold for incorporation
|
| 300 |
-
into a dwelling. In determining whether a product is a consumer product,
|
| 301 |
-
doubtful cases shall be resolved in favor of coverage. For a particular
|
| 302 |
-
product received by a particular user, "normally used" refers to a
|
| 303 |
-
typical or common use of that class of product, regardless of the status
|
| 304 |
-
of the particular user or of the way in which the particular user
|
| 305 |
-
actually uses, or expects or is expected to use, the product. A product
|
| 306 |
-
is a consumer product regardless of whether the product has substantial
|
| 307 |
-
commercial, industrial or non-consumer uses, unless such uses represent
|
| 308 |
-
the only significant mode of use of the product.
|
| 309 |
-
|
| 310 |
-
"Installation Information" for a User Product means any methods,
|
| 311 |
-
procedures, authorization keys, or other information required to install
|
| 312 |
-
and execute modified versions of a covered work in that User Product from
|
| 313 |
-
a modified version of its Corresponding Source. The information must
|
| 314 |
-
suffice to ensure that the continued functioning of the modified object
|
| 315 |
-
code is in no case prevented or interfered with solely because
|
| 316 |
-
modification has been made.
|
| 317 |
-
|
| 318 |
-
If you convey an object code work under this section in, or with, or
|
| 319 |
-
specifically for use in, a User Product, and the conveying occurs as
|
| 320 |
-
part of a transaction in which the right of possession and use of the
|
| 321 |
-
User Product is transferred to the recipient in perpetuity or for a
|
| 322 |
-
fixed term (regardless of how the transaction is characterized), the
|
| 323 |
-
Corresponding Source conveyed under this section must be accompanied
|
| 324 |
-
by the Installation Information. But this requirement does not apply
|
| 325 |
-
if neither you nor any third party retains the ability to install
|
| 326 |
-
modified object code on the User Product (for example, the work has
|
| 327 |
-
been installed in ROM).
|
| 328 |
-
|
| 329 |
-
The requirement to provide Installation Information does not include a
|
| 330 |
-
requirement to continue to provide support service, warranty, or updates
|
| 331 |
-
for a work that has been modified or installed by the recipient, or for
|
| 332 |
-
the User Product in which it has been modified or installed. Access to a
|
| 333 |
-
network may be denied when the modification itself materially and
|
| 334 |
-
adversely affects the operation of the network or violates the rules and
|
| 335 |
-
protocols for communication across the network.
|
| 336 |
-
|
| 337 |
-
Corresponding Source conveyed, and Installation Information provided,
|
| 338 |
-
in accord with this section must be in a format that is publicly
|
| 339 |
-
documented (and with an implementation available to the public in
|
| 340 |
-
source code form), and must require no special password or key for
|
| 341 |
-
unpacking, reading or copying.
|
| 342 |
-
|
| 343 |
-
7. Additional Terms.
|
| 344 |
-
|
| 345 |
-
"Additional permissions" are terms that supplement the terms of this
|
| 346 |
-
License by making exceptions from one or more of its conditions.
|
| 347 |
-
Additional permissions that are applicable to the entire Program shall
|
| 348 |
-
be treated as though they were included in this License, to the extent
|
| 349 |
-
that they are valid under applicable law. If additional permissions
|
| 350 |
-
apply only to part of the Program, that part may be used separately
|
| 351 |
-
under those permissions, but the entire Program remains governed by
|
| 352 |
-
this License without regard to the additional permissions.
|
| 353 |
-
|
| 354 |
-
When you convey a copy of a covered work, you may at your option
|
| 355 |
-
remove any additional permissions from that copy, or from any part of
|
| 356 |
-
it. (Additional permissions may be written to require their own
|
| 357 |
-
removal in certain cases when you modify the work.) You may place
|
| 358 |
-
additional permissions on material, added by you to a covered work,
|
| 359 |
-
for which you have or can give appropriate copyright permission.
|
| 360 |
-
|
| 361 |
-
Notwithstanding any other provision of this License, for material you
|
| 362 |
-
add to a covered work, you may (if authorized by the copyright holders of
|
| 363 |
-
that material) supplement the terms of this License with terms:
|
| 364 |
-
|
| 365 |
-
a) Disclaiming warranty or limiting liability differently from the
|
| 366 |
-
terms of sections 15 and 16 of this License; or
|
| 367 |
-
|
| 368 |
-
b) Requiring preservation of specified reasonable legal notices or
|
| 369 |
-
author attributions in that material or in the Appropriate Legal
|
| 370 |
-
Notices displayed by works containing it; or
|
| 371 |
-
|
| 372 |
-
c) Prohibiting misrepresentation of the origin of that material, or
|
| 373 |
-
requiring that modified versions of such material be marked in
|
| 374 |
-
reasonable ways as different from the original version; or
|
| 375 |
-
|
| 376 |
-
d) Limiting the use for publicity purposes of names of licensors or
|
| 377 |
-
authors of the material; or
|
| 378 |
-
|
| 379 |
-
e) Declining to grant rights under trademark law for use of some
|
| 380 |
-
trade names, trademarks, or service marks; or
|
| 381 |
-
|
| 382 |
-
f) Requiring indemnification of licensors and authors of that
|
| 383 |
-
material by anyone who conveys the material (or modified versions of
|
| 384 |
-
it) with contractual assumptions of liability to the recipient, for
|
| 385 |
-
any liability that these contractual assumptions directly impose on
|
| 386 |
-
those licensors and authors.
|
| 387 |
-
|
| 388 |
-
All other non-permissive additional terms are considered "further
|
| 389 |
-
restrictions" within the meaning of section 10. If the Program as you
|
| 390 |
-
received it, or any part of it, contains a notice stating that it is
|
| 391 |
-
governed by this License along with a term that is a further
|
| 392 |
-
restriction, you may remove that term. If a license document contains
|
| 393 |
-
a further restriction but permits relicensing or conveying under this
|
| 394 |
-
License, you may add to a covered work material governed by the terms
|
| 395 |
-
of that license document, provided that the further restriction does
|
| 396 |
-
not survive such relicensing or conveying.
|
| 397 |
-
|
| 398 |
-
If you add terms to a covered work in accord with this section, you
|
| 399 |
-
must place, in the relevant source files, a statement of the
|
| 400 |
-
additional terms that apply to those files, or a notice indicating
|
| 401 |
-
where to find the applicable terms.
|
| 402 |
-
|
| 403 |
-
Additional terms, permissive or non-permissive, may be stated in the
|
| 404 |
-
form of a separately written license, or stated as exceptions;
|
| 405 |
-
the above requirements apply either way.
|
| 406 |
-
|
| 407 |
-
8. Termination.
|
| 408 |
-
|
| 409 |
-
You may not propagate or modify a covered work except as expressly
|
| 410 |
-
provided under this License. Any attempt otherwise to propagate or
|
| 411 |
-
modify it is void, and will automatically terminate your rights under
|
| 412 |
-
this License (including any patent licenses granted under the third
|
| 413 |
-
paragraph of section 11).
|
| 414 |
-
|
| 415 |
-
However, if you cease all violation of this License, then your
|
| 416 |
-
license from a particular copyright holder is reinstated (a)
|
| 417 |
-
provisionally, unless and until the copyright holder explicitly and
|
| 418 |
-
finally terminates your license, and (b) permanently, if the copyright
|
| 419 |
-
holder fails to notify you of the violation by some reasonable means
|
| 420 |
-
prior to 60 days after the cessation.
|
| 421 |
-
|
| 422 |
-
Moreover, your license from a particular copyright holder is
|
| 423 |
-
reinstated permanently if the copyright holder notifies you of the
|
| 424 |
-
violation by some reasonable means, this is the first time you have
|
| 425 |
-
received notice of violation of this License (for any work) from that
|
| 426 |
-
copyright holder, and you cure the violation prior to 30 days after
|
| 427 |
-
your receipt of the notice.
|
| 428 |
-
|
| 429 |
-
Termination of your rights under this section does not terminate the
|
| 430 |
-
licenses of parties who have received copies or rights from you under
|
| 431 |
-
this License. If your rights have been terminated and not permanently
|
| 432 |
-
reinstated, you do not qualify to receive new licenses for the same
|
| 433 |
-
material under section 10.
|
| 434 |
-
|
| 435 |
-
9. Acceptance Not Required for Having Copies.
|
| 436 |
-
|
| 437 |
-
You are not required to accept this License in order to receive or
|
| 438 |
-
run a copy of the Program. Ancillary propagation of a covered work
|
| 439 |
-
occurring solely as a consequence of using peer-to-peer transmission
|
| 440 |
-
to receive a copy likewise does not require acceptance. However,
|
| 441 |
-
nothing other than this License grants you permission to propagate or
|
| 442 |
-
modify any covered work. These actions infringe copyright if you do
|
| 443 |
-
not accept this License. Therefore, by modifying or propagating a
|
| 444 |
-
covered work, you indicate your acceptance of this License to do so.
|
| 445 |
-
|
| 446 |
-
10. Automatic Licensing of Downstream Recipients.
|
| 447 |
-
|
| 448 |
-
Each time you convey a covered work, the recipient automatically
|
| 449 |
-
receives a license from the original licensors, to run, modify and
|
| 450 |
-
propagate that work, subject to this License. You are not responsible
|
| 451 |
-
for enforcing compliance by third parties with this License.
|
| 452 |
-
|
| 453 |
-
An "entity transaction" is a transaction transferring control of an
|
| 454 |
-
organization, or substantially all assets of one, or subdividing an
|
| 455 |
-
organization, or merging organizations. If propagation of a covered
|
| 456 |
-
work results from an entity transaction, each party to that
|
| 457 |
-
transaction who receives a copy of the work also receives whatever
|
| 458 |
-
licenses to the work the party's predecessor in interest had or could
|
| 459 |
-
give under the previous paragraph, plus a right to possession of the
|
| 460 |
-
Corresponding Source of the work from the predecessor in interest, if
|
| 461 |
-
the predecessor has it or can get it with reasonable efforts.
|
| 462 |
-
|
| 463 |
-
You may not impose any further restrictions on the exercise of the
|
| 464 |
-
rights granted or affirmed under this License. For example, you may
|
| 465 |
-
not impose a license fee, royalty, or other charge for exercise of
|
| 466 |
-
rights granted under this License, and you may not initiate litigation
|
| 467 |
-
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
| 468 |
-
any patent claim is infringed by making, using, selling, offering for
|
| 469 |
-
sale, or importing the Program or any portion of it.
|
| 470 |
-
|
| 471 |
-
11. Patents.
|
| 472 |
-
|
| 473 |
-
A "contributor" is a copyright holder who authorizes use under this
|
| 474 |
-
License of the Program or a work on which the Program is based. The
|
| 475 |
-
work thus licensed is called the contributor's "contributor version".
|
| 476 |
-
|
| 477 |
-
A contributor's "essential patent claims" are all patent claims
|
| 478 |
-
owned or controlled by the contributor, whether already acquired or
|
| 479 |
-
hereafter acquired, that would be infringed by some manner, permitted
|
| 480 |
-
by this License, of making, using, or selling its contributor version,
|
| 481 |
-
but do not include claims that would be infringed only as a
|
| 482 |
-
consequence of further modification of the contributor version. For
|
| 483 |
-
purposes of this definition, "control" includes the right to grant
|
| 484 |
-
patent sublicenses in a manner consistent with the requirements of
|
| 485 |
-
this License.
|
| 486 |
-
|
| 487 |
-
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
| 488 |
-
patent license under the contributor's essential patent claims, to
|
| 489 |
-
make, use, sell, offer for sale, import and otherwise run, modify and
|
| 490 |
-
propagate the contents of its contributor version.
|
| 491 |
-
|
| 492 |
-
In the following three paragraphs, a "patent license" is any express
|
| 493 |
-
agreement or commitment, however denominated, not to enforce a patent
|
| 494 |
-
(such as an express permission to practice a patent or covenant not to
|
| 495 |
-
sue for patent infringement). To "grant" such a patent license to a
|
| 496 |
-
party means to make such an agreement or commitment not to enforce a
|
| 497 |
-
patent against the party.
|
| 498 |
-
|
| 499 |
-
If you convey a covered work, knowingly relying on a patent license,
|
| 500 |
-
and the Corresponding Source of the work is not available for anyone
|
| 501 |
-
to copy, free of charge and under the terms of this License, through a
|
| 502 |
-
publicly available network server or other readily accessible means,
|
| 503 |
-
then you must either (1) cause the Corresponding Source to be so
|
| 504 |
-
available, or (2) arrange to deprive yourself of the benefit of the
|
| 505 |
-
patent license for this particular work, or (3) arrange, in a manner
|
| 506 |
-
consistent with the requirements of this License, to extend the patent
|
| 507 |
-
license to downstream recipients. "Knowingly relying" means you have
|
| 508 |
-
actual knowledge that, but for the patent license, your conveying the
|
| 509 |
-
covered work in a country, or your recipient's use of the covered work
|
| 510 |
-
in a country, would infringe one or more identifiable patents in that
|
| 511 |
-
country that you have reason to believe are valid.
|
| 512 |
-
|
| 513 |
-
If, pursuant to or in connection with a single transaction or
|
| 514 |
-
arrangement, you convey, or propagate by procuring conveyance of, a
|
| 515 |
-
covered work, and grant a patent license to some of the parties
|
| 516 |
-
receiving the covered work authorizing them to use, propagate, modify
|
| 517 |
-
or convey a specific copy of the covered work, then the patent license
|
| 518 |
-
you grant is automatically extended to all recipients of the covered
|
| 519 |
-
work and works based on it.
|
| 520 |
-
|
| 521 |
-
A patent license is "discriminatory" if it does not include within
|
| 522 |
-
the scope of its coverage, prohibits the exercise of, or is
|
| 523 |
-
conditioned on the non-exercise of one or more of the rights that are
|
| 524 |
-
specifically granted under this License. You may not convey a covered
|
| 525 |
-
work if you are a party to an arrangement with a third party that is
|
| 526 |
-
in the business of distributing software, under which you make payment
|
| 527 |
-
to the third party based on the extent of your activity of conveying
|
| 528 |
-
the work, and under which the third party grants, to any of the
|
| 529 |
-
parties who would receive the covered work from you, a discriminatory
|
| 530 |
-
patent license (a) in connection with copies of the covered work
|
| 531 |
-
conveyed by you (or copies made from those copies), or (b) primarily
|
| 532 |
-
for and in connection with specific products or compilations that
|
| 533 |
-
contain the covered work, unless you entered into that arrangement,
|
| 534 |
-
or that patent license was granted, prior to 28 March 2007.
|
| 535 |
-
|
| 536 |
-
Nothing in this License shall be construed as excluding or limiting
|
| 537 |
-
any implied license or other defenses to infringement that may
|
| 538 |
-
otherwise be available to you under applicable patent law.
|
| 539 |
-
|
| 540 |
-
12. No Surrender of Others' Freedom.
|
| 541 |
-
|
| 542 |
-
If conditions are imposed on you (whether by court order, agreement or
|
| 543 |
-
otherwise) that contradict the conditions of this License, they do not
|
| 544 |
-
excuse you from the conditions of this License. If you cannot convey a
|
| 545 |
-
covered work so as to satisfy simultaneously your obligations under this
|
| 546 |
-
License and any other pertinent obligations, then as a consequence you may
|
| 547 |
-
not convey it at all. For example, if you agree to terms that obligate you
|
| 548 |
-
to collect a royalty for further conveying from those to whom you convey
|
| 549 |
-
the Program, the only way you could satisfy both those terms and this
|
| 550 |
-
License would be to refrain entirely from conveying the Program.
|
| 551 |
-
|
| 552 |
-
13. Use with the GNU Affero General Public License.
|
| 553 |
-
|
| 554 |
-
Notwithstanding any other provision of this License, you have
|
| 555 |
-
permission to link or combine any covered work with a work licensed
|
| 556 |
-
under version 3 of the GNU Affero General Public License into a single
|
| 557 |
-
combined work, and to convey the resulting work. The terms of this
|
| 558 |
-
License will continue to apply to the part which is the covered work,
|
| 559 |
-
but the special requirements of the GNU Affero General Public License,
|
| 560 |
-
section 13, concerning interaction through a network will apply to the
|
| 561 |
-
combination as such.
|
| 562 |
-
|
| 563 |
-
14. Revised Versions of this License.
|
| 564 |
-
|
| 565 |
-
The Free Software Foundation may publish revised and/or new versions of
|
| 566 |
-
the GNU General Public License from time to time. Such new versions will
|
| 567 |
-
be similar in spirit to the present version, but may differ in detail to
|
| 568 |
-
address new problems or concerns.
|
| 569 |
-
|
| 570 |
-
Each version is given a distinguishing version number. If the
|
| 571 |
-
Program specifies that a certain numbered version of the GNU General
|
| 572 |
-
Public License "or any later version" applies to it, you have the
|
| 573 |
-
option of following the terms and conditions either of that numbered
|
| 574 |
-
version or of any later version published by the Free Software
|
| 575 |
-
Foundation. If the Program does not specify a version number of the
|
| 576 |
-
GNU General Public License, you may choose any version ever published
|
| 577 |
-
by the Free Software Foundation.
|
| 578 |
-
|
| 579 |
-
If the Program specifies that a proxy can decide which future
|
| 580 |
-
versions of the GNU General Public License can be used, that proxy's
|
| 581 |
-
public statement of acceptance of a version permanently authorizes you
|
| 582 |
-
to choose that version for the Program.
|
| 583 |
-
|
| 584 |
-
Later license versions may give you additional or different
|
| 585 |
-
permissions. However, no additional obligations are imposed on any
|
| 586 |
-
author or copyright holder as a result of your choosing to follow a
|
| 587 |
-
later version.
|
| 588 |
-
|
| 589 |
-
15. Disclaimer of Warranty.
|
| 590 |
-
|
| 591 |
-
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
| 592 |
-
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
| 593 |
-
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
| 594 |
-
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
| 595 |
-
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| 596 |
-
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
| 597 |
-
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
| 598 |
-
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
| 599 |
-
|
| 600 |
-
16. Limitation of Liability.
|
| 601 |
-
|
| 602 |
-
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
| 603 |
-
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
| 604 |
-
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
| 605 |
-
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
| 606 |
-
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
| 607 |
-
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
| 608 |
-
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
| 609 |
-
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
| 610 |
-
SUCH DAMAGES.
|
| 611 |
-
|
| 612 |
-
17. Interpretation of Sections 15 and 16.
|
| 613 |
-
|
| 614 |
-
If the disclaimer of warranty and limitation of liability provided
|
| 615 |
-
above cannot be given local legal effect according to their terms,
|
| 616 |
-
reviewing courts shall apply local law that most closely approximates
|
| 617 |
-
an absolute waiver of all civil liability in connection with the
|
| 618 |
-
Program, unless a warranty or assumption of liability accompanies a
|
| 619 |
-
copy of the Program in return for a fee.
|
| 620 |
-
|
| 621 |
-
END OF TERMS AND CONDITIONS
|
| 622 |
-
|
| 623 |
-
How to Apply These Terms to Your New Programs
|
| 624 |
-
|
| 625 |
-
If you develop a new program, and you want it to be of the greatest
|
| 626 |
-
possible use to the public, the best way to achieve this is to make it
|
| 627 |
-
free software which everyone can redistribute and change under these terms.
|
| 628 |
-
|
| 629 |
-
To do so, attach the following notices to the program. It is safest
|
| 630 |
-
to attach them to the start of each source file to most effectively
|
| 631 |
-
state the exclusion of warranty; and each file should have at least
|
| 632 |
-
the "copyright" line and a pointer to where the full notice is found.
|
| 633 |
-
|
| 634 |
-
<one line to give the program's name and a brief idea of what it does.>
|
| 635 |
-
Copyright (C) <year> <name of author>
|
| 636 |
-
|
| 637 |
-
This program is free software: you can redistribute it and/or modify
|
| 638 |
-
it under the terms of the GNU General Public License as published by
|
| 639 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 640 |
-
(at your option) any later version.
|
| 641 |
-
|
| 642 |
-
This program is distributed in the hope that it will be useful,
|
| 643 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 644 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 645 |
-
GNU General Public License for more details.
|
| 646 |
-
|
| 647 |
-
You should have received a copy of the GNU General Public License
|
| 648 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 649 |
-
|
| 650 |
-
Also add information on how to contact you by electronic and paper mail.
|
| 651 |
-
|
| 652 |
-
If the program does terminal interaction, make it output a short
|
| 653 |
-
notice like this when it starts in an interactive mode:
|
| 654 |
-
|
| 655 |
-
<program> Copyright (C) <year> <name of author>
|
| 656 |
-
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
| 657 |
-
This is free software, and you are welcome to redistribute it
|
| 658 |
-
under certain conditions; type `show c' for details.
|
| 659 |
-
|
| 660 |
-
The hypothetical commands `show w' and `show c' should show the appropriate
|
| 661 |
-
parts of the General Public License. Of course, your program's commands
|
| 662 |
-
might be different; for a GUI interface, you would use an "about box".
|
| 663 |
-
|
| 664 |
-
You should also get your employer (if you work as a programmer) or school,
|
| 665 |
-
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
| 666 |
-
For more information on this, and how to apply and follow the GNU GPL, see
|
| 667 |
-
<http://www.gnu.org/licenses/>.
|
| 668 |
-
|
| 669 |
-
The GNU General Public License does not permit incorporating your program
|
| 670 |
-
into proprietary programs. If your program is a subroutine library, you
|
| 671 |
-
may consider it more useful to permit linking proprietary applications with
|
| 672 |
-
the library. If this is what you want to do, use the GNU Lesser General
|
| 673 |
-
Public License instead of this License. But first, please read
|
| 674 |
-
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/Linux/stockfish_8_x64
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:d8d492ad30488ee16c84f1b8e81ba347eb19aa04d23f9b5ee9fcd57b37fe40ff
|
| 3 |
-
size 1163544
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/Linux/stockfish_8_x64_bmi2
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:0dfd94228e9e59c766935dd0be15af17d0e112b139a0d0df44f869a908caa7d7
|
| 3 |
-
size 1155352
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/Linux/stockfish_8_x64_modern
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:8bb21573bf736df1b99d5c1e200d16518c839fe9ac974e87b3ab679d29484f90
|
| 3 |
-
size 1155352
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/Readme.md
DELETED
|
@@ -1,115 +0,0 @@
|
|
| 1 |
-
### Overview
|
| 2 |
-
|
| 3 |
-
[](https://travis-ci.org/official-stockfish/Stockfish)
|
| 4 |
-
[](https://ci.appveyor.com/project/mcostalba/stockfish)
|
| 5 |
-
|
| 6 |
-
Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
|
| 7 |
-
not a complete chess program and requires some UCI-compatible GUI
|
| 8 |
-
(e.g. XBoard with PolyGlot, eboard, Arena, Sigma Chess, Shredder, Chess
|
| 9 |
-
Partner or Fritz) in order to be used comfortably. Read the
|
| 10 |
-
documentation for your GUI of choice for information about how to use
|
| 11 |
-
Stockfish with it.
|
| 12 |
-
|
| 13 |
-
This version of Stockfish supports up to 128 cores. The engine defaults
|
| 14 |
-
to one search thread, so it is therefore recommended to inspect the value of
|
| 15 |
-
the *Threads* UCI parameter, and to make sure it equals the number of CPU
|
| 16 |
-
cores on your computer.
|
| 17 |
-
|
| 18 |
-
This version of Stockfish has support for Syzygybases.
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
### Files
|
| 22 |
-
|
| 23 |
-
This distribution of Stockfish consists of the following files:
|
| 24 |
-
|
| 25 |
-
* Readme.md, the file you are currently reading.
|
| 26 |
-
|
| 27 |
-
* Copying.txt, a text file containing the GNU General Public License.
|
| 28 |
-
|
| 29 |
-
* src, a subdirectory containing the full source code, including a Makefile
|
| 30 |
-
that can be used to compile Stockfish on Unix-like systems.
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
### Syzygybases
|
| 34 |
-
|
| 35 |
-
**Configuration**
|
| 36 |
-
|
| 37 |
-
Syzygybases are configured using the UCI options "SyzygyPath",
|
| 38 |
-
"SyzygyProbeDepth", "Syzygy50MoveRule" and "SyzygyProbeLimit".
|
| 39 |
-
|
| 40 |
-
The option "SyzygyPath" should be set to the directory or directories that
|
| 41 |
-
contain the .rtbw and .rtbz files. Multiple directories should be
|
| 42 |
-
separated by ";" on Windows and by ":" on Unix-based operating systems.
|
| 43 |
-
**Do not use spaces around the ";" or ":".**
|
| 44 |
-
|
| 45 |
-
Example: `C:\tablebases\wdl345;C:\tablebases\wdl6;D:\tablebases\dtz345;D:\tablebases\dtz6`
|
| 46 |
-
|
| 47 |
-
It is recommended to store .rtbw files on an SSD. There is no loss in
|
| 48 |
-
storing the .rtbz files on a regular HD.
|
| 49 |
-
|
| 50 |
-
Increasing the "SyzygyProbeDepth" option lets the engine probe less
|
| 51 |
-
aggressively. Set this option to a higher value if you experience too much
|
| 52 |
-
slowdown (in terms of nps) due to TB probing.
|
| 53 |
-
|
| 54 |
-
Set the "Syzygy50MoveRule" option to false if you want tablebase positions
|
| 55 |
-
that are drawn by the 50-move rule to count as win or loss. This may be useful
|
| 56 |
-
for correspondence games (because of tablebase adjudication).
|
| 57 |
-
|
| 58 |
-
The "SyzygyProbeLimit" option should normally be left at its default value.
|
| 59 |
-
|
| 60 |
-
**What to expect**
|
| 61 |
-
If the engine is searching a position that is not in the tablebases (e.g.
|
| 62 |
-
a position with 7 pieces), it will access the tablebases during the search.
|
| 63 |
-
If the engine reports a very large score (typically 123.xx), this means
|
| 64 |
-
that it has found a winning line into a tablebase position.
|
| 65 |
-
|
| 66 |
-
If the engine is given a position to search that is in the tablebases, it
|
| 67 |
-
will use the tablebases at the beginning of the search to preselect all
|
| 68 |
-
good moves, i.e. all moves that preserve the win or preserve the draw while
|
| 69 |
-
taking into account the 50-move rule.
|
| 70 |
-
It will then perform a search only on those moves. **The engine will not move
|
| 71 |
-
immediately**, unless there is only a single good move. **The engine likely
|
| 72 |
-
will not report a mate score even if the position is known to be won.**
|
| 73 |
-
|
| 74 |
-
It is therefore clear that behaviour is not identical to what one might
|
| 75 |
-
be used to with Nalimov tablebases. There are technical reasons for this
|
| 76 |
-
difference, the main technical reason being that Nalimov tablebases use the
|
| 77 |
-
DTM metric (distance-to-mate), while Syzygybases use a variation of the
|
| 78 |
-
DTZ metric (distance-to-zero, zero meaning any move that resets the 50-move
|
| 79 |
-
counter). This special metric is one of the reasons that Syzygybases are
|
| 80 |
-
more compact than Nalimov tablebases, while still storing all information
|
| 81 |
-
needed for optimal play and in addition being able to take into account
|
| 82 |
-
the 50-move rule.
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
### Compiling it yourself
|
| 86 |
-
|
| 87 |
-
On Unix-like systems, it should be possible to compile Stockfish
|
| 88 |
-
directly from the source code with the included Makefile.
|
| 89 |
-
|
| 90 |
-
Stockfish has support for 32 or 64-bit CPUs, the hardware POPCNT
|
| 91 |
-
instruction, big-endian machines such as Power PC, and other platforms.
|
| 92 |
-
|
| 93 |
-
In general it is recommended to run `make help` to see a list of make
|
| 94 |
-
targets with corresponding descriptions. When not using the Makefile to
|
| 95 |
-
compile (for instance with Microsoft MSVC) you need to manually
|
| 96 |
-
set/unset some switches in the compiler command line; see file *types.h*
|
| 97 |
-
for a quick reference.
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
### Terms of use
|
| 101 |
-
|
| 102 |
-
Stockfish is free, and distributed under the **GNU General Public License**
|
| 103 |
-
(GPL). Essentially, this means that you are free to do almost exactly
|
| 104 |
-
what you want with the program, including distributing it among your
|
| 105 |
-
friends, making it available for download from your web site, selling
|
| 106 |
-
it (either by itself or as part of some bigger software package), or
|
| 107 |
-
using it as the starting point for a software project of your own.
|
| 108 |
-
|
| 109 |
-
The only real limitation is that whenever you distribute Stockfish in
|
| 110 |
-
some way, you must always include the full source code, or a pointer
|
| 111 |
-
to where the source code can be found. If you make any changes to the
|
| 112 |
-
source code, these changes must also be made available under the GPL.
|
| 113 |
-
|
| 114 |
-
For full details, read the copy of the GPL found in the file named
|
| 115 |
-
*Copying.txt*.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/appveyor.yml
DELETED
|
@@ -1,45 +0,0 @@
|
|
| 1 |
-
version: 1.0.{build}
|
| 2 |
-
clone_depth: 5
|
| 3 |
-
|
| 4 |
-
branches:
|
| 5 |
-
only:
|
| 6 |
-
- master
|
| 7 |
-
- appveyor
|
| 8 |
-
|
| 9 |
-
# Operating system (build VM template)
|
| 10 |
-
os: Visual Studio 2015
|
| 11 |
-
|
| 12 |
-
# Build platform, i.e. x86, x64, AnyCPU. This setting is optional.
|
| 13 |
-
platform:
|
| 14 |
-
- x86
|
| 15 |
-
- x64
|
| 16 |
-
- Any CPU
|
| 17 |
-
|
| 18 |
-
# build Configuration, i.e. Debug, Release, etc.
|
| 19 |
-
configuration: Debug
|
| 20 |
-
|
| 21 |
-
matrix:
|
| 22 |
-
# The build fail immediately once one of the job fails
|
| 23 |
-
fast_finish: true
|
| 24 |
-
|
| 25 |
-
# Scripts that are called at very beginning, before repo cloning
|
| 26 |
-
init:
|
| 27 |
-
- cmake --version
|
| 28 |
-
- msbuild /version
|
| 29 |
-
|
| 30 |
-
before_build:
|
| 31 |
-
- cd src
|
| 32 |
-
- echo project (Stockfish) >> CMakeLists.txt
|
| 33 |
-
- echo add_executable(stockfish benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp >> CMakeLists.txt
|
| 34 |
-
- echo main.cpp material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp >> CMakeLists.txt
|
| 35 |
-
- echo search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp syzygy/tbprobe.cpp) >> CMakeLists.txt
|
| 36 |
-
- echo set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src) >> CMakeLists.txt
|
| 37 |
-
# - echo target_compile_options(stockfish PUBLIC "/Ox") >> CMakeLists.txt
|
| 38 |
-
|
| 39 |
-
build_script:
|
| 40 |
-
- cmake -G "Visual Studio 14 2015 Win64" .
|
| 41 |
-
- cmake --build .
|
| 42 |
-
|
| 43 |
-
before_test:
|
| 44 |
-
- cd Debug
|
| 45 |
-
- stockfish.exe bench > null
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/Makefile
DELETED
|
@@ -1,545 +0,0 @@
|
|
| 1 |
-
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 2 |
-
# Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 3 |
-
# Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 4 |
-
# Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 5 |
-
#
|
| 6 |
-
# Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
-
# it under the terms of the GNU General Public License as published by
|
| 8 |
-
# the Free Software Foundation, either version 3 of the License, or
|
| 9 |
-
# (at your option) any later version.
|
| 10 |
-
#
|
| 11 |
-
# Stockfish is distributed in the hope that it will be useful,
|
| 12 |
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
-
# GNU General Public License for more details.
|
| 15 |
-
#
|
| 16 |
-
# You should have received a copy of the GNU General Public License
|
| 17 |
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
### ==========================================================================
|
| 21 |
-
### Section 1. General Configuration
|
| 22 |
-
### ==========================================================================
|
| 23 |
-
|
| 24 |
-
### Establish the operating system name
|
| 25 |
-
KERNEL = $(shell uname -s)
|
| 26 |
-
ifeq ($(KERNEL),Linux)
|
| 27 |
-
OS = $(shell uname -o)
|
| 28 |
-
endif
|
| 29 |
-
|
| 30 |
-
### Executable name
|
| 31 |
-
EXE = stockfish
|
| 32 |
-
|
| 33 |
-
### Installation dir definitions
|
| 34 |
-
PREFIX = /usr/local
|
| 35 |
-
BINDIR = $(PREFIX)/bin
|
| 36 |
-
|
| 37 |
-
### Built-in benchmark for pgo-builds
|
| 38 |
-
PGOBENCH = ./$(EXE) bench
|
| 39 |
-
|
| 40 |
-
### Object files
|
| 41 |
-
OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
|
| 42 |
-
material.o misc.o movegen.o movepick.o pawns.o position.o psqt.o \
|
| 43 |
-
search.o thread.o timeman.o tt.o uci.o ucioption.o syzygy/tbprobe.o
|
| 44 |
-
|
| 45 |
-
### ==========================================================================
|
| 46 |
-
### Section 2. High-level Configuration
|
| 47 |
-
### ==========================================================================
|
| 48 |
-
#
|
| 49 |
-
# flag --- Comp switch --- Description
|
| 50 |
-
# ----------------------------------------------------------------------------
|
| 51 |
-
#
|
| 52 |
-
# debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode
|
| 53 |
-
# sanitize = yes/no --- (-fsanitize ) --- enable undefined behavior checks
|
| 54 |
-
# optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations
|
| 55 |
-
# arch = (name) --- (-arch) --- Target architecture
|
| 56 |
-
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
|
| 57 |
-
# prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch asm-instruction
|
| 58 |
-
# popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt asm-instruction
|
| 59 |
-
# sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions
|
| 60 |
-
# pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction
|
| 61 |
-
#
|
| 62 |
-
# Note that Makefile is space sensitive, so when adding new architectures
|
| 63 |
-
# or modifying existing flags, you have to make sure there are no extra spaces
|
| 64 |
-
# at the end of the line for flag values.
|
| 65 |
-
|
| 66 |
-
### 2.1. General and architecture defaults
|
| 67 |
-
optimize = yes
|
| 68 |
-
debug = no
|
| 69 |
-
sanitize = no
|
| 70 |
-
bits = 32
|
| 71 |
-
prefetch = no
|
| 72 |
-
popcnt = no
|
| 73 |
-
sse = no
|
| 74 |
-
pext = no
|
| 75 |
-
|
| 76 |
-
### 2.2 Architecture specific
|
| 77 |
-
|
| 78 |
-
ifeq ($(ARCH),general-32)
|
| 79 |
-
arch = any
|
| 80 |
-
endif
|
| 81 |
-
|
| 82 |
-
ifeq ($(ARCH),x86-32-old)
|
| 83 |
-
arch = i386
|
| 84 |
-
endif
|
| 85 |
-
|
| 86 |
-
ifeq ($(ARCH),x86-32)
|
| 87 |
-
arch = i386
|
| 88 |
-
prefetch = yes
|
| 89 |
-
sse = yes
|
| 90 |
-
endif
|
| 91 |
-
|
| 92 |
-
ifeq ($(ARCH),general-64)
|
| 93 |
-
arch = any
|
| 94 |
-
bits = 64
|
| 95 |
-
endif
|
| 96 |
-
|
| 97 |
-
ifeq ($(ARCH),x86-64)
|
| 98 |
-
arch = x86_64
|
| 99 |
-
bits = 64
|
| 100 |
-
prefetch = yes
|
| 101 |
-
sse = yes
|
| 102 |
-
endif
|
| 103 |
-
|
| 104 |
-
ifeq ($(ARCH),x86-64-modern)
|
| 105 |
-
arch = x86_64
|
| 106 |
-
bits = 64
|
| 107 |
-
prefetch = yes
|
| 108 |
-
popcnt = yes
|
| 109 |
-
sse = yes
|
| 110 |
-
endif
|
| 111 |
-
|
| 112 |
-
ifeq ($(ARCH),x86-64-bmi2)
|
| 113 |
-
arch = x86_64
|
| 114 |
-
bits = 64
|
| 115 |
-
prefetch = yes
|
| 116 |
-
popcnt = yes
|
| 117 |
-
sse = yes
|
| 118 |
-
pext = yes
|
| 119 |
-
endif
|
| 120 |
-
|
| 121 |
-
ifeq ($(ARCH),armv7)
|
| 122 |
-
arch = armv7
|
| 123 |
-
prefetch = yes
|
| 124 |
-
endif
|
| 125 |
-
|
| 126 |
-
ifeq ($(ARCH),ppc-32)
|
| 127 |
-
arch = ppc
|
| 128 |
-
endif
|
| 129 |
-
|
| 130 |
-
ifeq ($(ARCH),ppc-64)
|
| 131 |
-
arch = ppc64
|
| 132 |
-
bits = 64
|
| 133 |
-
endif
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
### ==========================================================================
|
| 137 |
-
### Section 3. Low-level configuration
|
| 138 |
-
### ==========================================================================
|
| 139 |
-
|
| 140 |
-
### 3.1 Selecting compiler (default = gcc)
|
| 141 |
-
|
| 142 |
-
CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -fno-rtti -std=c++11 $(EXTRACXXFLAGS)
|
| 143 |
-
DEPENDFLAGS += -std=c++11
|
| 144 |
-
LDFLAGS += $(EXTRALDFLAGS)
|
| 145 |
-
|
| 146 |
-
ifeq ($(COMP),)
|
| 147 |
-
COMP=gcc
|
| 148 |
-
endif
|
| 149 |
-
|
| 150 |
-
ifeq ($(COMP),gcc)
|
| 151 |
-
comp=gcc
|
| 152 |
-
CXX=g++
|
| 153 |
-
CXXFLAGS += -pedantic -Wextra -Wshadow
|
| 154 |
-
|
| 155 |
-
ifeq ($(ARCH),armv7)
|
| 156 |
-
ifeq ($(OS),Android)
|
| 157 |
-
CXXFLAGS += -m$(bits)
|
| 158 |
-
endif
|
| 159 |
-
else
|
| 160 |
-
CXXFLAGS += -m$(bits)
|
| 161 |
-
endif
|
| 162 |
-
|
| 163 |
-
ifneq ($(KERNEL),Darwin)
|
| 164 |
-
LDFLAGS += -Wl,--no-as-needed
|
| 165 |
-
endif
|
| 166 |
-
endif
|
| 167 |
-
|
| 168 |
-
ifeq ($(COMP),mingw)
|
| 169 |
-
comp=mingw
|
| 170 |
-
|
| 171 |
-
ifeq ($(KERNEL),Linux)
|
| 172 |
-
ifeq ($(bits),64)
|
| 173 |
-
ifeq ($(shell which x86_64-w64-mingw32-c++-posix),)
|
| 174 |
-
CXX=x86_64-w64-mingw32-c++
|
| 175 |
-
else
|
| 176 |
-
CXX=x86_64-w64-mingw32-c++-posix
|
| 177 |
-
endif
|
| 178 |
-
else
|
| 179 |
-
ifeq ($(shell which i686-w64-mingw32-c++-posix),)
|
| 180 |
-
CXX=i686-w64-mingw32-c++
|
| 181 |
-
else
|
| 182 |
-
CXX=i686-w64-mingw32-c++-posix
|
| 183 |
-
endif
|
| 184 |
-
endif
|
| 185 |
-
else
|
| 186 |
-
CXX=g++
|
| 187 |
-
endif
|
| 188 |
-
|
| 189 |
-
CXXFLAGS += -Wextra -Wshadow
|
| 190 |
-
LDFLAGS += -static
|
| 191 |
-
endif
|
| 192 |
-
|
| 193 |
-
ifeq ($(COMP),icc)
|
| 194 |
-
comp=icc
|
| 195 |
-
CXX=icpc
|
| 196 |
-
CXXFLAGS += -diag-disable 1476,10120 -Wcheck -Wabi -Wdeprecated -strict-ansi
|
| 197 |
-
endif
|
| 198 |
-
|
| 199 |
-
ifeq ($(COMP),clang)
|
| 200 |
-
comp=clang
|
| 201 |
-
CXX=clang++
|
| 202 |
-
CXXFLAGS += -pedantic -Wextra -Wshadow
|
| 203 |
-
|
| 204 |
-
ifeq ($(ARCH),armv7)
|
| 205 |
-
ifeq ($(OS),Android)
|
| 206 |
-
CXXFLAGS += -m$(bits)
|
| 207 |
-
LDFLAGS += -m$(bits)
|
| 208 |
-
endif
|
| 209 |
-
else
|
| 210 |
-
CXXFLAGS += -m$(bits)
|
| 211 |
-
LDFLAGS += -m$(bits)
|
| 212 |
-
endif
|
| 213 |
-
|
| 214 |
-
ifeq ($(KERNEL),Darwin)
|
| 215 |
-
CXXFLAGS += -stdlib=libc++
|
| 216 |
-
DEPENDFLAGS += -stdlib=libc++
|
| 217 |
-
endif
|
| 218 |
-
endif
|
| 219 |
-
|
| 220 |
-
ifeq ($(comp),icc)
|
| 221 |
-
profile_prepare = icc-profile-prepare
|
| 222 |
-
profile_make = icc-profile-make
|
| 223 |
-
profile_use = icc-profile-use
|
| 224 |
-
profile_clean = icc-profile-clean
|
| 225 |
-
else
|
| 226 |
-
profile_prepare = gcc-profile-prepare
|
| 227 |
-
profile_make = gcc-profile-make
|
| 228 |
-
profile_use = gcc-profile-use
|
| 229 |
-
profile_clean = gcc-profile-clean
|
| 230 |
-
endif
|
| 231 |
-
|
| 232 |
-
ifeq ($(KERNEL),Darwin)
|
| 233 |
-
CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.9
|
| 234 |
-
LDFLAGS += -arch $(arch) -mmacosx-version-min=10.9
|
| 235 |
-
endif
|
| 236 |
-
|
| 237 |
-
### Travis CI script uses COMPILER to overwrite CXX
|
| 238 |
-
ifdef COMPILER
|
| 239 |
-
COMPCXX=$(COMPILER)
|
| 240 |
-
endif
|
| 241 |
-
|
| 242 |
-
### Allow overwriting CXX from command line
|
| 243 |
-
ifdef COMPCXX
|
| 244 |
-
CXX=$(COMPCXX)
|
| 245 |
-
endif
|
| 246 |
-
|
| 247 |
-
### On mingw use Windows threads, otherwise POSIX
|
| 248 |
-
ifneq ($(comp),mingw)
|
| 249 |
-
# On Android Bionic's C library comes with its own pthread implementation bundled in
|
| 250 |
-
ifneq ($(OS),Android)
|
| 251 |
-
# Haiku has pthreads in its libroot, so only link it in on other platforms
|
| 252 |
-
ifneq ($(KERNEL),Haiku)
|
| 253 |
-
LDFLAGS += -lpthread
|
| 254 |
-
endif
|
| 255 |
-
endif
|
| 256 |
-
endif
|
| 257 |
-
|
| 258 |
-
### 3.2.1 Debugging
|
| 259 |
-
ifeq ($(debug),no)
|
| 260 |
-
CXXFLAGS += -DNDEBUG
|
| 261 |
-
else
|
| 262 |
-
CXXFLAGS += -g
|
| 263 |
-
endif
|
| 264 |
-
|
| 265 |
-
### 3.2.2 Debugging with undefined behavior sanitizers
|
| 266 |
-
ifeq ($(sanitize),yes)
|
| 267 |
-
CXXFLAGS += -g3 -fsanitize=undefined
|
| 268 |
-
endif
|
| 269 |
-
|
| 270 |
-
### 3.3 Optimization
|
| 271 |
-
ifeq ($(optimize),yes)
|
| 272 |
-
|
| 273 |
-
CXXFLAGS += -O3
|
| 274 |
-
|
| 275 |
-
ifeq ($(comp),gcc)
|
| 276 |
-
|
| 277 |
-
ifeq ($(KERNEL),Darwin)
|
| 278 |
-
ifeq ($(arch),i386)
|
| 279 |
-
CXXFLAGS += -mdynamic-no-pic
|
| 280 |
-
endif
|
| 281 |
-
ifeq ($(arch),x86_64)
|
| 282 |
-
CXXFLAGS += -mdynamic-no-pic
|
| 283 |
-
endif
|
| 284 |
-
endif
|
| 285 |
-
|
| 286 |
-
ifeq ($(OS), Android)
|
| 287 |
-
CXXFLAGS += -fno-gcse -mthumb -march=armv7-a -mfloat-abi=softfp
|
| 288 |
-
endif
|
| 289 |
-
endif
|
| 290 |
-
|
| 291 |
-
ifeq ($(comp),icc)
|
| 292 |
-
ifeq ($(KERNEL),Darwin)
|
| 293 |
-
CXXFLAGS += -mdynamic-no-pic
|
| 294 |
-
endif
|
| 295 |
-
endif
|
| 296 |
-
|
| 297 |
-
ifeq ($(comp),clang)
|
| 298 |
-
ifeq ($(KERNEL),Darwin)
|
| 299 |
-
ifeq ($(pext),no)
|
| 300 |
-
CXXFLAGS += -flto
|
| 301 |
-
LDFLAGS += $(CXXFLAGS)
|
| 302 |
-
endif
|
| 303 |
-
ifeq ($(arch),i386)
|
| 304 |
-
CXXFLAGS += -mdynamic-no-pic
|
| 305 |
-
endif
|
| 306 |
-
ifeq ($(arch),x86_64)
|
| 307 |
-
CXXFLAGS += -mdynamic-no-pic
|
| 308 |
-
endif
|
| 309 |
-
endif
|
| 310 |
-
endif
|
| 311 |
-
endif
|
| 312 |
-
|
| 313 |
-
### 3.4 Bits
|
| 314 |
-
ifeq ($(bits),64)
|
| 315 |
-
CXXFLAGS += -DIS_64BIT
|
| 316 |
-
endif
|
| 317 |
-
|
| 318 |
-
### 3.5 prefetch
|
| 319 |
-
ifeq ($(prefetch),yes)
|
| 320 |
-
ifeq ($(sse),yes)
|
| 321 |
-
CXXFLAGS += -msse
|
| 322 |
-
DEPENDFLAGS += -msse
|
| 323 |
-
endif
|
| 324 |
-
else
|
| 325 |
-
CXXFLAGS += -DNO_PREFETCH
|
| 326 |
-
endif
|
| 327 |
-
|
| 328 |
-
### 3.6 popcnt
|
| 329 |
-
ifeq ($(popcnt),yes)
|
| 330 |
-
ifeq ($(comp),icc)
|
| 331 |
-
CXXFLAGS += -msse3 -DUSE_POPCNT
|
| 332 |
-
else
|
| 333 |
-
CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT
|
| 334 |
-
endif
|
| 335 |
-
endif
|
| 336 |
-
|
| 337 |
-
### 3.7 pext
|
| 338 |
-
ifeq ($(pext),yes)
|
| 339 |
-
CXXFLAGS += -DUSE_PEXT
|
| 340 |
-
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
|
| 341 |
-
CXXFLAGS += -mbmi2
|
| 342 |
-
endif
|
| 343 |
-
endif
|
| 344 |
-
|
| 345 |
-
### 3.8 Link Time Optimization, it works since gcc 4.5 but not on mingw under Windows.
|
| 346 |
-
### This is a mix of compile and link time options because the lto link phase
|
| 347 |
-
### needs access to the optimization flags.
|
| 348 |
-
ifeq ($(comp),gcc)
|
| 349 |
-
ifeq ($(optimize),yes)
|
| 350 |
-
ifeq ($(debug),no)
|
| 351 |
-
CXXFLAGS += -flto
|
| 352 |
-
LDFLAGS += $(CXXFLAGS)
|
| 353 |
-
endif
|
| 354 |
-
endif
|
| 355 |
-
endif
|
| 356 |
-
|
| 357 |
-
ifeq ($(comp),mingw)
|
| 358 |
-
ifeq ($(KERNEL),Linux)
|
| 359 |
-
ifeq ($(optimize),yes)
|
| 360 |
-
ifeq ($(debug),no)
|
| 361 |
-
CXXFLAGS += -flto
|
| 362 |
-
LDFLAGS += $(CXXFLAGS)
|
| 363 |
-
endif
|
| 364 |
-
endif
|
| 365 |
-
endif
|
| 366 |
-
endif
|
| 367 |
-
|
| 368 |
-
### 3.9 Android 5 can only run position independent executables. Note that this
|
| 369 |
-
### breaks Android 4.0 and earlier.
|
| 370 |
-
ifeq ($(OS), Android)
|
| 371 |
-
CXXFLAGS += -fPIE
|
| 372 |
-
LDFLAGS += -fPIE -pie
|
| 373 |
-
endif
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
### ==========================================================================
|
| 377 |
-
### Section 4. Public targets
|
| 378 |
-
### ==========================================================================
|
| 379 |
-
|
| 380 |
-
help:
|
| 381 |
-
@echo ""
|
| 382 |
-
@echo "To compile stockfish, type: "
|
| 383 |
-
@echo ""
|
| 384 |
-
@echo "make target ARCH=arch [COMP=compiler] [COMPCXX=cxx]"
|
| 385 |
-
@echo ""
|
| 386 |
-
@echo "Supported targets:"
|
| 387 |
-
@echo ""
|
| 388 |
-
@echo "build > Standard build"
|
| 389 |
-
@echo "profile-build > PGO build"
|
| 390 |
-
@echo "strip > Strip executable"
|
| 391 |
-
@echo "install > Install executable"
|
| 392 |
-
@echo "clean > Clean up"
|
| 393 |
-
@echo ""
|
| 394 |
-
@echo "Supported archs:"
|
| 395 |
-
@echo ""
|
| 396 |
-
@echo "x86-64 > x86 64-bit"
|
| 397 |
-
@echo "x86-64-modern > x86 64-bit with popcnt support"
|
| 398 |
-
@echo "x86-64-bmi2 > x86 64-bit with pext support"
|
| 399 |
-
@echo "x86-32 > x86 32-bit with SSE support"
|
| 400 |
-
@echo "x86-32-old > x86 32-bit fall back for old hardware"
|
| 401 |
-
@echo "ppc-64 > PPC 64-bit"
|
| 402 |
-
@echo "ppc-32 > PPC 32-bit"
|
| 403 |
-
@echo "armv7 > ARMv7 32-bit"
|
| 404 |
-
@echo "general-64 > unspecified 64-bit"
|
| 405 |
-
@echo "general-32 > unspecified 32-bit"
|
| 406 |
-
@echo ""
|
| 407 |
-
@echo "Supported compilers:"
|
| 408 |
-
@echo ""
|
| 409 |
-
@echo "gcc > Gnu compiler (default)"
|
| 410 |
-
@echo "mingw > Gnu compiler with MinGW under Windows"
|
| 411 |
-
@echo "clang > LLVM Clang compiler"
|
| 412 |
-
@echo "icc > Intel compiler"
|
| 413 |
-
@echo ""
|
| 414 |
-
@echo "Simple examples. If you don't know what to do, you likely want to run: "
|
| 415 |
-
@echo ""
|
| 416 |
-
@echo "make build ARCH=x86-64 (This is for 64-bit systems)"
|
| 417 |
-
@echo "make build ARCH=x86-32 (This is for 32-bit systems)"
|
| 418 |
-
@echo ""
|
| 419 |
-
@echo "Advanced examples, for experienced users: "
|
| 420 |
-
@echo ""
|
| 421 |
-
@echo "make build ARCH=x86-64 COMP=clang"
|
| 422 |
-
@echo "make profile-build ARCH=x86-64-modern COMP=gcc COMPCXX=g++-4.8"
|
| 423 |
-
@echo ""
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
.PHONY: build profile-build
|
| 427 |
-
build:
|
| 428 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
|
| 429 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
|
| 430 |
-
|
| 431 |
-
profile-build:
|
| 432 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
|
| 433 |
-
@echo ""
|
| 434 |
-
@echo "Step 0/4. Preparing for profile build."
|
| 435 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
|
| 436 |
-
@echo ""
|
| 437 |
-
@echo "Step 1/4. Building executable for benchmark ..."
|
| 438 |
-
@touch *.cpp *.h syzygy/*.cpp syzygy/*.h
|
| 439 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
|
| 440 |
-
@echo ""
|
| 441 |
-
@echo "Step 2/4. Running benchmark for pgo-build ..."
|
| 442 |
-
$(PGOBENCH) > /dev/null
|
| 443 |
-
@echo ""
|
| 444 |
-
@echo "Step 3/4. Building final executable ..."
|
| 445 |
-
@touch *.cpp *.h syzygy/*.cpp syzygy/*.h
|
| 446 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
|
| 447 |
-
@echo ""
|
| 448 |
-
@echo "Step 4/4. Deleting profile data ..."
|
| 449 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean)
|
| 450 |
-
|
| 451 |
-
strip:
|
| 452 |
-
strip $(EXE)
|
| 453 |
-
|
| 454 |
-
install:
|
| 455 |
-
-mkdir -p -m 755 $(BINDIR)
|
| 456 |
-
-cp $(EXE) $(BINDIR)
|
| 457 |
-
-strip $(BINDIR)/$(EXE)
|
| 458 |
-
|
| 459 |
-
clean:
|
| 460 |
-
$(RM) $(EXE) $(EXE).exe *.o .depend *~ core bench.txt *.gcda ./syzygy/*.o ./syzygy/*.gcda
|
| 461 |
-
|
| 462 |
-
default:
|
| 463 |
-
help
|
| 464 |
-
|
| 465 |
-
### ==========================================================================
|
| 466 |
-
### Section 5. Private targets
|
| 467 |
-
### ==========================================================================
|
| 468 |
-
|
| 469 |
-
all: $(EXE) .depend
|
| 470 |
-
|
| 471 |
-
config-sanity:
|
| 472 |
-
@echo ""
|
| 473 |
-
@echo "Config:"
|
| 474 |
-
@echo "debug: '$(debug)'"
|
| 475 |
-
@echo "optimize: '$(optimize)'"
|
| 476 |
-
@echo "arch: '$(arch)'"
|
| 477 |
-
@echo "bits: '$(bits)'"
|
| 478 |
-
@echo "kernel: '$(KERNEL)'"
|
| 479 |
-
@echo "os: '$(OS)'"
|
| 480 |
-
@echo "prefetch: '$(prefetch)'"
|
| 481 |
-
@echo "popcnt: '$(popcnt)'"
|
| 482 |
-
@echo "sse: '$(sse)'"
|
| 483 |
-
@echo "pext: '$(pext)'"
|
| 484 |
-
@echo ""
|
| 485 |
-
@echo "Flags:"
|
| 486 |
-
@echo "CXX: $(CXX)"
|
| 487 |
-
@echo "CXXFLAGS: $(CXXFLAGS)"
|
| 488 |
-
@echo "LDFLAGS: $(LDFLAGS)"
|
| 489 |
-
@echo ""
|
| 490 |
-
@echo "Testing config sanity. If this fails, try 'make help' ..."
|
| 491 |
-
@echo ""
|
| 492 |
-
@test "$(debug)" = "yes" || test "$(debug)" = "no"
|
| 493 |
-
@test "$(optimize)" = "yes" || test "$(optimize)" = "no"
|
| 494 |
-
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
|
| 495 |
-
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7"
|
| 496 |
-
@test "$(bits)" = "32" || test "$(bits)" = "64"
|
| 497 |
-
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
|
| 498 |
-
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
|
| 499 |
-
@test "$(sse)" = "yes" || test "$(sse)" = "no"
|
| 500 |
-
@test "$(pext)" = "yes" || test "$(pext)" = "no"
|
| 501 |
-
@test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw" || test "$(comp)" = "clang"
|
| 502 |
-
|
| 503 |
-
$(EXE): $(OBJS)
|
| 504 |
-
$(CXX) -o $@ $(OBJS) $(LDFLAGS)
|
| 505 |
-
|
| 506 |
-
gcc-profile-prepare:
|
| 507 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) gcc-profile-clean
|
| 508 |
-
|
| 509 |
-
gcc-profile-make:
|
| 510 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 511 |
-
EXTRACXXFLAGS='-fprofile-generate' \
|
| 512 |
-
EXTRALDFLAGS='-lgcov' \
|
| 513 |
-
all
|
| 514 |
-
|
| 515 |
-
gcc-profile-use:
|
| 516 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 517 |
-
EXTRACXXFLAGS='-fprofile-use -fno-peel-loops -fno-tracer' \
|
| 518 |
-
EXTRALDFLAGS='-lgcov' \
|
| 519 |
-
all
|
| 520 |
-
|
| 521 |
-
gcc-profile-clean:
|
| 522 |
-
@rm -rf *.gcda *.gcno syzygy/*.gcda syzygy/*.gcno bench.txt
|
| 523 |
-
|
| 524 |
-
icc-profile-prepare:
|
| 525 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) icc-profile-clean
|
| 526 |
-
@mkdir profdir
|
| 527 |
-
|
| 528 |
-
icc-profile-make:
|
| 529 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 530 |
-
EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \
|
| 531 |
-
all
|
| 532 |
-
|
| 533 |
-
icc-profile-use:
|
| 534 |
-
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 535 |
-
EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \
|
| 536 |
-
all
|
| 537 |
-
|
| 538 |
-
icc-profile-clean:
|
| 539 |
-
@rm -rf profdir bench.txt
|
| 540 |
-
|
| 541 |
-
.depend:
|
| 542 |
-
-@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null
|
| 543 |
-
|
| 544 |
-
-include .depend
|
| 545 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/benchmark.cpp
DELETED
|
@@ -1,183 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <fstream>
|
| 22 |
-
#include <iostream>
|
| 23 |
-
#include <istream>
|
| 24 |
-
#include <vector>
|
| 25 |
-
|
| 26 |
-
#include "misc.h"
|
| 27 |
-
#include "position.h"
|
| 28 |
-
#include "search.h"
|
| 29 |
-
#include "thread.h"
|
| 30 |
-
#include "uci.h"
|
| 31 |
-
|
| 32 |
-
using namespace std;
|
| 33 |
-
|
| 34 |
-
namespace {
|
| 35 |
-
|
| 36 |
-
const vector<string> Defaults = {
|
| 37 |
-
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
| 38 |
-
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10",
|
| 39 |
-
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11",
|
| 40 |
-
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
|
| 41 |
-
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14",
|
| 42 |
-
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14",
|
| 43 |
-
"r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15",
|
| 44 |
-
"r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13",
|
| 45 |
-
"r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16",
|
| 46 |
-
"4r1k1/r1q2ppp/ppp2n2/4P3/5Rb1/1N1BQ3/PPP3PP/R5K1 w - - 1 17",
|
| 47 |
-
"2rqkb1r/ppp2p2/2npb1p1/1N1Nn2p/2P1PP2/8/PP2B1PP/R1BQK2R b KQ - 0 11",
|
| 48 |
-
"r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16",
|
| 49 |
-
"3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22",
|
| 50 |
-
"r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18",
|
| 51 |
-
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22",
|
| 52 |
-
"3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26",
|
| 53 |
-
"6k1/6p1/6Pp/ppp5/3pn2P/1P3K2/1PP2P2/3N4 b - - 0 1",
|
| 54 |
-
"3b4/5kp1/1p1p1p1p/pP1PpP1P/P1P1P3/3KN3/8/8 w - - 0 1",
|
| 55 |
-
"2K5/p7/7P/5pR1/8/5k2/r7/8 w - - 0 1",
|
| 56 |
-
"8/6pk/1p6/8/PP3p1p/5P2/4KP1q/3Q4 w - - 0 1",
|
| 57 |
-
"7k/3p2pp/4q3/8/4Q3/5Kp1/P6b/8 w - - 0 1",
|
| 58 |
-
"8/2p5/8/2kPKp1p/2p4P/2P5/3P4/8 w - - 0 1",
|
| 59 |
-
"8/1p3pp1/7p/5P1P/2k3P1/8/2K2P2/8 w - - 0 1",
|
| 60 |
-
"8/pp2r1k1/2p1p3/3pP2p/1P1P1P1P/P5KR/8/8 w - - 0 1",
|
| 61 |
-
"8/3p4/p1bk3p/Pp6/1Kp1PpPp/2P2P1P/2P5/5B2 b - - 0 1",
|
| 62 |
-
"5k2/7R/4P2p/5K2/p1r2P1p/8/8/8 b - - 0 1",
|
| 63 |
-
"6k1/6p1/P6p/r1N5/5p2/7P/1b3PP1/4R1K1 w - - 0 1",
|
| 64 |
-
"1r3k2/4q3/2Pp3b/3Bp3/2Q2p2/1p1P2P1/1P2KP2/3N4 w - - 0 1",
|
| 65 |
-
"6k1/4pp1p/3p2p1/P1pPb3/R7/1r2P1PP/3B1P2/6K1 w - - 0 1",
|
| 66 |
-
"8/3p3B/5p2/5P2/p7/PP5b/k7/6K1 w - - 0 1",
|
| 67 |
-
|
| 68 |
-
// 5-man positions
|
| 69 |
-
"8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate
|
| 70 |
-
"8/8/8/5N2/8/p7/8/2NK3k w - - 0 1", // Na2 - mate
|
| 71 |
-
"8/3k4/8/8/8/4B3/4KB2/2B5 w - - 0 1", // draw
|
| 72 |
-
|
| 73 |
-
// 6-man positions
|
| 74 |
-
"8/8/1P6/5pr1/8/4R3/7k/2K5 w - - 0 1", // Re5 - mate
|
| 75 |
-
"8/2p4P/8/kr6/6R1/8/8/1K6 w - - 0 1", // Ka2 - mate
|
| 76 |
-
"8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1", // Nd2 - draw
|
| 77 |
-
|
| 78 |
-
// 7-man positions
|
| 79 |
-
"8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124", // Draw
|
| 80 |
-
|
| 81 |
-
// Mate and stalemate positions
|
| 82 |
-
"8/8/8/8/8/6k1/6p1/6K1 w - -",
|
| 83 |
-
"5k2/5P2/5K2/8/8/8/8/8 b - -",
|
| 84 |
-
"8/8/8/8/8/4k3/4p3/4K3 w - -",
|
| 85 |
-
"8/8/8/8/8/5K2/8/3Q1k2 b - -",
|
| 86 |
-
"7k/7P/6K1/8/3B4/8/8/8 b - -"
|
| 87 |
-
};
|
| 88 |
-
|
| 89 |
-
} // namespace
|
| 90 |
-
|
| 91 |
-
/// benchmark() runs a simple benchmark by letting Stockfish analyze a set
|
| 92 |
-
/// of positions for a given limit each. There are five parameters: the
|
| 93 |
-
/// transposition table size, the number of search threads that should
|
| 94 |
-
/// be used, the limit value spent for each position (optional, default is
|
| 95 |
-
/// depth 13), an optional file name where to look for positions in FEN
|
| 96 |
-
/// format (defaults are the positions defined above) and the type of the
|
| 97 |
-
/// limit value: depth (default), time in millisecs or number of nodes.
|
| 98 |
-
|
| 99 |
-
void benchmark(const Position& current, istream& is) {
|
| 100 |
-
|
| 101 |
-
string token;
|
| 102 |
-
vector<string> fens;
|
| 103 |
-
Search::LimitsType limits;
|
| 104 |
-
|
| 105 |
-
// Assign default values to missing arguments
|
| 106 |
-
string ttSize = (is >> token) ? token : "16";
|
| 107 |
-
string threads = (is >> token) ? token : "1";
|
| 108 |
-
string limit = (is >> token) ? token : "13";
|
| 109 |
-
string fenFile = (is >> token) ? token : "default";
|
| 110 |
-
string limitType = (is >> token) ? token : "depth";
|
| 111 |
-
|
| 112 |
-
Options["Hash"] = ttSize;
|
| 113 |
-
Options["Threads"] = threads;
|
| 114 |
-
Search::clear();
|
| 115 |
-
|
| 116 |
-
if (limitType == "time")
|
| 117 |
-
limits.movetime = stoi(limit); // movetime is in millisecs
|
| 118 |
-
|
| 119 |
-
else if (limitType == "nodes")
|
| 120 |
-
limits.nodes = stoi(limit);
|
| 121 |
-
|
| 122 |
-
else if (limitType == "mate")
|
| 123 |
-
limits.mate = stoi(limit);
|
| 124 |
-
|
| 125 |
-
else
|
| 126 |
-
limits.depth = stoi(limit);
|
| 127 |
-
|
| 128 |
-
if (fenFile == "default")
|
| 129 |
-
fens = Defaults;
|
| 130 |
-
|
| 131 |
-
else if (fenFile == "current")
|
| 132 |
-
fens.push_back(current.fen());
|
| 133 |
-
|
| 134 |
-
else
|
| 135 |
-
{
|
| 136 |
-
string fen;
|
| 137 |
-
ifstream file(fenFile);
|
| 138 |
-
|
| 139 |
-
if (!file.is_open())
|
| 140 |
-
{
|
| 141 |
-
cerr << "Unable to open file " << fenFile << endl;
|
| 142 |
-
return;
|
| 143 |
-
}
|
| 144 |
-
|
| 145 |
-
while (getline(file, fen))
|
| 146 |
-
if (!fen.empty())
|
| 147 |
-
fens.push_back(fen);
|
| 148 |
-
|
| 149 |
-
file.close();
|
| 150 |
-
}
|
| 151 |
-
|
| 152 |
-
uint64_t nodes = 0;
|
| 153 |
-
TimePoint elapsed = now();
|
| 154 |
-
Position pos;
|
| 155 |
-
|
| 156 |
-
for (size_t i = 0; i < fens.size(); ++i)
|
| 157 |
-
{
|
| 158 |
-
StateListPtr states(new std::deque<StateInfo>(1));
|
| 159 |
-
pos.set(fens[i], Options["UCI_Chess960"], &states->back(), Threads.main());
|
| 160 |
-
|
| 161 |
-
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
|
| 162 |
-
|
| 163 |
-
if (limitType == "perft")
|
| 164 |
-
nodes += Search::perft(pos, limits.depth * ONE_PLY);
|
| 165 |
-
|
| 166 |
-
else
|
| 167 |
-
{
|
| 168 |
-
limits.startTime = now();
|
| 169 |
-
Threads.start_thinking(pos, states, limits);
|
| 170 |
-
Threads.main()->wait_for_search_finished();
|
| 171 |
-
nodes += Threads.nodes_searched();
|
| 172 |
-
}
|
| 173 |
-
}
|
| 174 |
-
|
| 175 |
-
elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
|
| 176 |
-
|
| 177 |
-
dbg_print(); // Just before exiting
|
| 178 |
-
|
| 179 |
-
cerr << "\n==========================="
|
| 180 |
-
<< "\nTotal time (ms) : " << elapsed
|
| 181 |
-
<< "\nNodes searched : " << nodes
|
| 182 |
-
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl;
|
| 183 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/bitbase.cpp
DELETED
|
@@ -1,180 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm>
|
| 22 |
-
#include <cassert>
|
| 23 |
-
#include <numeric>
|
| 24 |
-
#include <vector>
|
| 25 |
-
|
| 26 |
-
#include "bitboard.h"
|
| 27 |
-
#include "types.h"
|
| 28 |
-
|
| 29 |
-
namespace {
|
| 30 |
-
|
| 31 |
-
// There are 24 possible pawn squares: the first 4 files and ranks from 2 to 7
|
| 32 |
-
const unsigned MAX_INDEX = 2*24*64*64; // stm * psq * wksq * bksq = 196608
|
| 33 |
-
|
| 34 |
-
// Each uint32_t stores results of 32 positions, one per bit
|
| 35 |
-
uint32_t KPKBitbase[MAX_INDEX / 32];
|
| 36 |
-
|
| 37 |
-
// A KPK bitbase index is an integer in [0, IndexMax] range
|
| 38 |
-
//
|
| 39 |
-
// Information is mapped in a way that minimizes the number of iterations:
|
| 40 |
-
//
|
| 41 |
-
// bit 0- 5: white king square (from SQ_A1 to SQ_H8)
|
| 42 |
-
// bit 6-11: black king square (from SQ_A1 to SQ_H8)
|
| 43 |
-
// bit 12: side to move (WHITE or BLACK)
|
| 44 |
-
// bit 13-14: white pawn file (from FILE_A to FILE_D)
|
| 45 |
-
// bit 15-17: white pawn RANK_7 - rank (from RANK_7 - RANK_7 to RANK_7 - RANK_2)
|
| 46 |
-
unsigned index(Color us, Square bksq, Square wksq, Square psq) {
|
| 47 |
-
return wksq | (bksq << 6) | (us << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15);
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
enum Result {
|
| 51 |
-
INVALID = 0,
|
| 52 |
-
UNKNOWN = 1,
|
| 53 |
-
DRAW = 2,
|
| 54 |
-
WIN = 4
|
| 55 |
-
};
|
| 56 |
-
|
| 57 |
-
Result& operator|=(Result& r, Result v) { return r = Result(r | v); }
|
| 58 |
-
|
| 59 |
-
struct KPKPosition {
|
| 60 |
-
KPKPosition() = default;
|
| 61 |
-
explicit KPKPosition(unsigned idx);
|
| 62 |
-
operator Result() const { return result; }
|
| 63 |
-
Result classify(const std::vector<KPKPosition>& db)
|
| 64 |
-
{ return us == WHITE ? classify<WHITE>(db) : classify<BLACK>(db); }
|
| 65 |
-
|
| 66 |
-
template<Color Us> Result classify(const std::vector<KPKPosition>& db);
|
| 67 |
-
|
| 68 |
-
Color us;
|
| 69 |
-
Square ksq[COLOR_NB], psq;
|
| 70 |
-
Result result;
|
| 71 |
-
};
|
| 72 |
-
|
| 73 |
-
} // namespace
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color us) {
|
| 77 |
-
|
| 78 |
-
assert(file_of(wpsq) <= FILE_D);
|
| 79 |
-
|
| 80 |
-
unsigned idx = index(us, bksq, wksq, wpsq);
|
| 81 |
-
return KPKBitbase[idx / 32] & (1 << (idx & 0x1F));
|
| 82 |
-
}
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
void Bitbases::init() {
|
| 86 |
-
|
| 87 |
-
std::vector<KPKPosition> db(MAX_INDEX);
|
| 88 |
-
unsigned idx, repeat = 1;
|
| 89 |
-
|
| 90 |
-
// Initialize db with known win / draw positions
|
| 91 |
-
for (idx = 0; idx < MAX_INDEX; ++idx)
|
| 92 |
-
db[idx] = KPKPosition(idx);
|
| 93 |
-
|
| 94 |
-
// Iterate through the positions until none of the unknown positions can be
|
| 95 |
-
// changed to either wins or draws (15 cycles needed).
|
| 96 |
-
while (repeat)
|
| 97 |
-
for (repeat = idx = 0; idx < MAX_INDEX; ++idx)
|
| 98 |
-
repeat |= (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN);
|
| 99 |
-
|
| 100 |
-
// Map 32 results into one KPKBitbase[] entry
|
| 101 |
-
for (idx = 0; idx < MAX_INDEX; ++idx)
|
| 102 |
-
if (db[idx] == WIN)
|
| 103 |
-
KPKBitbase[idx / 32] |= 1 << (idx & 0x1F);
|
| 104 |
-
}
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
namespace {
|
| 108 |
-
|
| 109 |
-
KPKPosition::KPKPosition(unsigned idx) {
|
| 110 |
-
|
| 111 |
-
ksq[WHITE] = Square((idx >> 0) & 0x3F);
|
| 112 |
-
ksq[BLACK] = Square((idx >> 6) & 0x3F);
|
| 113 |
-
us = Color ((idx >> 12) & 0x01);
|
| 114 |
-
psq = make_square(File((idx >> 13) & 0x3), RANK_7 - Rank((idx >> 15) & 0x7));
|
| 115 |
-
|
| 116 |
-
// Check if two pieces are on the same square or if a king can be captured
|
| 117 |
-
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
|
| 118 |
-
|| ksq[WHITE] == psq
|
| 119 |
-
|| ksq[BLACK] == psq
|
| 120 |
-
|| (us == WHITE && (StepAttacksBB[PAWN][psq] & ksq[BLACK])))
|
| 121 |
-
result = INVALID;
|
| 122 |
-
|
| 123 |
-
// Immediate win if a pawn can be promoted without getting captured
|
| 124 |
-
else if ( us == WHITE
|
| 125 |
-
&& rank_of(psq) == RANK_7
|
| 126 |
-
&& ksq[us] != psq + NORTH
|
| 127 |
-
&& ( distance(ksq[~us], psq + NORTH) > 1
|
| 128 |
-
|| (StepAttacksBB[KING][ksq[us]] & (psq + NORTH))))
|
| 129 |
-
result = WIN;
|
| 130 |
-
|
| 131 |
-
// Immediate draw if it is a stalemate or a king captures undefended pawn
|
| 132 |
-
else if ( us == BLACK
|
| 133 |
-
&& ( !(StepAttacksBB[KING][ksq[us]] & ~(StepAttacksBB[KING][ksq[~us]] | StepAttacksBB[PAWN][psq]))
|
| 134 |
-
|| (StepAttacksBB[KING][ksq[us]] & psq & ~StepAttacksBB[KING][ksq[~us]])))
|
| 135 |
-
result = DRAW;
|
| 136 |
-
|
| 137 |
-
// Position will be classified later
|
| 138 |
-
else
|
| 139 |
-
result = UNKNOWN;
|
| 140 |
-
}
|
| 141 |
-
|
| 142 |
-
template<Color Us>
|
| 143 |
-
Result KPKPosition::classify(const std::vector<KPKPosition>& db) {
|
| 144 |
-
|
| 145 |
-
// White to move: If one move leads to a position classified as WIN, the result
|
| 146 |
-
// of the current position is WIN. If all moves lead to positions classified
|
| 147 |
-
// as DRAW, the current position is classified as DRAW, otherwise the current
|
| 148 |
-
// position is classified as UNKNOWN.
|
| 149 |
-
//
|
| 150 |
-
// Black to move: If one move leads to a position classified as DRAW, the result
|
| 151 |
-
// of the current position is DRAW. If all moves lead to positions classified
|
| 152 |
-
// as WIN, the position is classified as WIN, otherwise the current position is
|
| 153 |
-
// classified as UNKNOWN.
|
| 154 |
-
|
| 155 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 156 |
-
const Result Good = (Us == WHITE ? WIN : DRAW);
|
| 157 |
-
const Result Bad = (Us == WHITE ? DRAW : WIN);
|
| 158 |
-
|
| 159 |
-
Result r = INVALID;
|
| 160 |
-
Bitboard b = StepAttacksBB[KING][ksq[Us]];
|
| 161 |
-
|
| 162 |
-
while (b)
|
| 163 |
-
r |= Us == WHITE ? db[index(Them, ksq[Them] , pop_lsb(&b), psq)]
|
| 164 |
-
: db[index(Them, pop_lsb(&b), ksq[Them] , psq)];
|
| 165 |
-
|
| 166 |
-
if (Us == WHITE)
|
| 167 |
-
{
|
| 168 |
-
if (rank_of(psq) < RANK_7) // Single push
|
| 169 |
-
r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH)];
|
| 170 |
-
|
| 171 |
-
if ( rank_of(psq) == RANK_2 // Double push
|
| 172 |
-
&& psq + NORTH != ksq[Us]
|
| 173 |
-
&& psq + NORTH != ksq[Them])
|
| 174 |
-
r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH + NORTH)];
|
| 175 |
-
}
|
| 176 |
-
|
| 177 |
-
return result = r & Good ? Good : r & UNKNOWN ? UNKNOWN : Bad;
|
| 178 |
-
}
|
| 179 |
-
|
| 180 |
-
} // namespace
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/bitboard.cpp
DELETED
|
@@ -1,333 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm>
|
| 22 |
-
|
| 23 |
-
#include "bitboard.h"
|
| 24 |
-
#include "misc.h"
|
| 25 |
-
|
| 26 |
-
uint8_t PopCnt16[1 << 16];
|
| 27 |
-
int SquareDistance[SQUARE_NB][SQUARE_NB];
|
| 28 |
-
|
| 29 |
-
Bitboard RookMasks [SQUARE_NB];
|
| 30 |
-
Bitboard RookMagics [SQUARE_NB];
|
| 31 |
-
Bitboard* RookAttacks[SQUARE_NB];
|
| 32 |
-
unsigned RookShifts [SQUARE_NB];
|
| 33 |
-
|
| 34 |
-
Bitboard BishopMasks [SQUARE_NB];
|
| 35 |
-
Bitboard BishopMagics [SQUARE_NB];
|
| 36 |
-
Bitboard* BishopAttacks[SQUARE_NB];
|
| 37 |
-
unsigned BishopShifts [SQUARE_NB];
|
| 38 |
-
|
| 39 |
-
Bitboard SquareBB[SQUARE_NB];
|
| 40 |
-
Bitboard FileBB[FILE_NB];
|
| 41 |
-
Bitboard RankBB[RANK_NB];
|
| 42 |
-
Bitboard AdjacentFilesBB[FILE_NB];
|
| 43 |
-
Bitboard InFrontBB[COLOR_NB][RANK_NB];
|
| 44 |
-
Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB];
|
| 45 |
-
Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
| 46 |
-
Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
| 47 |
-
Bitboard DistanceRingBB[SQUARE_NB][8];
|
| 48 |
-
Bitboard ForwardBB[COLOR_NB][SQUARE_NB];
|
| 49 |
-
Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB];
|
| 50 |
-
Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
|
| 51 |
-
Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
|
| 52 |
-
|
| 53 |
-
namespace {
|
| 54 |
-
|
| 55 |
-
// De Bruijn sequences. See chessprogramming.wikispaces.com/BitScan
|
| 56 |
-
const uint64_t DeBruijn64 = 0x3F79D71B4CB0A89ULL;
|
| 57 |
-
const uint32_t DeBruijn32 = 0x783A9B23;
|
| 58 |
-
|
| 59 |
-
int MSBTable[256]; // To implement software msb()
|
| 60 |
-
Square BSFTable[SQUARE_NB]; // To implement software bitscan
|
| 61 |
-
Bitboard RookTable[0x19000]; // To store rook attacks
|
| 62 |
-
Bitboard BishopTable[0x1480]; // To store bishop attacks
|
| 63 |
-
|
| 64 |
-
typedef unsigned (Fn)(Square, Bitboard);
|
| 65 |
-
|
| 66 |
-
void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[],
|
| 67 |
-
Bitboard masks[], unsigned shifts[], Square deltas[], Fn index);
|
| 68 |
-
|
| 69 |
-
// bsf_index() returns the index into BSFTable[] to look up the bitscan. Uses
|
| 70 |
-
// Matt Taylor's folding for 32 bit case, extended to 64 bit by Kim Walisch.
|
| 71 |
-
|
| 72 |
-
unsigned bsf_index(Bitboard b) {
|
| 73 |
-
b ^= b - 1;
|
| 74 |
-
return Is64Bit ? (b * DeBruijn64) >> 58
|
| 75 |
-
: ((unsigned(b) ^ unsigned(b >> 32)) * DeBruijn32) >> 26;
|
| 76 |
-
}
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
// popcount16() counts the non-zero bits using SWAR-Popcount algorithm
|
| 80 |
-
|
| 81 |
-
unsigned popcount16(unsigned u) {
|
| 82 |
-
u -= (u >> 1) & 0x5555U;
|
| 83 |
-
u = ((u >> 2) & 0x3333U) + (u & 0x3333U);
|
| 84 |
-
u = ((u >> 4) + u) & 0x0F0FU;
|
| 85 |
-
return (u * 0x0101U) >> 8;
|
| 86 |
-
}
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
#ifdef NO_BSF
|
| 90 |
-
|
| 91 |
-
/// Software fall-back of lsb() and msb() for CPU lacking hardware support
|
| 92 |
-
|
| 93 |
-
Square lsb(Bitboard b) {
|
| 94 |
-
assert(b);
|
| 95 |
-
return BSFTable[bsf_index(b)];
|
| 96 |
-
}
|
| 97 |
-
|
| 98 |
-
Square msb(Bitboard b) {
|
| 99 |
-
|
| 100 |
-
assert(b);
|
| 101 |
-
unsigned b32;
|
| 102 |
-
int result = 0;
|
| 103 |
-
|
| 104 |
-
if (b > 0xFFFFFFFF)
|
| 105 |
-
{
|
| 106 |
-
b >>= 32;
|
| 107 |
-
result = 32;
|
| 108 |
-
}
|
| 109 |
-
|
| 110 |
-
b32 = unsigned(b);
|
| 111 |
-
|
| 112 |
-
if (b32 > 0xFFFF)
|
| 113 |
-
{
|
| 114 |
-
b32 >>= 16;
|
| 115 |
-
result += 16;
|
| 116 |
-
}
|
| 117 |
-
|
| 118 |
-
if (b32 > 0xFF)
|
| 119 |
-
{
|
| 120 |
-
b32 >>= 8;
|
| 121 |
-
result += 8;
|
| 122 |
-
}
|
| 123 |
-
|
| 124 |
-
return Square(result + MSBTable[b32]);
|
| 125 |
-
}
|
| 126 |
-
|
| 127 |
-
#endif // ifdef NO_BSF
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
/// Bitboards::pretty() returns an ASCII representation of a bitboard suitable
|
| 131 |
-
/// to be printed to standard output. Useful for debugging.
|
| 132 |
-
|
| 133 |
-
const std::string Bitboards::pretty(Bitboard b) {
|
| 134 |
-
|
| 135 |
-
std::string s = "+---+---+---+---+---+---+---+---+\n";
|
| 136 |
-
|
| 137 |
-
for (Rank r = RANK_8; r >= RANK_1; --r)
|
| 138 |
-
{
|
| 139 |
-
for (File f = FILE_A; f <= FILE_H; ++f)
|
| 140 |
-
s += b & make_square(f, r) ? "| X " : "| ";
|
| 141 |
-
|
| 142 |
-
s += "|\n+---+---+---+---+---+---+---+---+\n";
|
| 143 |
-
}
|
| 144 |
-
|
| 145 |
-
return s;
|
| 146 |
-
}
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
/// Bitboards::init() initializes various bitboard tables. It is called at
|
| 150 |
-
/// startup and relies on global objects to be already zero-initialized.
|
| 151 |
-
|
| 152 |
-
void Bitboards::init() {
|
| 153 |
-
|
| 154 |
-
for (unsigned i = 0; i < (1 << 16); ++i)
|
| 155 |
-
PopCnt16[i] = (uint8_t) popcount16(i);
|
| 156 |
-
|
| 157 |
-
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
| 158 |
-
{
|
| 159 |
-
SquareBB[s] = 1ULL << s;
|
| 160 |
-
BSFTable[bsf_index(SquareBB[s])] = s;
|
| 161 |
-
}
|
| 162 |
-
|
| 163 |
-
for (Bitboard b = 2; b < 256; ++b)
|
| 164 |
-
MSBTable[b] = MSBTable[b - 1] + !more_than_one(b);
|
| 165 |
-
|
| 166 |
-
for (File f = FILE_A; f <= FILE_H; ++f)
|
| 167 |
-
FileBB[f] = f > FILE_A ? FileBB[f - 1] << 1 : FileABB;
|
| 168 |
-
|
| 169 |
-
for (Rank r = RANK_1; r <= RANK_8; ++r)
|
| 170 |
-
RankBB[r] = r > RANK_1 ? RankBB[r - 1] << 8 : Rank1BB;
|
| 171 |
-
|
| 172 |
-
for (File f = FILE_A; f <= FILE_H; ++f)
|
| 173 |
-
AdjacentFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_H ? FileBB[f + 1] : 0);
|
| 174 |
-
|
| 175 |
-
for (Rank r = RANK_1; r < RANK_8; ++r)
|
| 176 |
-
InFrontBB[WHITE][r] = ~(InFrontBB[BLACK][r + 1] = InFrontBB[BLACK][r] | RankBB[r]);
|
| 177 |
-
|
| 178 |
-
for (Color c = WHITE; c <= BLACK; ++c)
|
| 179 |
-
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
| 180 |
-
{
|
| 181 |
-
ForwardBB[c][s] = InFrontBB[c][rank_of(s)] & FileBB[file_of(s)];
|
| 182 |
-
PawnAttackSpan[c][s] = InFrontBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)];
|
| 183 |
-
PassedPawnMask[c][s] = ForwardBB[c][s] | PawnAttackSpan[c][s];
|
| 184 |
-
}
|
| 185 |
-
|
| 186 |
-
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
| 187 |
-
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
|
| 188 |
-
if (s1 != s2)
|
| 189 |
-
{
|
| 190 |
-
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
|
| 191 |
-
DistanceRingBB[s1][SquareDistance[s1][s2] - 1] |= s2;
|
| 192 |
-
}
|
| 193 |
-
|
| 194 |
-
int steps[][9] = { {}, { 7, 9 }, { 17, 15, 10, 6, -6, -10, -15, -17 },
|
| 195 |
-
{}, {}, {}, { 9, 7, -7, -9, 8, 1, -1, -8 } };
|
| 196 |
-
|
| 197 |
-
for (Color c = WHITE; c <= BLACK; ++c)
|
| 198 |
-
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
| 199 |
-
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
| 200 |
-
for (int i = 0; steps[pt][i]; ++i)
|
| 201 |
-
{
|
| 202 |
-
Square to = s + Square(c == WHITE ? steps[pt][i] : -steps[pt][i]);
|
| 203 |
-
|
| 204 |
-
if (is_ok(to) && distance(s, to) < 3)
|
| 205 |
-
StepAttacksBB[make_piece(c, pt)][s] |= to;
|
| 206 |
-
}
|
| 207 |
-
|
| 208 |
-
Square RookDeltas[] = { NORTH, EAST, SOUTH, WEST };
|
| 209 |
-
Square BishopDeltas[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
|
| 210 |
-
|
| 211 |
-
init_magics(RookTable, RookAttacks, RookMagics, RookMasks, RookShifts, RookDeltas, magic_index<ROOK>);
|
| 212 |
-
init_magics(BishopTable, BishopAttacks, BishopMagics, BishopMasks, BishopShifts, BishopDeltas, magic_index<BISHOP>);
|
| 213 |
-
|
| 214 |
-
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
| 215 |
-
{
|
| 216 |
-
PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0);
|
| 217 |
-
PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0);
|
| 218 |
-
|
| 219 |
-
for (Piece pc = W_BISHOP; pc <= W_ROOK; ++pc)
|
| 220 |
-
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
|
| 221 |
-
{
|
| 222 |
-
if (!(PseudoAttacks[pc][s1] & s2))
|
| 223 |
-
continue;
|
| 224 |
-
|
| 225 |
-
LineBB[s1][s2] = (attacks_bb(pc, s1, 0) & attacks_bb(pc, s2, 0)) | s1 | s2;
|
| 226 |
-
BetweenBB[s1][s2] = attacks_bb(pc, s1, SquareBB[s2]) & attacks_bb(pc, s2, SquareBB[s1]);
|
| 227 |
-
}
|
| 228 |
-
}
|
| 229 |
-
}
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
namespace {
|
| 233 |
-
|
| 234 |
-
Bitboard sliding_attack(Square deltas[], Square sq, Bitboard occupied) {
|
| 235 |
-
|
| 236 |
-
Bitboard attack = 0;
|
| 237 |
-
|
| 238 |
-
for (int i = 0; i < 4; ++i)
|
| 239 |
-
for (Square s = sq + deltas[i];
|
| 240 |
-
is_ok(s) && distance(s, s - deltas[i]) == 1;
|
| 241 |
-
s += deltas[i])
|
| 242 |
-
{
|
| 243 |
-
attack |= s;
|
| 244 |
-
|
| 245 |
-
if (occupied & s)
|
| 246 |
-
break;
|
| 247 |
-
}
|
| 248 |
-
|
| 249 |
-
return attack;
|
| 250 |
-
}
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
// init_magics() computes all rook and bishop attacks at startup. Magic
|
| 254 |
-
// bitboards are used to look up attacks of sliding pieces. As a reference see
|
| 255 |
-
// chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
|
| 256 |
-
// use the so called "fancy" approach.
|
| 257 |
-
|
| 258 |
-
void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[],
|
| 259 |
-
Bitboard masks[], unsigned shifts[], Square deltas[], Fn index) {
|
| 260 |
-
|
| 261 |
-
int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 },
|
| 262 |
-
{ 728, 10316, 55013, 32803, 12281, 15100, 16645, 255 } };
|
| 263 |
-
|
| 264 |
-
Bitboard occupancy[4096], reference[4096], edges, b;
|
| 265 |
-
int age[4096] = {0}, current = 0, i, size;
|
| 266 |
-
|
| 267 |
-
// attacks[s] is a pointer to the beginning of the attacks table for square 's'
|
| 268 |
-
attacks[SQ_A1] = table;
|
| 269 |
-
|
| 270 |
-
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
| 271 |
-
{
|
| 272 |
-
// Board edges are not considered in the relevant occupancies
|
| 273 |
-
edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s));
|
| 274 |
-
|
| 275 |
-
// Given a square 's', the mask is the bitboard of sliding attacks from
|
| 276 |
-
// 's' computed on an empty board. The index must be big enough to contain
|
| 277 |
-
// all the attacks for each possible subset of the mask and so is 2 power
|
| 278 |
-
// the number of 1s of the mask. Hence we deduce the size of the shift to
|
| 279 |
-
// apply to the 64 or 32 bits word to get the index.
|
| 280 |
-
masks[s] = sliding_attack(deltas, s, 0) & ~edges;
|
| 281 |
-
shifts[s] = (Is64Bit ? 64 : 32) - popcount(masks[s]);
|
| 282 |
-
|
| 283 |
-
// Use Carry-Rippler trick to enumerate all subsets of masks[s] and
|
| 284 |
-
// store the corresponding sliding attack bitboard in reference[].
|
| 285 |
-
b = size = 0;
|
| 286 |
-
do {
|
| 287 |
-
occupancy[size] = b;
|
| 288 |
-
reference[size] = sliding_attack(deltas, s, b);
|
| 289 |
-
|
| 290 |
-
if (HasPext)
|
| 291 |
-
attacks[s][pext(b, masks[s])] = reference[size];
|
| 292 |
-
|
| 293 |
-
size++;
|
| 294 |
-
b = (b - masks[s]) & masks[s];
|
| 295 |
-
} while (b);
|
| 296 |
-
|
| 297 |
-
// Set the offset for the table of the next square. We have individual
|
| 298 |
-
// table sizes for each square with "Fancy Magic Bitboards".
|
| 299 |
-
if (s < SQ_H8)
|
| 300 |
-
attacks[s + 1] = attacks[s] + size;
|
| 301 |
-
|
| 302 |
-
if (HasPext)
|
| 303 |
-
continue;
|
| 304 |
-
|
| 305 |
-
PRNG rng(seeds[Is64Bit][rank_of(s)]);
|
| 306 |
-
|
| 307 |
-
// Find a magic for square 's' picking up an (almost) random number
|
| 308 |
-
// until we find the one that passes the verification test.
|
| 309 |
-
do {
|
| 310 |
-
do
|
| 311 |
-
magics[s] = rng.sparse_rand<Bitboard>();
|
| 312 |
-
while (popcount((magics[s] * masks[s]) >> 56) < 6);
|
| 313 |
-
|
| 314 |
-
// A good magic must map every possible occupancy to an index that
|
| 315 |
-
// looks up the correct sliding attack in the attacks[s] database.
|
| 316 |
-
// Note that we build up the database for square 's' as a side
|
| 317 |
-
// effect of verifying the magic.
|
| 318 |
-
for (++current, i = 0; i < size; ++i)
|
| 319 |
-
{
|
| 320 |
-
unsigned idx = index(s, occupancy[i]);
|
| 321 |
-
|
| 322 |
-
if (age[idx] < current)
|
| 323 |
-
{
|
| 324 |
-
age[idx] = current;
|
| 325 |
-
attacks[s][idx] = reference[i];
|
| 326 |
-
}
|
| 327 |
-
else if (attacks[s][idx] != reference[i])
|
| 328 |
-
break;
|
| 329 |
-
}
|
| 330 |
-
} while (i < size);
|
| 331 |
-
}
|
| 332 |
-
}
|
| 333 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/bitboard.h
DELETED
|
@@ -1,338 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef BITBOARD_H_INCLUDED
|
| 22 |
-
#define BITBOARD_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include <string>
|
| 25 |
-
|
| 26 |
-
#include "types.h"
|
| 27 |
-
|
| 28 |
-
namespace Bitbases {
|
| 29 |
-
|
| 30 |
-
void init();
|
| 31 |
-
bool probe(Square wksq, Square wpsq, Square bksq, Color us);
|
| 32 |
-
|
| 33 |
-
}
|
| 34 |
-
|
| 35 |
-
namespace Bitboards {
|
| 36 |
-
|
| 37 |
-
void init();
|
| 38 |
-
const std::string pretty(Bitboard b);
|
| 39 |
-
|
| 40 |
-
}
|
| 41 |
-
|
| 42 |
-
const Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL;
|
| 43 |
-
|
| 44 |
-
const Bitboard FileABB = 0x0101010101010101ULL;
|
| 45 |
-
const Bitboard FileBBB = FileABB << 1;
|
| 46 |
-
const Bitboard FileCBB = FileABB << 2;
|
| 47 |
-
const Bitboard FileDBB = FileABB << 3;
|
| 48 |
-
const Bitboard FileEBB = FileABB << 4;
|
| 49 |
-
const Bitboard FileFBB = FileABB << 5;
|
| 50 |
-
const Bitboard FileGBB = FileABB << 6;
|
| 51 |
-
const Bitboard FileHBB = FileABB << 7;
|
| 52 |
-
|
| 53 |
-
const Bitboard Rank1BB = 0xFF;
|
| 54 |
-
const Bitboard Rank2BB = Rank1BB << (8 * 1);
|
| 55 |
-
const Bitboard Rank3BB = Rank1BB << (8 * 2);
|
| 56 |
-
const Bitboard Rank4BB = Rank1BB << (8 * 3);
|
| 57 |
-
const Bitboard Rank5BB = Rank1BB << (8 * 4);
|
| 58 |
-
const Bitboard Rank6BB = Rank1BB << (8 * 5);
|
| 59 |
-
const Bitboard Rank7BB = Rank1BB << (8 * 6);
|
| 60 |
-
const Bitboard Rank8BB = Rank1BB << (8 * 7);
|
| 61 |
-
|
| 62 |
-
extern int SquareDistance[SQUARE_NB][SQUARE_NB];
|
| 63 |
-
|
| 64 |
-
extern Bitboard SquareBB[SQUARE_NB];
|
| 65 |
-
extern Bitboard FileBB[FILE_NB];
|
| 66 |
-
extern Bitboard RankBB[RANK_NB];
|
| 67 |
-
extern Bitboard AdjacentFilesBB[FILE_NB];
|
| 68 |
-
extern Bitboard InFrontBB[COLOR_NB][RANK_NB];
|
| 69 |
-
extern Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB];
|
| 70 |
-
extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
| 71 |
-
extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
| 72 |
-
extern Bitboard DistanceRingBB[SQUARE_NB][8];
|
| 73 |
-
extern Bitboard ForwardBB[COLOR_NB][SQUARE_NB];
|
| 74 |
-
extern Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB];
|
| 75 |
-
extern Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
|
| 76 |
-
extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
/// Overloads of bitwise operators between a Bitboard and a Square for testing
|
| 80 |
-
/// whether a given bit is set in a bitboard, and for setting and clearing bits.
|
| 81 |
-
|
| 82 |
-
inline Bitboard operator&(Bitboard b, Square s) {
|
| 83 |
-
return b & SquareBB[s];
|
| 84 |
-
}
|
| 85 |
-
|
| 86 |
-
inline Bitboard operator|(Bitboard b, Square s) {
|
| 87 |
-
return b | SquareBB[s];
|
| 88 |
-
}
|
| 89 |
-
|
| 90 |
-
inline Bitboard operator^(Bitboard b, Square s) {
|
| 91 |
-
return b ^ SquareBB[s];
|
| 92 |
-
}
|
| 93 |
-
|
| 94 |
-
inline Bitboard& operator|=(Bitboard& b, Square s) {
|
| 95 |
-
return b |= SquareBB[s];
|
| 96 |
-
}
|
| 97 |
-
|
| 98 |
-
inline Bitboard& operator^=(Bitboard& b, Square s) {
|
| 99 |
-
return b ^= SquareBB[s];
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
inline bool more_than_one(Bitboard b) {
|
| 103 |
-
return b & (b - 1);
|
| 104 |
-
}
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
/// rank_bb() and file_bb() return a bitboard representing all the squares on
|
| 108 |
-
/// the given file or rank.
|
| 109 |
-
|
| 110 |
-
inline Bitboard rank_bb(Rank r) {
|
| 111 |
-
return RankBB[r];
|
| 112 |
-
}
|
| 113 |
-
|
| 114 |
-
inline Bitboard rank_bb(Square s) {
|
| 115 |
-
return RankBB[rank_of(s)];
|
| 116 |
-
}
|
| 117 |
-
|
| 118 |
-
inline Bitboard file_bb(File f) {
|
| 119 |
-
return FileBB[f];
|
| 120 |
-
}
|
| 121 |
-
|
| 122 |
-
inline Bitboard file_bb(Square s) {
|
| 123 |
-
return FileBB[file_of(s)];
|
| 124 |
-
}
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
/// shift() moves a bitboard one step along direction D. Mainly for pawns
|
| 128 |
-
|
| 129 |
-
template<Square D>
|
| 130 |
-
inline Bitboard shift(Bitboard b) {
|
| 131 |
-
return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
|
| 132 |
-
: D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7
|
| 133 |
-
: D == NORTH_WEST ? (b & ~FileABB) << 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9
|
| 134 |
-
: 0;
|
| 135 |
-
}
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
/// adjacent_files_bb() returns a bitboard representing all the squares on the
|
| 139 |
-
/// adjacent files of the given one.
|
| 140 |
-
|
| 141 |
-
inline Bitboard adjacent_files_bb(File f) {
|
| 142 |
-
return AdjacentFilesBB[f];
|
| 143 |
-
}
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
/// between_bb() returns a bitboard representing all the squares between the two
|
| 147 |
-
/// given ones. For instance, between_bb(SQ_C4, SQ_F7) returns a bitboard with
|
| 148 |
-
/// the bits for square d5 and e6 set. If s1 and s2 are not on the same rank, file
|
| 149 |
-
/// or diagonal, 0 is returned.
|
| 150 |
-
|
| 151 |
-
inline Bitboard between_bb(Square s1, Square s2) {
|
| 152 |
-
return BetweenBB[s1][s2];
|
| 153 |
-
}
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
/// in_front_bb() returns a bitboard representing all the squares on all the ranks
|
| 157 |
-
/// in front of the given one, from the point of view of the given color. For
|
| 158 |
-
/// instance, in_front_bb(BLACK, RANK_3) will return the squares on ranks 1 and 2.
|
| 159 |
-
|
| 160 |
-
inline Bitboard in_front_bb(Color c, Rank r) {
|
| 161 |
-
return InFrontBB[c][r];
|
| 162 |
-
}
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
/// forward_bb() returns a bitboard representing all the squares along the line
|
| 166 |
-
/// in front of the given one, from the point of view of the given color:
|
| 167 |
-
/// ForwardBB[c][s] = in_front_bb(c, s) & file_bb(s)
|
| 168 |
-
|
| 169 |
-
inline Bitboard forward_bb(Color c, Square s) {
|
| 170 |
-
return ForwardBB[c][s];
|
| 171 |
-
}
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
/// pawn_attack_span() returns a bitboard representing all the squares that can be
|
| 175 |
-
/// attacked by a pawn of the given color when it moves along its file, starting
|
| 176 |
-
/// from the given square:
|
| 177 |
-
/// PawnAttackSpan[c][s] = in_front_bb(c, s) & adjacent_files_bb(s);
|
| 178 |
-
|
| 179 |
-
inline Bitboard pawn_attack_span(Color c, Square s) {
|
| 180 |
-
return PawnAttackSpan[c][s];
|
| 181 |
-
}
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
/// passed_pawn_mask() returns a bitboard mask which can be used to test if a
|
| 185 |
-
/// pawn of the given color and on the given square is a passed pawn:
|
| 186 |
-
/// PassedPawnMask[c][s] = pawn_attack_span(c, s) | forward_bb(c, s)
|
| 187 |
-
|
| 188 |
-
inline Bitboard passed_pawn_mask(Color c, Square s) {
|
| 189 |
-
return PassedPawnMask[c][s];
|
| 190 |
-
}
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
/// aligned() returns true if the squares s1, s2 and s3 are aligned either on a
|
| 194 |
-
/// straight or on a diagonal line.
|
| 195 |
-
|
| 196 |
-
inline bool aligned(Square s1, Square s2, Square s3) {
|
| 197 |
-
return LineBB[s1][s2] & s3;
|
| 198 |
-
}
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
/// distance() functions return the distance between x and y, defined as the
|
| 202 |
-
/// number of steps for a king in x to reach y. Works with squares, ranks, files.
|
| 203 |
-
|
| 204 |
-
template<typename T> inline int distance(T x, T y) { return x < y ? y - x : x - y; }
|
| 205 |
-
template<> inline int distance<Square>(Square x, Square y) { return SquareDistance[x][y]; }
|
| 206 |
-
|
| 207 |
-
template<typename T1, typename T2> inline int distance(T2 x, T2 y);
|
| 208 |
-
template<> inline int distance<File>(Square x, Square y) { return distance(file_of(x), file_of(y)); }
|
| 209 |
-
template<> inline int distance<Rank>(Square x, Square y) { return distance(rank_of(x), rank_of(y)); }
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
/// attacks_bb() returns a bitboard representing all the squares attacked by a
|
| 213 |
-
/// piece of type Pt (bishop or rook) placed on 's'. The helper magic_index()
|
| 214 |
-
/// looks up the index using the 'magic bitboards' approach.
|
| 215 |
-
template<PieceType Pt>
|
| 216 |
-
inline unsigned magic_index(Square s, Bitboard occupied) {
|
| 217 |
-
|
| 218 |
-
extern Bitboard RookMasks[SQUARE_NB];
|
| 219 |
-
extern Bitboard RookMagics[SQUARE_NB];
|
| 220 |
-
extern unsigned RookShifts[SQUARE_NB];
|
| 221 |
-
extern Bitboard BishopMasks[SQUARE_NB];
|
| 222 |
-
extern Bitboard BishopMagics[SQUARE_NB];
|
| 223 |
-
extern unsigned BishopShifts[SQUARE_NB];
|
| 224 |
-
|
| 225 |
-
Bitboard* const Masks = Pt == ROOK ? RookMasks : BishopMasks;
|
| 226 |
-
Bitboard* const Magics = Pt == ROOK ? RookMagics : BishopMagics;
|
| 227 |
-
unsigned* const Shifts = Pt == ROOK ? RookShifts : BishopShifts;
|
| 228 |
-
|
| 229 |
-
if (HasPext)
|
| 230 |
-
return unsigned(pext(occupied, Masks[s]));
|
| 231 |
-
|
| 232 |
-
if (Is64Bit)
|
| 233 |
-
return unsigned(((occupied & Masks[s]) * Magics[s]) >> Shifts[s]);
|
| 234 |
-
|
| 235 |
-
unsigned lo = unsigned(occupied) & unsigned(Masks[s]);
|
| 236 |
-
unsigned hi = unsigned(occupied >> 32) & unsigned(Masks[s] >> 32);
|
| 237 |
-
return (lo * unsigned(Magics[s]) ^ hi * unsigned(Magics[s] >> 32)) >> Shifts[s];
|
| 238 |
-
}
|
| 239 |
-
|
| 240 |
-
template<PieceType Pt>
|
| 241 |
-
inline Bitboard attacks_bb(Square s, Bitboard occupied) {
|
| 242 |
-
|
| 243 |
-
extern Bitboard* RookAttacks[SQUARE_NB];
|
| 244 |
-
extern Bitboard* BishopAttacks[SQUARE_NB];
|
| 245 |
-
|
| 246 |
-
return (Pt == ROOK ? RookAttacks : BishopAttacks)[s][magic_index<Pt>(s, occupied)];
|
| 247 |
-
}
|
| 248 |
-
|
| 249 |
-
inline Bitboard attacks_bb(Piece pc, Square s, Bitboard occupied) {
|
| 250 |
-
|
| 251 |
-
switch (type_of(pc))
|
| 252 |
-
{
|
| 253 |
-
case BISHOP: return attacks_bb<BISHOP>(s, occupied);
|
| 254 |
-
case ROOK : return attacks_bb<ROOK>(s, occupied);
|
| 255 |
-
case QUEEN : return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
|
| 256 |
-
default : return StepAttacksBB[pc][s];
|
| 257 |
-
}
|
| 258 |
-
}
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
/// popcount() counts the number of non-zero bits in a bitboard
|
| 262 |
-
|
| 263 |
-
inline int popcount(Bitboard b) {
|
| 264 |
-
|
| 265 |
-
#ifndef USE_POPCNT
|
| 266 |
-
|
| 267 |
-
extern uint8_t PopCnt16[1 << 16];
|
| 268 |
-
union { Bitboard bb; uint16_t u[4]; } v = { b };
|
| 269 |
-
return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]];
|
| 270 |
-
|
| 271 |
-
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
| 272 |
-
|
| 273 |
-
return (int)_mm_popcnt_u64(b);
|
| 274 |
-
|
| 275 |
-
#else // Assumed gcc or compatible compiler
|
| 276 |
-
|
| 277 |
-
return __builtin_popcountll(b);
|
| 278 |
-
|
| 279 |
-
#endif
|
| 280 |
-
}
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
/// lsb() and msb() return the least/most significant bit in a non-zero bitboard
|
| 284 |
-
|
| 285 |
-
#if defined(__GNUC__)
|
| 286 |
-
|
| 287 |
-
inline Square lsb(Bitboard b) {
|
| 288 |
-
assert(b);
|
| 289 |
-
return Square(__builtin_ctzll(b));
|
| 290 |
-
}
|
| 291 |
-
|
| 292 |
-
inline Square msb(Bitboard b) {
|
| 293 |
-
assert(b);
|
| 294 |
-
return Square(63 - __builtin_clzll(b));
|
| 295 |
-
}
|
| 296 |
-
|
| 297 |
-
#elif defined(_WIN64) && defined(_MSC_VER)
|
| 298 |
-
|
| 299 |
-
inline Square lsb(Bitboard b) {
|
| 300 |
-
assert(b);
|
| 301 |
-
unsigned long idx;
|
| 302 |
-
_BitScanForward64(&idx, b);
|
| 303 |
-
return (Square) idx;
|
| 304 |
-
}
|
| 305 |
-
|
| 306 |
-
inline Square msb(Bitboard b) {
|
| 307 |
-
assert(b);
|
| 308 |
-
unsigned long idx;
|
| 309 |
-
_BitScanReverse64(&idx, b);
|
| 310 |
-
return (Square) idx;
|
| 311 |
-
}
|
| 312 |
-
|
| 313 |
-
#else
|
| 314 |
-
|
| 315 |
-
#define NO_BSF // Fallback on software implementation for other cases
|
| 316 |
-
|
| 317 |
-
Square lsb(Bitboard b);
|
| 318 |
-
Square msb(Bitboard b);
|
| 319 |
-
|
| 320 |
-
#endif
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
/// pop_lsb() finds and clears the least significant bit in a non-zero bitboard
|
| 324 |
-
|
| 325 |
-
inline Square pop_lsb(Bitboard* b) {
|
| 326 |
-
const Square s = lsb(*b);
|
| 327 |
-
*b &= *b - 1;
|
| 328 |
-
return s;
|
| 329 |
-
}
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
/// frontmost_sq() and backmost_sq() return the square corresponding to the
|
| 333 |
-
/// most/least advanced bit relative to the given color.
|
| 334 |
-
|
| 335 |
-
inline Square frontmost_sq(Color c, Bitboard b) { return c == WHITE ? msb(b) : lsb(b); }
|
| 336 |
-
inline Square backmost_sq(Color c, Bitboard b) { return c == WHITE ? lsb(b) : msb(b); }
|
| 337 |
-
|
| 338 |
-
#endif // #ifndef BITBOARD_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/endgame.cpp
DELETED
|
@@ -1,845 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm>
|
| 22 |
-
#include <cassert>
|
| 23 |
-
|
| 24 |
-
#include "bitboard.h"
|
| 25 |
-
#include "endgame.h"
|
| 26 |
-
#include "movegen.h"
|
| 27 |
-
|
| 28 |
-
using std::string;
|
| 29 |
-
|
| 30 |
-
namespace {
|
| 31 |
-
|
| 32 |
-
// Table used to drive the king towards the edge of the board
|
| 33 |
-
// in KX vs K and KQ vs KR endgames.
|
| 34 |
-
const int PushToEdges[SQUARE_NB] = {
|
| 35 |
-
100, 90, 80, 70, 70, 80, 90, 100,
|
| 36 |
-
90, 70, 60, 50, 50, 60, 70, 90,
|
| 37 |
-
80, 60, 40, 30, 30, 40, 60, 80,
|
| 38 |
-
70, 50, 30, 20, 20, 30, 50, 70,
|
| 39 |
-
70, 50, 30, 20, 20, 30, 50, 70,
|
| 40 |
-
80, 60, 40, 30, 30, 40, 60, 80,
|
| 41 |
-
90, 70, 60, 50, 50, 60, 70, 90,
|
| 42 |
-
100, 90, 80, 70, 70, 80, 90, 100
|
| 43 |
-
};
|
| 44 |
-
|
| 45 |
-
// Table used to drive the king towards a corner square of the
|
| 46 |
-
// right color in KBN vs K endgames.
|
| 47 |
-
const int PushToCorners[SQUARE_NB] = {
|
| 48 |
-
200, 190, 180, 170, 160, 150, 140, 130,
|
| 49 |
-
190, 180, 170, 160, 150, 140, 130, 140,
|
| 50 |
-
180, 170, 155, 140, 140, 125, 140, 150,
|
| 51 |
-
170, 160, 140, 120, 110, 140, 150, 160,
|
| 52 |
-
160, 150, 140, 110, 120, 140, 160, 170,
|
| 53 |
-
150, 140, 125, 140, 140, 155, 170, 180,
|
| 54 |
-
140, 130, 140, 150, 160, 170, 180, 190,
|
| 55 |
-
130, 140, 150, 160, 170, 180, 190, 200
|
| 56 |
-
};
|
| 57 |
-
|
| 58 |
-
// Tables used to drive a piece towards or away from another piece
|
| 59 |
-
const int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
|
| 60 |
-
const int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 };
|
| 61 |
-
|
| 62 |
-
// Pawn Rank based scaling factors used in KRPPKRP endgame
|
| 63 |
-
const int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 };
|
| 64 |
-
|
| 65 |
-
#ifndef NDEBUG
|
| 66 |
-
bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) {
|
| 67 |
-
return pos.non_pawn_material(c) == npm && pos.count<PAWN>(c) == pawnsCnt;
|
| 68 |
-
}
|
| 69 |
-
#endif
|
| 70 |
-
|
| 71 |
-
// Map the square as if strongSide is white and strongSide's only pawn
|
| 72 |
-
// is on the left half of the board.
|
| 73 |
-
Square normalize(const Position& pos, Color strongSide, Square sq) {
|
| 74 |
-
|
| 75 |
-
assert(pos.count<PAWN>(strongSide) == 1);
|
| 76 |
-
|
| 77 |
-
if (file_of(pos.square<PAWN>(strongSide)) >= FILE_E)
|
| 78 |
-
sq = Square(sq ^ 7); // Mirror SQ_H1 -> SQ_A1
|
| 79 |
-
|
| 80 |
-
if (strongSide == BLACK)
|
| 81 |
-
sq = ~sq;
|
| 82 |
-
|
| 83 |
-
return sq;
|
| 84 |
-
}
|
| 85 |
-
|
| 86 |
-
// Get the material key of Position out of the given endgame key code
|
| 87 |
-
// like "KBPKN". The trick here is to first forge an ad-hoc FEN string
|
| 88 |
-
// and then let a Position object do the work for us.
|
| 89 |
-
Key key(const string& code, Color c) {
|
| 90 |
-
|
| 91 |
-
assert(code.length() > 0 && code.length() < 8);
|
| 92 |
-
assert(code[0] == 'K');
|
| 93 |
-
|
| 94 |
-
string sides[] = { code.substr(code.find('K', 1)), // Weak
|
| 95 |
-
code.substr(0, code.find('K', 1)) }; // Strong
|
| 96 |
-
|
| 97 |
-
std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);
|
| 98 |
-
|
| 99 |
-
string fen = sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/8/8/"
|
| 100 |
-
+ sides[1] + char(8 - sides[1].length() + '0') + " w - - 0 10";
|
| 101 |
-
|
| 102 |
-
StateInfo st;
|
| 103 |
-
return Position().set(fen, false, &st, nullptr).material_key();
|
| 104 |
-
}
|
| 105 |
-
|
| 106 |
-
} // namespace
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
/// Endgames members definitions
|
| 110 |
-
|
| 111 |
-
Endgames::Endgames() {
|
| 112 |
-
|
| 113 |
-
add<KPK>("KPK");
|
| 114 |
-
add<KNNK>("KNNK");
|
| 115 |
-
add<KBNK>("KBNK");
|
| 116 |
-
add<KRKP>("KRKP");
|
| 117 |
-
add<KRKB>("KRKB");
|
| 118 |
-
add<KRKN>("KRKN");
|
| 119 |
-
add<KQKP>("KQKP");
|
| 120 |
-
add<KQKR>("KQKR");
|
| 121 |
-
|
| 122 |
-
add<KNPK>("KNPK");
|
| 123 |
-
add<KNPKB>("KNPKB");
|
| 124 |
-
add<KRPKR>("KRPKR");
|
| 125 |
-
add<KRPKB>("KRPKB");
|
| 126 |
-
add<KBPKB>("KBPKB");
|
| 127 |
-
add<KBPKN>("KBPKN");
|
| 128 |
-
add<KBPPKB>("KBPPKB");
|
| 129 |
-
add<KRPPKRP>("KRPPKRP");
|
| 130 |
-
}
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
template<EndgameType E, typename T>
|
| 134 |
-
void Endgames::add(const string& code) {
|
| 135 |
-
map<T>()[key(code, WHITE)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(WHITE));
|
| 136 |
-
map<T>()[key(code, BLACK)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(BLACK));
|
| 137 |
-
}
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
/// Mate with KX vs K. This function is used to evaluate positions with
|
| 141 |
-
/// king and plenty of material vs a lone king. It simply gives the
|
| 142 |
-
/// attacking side a bonus for driving the defending king towards the edge
|
| 143 |
-
/// of the board, and for keeping the distance between the two kings small.
|
| 144 |
-
template<>
|
| 145 |
-
Value Endgame<KXK>::operator()(const Position& pos) const {
|
| 146 |
-
|
| 147 |
-
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 148 |
-
assert(!pos.checkers()); // Eval is never called when in check
|
| 149 |
-
|
| 150 |
-
// Stalemate detection with lone king
|
| 151 |
-
if (pos.side_to_move() == weakSide && !MoveList<LEGAL>(pos).size())
|
| 152 |
-
return VALUE_DRAW;
|
| 153 |
-
|
| 154 |
-
Square winnerKSq = pos.square<KING>(strongSide);
|
| 155 |
-
Square loserKSq = pos.square<KING>(weakSide);
|
| 156 |
-
|
| 157 |
-
Value result = pos.non_pawn_material(strongSide)
|
| 158 |
-
+ pos.count<PAWN>(strongSide) * PawnValueEg
|
| 159 |
-
+ PushToEdges[loserKSq]
|
| 160 |
-
+ PushClose[distance(winnerKSq, loserKSq)];
|
| 161 |
-
|
| 162 |
-
if ( pos.count<QUEEN>(strongSide)
|
| 163 |
-
|| pos.count<ROOK>(strongSide)
|
| 164 |
-
||(pos.count<BISHOP>(strongSide) && pos.count<KNIGHT>(strongSide))
|
| 165 |
-
||(pos.count<BISHOP>(strongSide) > 1 && opposite_colors(pos.squares<BISHOP>(strongSide)[0],
|
| 166 |
-
pos.squares<BISHOP>(strongSide)[1])))
|
| 167 |
-
result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1);
|
| 168 |
-
|
| 169 |
-
return strongSide == pos.side_to_move() ? result : -result;
|
| 170 |
-
}
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
/// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the
|
| 174 |
-
/// defending king towards a corner square of the right color.
|
| 175 |
-
template<>
|
| 176 |
-
Value Endgame<KBNK>::operator()(const Position& pos) const {
|
| 177 |
-
|
| 178 |
-
assert(verify_material(pos, strongSide, KnightValueMg + BishopValueMg, 0));
|
| 179 |
-
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 180 |
-
|
| 181 |
-
Square winnerKSq = pos.square<KING>(strongSide);
|
| 182 |
-
Square loserKSq = pos.square<KING>(weakSide);
|
| 183 |
-
Square bishopSq = pos.square<BISHOP>(strongSide);
|
| 184 |
-
|
| 185 |
-
// kbnk_mate_table() tries to drive toward corners A1 or H8. If we have a
|
| 186 |
-
// bishop that cannot reach the above squares, we flip the kings in order
|
| 187 |
-
// to drive the enemy toward corners A8 or H1.
|
| 188 |
-
if (opposite_colors(bishopSq, SQ_A1))
|
| 189 |
-
{
|
| 190 |
-
winnerKSq = ~winnerKSq;
|
| 191 |
-
loserKSq = ~loserKSq;
|
| 192 |
-
}
|
| 193 |
-
|
| 194 |
-
Value result = VALUE_KNOWN_WIN
|
| 195 |
-
+ PushClose[distance(winnerKSq, loserKSq)]
|
| 196 |
-
+ PushToCorners[loserKSq];
|
| 197 |
-
|
| 198 |
-
return strongSide == pos.side_to_move() ? result : -result;
|
| 199 |
-
}
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
/// KP vs K. This endgame is evaluated with the help of a bitbase.
|
| 203 |
-
template<>
|
| 204 |
-
Value Endgame<KPK>::operator()(const Position& pos) const {
|
| 205 |
-
|
| 206 |
-
assert(verify_material(pos, strongSide, VALUE_ZERO, 1));
|
| 207 |
-
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 208 |
-
|
| 209 |
-
// Assume strongSide is white and the pawn is on files A-D
|
| 210 |
-
Square wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
| 211 |
-
Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
| 212 |
-
Square psq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
| 213 |
-
|
| 214 |
-
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
|
| 215 |
-
|
| 216 |
-
if (!Bitbases::probe(wksq, psq, bksq, us))
|
| 217 |
-
return VALUE_DRAW;
|
| 218 |
-
|
| 219 |
-
Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(psq));
|
| 220 |
-
|
| 221 |
-
return strongSide == pos.side_to_move() ? result : -result;
|
| 222 |
-
}
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
/// KR vs KP. This is a somewhat tricky endgame to evaluate precisely without
|
| 226 |
-
/// a bitbase. The function below returns drawish scores when the pawn is
|
| 227 |
-
/// far advanced with support of the king, while the attacking king is far
|
| 228 |
-
/// away.
|
| 229 |
-
template<>
|
| 230 |
-
Value Endgame<KRKP>::operator()(const Position& pos) const {
|
| 231 |
-
|
| 232 |
-
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
| 233 |
-
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
| 234 |
-
|
| 235 |
-
Square wksq = relative_square(strongSide, pos.square<KING>(strongSide));
|
| 236 |
-
Square bksq = relative_square(strongSide, pos.square<KING>(weakSide));
|
| 237 |
-
Square rsq = relative_square(strongSide, pos.square<ROOK>(strongSide));
|
| 238 |
-
Square psq = relative_square(strongSide, pos.square<PAWN>(weakSide));
|
| 239 |
-
|
| 240 |
-
Square queeningSq = make_square(file_of(psq), RANK_1);
|
| 241 |
-
Value result;
|
| 242 |
-
|
| 243 |
-
// If the stronger side's king is in front of the pawn, it's a win
|
| 244 |
-
if (wksq < psq && file_of(wksq) == file_of(psq))
|
| 245 |
-
result = RookValueEg - distance(wksq, psq);
|
| 246 |
-
|
| 247 |
-
// If the weaker side's king is too far from the pawn and the rook,
|
| 248 |
-
// it's a win.
|
| 249 |
-
else if ( distance(bksq, psq) >= 3 + (pos.side_to_move() == weakSide)
|
| 250 |
-
&& distance(bksq, rsq) >= 3)
|
| 251 |
-
result = RookValueEg - distance(wksq, psq);
|
| 252 |
-
|
| 253 |
-
// If the pawn is far advanced and supported by the defending king,
|
| 254 |
-
// the position is drawish
|
| 255 |
-
else if ( rank_of(bksq) <= RANK_3
|
| 256 |
-
&& distance(bksq, psq) == 1
|
| 257 |
-
&& rank_of(wksq) >= RANK_4
|
| 258 |
-
&& distance(wksq, psq) > 2 + (pos.side_to_move() == strongSide))
|
| 259 |
-
result = Value(80) - 8 * distance(wksq, psq);
|
| 260 |
-
|
| 261 |
-
else
|
| 262 |
-
result = Value(200) - 8 * ( distance(wksq, psq + SOUTH)
|
| 263 |
-
- distance(bksq, psq + SOUTH)
|
| 264 |
-
- distance(psq, queeningSq));
|
| 265 |
-
|
| 266 |
-
return strongSide == pos.side_to_move() ? result : -result;
|
| 267 |
-
}
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
/// KR vs KB. This is very simple, and always returns drawish scores. The
|
| 271 |
-
/// score is slightly bigger when the defending king is close to the edge.
|
| 272 |
-
template<>
|
| 273 |
-
Value Endgame<KRKB>::operator()(const Position& pos) const {
|
| 274 |
-
|
| 275 |
-
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
| 276 |
-
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
| 277 |
-
|
| 278 |
-
Value result = Value(PushToEdges[pos.square<KING>(weakSide)]);
|
| 279 |
-
return strongSide == pos.side_to_move() ? result : -result;
|
| 280 |
-
}
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
/// KR vs KN. The attacking side has slightly better winning chances than
|
| 284 |
-
/// in KR vs KB, particularly if the king and the knight are far apart.
|
| 285 |
-
template<>
|
| 286 |
-
Value Endgame<KRKN>::operator()(const Position& pos) const {
|
| 287 |
-
|
| 288 |
-
assert(verify_material(pos, strongSide, RookValueMg, 0));
|
| 289 |
-
assert(verify_material(pos, weakSide, KnightValueMg, 0));
|
| 290 |
-
|
| 291 |
-
Square bksq = pos.square<KING>(weakSide);
|
| 292 |
-
Square bnsq = pos.square<KNIGHT>(weakSide);
|
| 293 |
-
Value result = Value(PushToEdges[bksq] + PushAway[distance(bksq, bnsq)]);
|
| 294 |
-
return strongSide == pos.side_to_move() ? result : -result;
|
| 295 |
-
}
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
/// KQ vs KP. In general, this is a win for the stronger side, but there are a
|
| 299 |
-
/// few important exceptions. A pawn on 7th rank and on the A,C,F or H files
|
| 300 |
-
/// with a king positioned next to it can be a draw, so in that case, we only
|
| 301 |
-
/// use the distance between the kings.
|
| 302 |
-
template<>
|
| 303 |
-
Value Endgame<KQKP>::operator()(const Position& pos) const {
|
| 304 |
-
|
| 305 |
-
assert(verify_material(pos, strongSide, QueenValueMg, 0));
|
| 306 |
-
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
| 307 |
-
|
| 308 |
-
Square winnerKSq = pos.square<KING>(strongSide);
|
| 309 |
-
Square loserKSq = pos.square<KING>(weakSide);
|
| 310 |
-
Square pawnSq = pos.square<PAWN>(weakSide);
|
| 311 |
-
|
| 312 |
-
Value result = Value(PushClose[distance(winnerKSq, loserKSq)]);
|
| 313 |
-
|
| 314 |
-
if ( relative_rank(weakSide, pawnSq) != RANK_7
|
| 315 |
-
|| distance(loserKSq, pawnSq) != 1
|
| 316 |
-
|| !((FileABB | FileCBB | FileFBB | FileHBB) & pawnSq))
|
| 317 |
-
result += QueenValueEg - PawnValueEg;
|
| 318 |
-
|
| 319 |
-
return strongSide == pos.side_to_move() ? result : -result;
|
| 320 |
-
}
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
/// KQ vs KR. This is almost identical to KX vs K: We give the attacking
|
| 324 |
-
/// king a bonus for having the kings close together, and for forcing the
|
| 325 |
-
/// defending king towards the edge. If we also take care to avoid null move for
|
| 326 |
-
/// the defending side in the search, this is usually sufficient to win KQ vs KR.
|
| 327 |
-
template<>
|
| 328 |
-
Value Endgame<KQKR>::operator()(const Position& pos) const {
|
| 329 |
-
|
| 330 |
-
assert(verify_material(pos, strongSide, QueenValueMg, 0));
|
| 331 |
-
assert(verify_material(pos, weakSide, RookValueMg, 0));
|
| 332 |
-
|
| 333 |
-
Square winnerKSq = pos.square<KING>(strongSide);
|
| 334 |
-
Square loserKSq = pos.square<KING>(weakSide);
|
| 335 |
-
|
| 336 |
-
Value result = QueenValueEg
|
| 337 |
-
- RookValueEg
|
| 338 |
-
+ PushToEdges[loserKSq]
|
| 339 |
-
+ PushClose[distance(winnerKSq, loserKSq)];
|
| 340 |
-
|
| 341 |
-
return strongSide == pos.side_to_move() ? result : -result;
|
| 342 |
-
}
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
/// Some cases of trivial draws
|
| 346 |
-
template<> Value Endgame<KNNK>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
/// KB and one or more pawns vs K. It checks for draws with rook pawns and
|
| 350 |
-
/// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW
|
| 351 |
-
/// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
|
| 352 |
-
/// will be used.
|
| 353 |
-
template<>
|
| 354 |
-
ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
|
| 355 |
-
|
| 356 |
-
assert(pos.non_pawn_material(strongSide) == BishopValueMg);
|
| 357 |
-
assert(pos.count<PAWN>(strongSide) >= 1);
|
| 358 |
-
|
| 359 |
-
// No assertions about the material of weakSide, because we want draws to
|
| 360 |
-
// be detected even when the weaker side has some pawns.
|
| 361 |
-
|
| 362 |
-
Bitboard pawns = pos.pieces(strongSide, PAWN);
|
| 363 |
-
File pawnsFile = file_of(lsb(pawns));
|
| 364 |
-
|
| 365 |
-
// All pawns are on a single rook file?
|
| 366 |
-
if ( (pawnsFile == FILE_A || pawnsFile == FILE_H)
|
| 367 |
-
&& !(pawns & ~file_bb(pawnsFile)))
|
| 368 |
-
{
|
| 369 |
-
Square bishopSq = pos.square<BISHOP>(strongSide);
|
| 370 |
-
Square queeningSq = relative_square(strongSide, make_square(pawnsFile, RANK_8));
|
| 371 |
-
Square kingSq = pos.square<KING>(weakSide);
|
| 372 |
-
|
| 373 |
-
if ( opposite_colors(queeningSq, bishopSq)
|
| 374 |
-
&& distance(queeningSq, kingSq) <= 1)
|
| 375 |
-
return SCALE_FACTOR_DRAW;
|
| 376 |
-
}
|
| 377 |
-
|
| 378 |
-
// If all the pawns are on the same B or G file, then it's potentially a draw
|
| 379 |
-
if ( (pawnsFile == FILE_B || pawnsFile == FILE_G)
|
| 380 |
-
&& !(pos.pieces(PAWN) & ~file_bb(pawnsFile))
|
| 381 |
-
&& pos.non_pawn_material(weakSide) == 0
|
| 382 |
-
&& pos.count<PAWN>(weakSide) >= 1)
|
| 383 |
-
{
|
| 384 |
-
// Get weakSide pawn that is closest to the home rank
|
| 385 |
-
Square weakPawnSq = backmost_sq(weakSide, pos.pieces(weakSide, PAWN));
|
| 386 |
-
|
| 387 |
-
Square strongKingSq = pos.square<KING>(strongSide);
|
| 388 |
-
Square weakKingSq = pos.square<KING>(weakSide);
|
| 389 |
-
Square bishopSq = pos.square<BISHOP>(strongSide);
|
| 390 |
-
|
| 391 |
-
// There's potential for a draw if our pawn is blocked on the 7th rank,
|
| 392 |
-
// the bishop cannot attack it or they only have one pawn left
|
| 393 |
-
if ( relative_rank(strongSide, weakPawnSq) == RANK_7
|
| 394 |
-
&& (pos.pieces(strongSide, PAWN) & (weakPawnSq + pawn_push(weakSide)))
|
| 395 |
-
&& (opposite_colors(bishopSq, weakPawnSq) || pos.count<PAWN>(strongSide) == 1))
|
| 396 |
-
{
|
| 397 |
-
int strongKingDist = distance(weakPawnSq, strongKingSq);
|
| 398 |
-
int weakKingDist = distance(weakPawnSq, weakKingSq);
|
| 399 |
-
|
| 400 |
-
// It's a draw if the weak king is on its back two ranks, within 2
|
| 401 |
-
// squares of the blocking pawn and the strong king is not
|
| 402 |
-
// closer. (I think this rule only fails in practically
|
| 403 |
-
// unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w
|
| 404 |
-
// and positions where qsearch will immediately correct the
|
| 405 |
-
// problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w)
|
| 406 |
-
if ( relative_rank(strongSide, weakKingSq) >= RANK_7
|
| 407 |
-
&& weakKingDist <= 2
|
| 408 |
-
&& weakKingDist <= strongKingDist)
|
| 409 |
-
return SCALE_FACTOR_DRAW;
|
| 410 |
-
}
|
| 411 |
-
}
|
| 412 |
-
|
| 413 |
-
return SCALE_FACTOR_NONE;
|
| 414 |
-
}
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
/// KQ vs KR and one or more pawns. It tests for fortress draws with a rook on
|
| 418 |
-
/// the third rank defended by a pawn.
|
| 419 |
-
template<>
|
| 420 |
-
ScaleFactor Endgame<KQKRPs>::operator()(const Position& pos) const {
|
| 421 |
-
|
| 422 |
-
assert(verify_material(pos, strongSide, QueenValueMg, 0));
|
| 423 |
-
assert(pos.count<ROOK>(weakSide) == 1);
|
| 424 |
-
assert(pos.count<PAWN>(weakSide) >= 1);
|
| 425 |
-
|
| 426 |
-
Square kingSq = pos.square<KING>(weakSide);
|
| 427 |
-
Square rsq = pos.square<ROOK>(weakSide);
|
| 428 |
-
|
| 429 |
-
if ( relative_rank(weakSide, kingSq) <= RANK_2
|
| 430 |
-
&& relative_rank(weakSide, pos.square<KING>(strongSide)) >= RANK_4
|
| 431 |
-
&& relative_rank(weakSide, rsq) == RANK_3
|
| 432 |
-
&& ( pos.pieces(weakSide, PAWN)
|
| 433 |
-
& pos.attacks_from<KING>(kingSq)
|
| 434 |
-
& pos.attacks_from<PAWN>(rsq, strongSide)))
|
| 435 |
-
return SCALE_FACTOR_DRAW;
|
| 436 |
-
|
| 437 |
-
return SCALE_FACTOR_NONE;
|
| 438 |
-
}
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
/// KRP vs KR. This function knows a handful of the most important classes of
|
| 442 |
-
/// drawn positions, but is far from perfect. It would probably be a good idea
|
| 443 |
-
/// to add more knowledge in the future.
|
| 444 |
-
///
|
| 445 |
-
/// It would also be nice to rewrite the actual code for this function,
|
| 446 |
-
/// which is mostly copied from Glaurung 1.x, and isn't very pretty.
|
| 447 |
-
template<>
|
| 448 |
-
ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
|
| 449 |
-
|
| 450 |
-
assert(verify_material(pos, strongSide, RookValueMg, 1));
|
| 451 |
-
assert(verify_material(pos, weakSide, RookValueMg, 0));
|
| 452 |
-
|
| 453 |
-
// Assume strongSide is white and the pawn is on files A-D
|
| 454 |
-
Square wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
| 455 |
-
Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
| 456 |
-
Square wrsq = normalize(pos, strongSide, pos.square<ROOK>(strongSide));
|
| 457 |
-
Square wpsq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
| 458 |
-
Square brsq = normalize(pos, strongSide, pos.square<ROOK>(weakSide));
|
| 459 |
-
|
| 460 |
-
File f = file_of(wpsq);
|
| 461 |
-
Rank r = rank_of(wpsq);
|
| 462 |
-
Square queeningSq = make_square(f, RANK_8);
|
| 463 |
-
int tempo = (pos.side_to_move() == strongSide);
|
| 464 |
-
|
| 465 |
-
// If the pawn is not too far advanced and the defending king defends the
|
| 466 |
-
// queening square, use the third-rank defence.
|
| 467 |
-
if ( r <= RANK_5
|
| 468 |
-
&& distance(bksq, queeningSq) <= 1
|
| 469 |
-
&& wksq <= SQ_H5
|
| 470 |
-
&& (rank_of(brsq) == RANK_6 || (r <= RANK_3 && rank_of(wrsq) != RANK_6)))
|
| 471 |
-
return SCALE_FACTOR_DRAW;
|
| 472 |
-
|
| 473 |
-
// The defending side saves a draw by checking from behind in case the pawn
|
| 474 |
-
// has advanced to the 6th rank with the king behind.
|
| 475 |
-
if ( r == RANK_6
|
| 476 |
-
&& distance(bksq, queeningSq) <= 1
|
| 477 |
-
&& rank_of(wksq) + tempo <= RANK_6
|
| 478 |
-
&& (rank_of(brsq) == RANK_1 || (!tempo && distance<File>(brsq, wpsq) >= 3)))
|
| 479 |
-
return SCALE_FACTOR_DRAW;
|
| 480 |
-
|
| 481 |
-
if ( r >= RANK_6
|
| 482 |
-
&& bksq == queeningSq
|
| 483 |
-
&& rank_of(brsq) == RANK_1
|
| 484 |
-
&& (!tempo || distance(wksq, wpsq) >= 2))
|
| 485 |
-
return SCALE_FACTOR_DRAW;
|
| 486 |
-
|
| 487 |
-
// White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
|
| 488 |
-
// and the black rook is behind the pawn.
|
| 489 |
-
if ( wpsq == SQ_A7
|
| 490 |
-
&& wrsq == SQ_A8
|
| 491 |
-
&& (bksq == SQ_H7 || bksq == SQ_G7)
|
| 492 |
-
&& file_of(brsq) == FILE_A
|
| 493 |
-
&& (rank_of(brsq) <= RANK_3 || file_of(wksq) >= FILE_D || rank_of(wksq) <= RANK_5))
|
| 494 |
-
return SCALE_FACTOR_DRAW;
|
| 495 |
-
|
| 496 |
-
// If the defending king blocks the pawn and the attacking king is too far
|
| 497 |
-
// away, it's a draw.
|
| 498 |
-
if ( r <= RANK_5
|
| 499 |
-
&& bksq == wpsq + NORTH
|
| 500 |
-
&& distance(wksq, wpsq) - tempo >= 2
|
| 501 |
-
&& distance(wksq, brsq) - tempo >= 2)
|
| 502 |
-
return SCALE_FACTOR_DRAW;
|
| 503 |
-
|
| 504 |
-
// Pawn on the 7th rank supported by the rook from behind usually wins if the
|
| 505 |
-
// attacking king is closer to the queening square than the defending king,
|
| 506 |
-
// and the defending king cannot gain tempi by threatening the attacking rook.
|
| 507 |
-
if ( r == RANK_7
|
| 508 |
-
&& f != FILE_A
|
| 509 |
-
&& file_of(wrsq) == f
|
| 510 |
-
&& wrsq != queeningSq
|
| 511 |
-
&& (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo)
|
| 512 |
-
&& (distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo))
|
| 513 |
-
return ScaleFactor(SCALE_FACTOR_MAX - 2 * distance(wksq, queeningSq));
|
| 514 |
-
|
| 515 |
-
// Similar to the above, but with the pawn further back
|
| 516 |
-
if ( f != FILE_A
|
| 517 |
-
&& file_of(wrsq) == f
|
| 518 |
-
&& wrsq < wpsq
|
| 519 |
-
&& (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo)
|
| 520 |
-
&& (distance(wksq, wpsq + NORTH) < distance(bksq, wpsq + NORTH) - 2 + tempo)
|
| 521 |
-
&& ( distance(bksq, wrsq) + tempo >= 3
|
| 522 |
-
|| ( distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo
|
| 523 |
-
&& (distance(wksq, wpsq + NORTH) < distance(bksq, wrsq) + tempo))))
|
| 524 |
-
return ScaleFactor( SCALE_FACTOR_MAX
|
| 525 |
-
- 8 * distance(wpsq, queeningSq)
|
| 526 |
-
- 2 * distance(wksq, queeningSq));
|
| 527 |
-
|
| 528 |
-
// If the pawn is not far advanced and the defending king is somewhere in
|
| 529 |
-
// the pawn's path, it's probably a draw.
|
| 530 |
-
if (r <= RANK_4 && bksq > wpsq)
|
| 531 |
-
{
|
| 532 |
-
if (file_of(bksq) == file_of(wpsq))
|
| 533 |
-
return ScaleFactor(10);
|
| 534 |
-
if ( distance<File>(bksq, wpsq) == 1
|
| 535 |
-
&& distance(wksq, bksq) > 2)
|
| 536 |
-
return ScaleFactor(24 - 2 * distance(wksq, bksq));
|
| 537 |
-
}
|
| 538 |
-
return SCALE_FACTOR_NONE;
|
| 539 |
-
}
|
| 540 |
-
|
| 541 |
-
template<>
|
| 542 |
-
ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
|
| 543 |
-
|
| 544 |
-
assert(verify_material(pos, strongSide, RookValueMg, 1));
|
| 545 |
-
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
| 546 |
-
|
| 547 |
-
// Test for a rook pawn
|
| 548 |
-
if (pos.pieces(PAWN) & (FileABB | FileHBB))
|
| 549 |
-
{
|
| 550 |
-
Square ksq = pos.square<KING>(weakSide);
|
| 551 |
-
Square bsq = pos.square<BISHOP>(weakSide);
|
| 552 |
-
Square psq = pos.square<PAWN>(strongSide);
|
| 553 |
-
Rank rk = relative_rank(strongSide, psq);
|
| 554 |
-
Square push = pawn_push(strongSide);
|
| 555 |
-
|
| 556 |
-
// If the pawn is on the 5th rank and the pawn (currently) is on
|
| 557 |
-
// the same color square as the bishop then there is a chance of
|
| 558 |
-
// a fortress. Depending on the king position give a moderate
|
| 559 |
-
// reduction or a stronger one if the defending king is near the
|
| 560 |
-
// corner but not trapped there.
|
| 561 |
-
if (rk == RANK_5 && !opposite_colors(bsq, psq))
|
| 562 |
-
{
|
| 563 |
-
int d = distance(psq + 3 * push, ksq);
|
| 564 |
-
|
| 565 |
-
if (d <= 2 && !(d == 0 && ksq == pos.square<KING>(strongSide) + 2 * push))
|
| 566 |
-
return ScaleFactor(24);
|
| 567 |
-
else
|
| 568 |
-
return ScaleFactor(48);
|
| 569 |
-
}
|
| 570 |
-
|
| 571 |
-
// When the pawn has moved to the 6th rank we can be fairly sure
|
| 572 |
-
// it's drawn if the bishop attacks the square in front of the
|
| 573 |
-
// pawn from a reasonable distance and the defending king is near
|
| 574 |
-
// the corner
|
| 575 |
-
if ( rk == RANK_6
|
| 576 |
-
&& distance(psq + 2 * push, ksq) <= 1
|
| 577 |
-
&& (PseudoAttacks[BISHOP][bsq] & (psq + push))
|
| 578 |
-
&& distance<File>(bsq, psq) >= 2)
|
| 579 |
-
return ScaleFactor(8);
|
| 580 |
-
}
|
| 581 |
-
|
| 582 |
-
return SCALE_FACTOR_NONE;
|
| 583 |
-
}
|
| 584 |
-
|
| 585 |
-
/// KRPP vs KRP. There is just a single rule: if the stronger side has no passed
|
| 586 |
-
/// pawns and the defending king is actively placed, the position is drawish.
|
| 587 |
-
template<>
|
| 588 |
-
ScaleFactor Endgame<KRPPKRP>::operator()(const Position& pos) const {
|
| 589 |
-
|
| 590 |
-
assert(verify_material(pos, strongSide, RookValueMg, 2));
|
| 591 |
-
assert(verify_material(pos, weakSide, RookValueMg, 1));
|
| 592 |
-
|
| 593 |
-
Square wpsq1 = pos.squares<PAWN>(strongSide)[0];
|
| 594 |
-
Square wpsq2 = pos.squares<PAWN>(strongSide)[1];
|
| 595 |
-
Square bksq = pos.square<KING>(weakSide);
|
| 596 |
-
|
| 597 |
-
// Does the stronger side have a passed pawn?
|
| 598 |
-
if (pos.pawn_passed(strongSide, wpsq1) || pos.pawn_passed(strongSide, wpsq2))
|
| 599 |
-
return SCALE_FACTOR_NONE;
|
| 600 |
-
|
| 601 |
-
Rank r = std::max(relative_rank(strongSide, wpsq1), relative_rank(strongSide, wpsq2));
|
| 602 |
-
|
| 603 |
-
if ( distance<File>(bksq, wpsq1) <= 1
|
| 604 |
-
&& distance<File>(bksq, wpsq2) <= 1
|
| 605 |
-
&& relative_rank(strongSide, bksq) > r)
|
| 606 |
-
{
|
| 607 |
-
assert(r > RANK_1 && r < RANK_7);
|
| 608 |
-
return ScaleFactor(KRPPKRPScaleFactors[r]);
|
| 609 |
-
}
|
| 610 |
-
return SCALE_FACTOR_NONE;
|
| 611 |
-
}
|
| 612 |
-
|
| 613 |
-
|
| 614 |
-
/// K and two or more pawns vs K. There is just a single rule here: If all pawns
|
| 615 |
-
/// are on the same rook file and are blocked by the defending king, it's a draw.
|
| 616 |
-
template<>
|
| 617 |
-
ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
|
| 618 |
-
|
| 619 |
-
assert(pos.non_pawn_material(strongSide) == VALUE_ZERO);
|
| 620 |
-
assert(pos.count<PAWN>(strongSide) >= 2);
|
| 621 |
-
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 622 |
-
|
| 623 |
-
Square ksq = pos.square<KING>(weakSide);
|
| 624 |
-
Bitboard pawns = pos.pieces(strongSide, PAWN);
|
| 625 |
-
|
| 626 |
-
// If all pawns are ahead of the king, on a single rook file and
|
| 627 |
-
// the king is within one file of the pawns, it's a draw.
|
| 628 |
-
if ( !(pawns & ~in_front_bb(weakSide, rank_of(ksq)))
|
| 629 |
-
&& !((pawns & ~FileABB) && (pawns & ~FileHBB))
|
| 630 |
-
&& distance<File>(ksq, lsb(pawns)) <= 1)
|
| 631 |
-
return SCALE_FACTOR_DRAW;
|
| 632 |
-
|
| 633 |
-
return SCALE_FACTOR_NONE;
|
| 634 |
-
}
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
/// KBP vs KB. There are two rules: if the defending king is somewhere along the
|
| 638 |
-
/// path of the pawn, and the square of the king is not of the same color as the
|
| 639 |
-
/// stronger side's bishop, it's a draw. If the two bishops have opposite color,
|
| 640 |
-
/// it's almost always a draw.
|
| 641 |
-
template<>
|
| 642 |
-
ScaleFactor Endgame<KBPKB>::operator()(const Position& pos) const {
|
| 643 |
-
|
| 644 |
-
assert(verify_material(pos, strongSide, BishopValueMg, 1));
|
| 645 |
-
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
| 646 |
-
|
| 647 |
-
Square pawnSq = pos.square<PAWN>(strongSide);
|
| 648 |
-
Square strongBishopSq = pos.square<BISHOP>(strongSide);
|
| 649 |
-
Square weakBishopSq = pos.square<BISHOP>(weakSide);
|
| 650 |
-
Square weakKingSq = pos.square<KING>(weakSide);
|
| 651 |
-
|
| 652 |
-
// Case 1: Defending king blocks the pawn, and cannot be driven away
|
| 653 |
-
if ( file_of(weakKingSq) == file_of(pawnSq)
|
| 654 |
-
&& relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq)
|
| 655 |
-
&& ( opposite_colors(weakKingSq, strongBishopSq)
|
| 656 |
-
|| relative_rank(strongSide, weakKingSq) <= RANK_6))
|
| 657 |
-
return SCALE_FACTOR_DRAW;
|
| 658 |
-
|
| 659 |
-
// Case 2: Opposite colored bishops
|
| 660 |
-
if (opposite_colors(strongBishopSq, weakBishopSq))
|
| 661 |
-
{
|
| 662 |
-
// We assume that the position is drawn in the following three situations:
|
| 663 |
-
//
|
| 664 |
-
// a. The pawn is on rank 5 or further back.
|
| 665 |
-
// b. The defending king is somewhere in the pawn's path.
|
| 666 |
-
// c. The defending bishop attacks some square along the pawn's path,
|
| 667 |
-
// and is at least three squares away from the pawn.
|
| 668 |
-
//
|
| 669 |
-
// These rules are probably not perfect, but in practice they work
|
| 670 |
-
// reasonably well.
|
| 671 |
-
|
| 672 |
-
if (relative_rank(strongSide, pawnSq) <= RANK_5)
|
| 673 |
-
return SCALE_FACTOR_DRAW;
|
| 674 |
-
else
|
| 675 |
-
{
|
| 676 |
-
Bitboard path = forward_bb(strongSide, pawnSq);
|
| 677 |
-
|
| 678 |
-
if (path & pos.pieces(weakSide, KING))
|
| 679 |
-
return SCALE_FACTOR_DRAW;
|
| 680 |
-
|
| 681 |
-
if ( (pos.attacks_from<BISHOP>(weakBishopSq) & path)
|
| 682 |
-
&& distance(weakBishopSq, pawnSq) >= 3)
|
| 683 |
-
return SCALE_FACTOR_DRAW;
|
| 684 |
-
}
|
| 685 |
-
}
|
| 686 |
-
return SCALE_FACTOR_NONE;
|
| 687 |
-
}
|
| 688 |
-
|
| 689 |
-
|
| 690 |
-
/// KBPP vs KB. It detects a few basic draws with opposite-colored bishops
|
| 691 |
-
template<>
|
| 692 |
-
ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
|
| 693 |
-
|
| 694 |
-
assert(verify_material(pos, strongSide, BishopValueMg, 2));
|
| 695 |
-
assert(verify_material(pos, weakSide, BishopValueMg, 0));
|
| 696 |
-
|
| 697 |
-
Square wbsq = pos.square<BISHOP>(strongSide);
|
| 698 |
-
Square bbsq = pos.square<BISHOP>(weakSide);
|
| 699 |
-
|
| 700 |
-
if (!opposite_colors(wbsq, bbsq))
|
| 701 |
-
return SCALE_FACTOR_NONE;
|
| 702 |
-
|
| 703 |
-
Square ksq = pos.square<KING>(weakSide);
|
| 704 |
-
Square psq1 = pos.squares<PAWN>(strongSide)[0];
|
| 705 |
-
Square psq2 = pos.squares<PAWN>(strongSide)[1];
|
| 706 |
-
Rank r1 = rank_of(psq1);
|
| 707 |
-
Rank r2 = rank_of(psq2);
|
| 708 |
-
Square blockSq1, blockSq2;
|
| 709 |
-
|
| 710 |
-
if (relative_rank(strongSide, psq1) > relative_rank(strongSide, psq2))
|
| 711 |
-
{
|
| 712 |
-
blockSq1 = psq1 + pawn_push(strongSide);
|
| 713 |
-
blockSq2 = make_square(file_of(psq2), rank_of(psq1));
|
| 714 |
-
}
|
| 715 |
-
else
|
| 716 |
-
{
|
| 717 |
-
blockSq1 = psq2 + pawn_push(strongSide);
|
| 718 |
-
blockSq2 = make_square(file_of(psq1), rank_of(psq2));
|
| 719 |
-
}
|
| 720 |
-
|
| 721 |
-
switch (distance<File>(psq1, psq2))
|
| 722 |
-
{
|
| 723 |
-
case 0:
|
| 724 |
-
// Both pawns are on the same file. It's an easy draw if the defender firmly
|
| 725 |
-
// controls some square in the frontmost pawn's path.
|
| 726 |
-
if ( file_of(ksq) == file_of(blockSq1)
|
| 727 |
-
&& relative_rank(strongSide, ksq) >= relative_rank(strongSide, blockSq1)
|
| 728 |
-
&& opposite_colors(ksq, wbsq))
|
| 729 |
-
return SCALE_FACTOR_DRAW;
|
| 730 |
-
else
|
| 731 |
-
return SCALE_FACTOR_NONE;
|
| 732 |
-
|
| 733 |
-
case 1:
|
| 734 |
-
// Pawns on adjacent files. It's a draw if the defender firmly controls the
|
| 735 |
-
// square in front of the frontmost pawn's path, and the square diagonally
|
| 736 |
-
// behind this square on the file of the other pawn.
|
| 737 |
-
if ( ksq == blockSq1
|
| 738 |
-
&& opposite_colors(ksq, wbsq)
|
| 739 |
-
&& ( bbsq == blockSq2
|
| 740 |
-
|| (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(weakSide, BISHOP))
|
| 741 |
-
|| distance(r1, r2) >= 2))
|
| 742 |
-
return SCALE_FACTOR_DRAW;
|
| 743 |
-
|
| 744 |
-
else if ( ksq == blockSq2
|
| 745 |
-
&& opposite_colors(ksq, wbsq)
|
| 746 |
-
&& ( bbsq == blockSq1
|
| 747 |
-
|| (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(weakSide, BISHOP))))
|
| 748 |
-
return SCALE_FACTOR_DRAW;
|
| 749 |
-
else
|
| 750 |
-
return SCALE_FACTOR_NONE;
|
| 751 |
-
|
| 752 |
-
default:
|
| 753 |
-
// The pawns are not on the same file or adjacent files. No scaling.
|
| 754 |
-
return SCALE_FACTOR_NONE;
|
| 755 |
-
}
|
| 756 |
-
}
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
/// KBP vs KN. There is a single rule: If the defending king is somewhere along
|
| 760 |
-
/// the path of the pawn, and the square of the king is not of the same color as
|
| 761 |
-
/// the stronger side's bishop, it's a draw.
|
| 762 |
-
template<>
|
| 763 |
-
ScaleFactor Endgame<KBPKN>::operator()(const Position& pos) const {
|
| 764 |
-
|
| 765 |
-
assert(verify_material(pos, strongSide, BishopValueMg, 1));
|
| 766 |
-
assert(verify_material(pos, weakSide, KnightValueMg, 0));
|
| 767 |
-
|
| 768 |
-
Square pawnSq = pos.square<PAWN>(strongSide);
|
| 769 |
-
Square strongBishopSq = pos.square<BISHOP>(strongSide);
|
| 770 |
-
Square weakKingSq = pos.square<KING>(weakSide);
|
| 771 |
-
|
| 772 |
-
if ( file_of(weakKingSq) == file_of(pawnSq)
|
| 773 |
-
&& relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq)
|
| 774 |
-
&& ( opposite_colors(weakKingSq, strongBishopSq)
|
| 775 |
-
|| relative_rank(strongSide, weakKingSq) <= RANK_6))
|
| 776 |
-
return SCALE_FACTOR_DRAW;
|
| 777 |
-
|
| 778 |
-
return SCALE_FACTOR_NONE;
|
| 779 |
-
}
|
| 780 |
-
|
| 781 |
-
|
| 782 |
-
/// KNP vs K. There is a single rule: if the pawn is a rook pawn on the 7th rank
|
| 783 |
-
/// and the defending king prevents the pawn from advancing, the position is drawn.
|
| 784 |
-
template<>
|
| 785 |
-
ScaleFactor Endgame<KNPK>::operator()(const Position& pos) const {
|
| 786 |
-
|
| 787 |
-
assert(verify_material(pos, strongSide, KnightValueMg, 1));
|
| 788 |
-
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
|
| 789 |
-
|
| 790 |
-
// Assume strongSide is white and the pawn is on files A-D
|
| 791 |
-
Square pawnSq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
| 792 |
-
Square weakKingSq = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
| 793 |
-
|
| 794 |
-
if (pawnSq == SQ_A7 && distance(SQ_A8, weakKingSq) <= 1)
|
| 795 |
-
return SCALE_FACTOR_DRAW;
|
| 796 |
-
|
| 797 |
-
return SCALE_FACTOR_NONE;
|
| 798 |
-
}
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
/// KNP vs KB. If knight can block bishop from taking pawn, it's a win.
|
| 802 |
-
/// Otherwise the position is drawn.
|
| 803 |
-
template<>
|
| 804 |
-
ScaleFactor Endgame<KNPKB>::operator()(const Position& pos) const {
|
| 805 |
-
|
| 806 |
-
Square pawnSq = pos.square<PAWN>(strongSide);
|
| 807 |
-
Square bishopSq = pos.square<BISHOP>(weakSide);
|
| 808 |
-
Square weakKingSq = pos.square<KING>(weakSide);
|
| 809 |
-
|
| 810 |
-
// King needs to get close to promoting pawn to prevent knight from blocking.
|
| 811 |
-
// Rules for this are very tricky, so just approximate.
|
| 812 |
-
if (forward_bb(strongSide, pawnSq) & pos.attacks_from<BISHOP>(bishopSq))
|
| 813 |
-
return ScaleFactor(distance(weakKingSq, pawnSq));
|
| 814 |
-
|
| 815 |
-
return SCALE_FACTOR_NONE;
|
| 816 |
-
}
|
| 817 |
-
|
| 818 |
-
|
| 819 |
-
/// KP vs KP. This is done by removing the weakest side's pawn and probing the
|
| 820 |
-
/// KP vs K bitbase: If the weakest side has a draw without the pawn, it probably
|
| 821 |
-
/// has at least a draw with the pawn as well. The exception is when the stronger
|
| 822 |
-
/// side's pawn is far advanced and not on a rook file; in this case it is often
|
| 823 |
-
/// possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
|
| 824 |
-
template<>
|
| 825 |
-
ScaleFactor Endgame<KPKP>::operator()(const Position& pos) const {
|
| 826 |
-
|
| 827 |
-
assert(verify_material(pos, strongSide, VALUE_ZERO, 1));
|
| 828 |
-
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
|
| 829 |
-
|
| 830 |
-
// Assume strongSide is white and the pawn is on files A-D
|
| 831 |
-
Square wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
|
| 832 |
-
Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
|
| 833 |
-
Square psq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
|
| 834 |
-
|
| 835 |
-
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
|
| 836 |
-
|
| 837 |
-
// If the pawn has advanced to the fifth rank or further, and is not a
|
| 838 |
-
// rook pawn, it's too dangerous to assume that it's at least a draw.
|
| 839 |
-
if (rank_of(psq) >= RANK_5 && file_of(psq) != FILE_A)
|
| 840 |
-
return SCALE_FACTOR_NONE;
|
| 841 |
-
|
| 842 |
-
// Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw,
|
| 843 |
-
// it's probably at least a draw even with the pawn.
|
| 844 |
-
return Bitbases::probe(wksq, psq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;
|
| 845 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/endgame.h
DELETED
|
@@ -1,125 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef ENDGAME_H_INCLUDED
|
| 22 |
-
#define ENDGAME_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include <map>
|
| 25 |
-
#include <memory>
|
| 26 |
-
#include <string>
|
| 27 |
-
#include <type_traits>
|
| 28 |
-
#include <utility>
|
| 29 |
-
|
| 30 |
-
#include "position.h"
|
| 31 |
-
#include "types.h"
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
/// EndgameType lists all supported endgames
|
| 35 |
-
|
| 36 |
-
enum EndgameType {
|
| 37 |
-
|
| 38 |
-
// Evaluation functions
|
| 39 |
-
|
| 40 |
-
KNNK, // KNN vs K
|
| 41 |
-
KXK, // Generic "mate lone king" eval
|
| 42 |
-
KBNK, // KBN vs K
|
| 43 |
-
KPK, // KP vs K
|
| 44 |
-
KRKP, // KR vs KP
|
| 45 |
-
KRKB, // KR vs KB
|
| 46 |
-
KRKN, // KR vs KN
|
| 47 |
-
KQKP, // KQ vs KP
|
| 48 |
-
KQKR, // KQ vs KR
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
// Scaling functions
|
| 52 |
-
SCALING_FUNCTIONS,
|
| 53 |
-
|
| 54 |
-
KBPsK, // KB and pawns vs K
|
| 55 |
-
KQKRPs, // KQ vs KR and pawns
|
| 56 |
-
KRPKR, // KRP vs KR
|
| 57 |
-
KRPKB, // KRP vs KB
|
| 58 |
-
KRPPKRP, // KRPP vs KRP
|
| 59 |
-
KPsK, // K and pawns vs K
|
| 60 |
-
KBPKB, // KBP vs KB
|
| 61 |
-
KBPPKB, // KBPP vs KB
|
| 62 |
-
KBPKN, // KBP vs KN
|
| 63 |
-
KNPK, // KNP vs K
|
| 64 |
-
KNPKB, // KNP vs KB
|
| 65 |
-
KPKP // KP vs KP
|
| 66 |
-
};
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
/// Endgame functions can be of two types depending on whether they return a
|
| 70 |
-
/// Value or a ScaleFactor.
|
| 71 |
-
template<EndgameType E> using
|
| 72 |
-
eg_type = typename std::conditional<(E < SCALING_FUNCTIONS), Value, ScaleFactor>::type;
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
/// Base and derived templates for endgame evaluation and scaling functions
|
| 76 |
-
|
| 77 |
-
template<typename T>
|
| 78 |
-
struct EndgameBase {
|
| 79 |
-
|
| 80 |
-
virtual ~EndgameBase() = default;
|
| 81 |
-
virtual Color strong_side() const = 0;
|
| 82 |
-
virtual T operator()(const Position&) const = 0;
|
| 83 |
-
};
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
template<EndgameType E, typename T = eg_type<E>>
|
| 87 |
-
struct Endgame : public EndgameBase<T> {
|
| 88 |
-
|
| 89 |
-
explicit Endgame(Color c) : strongSide(c), weakSide(~c) {}
|
| 90 |
-
Color strong_side() const { return strongSide; }
|
| 91 |
-
T operator()(const Position&) const;
|
| 92 |
-
|
| 93 |
-
private:
|
| 94 |
-
Color strongSide, weakSide;
|
| 95 |
-
};
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
/// The Endgames class stores the pointers to endgame evaluation and scaling
|
| 99 |
-
/// base objects in two std::map. We use polymorphism to invoke the actual
|
| 100 |
-
/// endgame function by calling its virtual operator().
|
| 101 |
-
|
| 102 |
-
class Endgames {
|
| 103 |
-
|
| 104 |
-
template<typename T> using Map = std::map<Key, std::unique_ptr<EndgameBase<T>>>;
|
| 105 |
-
|
| 106 |
-
template<EndgameType E, typename T = eg_type<E>>
|
| 107 |
-
void add(const std::string& code);
|
| 108 |
-
|
| 109 |
-
template<typename T>
|
| 110 |
-
Map<T>& map() {
|
| 111 |
-
return std::get<std::is_same<T, ScaleFactor>::value>(maps);
|
| 112 |
-
}
|
| 113 |
-
|
| 114 |
-
std::pair<Map<Value>, Map<ScaleFactor>> maps;
|
| 115 |
-
|
| 116 |
-
public:
|
| 117 |
-
Endgames();
|
| 118 |
-
|
| 119 |
-
template<typename T>
|
| 120 |
-
EndgameBase<T>* probe(Key key) {
|
| 121 |
-
return map<T>().count(key) ? map<T>()[key].get() : nullptr;
|
| 122 |
-
}
|
| 123 |
-
};
|
| 124 |
-
|
| 125 |
-
#endif // #ifndef ENDGAME_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/evaluate.cpp
DELETED
|
@@ -1,927 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm>
|
| 22 |
-
#include <cassert>
|
| 23 |
-
#include <cstring> // For std::memset
|
| 24 |
-
#include <iomanip>
|
| 25 |
-
#include <sstream>
|
| 26 |
-
|
| 27 |
-
#include "bitboard.h"
|
| 28 |
-
#include "evaluate.h"
|
| 29 |
-
#include "material.h"
|
| 30 |
-
#include "pawns.h"
|
| 31 |
-
|
| 32 |
-
namespace {
|
| 33 |
-
|
| 34 |
-
namespace Trace {
|
| 35 |
-
|
| 36 |
-
enum Term { // The first 8 entries are for PieceType
|
| 37 |
-
MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERM_NB
|
| 38 |
-
};
|
| 39 |
-
|
| 40 |
-
double scores[TERM_NB][COLOR_NB][PHASE_NB];
|
| 41 |
-
|
| 42 |
-
double to_cp(Value v) { return double(v) / PawnValueEg; }
|
| 43 |
-
|
| 44 |
-
void add(int idx, Color c, Score s) {
|
| 45 |
-
scores[idx][c][MG] = to_cp(mg_value(s));
|
| 46 |
-
scores[idx][c][EG] = to_cp(eg_value(s));
|
| 47 |
-
}
|
| 48 |
-
|
| 49 |
-
void add(int idx, Score w, Score b = SCORE_ZERO) {
|
| 50 |
-
add(idx, WHITE, w); add(idx, BLACK, b);
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
std::ostream& operator<<(std::ostream& os, Term t) {
|
| 54 |
-
|
| 55 |
-
if (t == MATERIAL || t == IMBALANCE || t == Term(PAWN) || t == TOTAL)
|
| 56 |
-
os << " --- --- | --- --- | ";
|
| 57 |
-
else
|
| 58 |
-
os << std::setw(5) << scores[t][WHITE][MG] << " "
|
| 59 |
-
<< std::setw(5) << scores[t][WHITE][EG] << " | "
|
| 60 |
-
<< std::setw(5) << scores[t][BLACK][MG] << " "
|
| 61 |
-
<< std::setw(5) << scores[t][BLACK][EG] << " | ";
|
| 62 |
-
|
| 63 |
-
os << std::setw(5) << scores[t][WHITE][MG] - scores[t][BLACK][MG] << " "
|
| 64 |
-
<< std::setw(5) << scores[t][WHITE][EG] - scores[t][BLACK][EG] << " \n";
|
| 65 |
-
|
| 66 |
-
return os;
|
| 67 |
-
}
|
| 68 |
-
}
|
| 69 |
-
|
| 70 |
-
using namespace Trace;
|
| 71 |
-
|
| 72 |
-
// Struct EvalInfo contains various information computed and collected
|
| 73 |
-
// by the evaluation functions.
|
| 74 |
-
struct EvalInfo {
|
| 75 |
-
|
| 76 |
-
// attackedBy[color][piece type] is a bitboard representing all squares
|
| 77 |
-
// attacked by a given color and piece type (can be also ALL_PIECES).
|
| 78 |
-
Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
|
| 79 |
-
|
| 80 |
-
// attackedBy2[color] are the squares attacked by 2 pieces of a given color,
|
| 81 |
-
// possibly via x-ray or by one pawn and one piece. Diagonal x-ray through
|
| 82 |
-
// pawn or squares attacked by 2 pawns are not explicitly added.
|
| 83 |
-
Bitboard attackedBy2[COLOR_NB];
|
| 84 |
-
|
| 85 |
-
// kingRing[color] is the zone around the king which is considered
|
| 86 |
-
// by the king safety evaluation. This consists of the squares directly
|
| 87 |
-
// adjacent to the king, and the three (or two, for a king on an edge file)
|
| 88 |
-
// squares two ranks in front of the king. For instance, if black's king
|
| 89 |
-
// is on g8, kingRing[BLACK] is a bitboard containing the squares f8, h8,
|
| 90 |
-
// f7, g7, h7, f6, g6 and h6.
|
| 91 |
-
Bitboard kingRing[COLOR_NB];
|
| 92 |
-
|
| 93 |
-
// kingAttackersCount[color] is the number of pieces of the given color
|
| 94 |
-
// which attack a square in the kingRing of the enemy king.
|
| 95 |
-
int kingAttackersCount[COLOR_NB];
|
| 96 |
-
|
| 97 |
-
// kingAttackersWeight[color] is the sum of the "weights" of the pieces of the
|
| 98 |
-
// given color which attack a square in the kingRing of the enemy king. The
|
| 99 |
-
// weights of the individual piece types are given by the elements in the
|
| 100 |
-
// KingAttackWeights array.
|
| 101 |
-
int kingAttackersWeight[COLOR_NB];
|
| 102 |
-
|
| 103 |
-
// kingAdjacentZoneAttacksCount[color] is the number of attacks by the given
|
| 104 |
-
// color to squares directly adjacent to the enemy king. Pieces which attack
|
| 105 |
-
// more than one square are counted multiple times. For instance, if there is
|
| 106 |
-
// a white knight on g5 and black's king is on g8, this white knight adds 2
|
| 107 |
-
// to kingAdjacentZoneAttacksCount[WHITE].
|
| 108 |
-
int kingAdjacentZoneAttacksCount[COLOR_NB];
|
| 109 |
-
|
| 110 |
-
Bitboard pinnedPieces[COLOR_NB];
|
| 111 |
-
Material::Entry* me;
|
| 112 |
-
Pawns::Entry* pi;
|
| 113 |
-
};
|
| 114 |
-
|
| 115 |
-
#define V(v) Value(v)
|
| 116 |
-
#define S(mg, eg) make_score(mg, eg)
|
| 117 |
-
|
| 118 |
-
// MobilityBonus[PieceType][attacked] contains bonuses for middle and end
|
| 119 |
-
// game, indexed by piece type and number of attacked squares in the MobilityArea.
|
| 120 |
-
const Score MobilityBonus[][32] = {
|
| 121 |
-
{}, {},
|
| 122 |
-
{ S(-75,-76), S(-56,-54), S( -9,-26), S( -2,-10), S( 6, 5), S( 15, 11), // Knights
|
| 123 |
-
S( 22, 26), S( 30, 28), S( 36, 29) },
|
| 124 |
-
{ S(-48,-58), S(-21,-19), S( 16, -2), S( 26, 12), S( 37, 22), S( 51, 42), // Bishops
|
| 125 |
-
S( 54, 54), S( 63, 58), S( 65, 63), S( 71, 70), S( 79, 74), S( 81, 86),
|
| 126 |
-
S( 92, 90), S( 97, 94) },
|
| 127 |
-
{ S(-56,-78), S(-25,-18), S(-11, 26), S( -5, 55), S( -4, 70), S( -1, 81), // Rooks
|
| 128 |
-
S( 8,109), S( 14,120), S( 21,128), S( 23,143), S( 31,154), S( 32,160),
|
| 129 |
-
S( 43,165), S( 49,168), S( 59,169) },
|
| 130 |
-
{ S(-40,-35), S(-25,-12), S( 2, 7), S( 4, 19), S( 14, 37), S( 24, 55), // Queens
|
| 131 |
-
S( 25, 62), S( 40, 76), S( 43, 79), S( 47, 87), S( 54, 94), S( 56,102),
|
| 132 |
-
S( 60,111), S( 70,116), S( 72,118), S( 73,122), S( 75,128), S( 77,130),
|
| 133 |
-
S( 85,133), S( 94,136), S( 99,140), S(108,157), S(112,158), S(113,161),
|
| 134 |
-
S(118,174), S(119,177), S(123,191), S(128,199) }
|
| 135 |
-
};
|
| 136 |
-
|
| 137 |
-
// Outpost[knight/bishop][supported by pawn] contains bonuses for knights and
|
| 138 |
-
// bishops outposts, bigger if outpost piece is supported by a pawn.
|
| 139 |
-
const Score Outpost[][2] = {
|
| 140 |
-
{ S(43,11), S(65,20) }, // Knights
|
| 141 |
-
{ S(20, 3), S(29, 8) } // Bishops
|
| 142 |
-
};
|
| 143 |
-
|
| 144 |
-
// ReachableOutpost[knight/bishop][supported by pawn] contains bonuses for
|
| 145 |
-
// knights and bishops which can reach an outpost square in one move, bigger
|
| 146 |
-
// if outpost square is supported by a pawn.
|
| 147 |
-
const Score ReachableOutpost[][2] = {
|
| 148 |
-
{ S(21, 5), S(35, 8) }, // Knights
|
| 149 |
-
{ S( 8, 0), S(14, 4) } // Bishops
|
| 150 |
-
};
|
| 151 |
-
|
| 152 |
-
// RookOnFile[semiopen/open] contains bonuses for each rook when there is no
|
| 153 |
-
// friendly pawn on the rook file.
|
| 154 |
-
const Score RookOnFile[2] = { S(20, 7), S(45, 20) };
|
| 155 |
-
|
| 156 |
-
// ThreatBySafePawn[PieceType] contains bonuses according to which piece
|
| 157 |
-
// type is attacked by a pawn which is protected or is not attacked.
|
| 158 |
-
const Score ThreatBySafePawn[PIECE_TYPE_NB] = {
|
| 159 |
-
S(0, 0), S(0, 0), S(176, 139), S(131, 127), S(217, 218), S(203, 215)
|
| 160 |
-
};
|
| 161 |
-
|
| 162 |
-
// Threat[by minor/by rook][attacked PieceType] contains
|
| 163 |
-
// bonuses according to which piece type attacks which one.
|
| 164 |
-
// Attacks on lesser pieces which are pawn-defended are not considered.
|
| 165 |
-
const Score Threat[][PIECE_TYPE_NB] = {
|
| 166 |
-
{ S(0, 0), S(0, 33), S(45, 43), S(46, 47), S(72,107), S(48,118) }, // by Minor
|
| 167 |
-
{ S(0, 0), S(0, 25), S(40, 62), S(40, 59), S( 0, 34), S(35, 48) } // by Rook
|
| 168 |
-
};
|
| 169 |
-
|
| 170 |
-
// ThreatByKing[on one/on many] contains bonuses for King attacks on
|
| 171 |
-
// pawns or pieces which are not pawn-defended.
|
| 172 |
-
const Score ThreatByKing[2] = { S(3, 62), S(9, 138) };
|
| 173 |
-
|
| 174 |
-
// Passed[mg/eg][Rank] contains midgame and endgame bonuses for passed pawns.
|
| 175 |
-
// We don't use a Score because we process the two components independently.
|
| 176 |
-
const Value Passed[][RANK_NB] = {
|
| 177 |
-
{ V(5), V( 5), V(31), V(73), V(166), V(252) },
|
| 178 |
-
{ V(7), V(14), V(38), V(73), V(166), V(252) }
|
| 179 |
-
};
|
| 180 |
-
|
| 181 |
-
// PassedFile[File] contains a bonus according to the file of a passed pawn
|
| 182 |
-
const Score PassedFile[FILE_NB] = {
|
| 183 |
-
S( 9, 10), S( 2, 10), S( 1, -8), S(-20,-12),
|
| 184 |
-
S(-20,-12), S( 1, -8), S( 2, 10), S( 9, 10)
|
| 185 |
-
};
|
| 186 |
-
|
| 187 |
-
// Assorted bonuses and penalties used by evaluation
|
| 188 |
-
const Score MinorBehindPawn = S(16, 0);
|
| 189 |
-
const Score BishopPawns = S( 8, 12);
|
| 190 |
-
const Score RookOnPawn = S( 8, 24);
|
| 191 |
-
const Score TrappedRook = S(92, 0);
|
| 192 |
-
const Score CloseEnemies = S( 7, 0);
|
| 193 |
-
const Score SafeCheck = S(20, 20);
|
| 194 |
-
const Score OtherCheck = S(10, 10);
|
| 195 |
-
const Score ThreatByHangingPawn = S(71, 61);
|
| 196 |
-
const Score LooseEnemies = S( 0, 25);
|
| 197 |
-
const Score WeakQueen = S(35, 0);
|
| 198 |
-
const Score Hanging = S(48, 27);
|
| 199 |
-
const Score ThreatByPawnPush = S(38, 22);
|
| 200 |
-
const Score Unstoppable = S( 0, 20);
|
| 201 |
-
const Score PawnlessFlank = S(20, 80);
|
| 202 |
-
const Score HinderPassedPawn = S( 7, 0);
|
| 203 |
-
|
| 204 |
-
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
|
| 205 |
-
// a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
|
| 206 |
-
// happen in Chess960 games.
|
| 207 |
-
const Score TrappedBishopA1H1 = S(50, 50);
|
| 208 |
-
|
| 209 |
-
#undef S
|
| 210 |
-
#undef V
|
| 211 |
-
|
| 212 |
-
// KingAttackWeights[PieceType] contains king attack weights by piece type
|
| 213 |
-
const int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 78, 56, 45, 11 };
|
| 214 |
-
|
| 215 |
-
// Penalties for enemy's safe checks
|
| 216 |
-
const int QueenContactCheck = 997;
|
| 217 |
-
const int QueenCheck = 695;
|
| 218 |
-
const int RookCheck = 638;
|
| 219 |
-
const int BishopCheck = 538;
|
| 220 |
-
const int KnightCheck = 874;
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
// eval_init() initializes king and attack bitboards for a given color
|
| 224 |
-
// adding pawn attacks. To be done at the beginning of the evaluation.
|
| 225 |
-
|
| 226 |
-
template<Color Us>
|
| 227 |
-
void eval_init(const Position& pos, EvalInfo& ei) {
|
| 228 |
-
|
| 229 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 230 |
-
const Square Down = (Us == WHITE ? SOUTH : NORTH);
|
| 231 |
-
|
| 232 |
-
ei.pinnedPieces[Us] = pos.pinned_pieces(Us);
|
| 233 |
-
Bitboard b = ei.attackedBy[Them][KING];
|
| 234 |
-
ei.attackedBy[Them][ALL_PIECES] |= b;
|
| 235 |
-
ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
|
| 236 |
-
ei.attackedBy2[Us] = ei.attackedBy[Us][PAWN] & ei.attackedBy[Us][KING];
|
| 237 |
-
|
| 238 |
-
// Init king safety tables only if we are going to use them
|
| 239 |
-
if (pos.non_pawn_material(Us) >= QueenValueMg)
|
| 240 |
-
{
|
| 241 |
-
ei.kingRing[Them] = b | shift<Down>(b);
|
| 242 |
-
b &= ei.attackedBy[Us][PAWN];
|
| 243 |
-
ei.kingAttackersCount[Us] = popcount(b);
|
| 244 |
-
ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
|
| 245 |
-
}
|
| 246 |
-
else
|
| 247 |
-
ei.kingRing[Them] = ei.kingAttackersCount[Us] = 0;
|
| 248 |
-
}
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
// evaluate_pieces() assigns bonuses and penalties to the pieces of a given
|
| 252 |
-
// color and type.
|
| 253 |
-
|
| 254 |
-
template<bool DoTrace, Color Us = WHITE, PieceType Pt = KNIGHT>
|
| 255 |
-
Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility,
|
| 256 |
-
const Bitboard* mobilityArea) {
|
| 257 |
-
Bitboard b, bb;
|
| 258 |
-
Square s;
|
| 259 |
-
Score score = SCORE_ZERO;
|
| 260 |
-
|
| 261 |
-
const PieceType NextPt = (Us == WHITE ? Pt : PieceType(Pt + 1));
|
| 262 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 263 |
-
const Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB
|
| 264 |
-
: Rank5BB | Rank4BB | Rank3BB);
|
| 265 |
-
const Square* pl = pos.squares<Pt>(Us);
|
| 266 |
-
|
| 267 |
-
ei.attackedBy[Us][Pt] = 0;
|
| 268 |
-
|
| 269 |
-
while ((s = *pl++) != SQ_NONE)
|
| 270 |
-
{
|
| 271 |
-
// Find attacked squares, including x-ray attacks for bishops and rooks
|
| 272 |
-
b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(Us, QUEEN))
|
| 273 |
-
: Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(Us, ROOK, QUEEN))
|
| 274 |
-
: pos.attacks_from<Pt>(s);
|
| 275 |
-
|
| 276 |
-
if (ei.pinnedPieces[Us] & s)
|
| 277 |
-
b &= LineBB[pos.square<KING>(Us)][s];
|
| 278 |
-
|
| 279 |
-
ei.attackedBy2[Us] |= ei.attackedBy[Us][ALL_PIECES] & b;
|
| 280 |
-
ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][Pt] |= b;
|
| 281 |
-
|
| 282 |
-
if (b & ei.kingRing[Them])
|
| 283 |
-
{
|
| 284 |
-
ei.kingAttackersCount[Us]++;
|
| 285 |
-
ei.kingAttackersWeight[Us] += KingAttackWeights[Pt];
|
| 286 |
-
ei.kingAdjacentZoneAttacksCount[Us] += popcount(b & ei.attackedBy[Them][KING]);
|
| 287 |
-
}
|
| 288 |
-
|
| 289 |
-
if (Pt == QUEEN)
|
| 290 |
-
b &= ~( ei.attackedBy[Them][KNIGHT]
|
| 291 |
-
| ei.attackedBy[Them][BISHOP]
|
| 292 |
-
| ei.attackedBy[Them][ROOK]);
|
| 293 |
-
|
| 294 |
-
int mob = popcount(b & mobilityArea[Us]);
|
| 295 |
-
|
| 296 |
-
mobility[Us] += MobilityBonus[Pt][mob];
|
| 297 |
-
|
| 298 |
-
if (Pt == BISHOP || Pt == KNIGHT)
|
| 299 |
-
{
|
| 300 |
-
// Bonus for outpost squares
|
| 301 |
-
bb = OutpostRanks & ~ei.pi->pawn_attacks_span(Them);
|
| 302 |
-
if (bb & s)
|
| 303 |
-
score += Outpost[Pt == BISHOP][!!(ei.attackedBy[Us][PAWN] & s)];
|
| 304 |
-
else
|
| 305 |
-
{
|
| 306 |
-
bb &= b & ~pos.pieces(Us);
|
| 307 |
-
if (bb)
|
| 308 |
-
score += ReachableOutpost[Pt == BISHOP][!!(ei.attackedBy[Us][PAWN] & bb)];
|
| 309 |
-
}
|
| 310 |
-
|
| 311 |
-
// Bonus when behind a pawn
|
| 312 |
-
if ( relative_rank(Us, s) < RANK_5
|
| 313 |
-
&& (pos.pieces(PAWN) & (s + pawn_push(Us))))
|
| 314 |
-
score += MinorBehindPawn;
|
| 315 |
-
|
| 316 |
-
// Penalty for pawns on the same color square as the bishop
|
| 317 |
-
if (Pt == BISHOP)
|
| 318 |
-
score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
|
| 319 |
-
|
| 320 |
-
// An important Chess960 pattern: A cornered bishop blocked by a friendly
|
| 321 |
-
// pawn diagonally in front of it is a very serious problem, especially
|
| 322 |
-
// when that pawn is also blocked.
|
| 323 |
-
if ( Pt == BISHOP
|
| 324 |
-
&& pos.is_chess960()
|
| 325 |
-
&& (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
|
| 326 |
-
{
|
| 327 |
-
Square d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST);
|
| 328 |
-
if (pos.piece_on(s + d) == make_piece(Us, PAWN))
|
| 329 |
-
score -= !pos.empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
|
| 330 |
-
: pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2
|
| 331 |
-
: TrappedBishopA1H1;
|
| 332 |
-
}
|
| 333 |
-
}
|
| 334 |
-
|
| 335 |
-
if (Pt == ROOK)
|
| 336 |
-
{
|
| 337 |
-
// Bonus for aligning with enemy pawns on the same rank/file
|
| 338 |
-
if (relative_rank(Us, s) >= RANK_5)
|
| 339 |
-
score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s]);
|
| 340 |
-
|
| 341 |
-
// Bonus when on an open or semi-open file
|
| 342 |
-
if (ei.pi->semiopen_file(Us, file_of(s)))
|
| 343 |
-
score += RookOnFile[!!ei.pi->semiopen_file(Them, file_of(s))];
|
| 344 |
-
|
| 345 |
-
// Penalize when trapped by the king, even more if the king cannot castle
|
| 346 |
-
else if (mob <= 3)
|
| 347 |
-
{
|
| 348 |
-
Square ksq = pos.square<KING>(Us);
|
| 349 |
-
|
| 350 |
-
if ( ((file_of(ksq) < FILE_E) == (file_of(s) < file_of(ksq)))
|
| 351 |
-
&& (rank_of(ksq) == rank_of(s) || relative_rank(Us, ksq) == RANK_1)
|
| 352 |
-
&& !ei.pi->semiopen_side(Us, file_of(ksq), file_of(s) < file_of(ksq)))
|
| 353 |
-
score -= (TrappedRook - make_score(mob * 22, 0)) * (1 + !pos.can_castle(Us));
|
| 354 |
-
}
|
| 355 |
-
}
|
| 356 |
-
|
| 357 |
-
if (Pt == QUEEN)
|
| 358 |
-
{
|
| 359 |
-
// Penalty if any relative pin or discovered attack against the queen
|
| 360 |
-
Bitboard pinners;
|
| 361 |
-
if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, pinners))
|
| 362 |
-
score -= WeakQueen;
|
| 363 |
-
}
|
| 364 |
-
}
|
| 365 |
-
|
| 366 |
-
if (DoTrace)
|
| 367 |
-
Trace::add(Pt, Us, score);
|
| 368 |
-
|
| 369 |
-
// Recursively call evaluate_pieces() of next piece type until KING is excluded
|
| 370 |
-
return score - evaluate_pieces<DoTrace, Them, NextPt>(pos, ei, mobility, mobilityArea);
|
| 371 |
-
}
|
| 372 |
-
|
| 373 |
-
template<>
|
| 374 |
-
Score evaluate_pieces<false, WHITE, KING>(const Position&, EvalInfo&, Score*, const Bitboard*) { return SCORE_ZERO; }
|
| 375 |
-
template<>
|
| 376 |
-
Score evaluate_pieces< true, WHITE, KING>(const Position&, EvalInfo&, Score*, const Bitboard*) { return SCORE_ZERO; }
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
// evaluate_king() assigns bonuses and penalties to a king of a given color
|
| 380 |
-
|
| 381 |
-
const Bitboard WhiteCamp = Rank1BB | Rank2BB | Rank3BB | Rank4BB | Rank5BB;
|
| 382 |
-
const Bitboard BlackCamp = Rank8BB | Rank7BB | Rank6BB | Rank5BB | Rank4BB;
|
| 383 |
-
const Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB;
|
| 384 |
-
const Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB;
|
| 385 |
-
const Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB;
|
| 386 |
-
|
| 387 |
-
const Bitboard KingFlank[COLOR_NB][FILE_NB] = {
|
| 388 |
-
{ QueenSide & WhiteCamp, QueenSide & WhiteCamp, QueenSide & WhiteCamp, CenterFiles & WhiteCamp,
|
| 389 |
-
CenterFiles & WhiteCamp, KingSide & WhiteCamp, KingSide & WhiteCamp, KingSide & WhiteCamp },
|
| 390 |
-
{ QueenSide & BlackCamp, QueenSide & BlackCamp, QueenSide & BlackCamp, CenterFiles & BlackCamp,
|
| 391 |
-
CenterFiles & BlackCamp, KingSide & BlackCamp, KingSide & BlackCamp, KingSide & BlackCamp },
|
| 392 |
-
};
|
| 393 |
-
|
| 394 |
-
template<Color Us, bool DoTrace>
|
| 395 |
-
Score evaluate_king(const Position& pos, const EvalInfo& ei) {
|
| 396 |
-
|
| 397 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 398 |
-
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
| 399 |
-
|
| 400 |
-
Bitboard undefended, b, b1, b2, safe, other;
|
| 401 |
-
int kingDanger;
|
| 402 |
-
const Square ksq = pos.square<KING>(Us);
|
| 403 |
-
|
| 404 |
-
// King shelter and enemy pawns storm
|
| 405 |
-
Score score = ei.pi->king_safety<Us>(pos, ksq);
|
| 406 |
-
|
| 407 |
-
// Main king safety evaluation
|
| 408 |
-
if (ei.kingAttackersCount[Them])
|
| 409 |
-
{
|
| 410 |
-
// Find the attacked squares which are defended only by the king...
|
| 411 |
-
undefended = ei.attackedBy[Them][ALL_PIECES]
|
| 412 |
-
& ei.attackedBy[Us][KING]
|
| 413 |
-
& ~ei.attackedBy2[Us];
|
| 414 |
-
|
| 415 |
-
// ... and those which are not defended at all in the larger king ring
|
| 416 |
-
b = ei.attackedBy[Them][ALL_PIECES] & ~ei.attackedBy[Us][ALL_PIECES]
|
| 417 |
-
& ei.kingRing[Us] & ~pos.pieces(Them);
|
| 418 |
-
|
| 419 |
-
// Initialize the 'kingDanger' variable, which will be transformed
|
| 420 |
-
// later into a king danger score. The initial value is based on the
|
| 421 |
-
// number and types of the enemy's attacking pieces, the number of
|
| 422 |
-
// attacked and undefended squares around our king and the quality of
|
| 423 |
-
// the pawn shelter (current 'score' value).
|
| 424 |
-
kingDanger = std::min(807, ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them])
|
| 425 |
-
+ 101 * ei.kingAdjacentZoneAttacksCount[Them]
|
| 426 |
-
+ 235 * popcount(undefended)
|
| 427 |
-
+ 134 * (popcount(b) + !!ei.pinnedPieces[Us])
|
| 428 |
-
- 717 * !pos.count<QUEEN>(Them)
|
| 429 |
-
- 7 * mg_value(score) / 5 - 5;
|
| 430 |
-
|
| 431 |
-
// Analyse the enemy's safe queen contact checks. Firstly, find the
|
| 432 |
-
// undefended squares around the king reachable by the enemy queen...
|
| 433 |
-
b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces(Them);
|
| 434 |
-
|
| 435 |
-
// ...and keep squares supported by another enemy piece
|
| 436 |
-
kingDanger += QueenContactCheck * popcount(b & ei.attackedBy2[Them]);
|
| 437 |
-
|
| 438 |
-
// Analyse the safe enemy's checks which are possible on next move...
|
| 439 |
-
safe = ~(ei.attackedBy[Us][ALL_PIECES] | pos.pieces(Them));
|
| 440 |
-
|
| 441 |
-
// ... and some other potential checks, only requiring the square to be
|
| 442 |
-
// safe from pawn-attacks, and not being occupied by a blocked pawn.
|
| 443 |
-
other = ~( ei.attackedBy[Us][PAWN]
|
| 444 |
-
| (pos.pieces(Them, PAWN) & shift<Up>(pos.pieces(PAWN))));
|
| 445 |
-
|
| 446 |
-
b1 = pos.attacks_from<ROOK >(ksq);
|
| 447 |
-
b2 = pos.attacks_from<BISHOP>(ksq);
|
| 448 |
-
|
| 449 |
-
// Enemy queen safe checks
|
| 450 |
-
if ((b1 | b2) & ei.attackedBy[Them][QUEEN] & safe)
|
| 451 |
-
kingDanger += QueenCheck, score -= SafeCheck;
|
| 452 |
-
|
| 453 |
-
// For other pieces, also consider the square safe if attacked twice,
|
| 454 |
-
// and only defended by a queen.
|
| 455 |
-
safe |= ei.attackedBy2[Them]
|
| 456 |
-
& ~(ei.attackedBy2[Us] | pos.pieces(Them))
|
| 457 |
-
& ei.attackedBy[Us][QUEEN];
|
| 458 |
-
|
| 459 |
-
// Enemy rooks safe and other checks
|
| 460 |
-
if (b1 & ei.attackedBy[Them][ROOK] & safe)
|
| 461 |
-
kingDanger += RookCheck, score -= SafeCheck;
|
| 462 |
-
|
| 463 |
-
else if (b1 & ei.attackedBy[Them][ROOK] & other)
|
| 464 |
-
score -= OtherCheck;
|
| 465 |
-
|
| 466 |
-
// Enemy bishops safe and other checks
|
| 467 |
-
if (b2 & ei.attackedBy[Them][BISHOP] & safe)
|
| 468 |
-
kingDanger += BishopCheck, score -= SafeCheck;
|
| 469 |
-
|
| 470 |
-
else if (b2 & ei.attackedBy[Them][BISHOP] & other)
|
| 471 |
-
score -= OtherCheck;
|
| 472 |
-
|
| 473 |
-
// Enemy knights safe and other checks
|
| 474 |
-
b = pos.attacks_from<KNIGHT>(ksq) & ei.attackedBy[Them][KNIGHT];
|
| 475 |
-
if (b & safe)
|
| 476 |
-
kingDanger += KnightCheck, score -= SafeCheck;
|
| 477 |
-
|
| 478 |
-
else if (b & other)
|
| 479 |
-
score -= OtherCheck;
|
| 480 |
-
|
| 481 |
-
// Compute the king danger score and subtract it from the evaluation
|
| 482 |
-
if (kingDanger > 0)
|
| 483 |
-
score -= make_score(std::min(kingDanger * kingDanger / 4096, 2 * int(BishopValueMg)), 0);
|
| 484 |
-
}
|
| 485 |
-
|
| 486 |
-
// King tropism: firstly, find squares that opponent attacks in our king flank
|
| 487 |
-
File kf = file_of(ksq);
|
| 488 |
-
b = ei.attackedBy[Them][ALL_PIECES] & KingFlank[Us][kf];
|
| 489 |
-
|
| 490 |
-
assert(((Us == WHITE ? b << 4 : b >> 4) & b) == 0);
|
| 491 |
-
assert(popcount(Us == WHITE ? b << 4 : b >> 4) == popcount(b));
|
| 492 |
-
|
| 493 |
-
// Secondly, add the squares which are attacked twice in that flank and
|
| 494 |
-
// which are not defended by our pawns.
|
| 495 |
-
b = (Us == WHITE ? b << 4 : b >> 4)
|
| 496 |
-
| (b & ei.attackedBy2[Them] & ~ei.attackedBy[Us][PAWN]);
|
| 497 |
-
|
| 498 |
-
score -= CloseEnemies * popcount(b);
|
| 499 |
-
|
| 500 |
-
// Penalty when our king is on a pawnless flank
|
| 501 |
-
if (!(pos.pieces(PAWN) & (KingFlank[WHITE][kf] | KingFlank[BLACK][kf])))
|
| 502 |
-
score -= PawnlessFlank;
|
| 503 |
-
|
| 504 |
-
if (DoTrace)
|
| 505 |
-
Trace::add(KING, Us, score);
|
| 506 |
-
|
| 507 |
-
return score;
|
| 508 |
-
}
|
| 509 |
-
|
| 510 |
-
|
| 511 |
-
// evaluate_threats() assigns bonuses according to the types of the attacking
|
| 512 |
-
// and the attacked pieces.
|
| 513 |
-
|
| 514 |
-
template<Color Us, bool DoTrace>
|
| 515 |
-
Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
|
| 516 |
-
|
| 517 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 518 |
-
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
| 519 |
-
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
| 520 |
-
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
| 521 |
-
const Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB);
|
| 522 |
-
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
| 523 |
-
|
| 524 |
-
enum { Minor, Rook };
|
| 525 |
-
|
| 526 |
-
Bitboard b, weak, defended, safeThreats;
|
| 527 |
-
Score score = SCORE_ZERO;
|
| 528 |
-
|
| 529 |
-
// Small bonus if the opponent has loose pawns or pieces
|
| 530 |
-
if ( (pos.pieces(Them) ^ pos.pieces(Them, QUEEN, KING))
|
| 531 |
-
& ~(ei.attackedBy[Us][ALL_PIECES] | ei.attackedBy[Them][ALL_PIECES]))
|
| 532 |
-
score += LooseEnemies;
|
| 533 |
-
|
| 534 |
-
// Non-pawn enemies attacked by a pawn
|
| 535 |
-
weak = (pos.pieces(Them) ^ pos.pieces(Them, PAWN)) & ei.attackedBy[Us][PAWN];
|
| 536 |
-
|
| 537 |
-
if (weak)
|
| 538 |
-
{
|
| 539 |
-
b = pos.pieces(Us, PAWN) & ( ~ei.attackedBy[Them][ALL_PIECES]
|
| 540 |
-
| ei.attackedBy[Us][ALL_PIECES]);
|
| 541 |
-
|
| 542 |
-
safeThreats = (shift<Right>(b) | shift<Left>(b)) & weak;
|
| 543 |
-
|
| 544 |
-
if (weak ^ safeThreats)
|
| 545 |
-
score += ThreatByHangingPawn;
|
| 546 |
-
|
| 547 |
-
while (safeThreats)
|
| 548 |
-
score += ThreatBySafePawn[type_of(pos.piece_on(pop_lsb(&safeThreats)))];
|
| 549 |
-
}
|
| 550 |
-
|
| 551 |
-
// Non-pawn enemies defended by a pawn
|
| 552 |
-
defended = (pos.pieces(Them) ^ pos.pieces(Them, PAWN)) & ei.attackedBy[Them][PAWN];
|
| 553 |
-
|
| 554 |
-
// Enemies not defended by a pawn and under our attack
|
| 555 |
-
weak = pos.pieces(Them)
|
| 556 |
-
& ~ei.attackedBy[Them][PAWN]
|
| 557 |
-
& ei.attackedBy[Us][ALL_PIECES];
|
| 558 |
-
|
| 559 |
-
// Add a bonus according to the kind of attacking pieces
|
| 560 |
-
if (defended | weak)
|
| 561 |
-
{
|
| 562 |
-
b = (defended | weak) & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
|
| 563 |
-
while (b)
|
| 564 |
-
score += Threat[Minor][type_of(pos.piece_on(pop_lsb(&b)))];
|
| 565 |
-
|
| 566 |
-
b = (pos.pieces(Them, QUEEN) | weak) & ei.attackedBy[Us][ROOK];
|
| 567 |
-
while (b)
|
| 568 |
-
score += Threat[Rook ][type_of(pos.piece_on(pop_lsb(&b)))];
|
| 569 |
-
|
| 570 |
-
score += Hanging * popcount(weak & ~ei.attackedBy[Them][ALL_PIECES]);
|
| 571 |
-
|
| 572 |
-
b = weak & ei.attackedBy[Us][KING];
|
| 573 |
-
if (b)
|
| 574 |
-
score += ThreatByKing[more_than_one(b)];
|
| 575 |
-
}
|
| 576 |
-
|
| 577 |
-
// Bonus if some pawns can safely push and attack an enemy piece
|
| 578 |
-
b = pos.pieces(Us, PAWN) & ~TRank7BB;
|
| 579 |
-
b = shift<Up>(b | (shift<Up>(b & TRank2BB) & ~pos.pieces()));
|
| 580 |
-
|
| 581 |
-
b &= ~pos.pieces()
|
| 582 |
-
& ~ei.attackedBy[Them][PAWN]
|
| 583 |
-
& (ei.attackedBy[Us][ALL_PIECES] | ~ei.attackedBy[Them][ALL_PIECES]);
|
| 584 |
-
|
| 585 |
-
b = (shift<Left>(b) | shift<Right>(b))
|
| 586 |
-
& pos.pieces(Them)
|
| 587 |
-
& ~ei.attackedBy[Us][PAWN];
|
| 588 |
-
|
| 589 |
-
score += ThreatByPawnPush * popcount(b);
|
| 590 |
-
|
| 591 |
-
if (DoTrace)
|
| 592 |
-
Trace::add(THREAT, Us, score);
|
| 593 |
-
|
| 594 |
-
return score;
|
| 595 |
-
}
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
// evaluate_passed_pawns() evaluates the passed pawns of the given color
|
| 599 |
-
|
| 600 |
-
template<Color Us, bool DoTrace>
|
| 601 |
-
Score evaluate_passed_pawns(const Position& pos, const EvalInfo& ei) {
|
| 602 |
-
|
| 603 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 604 |
-
|
| 605 |
-
Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares;
|
| 606 |
-
Score score = SCORE_ZERO;
|
| 607 |
-
|
| 608 |
-
b = ei.pi->passed_pawns(Us);
|
| 609 |
-
|
| 610 |
-
while (b)
|
| 611 |
-
{
|
| 612 |
-
Square s = pop_lsb(&b);
|
| 613 |
-
|
| 614 |
-
assert(pos.pawn_passed(Us, s));
|
| 615 |
-
assert(!(pos.pieces(PAWN) & forward_bb(Us, s)));
|
| 616 |
-
|
| 617 |
-
bb = forward_bb(Us, s) & (ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them));
|
| 618 |
-
score -= HinderPassedPawn * popcount(bb);
|
| 619 |
-
|
| 620 |
-
int r = relative_rank(Us, s) - RANK_2;
|
| 621 |
-
int rr = r * (r - 1);
|
| 622 |
-
|
| 623 |
-
Value mbonus = Passed[MG][r], ebonus = Passed[EG][r];
|
| 624 |
-
|
| 625 |
-
if (rr)
|
| 626 |
-
{
|
| 627 |
-
Square blockSq = s + pawn_push(Us);
|
| 628 |
-
|
| 629 |
-
// Adjust bonus based on the king's proximity
|
| 630 |
-
ebonus += distance(pos.square<KING>(Them), blockSq) * 5 * rr
|
| 631 |
-
- distance(pos.square<KING>(Us ), blockSq) * 2 * rr;
|
| 632 |
-
|
| 633 |
-
// If blockSq is not the queening square then consider also a second push
|
| 634 |
-
if (relative_rank(Us, blockSq) != RANK_8)
|
| 635 |
-
ebonus -= distance(pos.square<KING>(Us), blockSq + pawn_push(Us)) * rr;
|
| 636 |
-
|
| 637 |
-
// If the pawn is free to advance, then increase the bonus
|
| 638 |
-
if (pos.empty(blockSq))
|
| 639 |
-
{
|
| 640 |
-
// If there is a rook or queen attacking/defending the pawn from behind,
|
| 641 |
-
// consider all the squaresToQueen. Otherwise consider only the squares
|
| 642 |
-
// in the pawn's path attacked or occupied by the enemy.
|
| 643 |
-
defendedSquares = unsafeSquares = squaresToQueen = forward_bb(Us, s);
|
| 644 |
-
|
| 645 |
-
bb = forward_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from<ROOK>(s);
|
| 646 |
-
|
| 647 |
-
if (!(pos.pieces(Us) & bb))
|
| 648 |
-
defendedSquares &= ei.attackedBy[Us][ALL_PIECES];
|
| 649 |
-
|
| 650 |
-
if (!(pos.pieces(Them) & bb))
|
| 651 |
-
unsafeSquares &= ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them);
|
| 652 |
-
|
| 653 |
-
// If there aren't any enemy attacks, assign a big bonus. Otherwise
|
| 654 |
-
// assign a smaller bonus if the block square isn't attacked.
|
| 655 |
-
int k = !unsafeSquares ? 18 : !(unsafeSquares & blockSq) ? 8 : 0;
|
| 656 |
-
|
| 657 |
-
// If the path to the queen is fully defended, assign a big bonus.
|
| 658 |
-
// Otherwise assign a smaller bonus if the block square is defended.
|
| 659 |
-
if (defendedSquares == squaresToQueen)
|
| 660 |
-
k += 6;
|
| 661 |
-
|
| 662 |
-
else if (defendedSquares & blockSq)
|
| 663 |
-
k += 4;
|
| 664 |
-
|
| 665 |
-
mbonus += k * rr, ebonus += k * rr;
|
| 666 |
-
}
|
| 667 |
-
else if (pos.pieces(Us) & blockSq)
|
| 668 |
-
mbonus += rr + r * 2, ebonus += rr + r * 2;
|
| 669 |
-
} // rr != 0
|
| 670 |
-
|
| 671 |
-
score += make_score(mbonus, ebonus) + PassedFile[file_of(s)];
|
| 672 |
-
}
|
| 673 |
-
|
| 674 |
-
if (DoTrace)
|
| 675 |
-
Trace::add(PASSED, Us, score);
|
| 676 |
-
|
| 677 |
-
// Add the scores to the middlegame and endgame eval
|
| 678 |
-
return score;
|
| 679 |
-
}
|
| 680 |
-
|
| 681 |
-
|
| 682 |
-
// evaluate_space() computes the space evaluation for a given side. The
|
| 683 |
-
// space evaluation is a simple bonus based on the number of safe squares
|
| 684 |
-
// available for minor pieces on the central four files on ranks 2--4. Safe
|
| 685 |
-
// squares one, two or three squares behind a friendly pawn are counted
|
| 686 |
-
// twice. Finally, the space bonus is multiplied by a weight. The aim is to
|
| 687 |
-
// improve play on game opening.
|
| 688 |
-
template<Color Us>
|
| 689 |
-
Score evaluate_space(const Position& pos, const EvalInfo& ei) {
|
| 690 |
-
|
| 691 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 692 |
-
const Bitboard SpaceMask =
|
| 693 |
-
Us == WHITE ? (FileCBB | FileDBB | FileEBB | FileFBB) & (Rank2BB | Rank3BB | Rank4BB)
|
| 694 |
-
: (FileCBB | FileDBB | FileEBB | FileFBB) & (Rank7BB | Rank6BB | Rank5BB);
|
| 695 |
-
|
| 696 |
-
// Find the safe squares for our pieces inside the area defined by
|
| 697 |
-
// SpaceMask. A square is unsafe if it is attacked by an enemy
|
| 698 |
-
// pawn, or if it is undefended and attacked by an enemy piece.
|
| 699 |
-
Bitboard safe = SpaceMask
|
| 700 |
-
& ~pos.pieces(Us, PAWN)
|
| 701 |
-
& ~ei.attackedBy[Them][PAWN]
|
| 702 |
-
& (ei.attackedBy[Us][ALL_PIECES] | ~ei.attackedBy[Them][ALL_PIECES]);
|
| 703 |
-
|
| 704 |
-
// Find all squares which are at most three squares behind some friendly pawn
|
| 705 |
-
Bitboard behind = pos.pieces(Us, PAWN);
|
| 706 |
-
behind |= (Us == WHITE ? behind >> 8 : behind << 8);
|
| 707 |
-
behind |= (Us == WHITE ? behind >> 16 : behind << 16);
|
| 708 |
-
|
| 709 |
-
// Since SpaceMask[Us] is fully on our half of the board...
|
| 710 |
-
assert(unsigned(safe >> (Us == WHITE ? 32 : 0)) == 0);
|
| 711 |
-
|
| 712 |
-
// ...count safe + (behind & safe) with a single popcount
|
| 713 |
-
int bonus = popcount((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe));
|
| 714 |
-
bonus = std::min(16, bonus);
|
| 715 |
-
int weight = pos.count<ALL_PIECES>(Us) - 2 * ei.pi->open_files();
|
| 716 |
-
|
| 717 |
-
return make_score(bonus * weight * weight / 18, 0);
|
| 718 |
-
}
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
// evaluate_initiative() computes the initiative correction value for the
|
| 722 |
-
// position, i.e., second order bonus/malus based on the known attacking/defending
|
| 723 |
-
// status of the players.
|
| 724 |
-
Score evaluate_initiative(const Position& pos, int asymmetry, Value eg) {
|
| 725 |
-
|
| 726 |
-
int kingDistance = distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
|
| 727 |
-
- distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
|
| 728 |
-
int pawns = pos.count<PAWN>(WHITE) + pos.count<PAWN>(BLACK);
|
| 729 |
-
|
| 730 |
-
// Compute the initiative bonus for the attacking side
|
| 731 |
-
int initiative = 8 * (asymmetry + kingDistance - 15) + 12 * pawns;
|
| 732 |
-
|
| 733 |
-
// Now apply the bonus: note that we find the attacking side by extracting
|
| 734 |
-
// the sign of the endgame value, and that we carefully cap the bonus so
|
| 735 |
-
// that the endgame score will never be divided by more than two.
|
| 736 |
-
int value = ((eg > 0) - (eg < 0)) * std::max(initiative, -abs(eg / 2));
|
| 737 |
-
|
| 738 |
-
return make_score(0, value);
|
| 739 |
-
}
|
| 740 |
-
|
| 741 |
-
|
| 742 |
-
// evaluate_scale_factor() computes the scale factor for the winning side
|
| 743 |
-
ScaleFactor evaluate_scale_factor(const Position& pos, const EvalInfo& ei, Value eg) {
|
| 744 |
-
|
| 745 |
-
Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK;
|
| 746 |
-
ScaleFactor sf = ei.me->scale_factor(pos, strongSide);
|
| 747 |
-
|
| 748 |
-
// If we don't already have an unusual scale factor, check for certain
|
| 749 |
-
// types of endgames, and use a lower scale for those.
|
| 750 |
-
if ( ei.me->game_phase() < PHASE_MIDGAME
|
| 751 |
-
&& (sf == SCALE_FACTOR_NORMAL || sf == SCALE_FACTOR_ONEPAWN))
|
| 752 |
-
{
|
| 753 |
-
if (pos.opposite_bishops())
|
| 754 |
-
{
|
| 755 |
-
// Endgame with opposite-colored bishops and no other pieces (ignoring pawns)
|
| 756 |
-
// is almost a draw, in case of KBP vs KB, it is even more a draw.
|
| 757 |
-
if ( pos.non_pawn_material(WHITE) == BishopValueMg
|
| 758 |
-
&& pos.non_pawn_material(BLACK) == BishopValueMg)
|
| 759 |
-
sf = more_than_one(pos.pieces(PAWN)) ? ScaleFactor(31) : ScaleFactor(9);
|
| 760 |
-
|
| 761 |
-
// Endgame with opposite-colored bishops, but also other pieces. Still
|
| 762 |
-
// a bit drawish, but not as drawish as with only the two bishops.
|
| 763 |
-
else
|
| 764 |
-
sf = ScaleFactor(46);
|
| 765 |
-
}
|
| 766 |
-
// Endings where weaker side can place his king in front of the opponent's
|
| 767 |
-
// pawns are drawish.
|
| 768 |
-
else if ( abs(eg) <= BishopValueEg
|
| 769 |
-
&& pos.count<PAWN>(strongSide) <= 2
|
| 770 |
-
&& !pos.pawn_passed(~strongSide, pos.square<KING>(~strongSide)))
|
| 771 |
-
sf = ScaleFactor(37 + 7 * pos.count<PAWN>(strongSide));
|
| 772 |
-
}
|
| 773 |
-
|
| 774 |
-
return sf;
|
| 775 |
-
}
|
| 776 |
-
|
| 777 |
-
} // namespace
|
| 778 |
-
|
| 779 |
-
|
| 780 |
-
/// evaluate() is the main evaluation function. It returns a static evaluation
|
| 781 |
-
/// of the position from the point of view of the side to move.
|
| 782 |
-
|
| 783 |
-
template<bool DoTrace>
|
| 784 |
-
Value Eval::evaluate(const Position& pos) {
|
| 785 |
-
|
| 786 |
-
assert(!pos.checkers());
|
| 787 |
-
|
| 788 |
-
Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO };
|
| 789 |
-
EvalInfo ei;
|
| 790 |
-
|
| 791 |
-
// Probe the material hash table
|
| 792 |
-
ei.me = Material::probe(pos);
|
| 793 |
-
|
| 794 |
-
// If we have a specialized evaluation function for the current material
|
| 795 |
-
// configuration, call it and return.
|
| 796 |
-
if (ei.me->specialized_eval_exists())
|
| 797 |
-
return ei.me->evaluate(pos);
|
| 798 |
-
|
| 799 |
-
// Initialize score by reading the incrementally updated scores included in
|
| 800 |
-
// the position object (material + piece square tables) and the material
|
| 801 |
-
// imbalance. Score is computed internally from the white point of view.
|
| 802 |
-
Score score = pos.psq_score() + ei.me->imbalance();
|
| 803 |
-
|
| 804 |
-
// Probe the pawn hash table
|
| 805 |
-
ei.pi = Pawns::probe(pos);
|
| 806 |
-
score += ei.pi->pawns_score();
|
| 807 |
-
|
| 808 |
-
// Initialize attack and king safety bitboards
|
| 809 |
-
ei.attackedBy[WHITE][ALL_PIECES] = ei.attackedBy[BLACK][ALL_PIECES] = 0;
|
| 810 |
-
ei.attackedBy[WHITE][KING] = pos.attacks_from<KING>(pos.square<KING>(WHITE));
|
| 811 |
-
ei.attackedBy[BLACK][KING] = pos.attacks_from<KING>(pos.square<KING>(BLACK));
|
| 812 |
-
eval_init<WHITE>(pos, ei);
|
| 813 |
-
eval_init<BLACK>(pos, ei);
|
| 814 |
-
|
| 815 |
-
// Pawns blocked or on ranks 2 and 3 will be excluded from the mobility area
|
| 816 |
-
Bitboard blockedPawns[] = {
|
| 817 |
-
pos.pieces(WHITE, PAWN) & (shift<SOUTH>(pos.pieces()) | Rank2BB | Rank3BB),
|
| 818 |
-
pos.pieces(BLACK, PAWN) & (shift<NORTH>(pos.pieces()) | Rank7BB | Rank6BB)
|
| 819 |
-
};
|
| 820 |
-
|
| 821 |
-
// Do not include in mobility area squares protected by enemy pawns, or occupied
|
| 822 |
-
// by our blocked pawns or king.
|
| 823 |
-
Bitboard mobilityArea[] = {
|
| 824 |
-
~(ei.attackedBy[BLACK][PAWN] | blockedPawns[WHITE] | pos.square<KING>(WHITE)),
|
| 825 |
-
~(ei.attackedBy[WHITE][PAWN] | blockedPawns[BLACK] | pos.square<KING>(BLACK))
|
| 826 |
-
};
|
| 827 |
-
|
| 828 |
-
// Evaluate all pieces but king and pawns
|
| 829 |
-
score += evaluate_pieces<DoTrace>(pos, ei, mobility, mobilityArea);
|
| 830 |
-
score += mobility[WHITE] - mobility[BLACK];
|
| 831 |
-
|
| 832 |
-
// Evaluate kings after all other pieces because we need full attack
|
| 833 |
-
// information when computing the king safety evaluation.
|
| 834 |
-
score += evaluate_king<WHITE, DoTrace>(pos, ei)
|
| 835 |
-
- evaluate_king<BLACK, DoTrace>(pos, ei);
|
| 836 |
-
|
| 837 |
-
// Evaluate tactical threats, we need full attack information including king
|
| 838 |
-
score += evaluate_threats<WHITE, DoTrace>(pos, ei)
|
| 839 |
-
- evaluate_threats<BLACK, DoTrace>(pos, ei);
|
| 840 |
-
|
| 841 |
-
// Evaluate passed pawns, we need full attack information including king
|
| 842 |
-
score += evaluate_passed_pawns<WHITE, DoTrace>(pos, ei)
|
| 843 |
-
- evaluate_passed_pawns<BLACK, DoTrace>(pos, ei);
|
| 844 |
-
|
| 845 |
-
// If both sides have only pawns, score for potential unstoppable pawns
|
| 846 |
-
if (!pos.non_pawn_material(WHITE) && !pos.non_pawn_material(BLACK))
|
| 847 |
-
{
|
| 848 |
-
Bitboard b;
|
| 849 |
-
if ((b = ei.pi->passed_pawns(WHITE)) != 0)
|
| 850 |
-
score += Unstoppable * int(relative_rank(WHITE, frontmost_sq(WHITE, b)));
|
| 851 |
-
|
| 852 |
-
if ((b = ei.pi->passed_pawns(BLACK)) != 0)
|
| 853 |
-
score -= Unstoppable * int(relative_rank(BLACK, frontmost_sq(BLACK, b)));
|
| 854 |
-
}
|
| 855 |
-
|
| 856 |
-
// Evaluate space for both sides, only during opening
|
| 857 |
-
if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >= 12222)
|
| 858 |
-
score += evaluate_space<WHITE>(pos, ei)
|
| 859 |
-
- evaluate_space<BLACK>(pos, ei);
|
| 860 |
-
|
| 861 |
-
// Evaluate position potential for the winning side
|
| 862 |
-
score += evaluate_initiative(pos, ei.pi->pawn_asymmetry(), eg_value(score));
|
| 863 |
-
|
| 864 |
-
// Evaluate scale factor for the winning side
|
| 865 |
-
ScaleFactor sf = evaluate_scale_factor(pos, ei, eg_value(score));
|
| 866 |
-
|
| 867 |
-
// Interpolate between a middlegame and a (scaled by 'sf') endgame score
|
| 868 |
-
Value v = mg_value(score) * int(ei.me->game_phase())
|
| 869 |
-
+ eg_value(score) * int(PHASE_MIDGAME - ei.me->game_phase()) * sf / SCALE_FACTOR_NORMAL;
|
| 870 |
-
|
| 871 |
-
v /= int(PHASE_MIDGAME);
|
| 872 |
-
|
| 873 |
-
// In case of tracing add all remaining individual evaluation terms
|
| 874 |
-
if (DoTrace)
|
| 875 |
-
{
|
| 876 |
-
Trace::add(MATERIAL, pos.psq_score());
|
| 877 |
-
Trace::add(IMBALANCE, ei.me->imbalance());
|
| 878 |
-
Trace::add(PAWN, ei.pi->pawns_score());
|
| 879 |
-
Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]);
|
| 880 |
-
Trace::add(SPACE, evaluate_space<WHITE>(pos, ei)
|
| 881 |
-
, evaluate_space<BLACK>(pos, ei));
|
| 882 |
-
Trace::add(TOTAL, score);
|
| 883 |
-
}
|
| 884 |
-
|
| 885 |
-
return (pos.side_to_move() == WHITE ? v : -v) + Eval::Tempo; // Side to move point of view
|
| 886 |
-
}
|
| 887 |
-
|
| 888 |
-
// Explicit template instantiations
|
| 889 |
-
template Value Eval::evaluate<true >(const Position&);
|
| 890 |
-
template Value Eval::evaluate<false>(const Position&);
|
| 891 |
-
|
| 892 |
-
|
| 893 |
-
/// trace() is like evaluate(), but instead of returning a value, it returns
|
| 894 |
-
/// a string (suitable for outputting to stdout) that contains the detailed
|
| 895 |
-
/// descriptions and values of each evaluation term. Useful for debugging.
|
| 896 |
-
|
| 897 |
-
std::string Eval::trace(const Position& pos) {
|
| 898 |
-
|
| 899 |
-
std::memset(scores, 0, sizeof(scores));
|
| 900 |
-
|
| 901 |
-
Value v = evaluate<true>(pos);
|
| 902 |
-
v = pos.side_to_move() == WHITE ? v : -v; // White's point of view
|
| 903 |
-
|
| 904 |
-
std::stringstream ss;
|
| 905 |
-
ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2)
|
| 906 |
-
<< " Eval term | White | Black | Total \n"
|
| 907 |
-
<< " | MG EG | MG EG | MG EG \n"
|
| 908 |
-
<< "----------------+-------------+-------------+-------------\n"
|
| 909 |
-
<< " Material | " << Term(MATERIAL)
|
| 910 |
-
<< " Imbalance | " << Term(IMBALANCE)
|
| 911 |
-
<< " Pawns | " << Term(PAWN)
|
| 912 |
-
<< " Knights | " << Term(KNIGHT)
|
| 913 |
-
<< " Bishop | " << Term(BISHOP)
|
| 914 |
-
<< " Rooks | " << Term(ROOK)
|
| 915 |
-
<< " Queens | " << Term(QUEEN)
|
| 916 |
-
<< " Mobility | " << Term(MOBILITY)
|
| 917 |
-
<< " King safety | " << Term(KING)
|
| 918 |
-
<< " Threats | " << Term(THREAT)
|
| 919 |
-
<< " Passed pawns | " << Term(PASSED)
|
| 920 |
-
<< " Space | " << Term(SPACE)
|
| 921 |
-
<< "----------------+-------------+-------------+-------------\n"
|
| 922 |
-
<< " Total | " << Term(TOTAL);
|
| 923 |
-
|
| 924 |
-
ss << "\nTotal Evaluation: " << to_cp(v) << " (white side)\n";
|
| 925 |
-
|
| 926 |
-
return ss.str();
|
| 927 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/evaluate.h
DELETED
|
@@ -1,40 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef EVALUATE_H_INCLUDED
|
| 22 |
-
#define EVALUATE_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include <string>
|
| 25 |
-
|
| 26 |
-
#include "types.h"
|
| 27 |
-
|
| 28 |
-
class Position;
|
| 29 |
-
|
| 30 |
-
namespace Eval {
|
| 31 |
-
|
| 32 |
-
const Value Tempo = Value(20); // Must be visible to search
|
| 33 |
-
|
| 34 |
-
std::string trace(const Position& pos);
|
| 35 |
-
|
| 36 |
-
template<bool DoTrace = false>
|
| 37 |
-
Value evaluate(const Position& pos);
|
| 38 |
-
}
|
| 39 |
-
|
| 40 |
-
#endif // #ifndef EVALUATE_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/main.cpp
DELETED
|
@@ -1,54 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <iostream>
|
| 22 |
-
|
| 23 |
-
#include "bitboard.h"
|
| 24 |
-
#include "position.h"
|
| 25 |
-
#include "search.h"
|
| 26 |
-
#include "thread.h"
|
| 27 |
-
#include "tt.h"
|
| 28 |
-
#include "uci.h"
|
| 29 |
-
#include "syzygy/tbprobe.h"
|
| 30 |
-
|
| 31 |
-
namespace PSQT {
|
| 32 |
-
void init();
|
| 33 |
-
}
|
| 34 |
-
|
| 35 |
-
int main(int argc, char* argv[]) {
|
| 36 |
-
|
| 37 |
-
std::cout << engine_info() << std::endl;
|
| 38 |
-
|
| 39 |
-
UCI::init(Options);
|
| 40 |
-
PSQT::init();
|
| 41 |
-
Bitboards::init();
|
| 42 |
-
Position::init();
|
| 43 |
-
Bitbases::init();
|
| 44 |
-
Search::init();
|
| 45 |
-
Pawns::init();
|
| 46 |
-
Threads.init();
|
| 47 |
-
Tablebases::init(Options["SyzygyPath"]);
|
| 48 |
-
TT.resize(Options["Hash"]);
|
| 49 |
-
|
| 50 |
-
UCI::loop(argc, argv);
|
| 51 |
-
|
| 52 |
-
Threads.exit();
|
| 53 |
-
return 0;
|
| 54 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/material.cpp
DELETED
|
@@ -1,225 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm> // For std::min
|
| 22 |
-
#include <cassert>
|
| 23 |
-
#include <cstring> // For std::memset
|
| 24 |
-
|
| 25 |
-
#include "material.h"
|
| 26 |
-
#include "thread.h"
|
| 27 |
-
|
| 28 |
-
using namespace std;
|
| 29 |
-
|
| 30 |
-
namespace {
|
| 31 |
-
|
| 32 |
-
// Polynomial material imbalance parameters
|
| 33 |
-
|
| 34 |
-
const int QuadraticOurs[][PIECE_TYPE_NB] = {
|
| 35 |
-
// OUR PIECES
|
| 36 |
-
// pair pawn knight bishop rook queen
|
| 37 |
-
{1667 }, // Bishop pair
|
| 38 |
-
{ 40, 2 }, // Pawn
|
| 39 |
-
{ 32, 255, -3 }, // Knight OUR PIECES
|
| 40 |
-
{ 0, 104, 4, 0 }, // Bishop
|
| 41 |
-
{ -26, -2, 47, 105, -149 }, // Rook
|
| 42 |
-
{-185, 24, 122, 137, -134, 0 } // Queen
|
| 43 |
-
};
|
| 44 |
-
|
| 45 |
-
const int QuadraticTheirs[][PIECE_TYPE_NB] = {
|
| 46 |
-
// THEIR PIECES
|
| 47 |
-
// pair pawn knight bishop rook queen
|
| 48 |
-
{ 0 }, // Bishop pair
|
| 49 |
-
{ 36, 0 }, // Pawn
|
| 50 |
-
{ 9, 63, 0 }, // Knight OUR PIECES
|
| 51 |
-
{ 59, 65, 42, 0 }, // Bishop
|
| 52 |
-
{ 46, 39, 24, -24, 0 }, // Rook
|
| 53 |
-
{ 101, 100, -37, 141, 268, 0 } // Queen
|
| 54 |
-
};
|
| 55 |
-
|
| 56 |
-
// Endgame evaluation and scaling functions are accessed directly and not through
|
| 57 |
-
// the function maps because they correspond to more than one material hash key.
|
| 58 |
-
Endgame<KXK> EvaluateKXK[] = { Endgame<KXK>(WHITE), Endgame<KXK>(BLACK) };
|
| 59 |
-
|
| 60 |
-
Endgame<KBPsK> ScaleKBPsK[] = { Endgame<KBPsK>(WHITE), Endgame<KBPsK>(BLACK) };
|
| 61 |
-
Endgame<KQKRPs> ScaleKQKRPs[] = { Endgame<KQKRPs>(WHITE), Endgame<KQKRPs>(BLACK) };
|
| 62 |
-
Endgame<KPsK> ScaleKPsK[] = { Endgame<KPsK>(WHITE), Endgame<KPsK>(BLACK) };
|
| 63 |
-
Endgame<KPKP> ScaleKPKP[] = { Endgame<KPKP>(WHITE), Endgame<KPKP>(BLACK) };
|
| 64 |
-
|
| 65 |
-
// Helper used to detect a given material distribution
|
| 66 |
-
bool is_KXK(const Position& pos, Color us) {
|
| 67 |
-
return !more_than_one(pos.pieces(~us))
|
| 68 |
-
&& pos.non_pawn_material(us) >= RookValueMg;
|
| 69 |
-
}
|
| 70 |
-
|
| 71 |
-
bool is_KBPsKs(const Position& pos, Color us) {
|
| 72 |
-
return pos.non_pawn_material(us) == BishopValueMg
|
| 73 |
-
&& pos.count<BISHOP>(us) == 1
|
| 74 |
-
&& pos.count<PAWN >(us) >= 1;
|
| 75 |
-
}
|
| 76 |
-
|
| 77 |
-
bool is_KQKRPs(const Position& pos, Color us) {
|
| 78 |
-
return !pos.count<PAWN>(us)
|
| 79 |
-
&& pos.non_pawn_material(us) == QueenValueMg
|
| 80 |
-
&& pos.count<QUEEN>(us) == 1
|
| 81 |
-
&& pos.count<ROOK>(~us) == 1
|
| 82 |
-
&& pos.count<PAWN>(~us) >= 1;
|
| 83 |
-
}
|
| 84 |
-
|
| 85 |
-
/// imbalance() calculates the imbalance by comparing the piece count of each
|
| 86 |
-
/// piece type for both colors.
|
| 87 |
-
template<Color Us>
|
| 88 |
-
int imbalance(const int pieceCount[][PIECE_TYPE_NB]) {
|
| 89 |
-
|
| 90 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 91 |
-
|
| 92 |
-
int bonus = 0;
|
| 93 |
-
|
| 94 |
-
// Second-degree polynomial material imbalance by Tord Romstad
|
| 95 |
-
for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1)
|
| 96 |
-
{
|
| 97 |
-
if (!pieceCount[Us][pt1])
|
| 98 |
-
continue;
|
| 99 |
-
|
| 100 |
-
int v = 0;
|
| 101 |
-
|
| 102 |
-
for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2)
|
| 103 |
-
v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2]
|
| 104 |
-
+ QuadraticTheirs[pt1][pt2] * pieceCount[Them][pt2];
|
| 105 |
-
|
| 106 |
-
bonus += pieceCount[Us][pt1] * v;
|
| 107 |
-
}
|
| 108 |
-
|
| 109 |
-
return bonus;
|
| 110 |
-
}
|
| 111 |
-
|
| 112 |
-
} // namespace
|
| 113 |
-
|
| 114 |
-
namespace Material {
|
| 115 |
-
|
| 116 |
-
/// Material::probe() looks up the current position's material configuration in
|
| 117 |
-
/// the material hash table. It returns a pointer to the Entry if the position
|
| 118 |
-
/// is found. Otherwise a new Entry is computed and stored there, so we don't
|
| 119 |
-
/// have to recompute all when the same material configuration occurs again.
|
| 120 |
-
|
| 121 |
-
Entry* probe(const Position& pos) {
|
| 122 |
-
|
| 123 |
-
Key key = pos.material_key();
|
| 124 |
-
Entry* e = pos.this_thread()->materialTable[key];
|
| 125 |
-
|
| 126 |
-
if (e->key == key)
|
| 127 |
-
return e;
|
| 128 |
-
|
| 129 |
-
std::memset(e, 0, sizeof(Entry));
|
| 130 |
-
e->key = key;
|
| 131 |
-
e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
|
| 132 |
-
e->gamePhase = pos.game_phase();
|
| 133 |
-
|
| 134 |
-
// Let's look if we have a specialized evaluation function for this particular
|
| 135 |
-
// material configuration. Firstly we look for a fixed configuration one, then
|
| 136 |
-
// for a generic one if the previous search failed.
|
| 137 |
-
if ((e->evaluationFunction = pos.this_thread()->endgames.probe<Value>(key)) != nullptr)
|
| 138 |
-
return e;
|
| 139 |
-
|
| 140 |
-
for (Color c = WHITE; c <= BLACK; ++c)
|
| 141 |
-
if (is_KXK(pos, c))
|
| 142 |
-
{
|
| 143 |
-
e->evaluationFunction = &EvaluateKXK[c];
|
| 144 |
-
return e;
|
| 145 |
-
}
|
| 146 |
-
|
| 147 |
-
// OK, we didn't find any special evaluation function for the current material
|
| 148 |
-
// configuration. Is there a suitable specialized scaling function?
|
| 149 |
-
EndgameBase<ScaleFactor>* sf;
|
| 150 |
-
|
| 151 |
-
if ((sf = pos.this_thread()->endgames.probe<ScaleFactor>(key)) != nullptr)
|
| 152 |
-
{
|
| 153 |
-
e->scalingFunction[sf->strong_side()] = sf; // Only strong color assigned
|
| 154 |
-
return e;
|
| 155 |
-
}
|
| 156 |
-
|
| 157 |
-
// We didn't find any specialized scaling function, so fall back on generic
|
| 158 |
-
// ones that refer to more than one material distribution. Note that in this
|
| 159 |
-
// case we don't return after setting the function.
|
| 160 |
-
for (Color c = WHITE; c <= BLACK; ++c)
|
| 161 |
-
{
|
| 162 |
-
if (is_KBPsKs(pos, c))
|
| 163 |
-
e->scalingFunction[c] = &ScaleKBPsK[c];
|
| 164 |
-
|
| 165 |
-
else if (is_KQKRPs(pos, c))
|
| 166 |
-
e->scalingFunction[c] = &ScaleKQKRPs[c];
|
| 167 |
-
}
|
| 168 |
-
|
| 169 |
-
Value npm_w = pos.non_pawn_material(WHITE);
|
| 170 |
-
Value npm_b = pos.non_pawn_material(BLACK);
|
| 171 |
-
|
| 172 |
-
if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) // Only pawns on the board
|
| 173 |
-
{
|
| 174 |
-
if (!pos.count<PAWN>(BLACK))
|
| 175 |
-
{
|
| 176 |
-
assert(pos.count<PAWN>(WHITE) >= 2);
|
| 177 |
-
|
| 178 |
-
e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
|
| 179 |
-
}
|
| 180 |
-
else if (!pos.count<PAWN>(WHITE))
|
| 181 |
-
{
|
| 182 |
-
assert(pos.count<PAWN>(BLACK) >= 2);
|
| 183 |
-
|
| 184 |
-
e->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
|
| 185 |
-
}
|
| 186 |
-
else if (pos.count<PAWN>(WHITE) == 1 && pos.count<PAWN>(BLACK) == 1)
|
| 187 |
-
{
|
| 188 |
-
// This is a special case because we set scaling functions
|
| 189 |
-
// for both colors instead of only one.
|
| 190 |
-
e->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
|
| 191 |
-
e->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
|
| 192 |
-
}
|
| 193 |
-
}
|
| 194 |
-
|
| 195 |
-
// Zero or just one pawn makes it difficult to win, even with a small material
|
| 196 |
-
// advantage. This catches some trivial draws like KK, KBK and KNK and gives a
|
| 197 |
-
// drawish scale factor for cases such as KRKBP and KmmKm (except for KBBKN).
|
| 198 |
-
if (!pos.count<PAWN>(WHITE) && npm_w - npm_b <= BishopValueMg)
|
| 199 |
-
e->factor[WHITE] = uint8_t(npm_w < RookValueMg ? SCALE_FACTOR_DRAW :
|
| 200 |
-
npm_b <= BishopValueMg ? 4 : 14);
|
| 201 |
-
|
| 202 |
-
if (!pos.count<PAWN>(BLACK) && npm_b - npm_w <= BishopValueMg)
|
| 203 |
-
e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW :
|
| 204 |
-
npm_w <= BishopValueMg ? 4 : 14);
|
| 205 |
-
|
| 206 |
-
if (pos.count<PAWN>(WHITE) == 1 && npm_w - npm_b <= BishopValueMg)
|
| 207 |
-
e->factor[WHITE] = (uint8_t) SCALE_FACTOR_ONEPAWN;
|
| 208 |
-
|
| 209 |
-
if (pos.count<PAWN>(BLACK) == 1 && npm_b - npm_w <= BishopValueMg)
|
| 210 |
-
e->factor[BLACK] = (uint8_t) SCALE_FACTOR_ONEPAWN;
|
| 211 |
-
|
| 212 |
-
// Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
|
| 213 |
-
// for the bishop pair "extended piece", which allows us to be more flexible
|
| 214 |
-
// in defining bishop pair bonuses.
|
| 215 |
-
const int PieceCount[COLOR_NB][PIECE_TYPE_NB] = {
|
| 216 |
-
{ pos.count<BISHOP>(WHITE) > 1, pos.count<PAWN>(WHITE), pos.count<KNIGHT>(WHITE),
|
| 217 |
-
pos.count<BISHOP>(WHITE) , pos.count<ROOK>(WHITE), pos.count<QUEEN >(WHITE) },
|
| 218 |
-
{ pos.count<BISHOP>(BLACK) > 1, pos.count<PAWN>(BLACK), pos.count<KNIGHT>(BLACK),
|
| 219 |
-
pos.count<BISHOP>(BLACK) , pos.count<ROOK>(BLACK), pos.count<QUEEN >(BLACK) } };
|
| 220 |
-
|
| 221 |
-
e->value = int16_t((imbalance<WHITE>(PieceCount) - imbalance<BLACK>(PieceCount)) / 16);
|
| 222 |
-
return e;
|
| 223 |
-
}
|
| 224 |
-
|
| 225 |
-
} // namespace Material
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/material.h
DELETED
|
@@ -1,73 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef MATERIAL_H_INCLUDED
|
| 22 |
-
#define MATERIAL_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include "endgame.h"
|
| 25 |
-
#include "misc.h"
|
| 26 |
-
#include "position.h"
|
| 27 |
-
#include "types.h"
|
| 28 |
-
|
| 29 |
-
namespace Material {
|
| 30 |
-
|
| 31 |
-
/// Material::Entry contains various information about a material configuration.
|
| 32 |
-
/// It contains a material imbalance evaluation, a function pointer to a special
|
| 33 |
-
/// endgame evaluation function (which in most cases is NULL, meaning that the
|
| 34 |
-
/// standard evaluation function will be used), and scale factors.
|
| 35 |
-
///
|
| 36 |
-
/// The scale factors are used to scale the evaluation score up or down. For
|
| 37 |
-
/// instance, in KRB vs KR endgames, the score is scaled down by a factor of 4,
|
| 38 |
-
/// which will result in scores of absolute value less than one pawn.
|
| 39 |
-
|
| 40 |
-
struct Entry {
|
| 41 |
-
|
| 42 |
-
Score imbalance() const { return make_score(value, value); }
|
| 43 |
-
Phase game_phase() const { return gamePhase; }
|
| 44 |
-
bool specialized_eval_exists() const { return evaluationFunction != nullptr; }
|
| 45 |
-
Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); }
|
| 46 |
-
|
| 47 |
-
// scale_factor takes a position and a color as input and returns a scale factor
|
| 48 |
-
// for the given color. We have to provide the position in addition to the color
|
| 49 |
-
// because the scale factor may also be a function which should be applied to
|
| 50 |
-
// the position. For instance, in KBP vs K endgames, the scaling function looks
|
| 51 |
-
// for rook pawns and wrong-colored bishops.
|
| 52 |
-
ScaleFactor scale_factor(const Position& pos, Color c) const {
|
| 53 |
-
ScaleFactor sf = scalingFunction[c] ? (*scalingFunction[c])(pos)
|
| 54 |
-
: SCALE_FACTOR_NONE;
|
| 55 |
-
return sf != SCALE_FACTOR_NONE ? sf : ScaleFactor(factor[c]);
|
| 56 |
-
}
|
| 57 |
-
|
| 58 |
-
Key key;
|
| 59 |
-
int16_t value;
|
| 60 |
-
uint8_t factor[COLOR_NB];
|
| 61 |
-
EndgameBase<Value>* evaluationFunction;
|
| 62 |
-
EndgameBase<ScaleFactor>* scalingFunction[COLOR_NB]; // Could be one for each
|
| 63 |
-
// side (e.g. KPKP, KBPsKs)
|
| 64 |
-
Phase gamePhase;
|
| 65 |
-
};
|
| 66 |
-
|
| 67 |
-
typedef HashTable<Entry, 8192> Table;
|
| 68 |
-
|
| 69 |
-
Entry* probe(const Position& pos);
|
| 70 |
-
|
| 71 |
-
} // namespace Material
|
| 72 |
-
|
| 73 |
-
#endif // #ifndef MATERIAL_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/misc.cpp
DELETED
|
@@ -1,187 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <fstream>
|
| 22 |
-
#include <iomanip>
|
| 23 |
-
#include <iostream>
|
| 24 |
-
#include <sstream>
|
| 25 |
-
|
| 26 |
-
#include "misc.h"
|
| 27 |
-
#include "thread.h"
|
| 28 |
-
|
| 29 |
-
using namespace std;
|
| 30 |
-
|
| 31 |
-
namespace {
|
| 32 |
-
|
| 33 |
-
/// Version number. If Version is left empty, then compile date in the format
|
| 34 |
-
/// DD-MM-YY and show in engine_info.
|
| 35 |
-
const string Version = "8";
|
| 36 |
-
|
| 37 |
-
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
|
| 38 |
-
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
|
| 39 |
-
/// can toggle the logging of std::cout and std:cin at runtime whilst preserving
|
| 40 |
-
/// usual I/O functionality, all without changing a single line of code!
|
| 41 |
-
/// Idea from http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81
|
| 42 |
-
|
| 43 |
-
struct Tie: public streambuf { // MSVC requires split streambuf for cin and cout
|
| 44 |
-
|
| 45 |
-
Tie(streambuf* b, streambuf* l) : buf(b), logBuf(l) {}
|
| 46 |
-
|
| 47 |
-
int sync() { return logBuf->pubsync(), buf->pubsync(); }
|
| 48 |
-
int overflow(int c) { return log(buf->sputc((char)c), "<< "); }
|
| 49 |
-
int underflow() { return buf->sgetc(); }
|
| 50 |
-
int uflow() { return log(buf->sbumpc(), ">> "); }
|
| 51 |
-
|
| 52 |
-
streambuf *buf, *logBuf;
|
| 53 |
-
|
| 54 |
-
int log(int c, const char* prefix) {
|
| 55 |
-
|
| 56 |
-
static int last = '\n'; // Single log file
|
| 57 |
-
|
| 58 |
-
if (last == '\n')
|
| 59 |
-
logBuf->sputn(prefix, 3);
|
| 60 |
-
|
| 61 |
-
return last = logBuf->sputc((char)c);
|
| 62 |
-
}
|
| 63 |
-
};
|
| 64 |
-
|
| 65 |
-
class Logger {
|
| 66 |
-
|
| 67 |
-
Logger() : in(cin.rdbuf(), file.rdbuf()), out(cout.rdbuf(), file.rdbuf()) {}
|
| 68 |
-
~Logger() { start(""); }
|
| 69 |
-
|
| 70 |
-
ofstream file;
|
| 71 |
-
Tie in, out;
|
| 72 |
-
|
| 73 |
-
public:
|
| 74 |
-
static void start(const std::string& fname) {
|
| 75 |
-
|
| 76 |
-
static Logger l;
|
| 77 |
-
|
| 78 |
-
if (!fname.empty() && !l.file.is_open())
|
| 79 |
-
{
|
| 80 |
-
l.file.open(fname, ifstream::out);
|
| 81 |
-
cin.rdbuf(&l.in);
|
| 82 |
-
cout.rdbuf(&l.out);
|
| 83 |
-
}
|
| 84 |
-
else if (fname.empty() && l.file.is_open())
|
| 85 |
-
{
|
| 86 |
-
cout.rdbuf(l.out.buf);
|
| 87 |
-
cin.rdbuf(l.in.buf);
|
| 88 |
-
l.file.close();
|
| 89 |
-
}
|
| 90 |
-
}
|
| 91 |
-
};
|
| 92 |
-
|
| 93 |
-
} // namespace
|
| 94 |
-
|
| 95 |
-
/// engine_info() returns the full name of the current Stockfish version. This
|
| 96 |
-
/// will be either "Stockfish <Tag> DD-MM-YY" (where DD-MM-YY is the date when
|
| 97 |
-
/// the program was compiled) or "Stockfish <Version>", depending on whether
|
| 98 |
-
/// Version is empty.
|
| 99 |
-
|
| 100 |
-
const string engine_info(bool to_uci) {
|
| 101 |
-
|
| 102 |
-
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
|
| 103 |
-
string month, day, year;
|
| 104 |
-
stringstream ss, date(__DATE__); // From compiler, format is "Sep 21 2008"
|
| 105 |
-
|
| 106 |
-
ss << "Stockfish " << Version << setfill('0');
|
| 107 |
-
|
| 108 |
-
if (Version.empty())
|
| 109 |
-
{
|
| 110 |
-
date >> month >> day >> year;
|
| 111 |
-
ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2);
|
| 112 |
-
}
|
| 113 |
-
|
| 114 |
-
ss << (Is64Bit ? " 64" : "")
|
| 115 |
-
<< (HasPext ? " BMI2" : (HasPopCnt ? " POPCNT" : ""))
|
| 116 |
-
<< (to_uci ? "\nid author ": " by ")
|
| 117 |
-
<< "T. Romstad, M. Costalba, J. Kiiski, G. Linscott";
|
| 118 |
-
|
| 119 |
-
return ss.str();
|
| 120 |
-
}
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
/// Debug functions used mainly to collect run-time statistics
|
| 124 |
-
static int64_t hits[2], means[2];
|
| 125 |
-
|
| 126 |
-
void dbg_hit_on(bool b) { ++hits[0]; if (b) ++hits[1]; }
|
| 127 |
-
void dbg_hit_on(bool c, bool b) { if (c) dbg_hit_on(b); }
|
| 128 |
-
void dbg_mean_of(int v) { ++means[0]; means[1] += v; }
|
| 129 |
-
|
| 130 |
-
void dbg_print() {
|
| 131 |
-
|
| 132 |
-
if (hits[0])
|
| 133 |
-
cerr << "Total " << hits[0] << " Hits " << hits[1]
|
| 134 |
-
<< " hit rate (%) " << 100 * hits[1] / hits[0] << endl;
|
| 135 |
-
|
| 136 |
-
if (means[0])
|
| 137 |
-
cerr << "Total " << means[0] << " Mean "
|
| 138 |
-
<< (double)means[1] / means[0] << endl;
|
| 139 |
-
}
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
/// Used to serialize access to std::cout to avoid multiple threads writing at
|
| 143 |
-
/// the same time.
|
| 144 |
-
|
| 145 |
-
std::ostream& operator<<(std::ostream& os, SyncCout sc) {
|
| 146 |
-
|
| 147 |
-
static Mutex m;
|
| 148 |
-
|
| 149 |
-
if (sc == IO_LOCK)
|
| 150 |
-
m.lock();
|
| 151 |
-
|
| 152 |
-
if (sc == IO_UNLOCK)
|
| 153 |
-
m.unlock();
|
| 154 |
-
|
| 155 |
-
return os;
|
| 156 |
-
}
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
/// Trampoline helper to avoid moving Logger to misc.h
|
| 160 |
-
void start_logger(const std::string& fname) { Logger::start(fname); }
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
/// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking
|
| 164 |
-
/// function that doesn't stall the CPU waiting for data to be loaded from memory,
|
| 165 |
-
/// which can be quite slow.
|
| 166 |
-
#ifdef NO_PREFETCH
|
| 167 |
-
|
| 168 |
-
void prefetch(void*) {}
|
| 169 |
-
|
| 170 |
-
#else
|
| 171 |
-
|
| 172 |
-
void prefetch(void* addr) {
|
| 173 |
-
|
| 174 |
-
# if defined(__INTEL_COMPILER)
|
| 175 |
-
// This hack prevents prefetches from being optimized away by
|
| 176 |
-
// Intel compiler. Both MSVC and gcc seem not be affected by this.
|
| 177 |
-
__asm__ ("");
|
| 178 |
-
# endif
|
| 179 |
-
|
| 180 |
-
# if defined(__INTEL_COMPILER) || defined(_MSC_VER)
|
| 181 |
-
_mm_prefetch((char*)addr, _MM_HINT_T0);
|
| 182 |
-
# else
|
| 183 |
-
__builtin_prefetch(addr);
|
| 184 |
-
# endif
|
| 185 |
-
}
|
| 186 |
-
|
| 187 |
-
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/misc.h
DELETED
|
@@ -1,100 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef MISC_H_INCLUDED
|
| 22 |
-
#define MISC_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include <cassert>
|
| 25 |
-
#include <chrono>
|
| 26 |
-
#include <ostream>
|
| 27 |
-
#include <string>
|
| 28 |
-
#include <vector>
|
| 29 |
-
|
| 30 |
-
#include "types.h"
|
| 31 |
-
|
| 32 |
-
const std::string engine_info(bool to_uci = false);
|
| 33 |
-
void prefetch(void* addr);
|
| 34 |
-
void start_logger(const std::string& fname);
|
| 35 |
-
|
| 36 |
-
void dbg_hit_on(bool b);
|
| 37 |
-
void dbg_hit_on(bool c, bool b);
|
| 38 |
-
void dbg_mean_of(int v);
|
| 39 |
-
void dbg_print();
|
| 40 |
-
|
| 41 |
-
typedef std::chrono::milliseconds::rep TimePoint; // A value in milliseconds
|
| 42 |
-
|
| 43 |
-
inline TimePoint now() {
|
| 44 |
-
return std::chrono::duration_cast<std::chrono::milliseconds>
|
| 45 |
-
(std::chrono::steady_clock::now().time_since_epoch()).count();
|
| 46 |
-
}
|
| 47 |
-
|
| 48 |
-
template<class Entry, int Size>
|
| 49 |
-
struct HashTable {
|
| 50 |
-
Entry* operator[](Key key) { return &table[(uint32_t)key & (Size - 1)]; }
|
| 51 |
-
|
| 52 |
-
private:
|
| 53 |
-
std::vector<Entry> table = std::vector<Entry>(Size);
|
| 54 |
-
};
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
enum SyncCout { IO_LOCK, IO_UNLOCK };
|
| 58 |
-
std::ostream& operator<<(std::ostream&, SyncCout);
|
| 59 |
-
|
| 60 |
-
#define sync_cout std::cout << IO_LOCK
|
| 61 |
-
#define sync_endl std::endl << IO_UNLOCK
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
/// xorshift64star Pseudo-Random Number Generator
|
| 65 |
-
/// This class is based on original code written and dedicated
|
| 66 |
-
/// to the public domain by Sebastiano Vigna (2014).
|
| 67 |
-
/// It has the following characteristics:
|
| 68 |
-
///
|
| 69 |
-
/// - Outputs 64-bit numbers
|
| 70 |
-
/// - Passes Dieharder and SmallCrush test batteries
|
| 71 |
-
/// - Does not require warm-up, no zeroland to escape
|
| 72 |
-
/// - Internal state is a single 64-bit integer
|
| 73 |
-
/// - Period is 2^64 - 1
|
| 74 |
-
/// - Speed: 1.60 ns/call (Core i7 @3.40GHz)
|
| 75 |
-
///
|
| 76 |
-
/// For further analysis see
|
| 77 |
-
/// <http://vigna.di.unimi.it/ftp/papers/xorshift.pdf>
|
| 78 |
-
|
| 79 |
-
class PRNG {
|
| 80 |
-
|
| 81 |
-
uint64_t s;
|
| 82 |
-
|
| 83 |
-
uint64_t rand64() {
|
| 84 |
-
|
| 85 |
-
s ^= s >> 12, s ^= s << 25, s ^= s >> 27;
|
| 86 |
-
return s * 2685821657736338717LL;
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
public:
|
| 90 |
-
PRNG(uint64_t seed) : s(seed) { assert(seed); }
|
| 91 |
-
|
| 92 |
-
template<typename T> T rand() { return T(rand64()); }
|
| 93 |
-
|
| 94 |
-
/// Special generator used to fast init magic numbers.
|
| 95 |
-
/// Output values only have 1/8th of their bits set on average.
|
| 96 |
-
template<typename T> T sparse_rand()
|
| 97 |
-
{ return T(rand64() & rand64() & rand64()); }
|
| 98 |
-
};
|
| 99 |
-
|
| 100 |
-
#endif // #ifndef MISC_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/movegen.cpp
DELETED
|
@@ -1,420 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <cassert>
|
| 22 |
-
|
| 23 |
-
#include "movegen.h"
|
| 24 |
-
#include "position.h"
|
| 25 |
-
|
| 26 |
-
namespace {
|
| 27 |
-
|
| 28 |
-
template<CastlingRight Cr, bool Checks, bool Chess960>
|
| 29 |
-
ExtMove* generate_castling(const Position& pos, ExtMove* moveList, Color us) {
|
| 30 |
-
|
| 31 |
-
static const bool KingSide = (Cr == WHITE_OO || Cr == BLACK_OO);
|
| 32 |
-
|
| 33 |
-
if (pos.castling_impeded(Cr) || !pos.can_castle(Cr))
|
| 34 |
-
return moveList;
|
| 35 |
-
|
| 36 |
-
// After castling, the rook and king final positions are the same in Chess960
|
| 37 |
-
// as they would be in standard chess.
|
| 38 |
-
Square kfrom = pos.square<KING>(us);
|
| 39 |
-
Square rfrom = pos.castling_rook_square(Cr);
|
| 40 |
-
Square kto = relative_square(us, KingSide ? SQ_G1 : SQ_C1);
|
| 41 |
-
Bitboard enemies = pos.pieces(~us);
|
| 42 |
-
|
| 43 |
-
assert(!pos.checkers());
|
| 44 |
-
|
| 45 |
-
const Square K = Chess960 ? kto > kfrom ? WEST : EAST
|
| 46 |
-
: KingSide ? WEST : EAST;
|
| 47 |
-
|
| 48 |
-
for (Square s = kto; s != kfrom; s += K)
|
| 49 |
-
if (pos.attackers_to(s) & enemies)
|
| 50 |
-
return moveList;
|
| 51 |
-
|
| 52 |
-
// Because we generate only legal castling moves we need to verify that
|
| 53 |
-
// when moving the castling rook we do not discover some hidden checker.
|
| 54 |
-
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
|
| 55 |
-
if (Chess960 && (attacks_bb<ROOK>(kto, pos.pieces() ^ rfrom) & pos.pieces(~us, ROOK, QUEEN)))
|
| 56 |
-
return moveList;
|
| 57 |
-
|
| 58 |
-
Move m = make<CASTLING>(kfrom, rfrom);
|
| 59 |
-
|
| 60 |
-
if (Checks && !pos.gives_check(m))
|
| 61 |
-
return moveList;
|
| 62 |
-
|
| 63 |
-
*moveList++ = m;
|
| 64 |
-
return moveList;
|
| 65 |
-
}
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
template<GenType Type, Square D>
|
| 69 |
-
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
|
| 70 |
-
|
| 71 |
-
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
| 72 |
-
*moveList++ = make<PROMOTION>(to - D, to, QUEEN);
|
| 73 |
-
|
| 74 |
-
if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
|
| 75 |
-
{
|
| 76 |
-
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
|
| 77 |
-
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
|
| 78 |
-
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
|
| 79 |
-
}
|
| 80 |
-
|
| 81 |
-
// Knight promotion is the only promotion that can give a direct check
|
| 82 |
-
// that's not already included in the queen promotion.
|
| 83 |
-
if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ksq))
|
| 84 |
-
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
|
| 85 |
-
else
|
| 86 |
-
(void)ksq; // Silence a warning under MSVC
|
| 87 |
-
|
| 88 |
-
return moveList;
|
| 89 |
-
}
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
template<Color Us, GenType Type>
|
| 93 |
-
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
|
| 94 |
-
|
| 95 |
-
// Compute our parametrized parameters at compile time, named according to
|
| 96 |
-
// the point of view of white side.
|
| 97 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 98 |
-
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
|
| 99 |
-
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
| 100 |
-
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
| 101 |
-
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
| 102 |
-
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
| 103 |
-
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
| 104 |
-
|
| 105 |
-
Bitboard emptySquares;
|
| 106 |
-
|
| 107 |
-
Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB;
|
| 108 |
-
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
|
| 109 |
-
|
| 110 |
-
Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target:
|
| 111 |
-
Type == CAPTURES ? target : pos.pieces(Them));
|
| 112 |
-
|
| 113 |
-
// Single and double pawn pushes, no promotions
|
| 114 |
-
if (Type != CAPTURES)
|
| 115 |
-
{
|
| 116 |
-
emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
|
| 117 |
-
|
| 118 |
-
Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares;
|
| 119 |
-
Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares;
|
| 120 |
-
|
| 121 |
-
if (Type == EVASIONS) // Consider only blocking squares
|
| 122 |
-
{
|
| 123 |
-
b1 &= target;
|
| 124 |
-
b2 &= target;
|
| 125 |
-
}
|
| 126 |
-
|
| 127 |
-
if (Type == QUIET_CHECKS)
|
| 128 |
-
{
|
| 129 |
-
Square ksq = pos.square<KING>(Them);
|
| 130 |
-
|
| 131 |
-
b1 &= pos.attacks_from<PAWN>(ksq, Them);
|
| 132 |
-
b2 &= pos.attacks_from<PAWN>(ksq, Them);
|
| 133 |
-
|
| 134 |
-
// Add pawn pushes which give discovered check. This is possible only
|
| 135 |
-
// if the pawn is not on the same file as the enemy king, because we
|
| 136 |
-
// don't generate captures. Note that a possible discovery check
|
| 137 |
-
// promotion has been already generated amongst the captures.
|
| 138 |
-
Bitboard dcCandidates = pos.discovered_check_candidates();
|
| 139 |
-
if (pawnsNotOn7 & dcCandidates)
|
| 140 |
-
{
|
| 141 |
-
Bitboard dc1 = shift<Up>(pawnsNotOn7 & dcCandidates) & emptySquares & ~file_bb(ksq);
|
| 142 |
-
Bitboard dc2 = shift<Up>(dc1 & TRank3BB) & emptySquares;
|
| 143 |
-
|
| 144 |
-
b1 |= dc1;
|
| 145 |
-
b2 |= dc2;
|
| 146 |
-
}
|
| 147 |
-
}
|
| 148 |
-
|
| 149 |
-
while (b1)
|
| 150 |
-
{
|
| 151 |
-
Square to = pop_lsb(&b1);
|
| 152 |
-
*moveList++ = make_move(to - Up, to);
|
| 153 |
-
}
|
| 154 |
-
|
| 155 |
-
while (b2)
|
| 156 |
-
{
|
| 157 |
-
Square to = pop_lsb(&b2);
|
| 158 |
-
*moveList++ = make_move(to - Up - Up, to);
|
| 159 |
-
}
|
| 160 |
-
}
|
| 161 |
-
|
| 162 |
-
// Promotions and underpromotions
|
| 163 |
-
if (pawnsOn7 && (Type != EVASIONS || (target & TRank8BB)))
|
| 164 |
-
{
|
| 165 |
-
if (Type == CAPTURES)
|
| 166 |
-
emptySquares = ~pos.pieces();
|
| 167 |
-
|
| 168 |
-
if (Type == EVASIONS)
|
| 169 |
-
emptySquares &= target;
|
| 170 |
-
|
| 171 |
-
Bitboard b1 = shift<Right>(pawnsOn7) & enemies;
|
| 172 |
-
Bitboard b2 = shift<Left >(pawnsOn7) & enemies;
|
| 173 |
-
Bitboard b3 = shift<Up >(pawnsOn7) & emptySquares;
|
| 174 |
-
|
| 175 |
-
Square ksq = pos.square<KING>(Them);
|
| 176 |
-
|
| 177 |
-
while (b1)
|
| 178 |
-
moveList = make_promotions<Type, Right>(moveList, pop_lsb(&b1), ksq);
|
| 179 |
-
|
| 180 |
-
while (b2)
|
| 181 |
-
moveList = make_promotions<Type, Left >(moveList, pop_lsb(&b2), ksq);
|
| 182 |
-
|
| 183 |
-
while (b3)
|
| 184 |
-
moveList = make_promotions<Type, Up >(moveList, pop_lsb(&b3), ksq);
|
| 185 |
-
}
|
| 186 |
-
|
| 187 |
-
// Standard and en-passant captures
|
| 188 |
-
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
| 189 |
-
{
|
| 190 |
-
Bitboard b1 = shift<Right>(pawnsNotOn7) & enemies;
|
| 191 |
-
Bitboard b2 = shift<Left >(pawnsNotOn7) & enemies;
|
| 192 |
-
|
| 193 |
-
while (b1)
|
| 194 |
-
{
|
| 195 |
-
Square to = pop_lsb(&b1);
|
| 196 |
-
*moveList++ = make_move(to - Right, to);
|
| 197 |
-
}
|
| 198 |
-
|
| 199 |
-
while (b2)
|
| 200 |
-
{
|
| 201 |
-
Square to = pop_lsb(&b2);
|
| 202 |
-
*moveList++ = make_move(to - Left, to);
|
| 203 |
-
}
|
| 204 |
-
|
| 205 |
-
if (pos.ep_square() != SQ_NONE)
|
| 206 |
-
{
|
| 207 |
-
assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6));
|
| 208 |
-
|
| 209 |
-
// An en passant capture can be an evasion only if the checking piece
|
| 210 |
-
// is the double pushed pawn and so is in the target. Otherwise this
|
| 211 |
-
// is a discovery check and we are forced to do otherwise.
|
| 212 |
-
if (Type == EVASIONS && !(target & (pos.ep_square() - Up)))
|
| 213 |
-
return moveList;
|
| 214 |
-
|
| 215 |
-
b1 = pawnsNotOn7 & pos.attacks_from<PAWN>(pos.ep_square(), Them);
|
| 216 |
-
|
| 217 |
-
assert(b1);
|
| 218 |
-
|
| 219 |
-
while (b1)
|
| 220 |
-
*moveList++ = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square());
|
| 221 |
-
}
|
| 222 |
-
}
|
| 223 |
-
|
| 224 |
-
return moveList;
|
| 225 |
-
}
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
template<PieceType Pt, bool Checks>
|
| 229 |
-
ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us,
|
| 230 |
-
Bitboard target) {
|
| 231 |
-
|
| 232 |
-
assert(Pt != KING && Pt != PAWN);
|
| 233 |
-
|
| 234 |
-
const Square* pl = pos.squares<Pt>(us);
|
| 235 |
-
|
| 236 |
-
for (Square from = *pl; from != SQ_NONE; from = *++pl)
|
| 237 |
-
{
|
| 238 |
-
if (Checks)
|
| 239 |
-
{
|
| 240 |
-
if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
|
| 241 |
-
&& !(PseudoAttacks[Pt][from] & target & pos.check_squares(Pt)))
|
| 242 |
-
continue;
|
| 243 |
-
|
| 244 |
-
if (pos.discovered_check_candidates() & from)
|
| 245 |
-
continue;
|
| 246 |
-
}
|
| 247 |
-
|
| 248 |
-
Bitboard b = pos.attacks_from<Pt>(from) & target;
|
| 249 |
-
|
| 250 |
-
if (Checks)
|
| 251 |
-
b &= pos.check_squares(Pt);
|
| 252 |
-
|
| 253 |
-
while (b)
|
| 254 |
-
*moveList++ = make_move(from, pop_lsb(&b));
|
| 255 |
-
}
|
| 256 |
-
|
| 257 |
-
return moveList;
|
| 258 |
-
}
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
template<Color Us, GenType Type>
|
| 262 |
-
ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) {
|
| 263 |
-
|
| 264 |
-
const bool Checks = Type == QUIET_CHECKS;
|
| 265 |
-
|
| 266 |
-
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
|
| 267 |
-
moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target);
|
| 268 |
-
moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target);
|
| 269 |
-
moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target);
|
| 270 |
-
moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target);
|
| 271 |
-
|
| 272 |
-
if (Type != QUIET_CHECKS && Type != EVASIONS)
|
| 273 |
-
{
|
| 274 |
-
Square ksq = pos.square<KING>(Us);
|
| 275 |
-
Bitboard b = pos.attacks_from<KING>(ksq) & target;
|
| 276 |
-
while (b)
|
| 277 |
-
*moveList++ = make_move(ksq, pop_lsb(&b));
|
| 278 |
-
}
|
| 279 |
-
|
| 280 |
-
if (Type != CAPTURES && Type != EVASIONS && pos.can_castle(Us))
|
| 281 |
-
{
|
| 282 |
-
if (pos.is_chess960())
|
| 283 |
-
{
|
| 284 |
-
moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, true>(pos, moveList, Us);
|
| 285 |
-
moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, true>(pos, moveList, Us);
|
| 286 |
-
}
|
| 287 |
-
else
|
| 288 |
-
{
|
| 289 |
-
moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, false>(pos, moveList, Us);
|
| 290 |
-
moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, false>(pos, moveList, Us);
|
| 291 |
-
}
|
| 292 |
-
}
|
| 293 |
-
|
| 294 |
-
return moveList;
|
| 295 |
-
}
|
| 296 |
-
|
| 297 |
-
} // namespace
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
/// generate<CAPTURES> generates all pseudo-legal captures and queen
|
| 301 |
-
/// promotions. Returns a pointer to the end of the move list.
|
| 302 |
-
///
|
| 303 |
-
/// generate<QUIETS> generates all pseudo-legal non-captures and
|
| 304 |
-
/// underpromotions. Returns a pointer to the end of the move list.
|
| 305 |
-
///
|
| 306 |
-
/// generate<NON_EVASIONS> generates all pseudo-legal captures and
|
| 307 |
-
/// non-captures. Returns a pointer to the end of the move list.
|
| 308 |
-
|
| 309 |
-
template<GenType Type>
|
| 310 |
-
ExtMove* generate(const Position& pos, ExtMove* moveList) {
|
| 311 |
-
|
| 312 |
-
assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS);
|
| 313 |
-
assert(!pos.checkers());
|
| 314 |
-
|
| 315 |
-
Color us = pos.side_to_move();
|
| 316 |
-
|
| 317 |
-
Bitboard target = Type == CAPTURES ? pos.pieces(~us)
|
| 318 |
-
: Type == QUIETS ? ~pos.pieces()
|
| 319 |
-
: Type == NON_EVASIONS ? ~pos.pieces(us) : 0;
|
| 320 |
-
|
| 321 |
-
return us == WHITE ? generate_all<WHITE, Type>(pos, moveList, target)
|
| 322 |
-
: generate_all<BLACK, Type>(pos, moveList, target);
|
| 323 |
-
}
|
| 324 |
-
|
| 325 |
-
// Explicit template instantiations
|
| 326 |
-
template ExtMove* generate<CAPTURES>(const Position&, ExtMove*);
|
| 327 |
-
template ExtMove* generate<QUIETS>(const Position&, ExtMove*);
|
| 328 |
-
template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight
|
| 332 |
-
/// underpromotions that give check. Returns a pointer to the end of the move list.
|
| 333 |
-
template<>
|
| 334 |
-
ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
|
| 335 |
-
|
| 336 |
-
assert(!pos.checkers());
|
| 337 |
-
|
| 338 |
-
Color us = pos.side_to_move();
|
| 339 |
-
Bitboard dc = pos.discovered_check_candidates();
|
| 340 |
-
|
| 341 |
-
while (dc)
|
| 342 |
-
{
|
| 343 |
-
Square from = pop_lsb(&dc);
|
| 344 |
-
PieceType pt = type_of(pos.piece_on(from));
|
| 345 |
-
|
| 346 |
-
if (pt == PAWN)
|
| 347 |
-
continue; // Will be generated together with direct checks
|
| 348 |
-
|
| 349 |
-
Bitboard b = pos.attacks_from(Piece(pt), from) & ~pos.pieces();
|
| 350 |
-
|
| 351 |
-
if (pt == KING)
|
| 352 |
-
b &= ~PseudoAttacks[QUEEN][pos.square<KING>(~us)];
|
| 353 |
-
|
| 354 |
-
while (b)
|
| 355 |
-
*moveList++ = make_move(from, pop_lsb(&b));
|
| 356 |
-
}
|
| 357 |
-
|
| 358 |
-
return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList, ~pos.pieces())
|
| 359 |
-
: generate_all<BLACK, QUIET_CHECKS>(pos, moveList, ~pos.pieces());
|
| 360 |
-
}
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
/// generate<EVASIONS> generates all pseudo-legal check evasions when the side
|
| 364 |
-
/// to move is in check. Returns a pointer to the end of the move list.
|
| 365 |
-
template<>
|
| 366 |
-
ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* moveList) {
|
| 367 |
-
|
| 368 |
-
assert(pos.checkers());
|
| 369 |
-
|
| 370 |
-
Color us = pos.side_to_move();
|
| 371 |
-
Square ksq = pos.square<KING>(us);
|
| 372 |
-
Bitboard sliderAttacks = 0;
|
| 373 |
-
Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN);
|
| 374 |
-
|
| 375 |
-
// Find all the squares attacked by slider checkers. We will remove them from
|
| 376 |
-
// the king evasions in order to skip known illegal moves, which avoids any
|
| 377 |
-
// useless legality checks later on.
|
| 378 |
-
while (sliders)
|
| 379 |
-
{
|
| 380 |
-
Square checksq = pop_lsb(&sliders);
|
| 381 |
-
sliderAttacks |= LineBB[checksq][ksq] ^ checksq;
|
| 382 |
-
}
|
| 383 |
-
|
| 384 |
-
// Generate evasions for king, capture and non capture moves
|
| 385 |
-
Bitboard b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
|
| 386 |
-
while (b)
|
| 387 |
-
*moveList++ = make_move(ksq, pop_lsb(&b));
|
| 388 |
-
|
| 389 |
-
if (more_than_one(pos.checkers()))
|
| 390 |
-
return moveList; // Double check, only a king move can save the day
|
| 391 |
-
|
| 392 |
-
// Generate blocking evasions or captures of the checking piece
|
| 393 |
-
Square checksq = lsb(pos.checkers());
|
| 394 |
-
Bitboard target = between_bb(checksq, ksq) | checksq;
|
| 395 |
-
|
| 396 |
-
return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, moveList, target)
|
| 397 |
-
: generate_all<BLACK, EVASIONS>(pos, moveList, target);
|
| 398 |
-
}
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
/// generate<LEGAL> generates all the legal moves in the given position
|
| 402 |
-
|
| 403 |
-
template<>
|
| 404 |
-
ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
|
| 405 |
-
|
| 406 |
-
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
|
| 407 |
-
Square ksq = pos.square<KING>(pos.side_to_move());
|
| 408 |
-
ExtMove* cur = moveList;
|
| 409 |
-
|
| 410 |
-
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
|
| 411 |
-
: generate<NON_EVASIONS>(pos, moveList);
|
| 412 |
-
while (cur != moveList)
|
| 413 |
-
if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == ENPASSANT)
|
| 414 |
-
&& !pos.legal(*cur))
|
| 415 |
-
*cur = (--moveList)->move;
|
| 416 |
-
else
|
| 417 |
-
++cur;
|
| 418 |
-
|
| 419 |
-
return moveList;
|
| 420 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/movegen.h
DELETED
|
@@ -1,70 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef MOVEGEN_H_INCLUDED
|
| 22 |
-
#define MOVEGEN_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include "types.h"
|
| 25 |
-
|
| 26 |
-
class Position;
|
| 27 |
-
|
| 28 |
-
enum GenType {
|
| 29 |
-
CAPTURES,
|
| 30 |
-
QUIETS,
|
| 31 |
-
QUIET_CHECKS,
|
| 32 |
-
EVASIONS,
|
| 33 |
-
NON_EVASIONS,
|
| 34 |
-
LEGAL
|
| 35 |
-
};
|
| 36 |
-
|
| 37 |
-
struct ExtMove {
|
| 38 |
-
Move move;
|
| 39 |
-
Value value;
|
| 40 |
-
|
| 41 |
-
operator Move() const { return move; }
|
| 42 |
-
void operator=(Move m) { move = m; }
|
| 43 |
-
};
|
| 44 |
-
|
| 45 |
-
inline bool operator<(const ExtMove& f, const ExtMove& s) {
|
| 46 |
-
return f.value < s.value;
|
| 47 |
-
}
|
| 48 |
-
|
| 49 |
-
template<GenType>
|
| 50 |
-
ExtMove* generate(const Position& pos, ExtMove* moveList);
|
| 51 |
-
|
| 52 |
-
/// The MoveList struct is a simple wrapper around generate(). It sometimes comes
|
| 53 |
-
/// in handy to use this class instead of the low level generate() function.
|
| 54 |
-
template<GenType T>
|
| 55 |
-
struct MoveList {
|
| 56 |
-
|
| 57 |
-
explicit MoveList(const Position& pos) : last(generate<T>(pos, moveList)) {}
|
| 58 |
-
const ExtMove* begin() const { return moveList; }
|
| 59 |
-
const ExtMove* end() const { return last; }
|
| 60 |
-
size_t size() const { return last - moveList; }
|
| 61 |
-
bool contains(Move move) const {
|
| 62 |
-
for (const auto& m : *this) if (m == move) return true;
|
| 63 |
-
return false;
|
| 64 |
-
}
|
| 65 |
-
|
| 66 |
-
private:
|
| 67 |
-
ExtMove moveList[MAX_MOVES], *last;
|
| 68 |
-
};
|
| 69 |
-
|
| 70 |
-
#endif // #ifndef MOVEGEN_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/movepick.cpp
DELETED
|
@@ -1,350 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <cassert>
|
| 22 |
-
|
| 23 |
-
#include "movepick.h"
|
| 24 |
-
#include "thread.h"
|
| 25 |
-
|
| 26 |
-
namespace {
|
| 27 |
-
|
| 28 |
-
enum Stages {
|
| 29 |
-
MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES,
|
| 30 |
-
EVASION, EVASIONS_INIT, ALL_EVASIONS,
|
| 31 |
-
PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES,
|
| 32 |
-
QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS,
|
| 33 |
-
QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2,
|
| 34 |
-
QSEARCH_RECAPTURES, QRECAPTURES
|
| 35 |
-
};
|
| 36 |
-
|
| 37 |
-
// Our insertion sort, which is guaranteed to be stable, as it should be
|
| 38 |
-
void insertion_sort(ExtMove* begin, ExtMove* end)
|
| 39 |
-
{
|
| 40 |
-
ExtMove tmp, *p, *q;
|
| 41 |
-
|
| 42 |
-
for (p = begin + 1; p < end; ++p)
|
| 43 |
-
{
|
| 44 |
-
tmp = *p;
|
| 45 |
-
for (q = p; q != begin && *(q-1) < tmp; --q)
|
| 46 |
-
*q = *(q-1);
|
| 47 |
-
*q = tmp;
|
| 48 |
-
}
|
| 49 |
-
}
|
| 50 |
-
|
| 51 |
-
// pick_best() finds the best move in the range (begin, end) and moves it to
|
| 52 |
-
// the front. It's faster than sorting all the moves in advance when there
|
| 53 |
-
// are few moves, e.g., the possible captures.
|
| 54 |
-
Move pick_best(ExtMove* begin, ExtMove* end)
|
| 55 |
-
{
|
| 56 |
-
std::swap(*begin, *std::max_element(begin, end));
|
| 57 |
-
return *begin;
|
| 58 |
-
}
|
| 59 |
-
|
| 60 |
-
} // namespace
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
/// Constructors of the MovePicker class. As arguments we pass information
|
| 64 |
-
/// to help it to return the (presumably) good moves first, to decide which
|
| 65 |
-
/// moves to return (in the quiescence search, for instance, we only want to
|
| 66 |
-
/// search captures, promotions, and some checks) and how important good move
|
| 67 |
-
/// ordering is at the current node.
|
| 68 |
-
|
| 69 |
-
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Search::Stack* s)
|
| 70 |
-
: pos(p), ss(s), depth(d) {
|
| 71 |
-
|
| 72 |
-
assert(d > DEPTH_ZERO);
|
| 73 |
-
|
| 74 |
-
Square prevSq = to_sq((ss-1)->currentMove);
|
| 75 |
-
countermove = pos.this_thread()->counterMoves[pos.piece_on(prevSq)][prevSq];
|
| 76 |
-
|
| 77 |
-
stage = pos.checkers() ? EVASION : MAIN_SEARCH;
|
| 78 |
-
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
|
| 79 |
-
stage += (ttMove == MOVE_NONE);
|
| 80 |
-
}
|
| 81 |
-
|
| 82 |
-
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s)
|
| 83 |
-
: pos(p) {
|
| 84 |
-
|
| 85 |
-
assert(d <= DEPTH_ZERO);
|
| 86 |
-
|
| 87 |
-
if (pos.checkers())
|
| 88 |
-
stage = EVASION;
|
| 89 |
-
|
| 90 |
-
else if (d > DEPTH_QS_NO_CHECKS)
|
| 91 |
-
stage = QSEARCH_WITH_CHECKS;
|
| 92 |
-
|
| 93 |
-
else if (d > DEPTH_QS_RECAPTURES)
|
| 94 |
-
stage = QSEARCH_NO_CHECKS;
|
| 95 |
-
|
| 96 |
-
else
|
| 97 |
-
{
|
| 98 |
-
stage = QSEARCH_RECAPTURES;
|
| 99 |
-
recaptureSquare = s;
|
| 100 |
-
return;
|
| 101 |
-
}
|
| 102 |
-
|
| 103 |
-
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
|
| 104 |
-
stage += (ttMove == MOVE_NONE);
|
| 105 |
-
}
|
| 106 |
-
|
| 107 |
-
MovePicker::MovePicker(const Position& p, Move ttm, Value th)
|
| 108 |
-
: pos(p), threshold(th) {
|
| 109 |
-
|
| 110 |
-
assert(!pos.checkers());
|
| 111 |
-
|
| 112 |
-
stage = PROBCUT;
|
| 113 |
-
|
| 114 |
-
// In ProbCut we generate captures with SEE higher than the given threshold
|
| 115 |
-
ttMove = ttm
|
| 116 |
-
&& pos.pseudo_legal(ttm)
|
| 117 |
-
&& pos.capture(ttm)
|
| 118 |
-
&& pos.see_ge(ttm, threshold + 1)? ttm : MOVE_NONE;
|
| 119 |
-
|
| 120 |
-
stage += (ttMove == MOVE_NONE);
|
| 121 |
-
}
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
/// score() assigns a numerical value to each move in a move list. The moves with
|
| 125 |
-
/// highest values will be picked first.
|
| 126 |
-
template<>
|
| 127 |
-
void MovePicker::score<CAPTURES>() {
|
| 128 |
-
// Winning and equal captures in the main search are ordered by MVV, preferring
|
| 129 |
-
// captures near our home rank. Surprisingly, this appears to perform slightly
|
| 130 |
-
// better than SEE-based move ordering: exchanging big pieces before capturing
|
| 131 |
-
// a hanging piece probably helps to reduce the subtree size.
|
| 132 |
-
// In the main search we want to push captures with negative SEE values to the
|
| 133 |
-
// badCaptures[] array, but instead of doing it now we delay until the move
|
| 134 |
-
// has been picked up, saving some SEE calls in case we get a cutoff.
|
| 135 |
-
for (auto& m : *this)
|
| 136 |
-
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
|
| 137 |
-
- Value(200 * relative_rank(pos.side_to_move(), to_sq(m)));
|
| 138 |
-
}
|
| 139 |
-
|
| 140 |
-
template<>
|
| 141 |
-
void MovePicker::score<QUIETS>() {
|
| 142 |
-
|
| 143 |
-
const HistoryStats& history = pos.this_thread()->history;
|
| 144 |
-
const FromToStats& fromTo = pos.this_thread()->fromTo;
|
| 145 |
-
|
| 146 |
-
const CounterMoveStats* cm = (ss-1)->counterMoves;
|
| 147 |
-
const CounterMoveStats* fm = (ss-2)->counterMoves;
|
| 148 |
-
const CounterMoveStats* f2 = (ss-4)->counterMoves;
|
| 149 |
-
|
| 150 |
-
Color c = pos.side_to_move();
|
| 151 |
-
|
| 152 |
-
for (auto& m : *this)
|
| 153 |
-
m.value = history[pos.moved_piece(m)][to_sq(m)]
|
| 154 |
-
+ (cm ? (*cm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
|
| 155 |
-
+ (fm ? (*fm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
|
| 156 |
-
+ (f2 ? (*f2)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
|
| 157 |
-
+ fromTo.get(c, m);
|
| 158 |
-
}
|
| 159 |
-
|
| 160 |
-
template<>
|
| 161 |
-
void MovePicker::score<EVASIONS>() {
|
| 162 |
-
// Try captures ordered by MVV/LVA, then non-captures ordered by history value
|
| 163 |
-
const HistoryStats& history = pos.this_thread()->history;
|
| 164 |
-
const FromToStats& fromTo = pos.this_thread()->fromTo;
|
| 165 |
-
Color c = pos.side_to_move();
|
| 166 |
-
|
| 167 |
-
for (auto& m : *this)
|
| 168 |
-
if (pos.capture(m))
|
| 169 |
-
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
|
| 170 |
-
- Value(type_of(pos.moved_piece(m))) + HistoryStats::Max;
|
| 171 |
-
else
|
| 172 |
-
m.value = history[pos.moved_piece(m)][to_sq(m)] + fromTo.get(c, m);
|
| 173 |
-
}
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
/// next_move() is the most important method of the MovePicker class. It returns
|
| 177 |
-
/// a new pseudo legal move every time it is called, until there are no more moves
|
| 178 |
-
/// left. It picks the move with the biggest value from a list of generated moves
|
| 179 |
-
/// taking care not to return the ttMove if it has already been searched.
|
| 180 |
-
|
| 181 |
-
Move MovePicker::next_move() {
|
| 182 |
-
|
| 183 |
-
Move move;
|
| 184 |
-
|
| 185 |
-
switch (stage) {
|
| 186 |
-
|
| 187 |
-
case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS:
|
| 188 |
-
case QSEARCH_NO_CHECKS: case PROBCUT:
|
| 189 |
-
++stage;
|
| 190 |
-
return ttMove;
|
| 191 |
-
|
| 192 |
-
case CAPTURES_INIT:
|
| 193 |
-
endBadCaptures = cur = moves;
|
| 194 |
-
endMoves = generate<CAPTURES>(pos, cur);
|
| 195 |
-
score<CAPTURES>();
|
| 196 |
-
++stage;
|
| 197 |
-
|
| 198 |
-
case GOOD_CAPTURES:
|
| 199 |
-
while (cur < endMoves)
|
| 200 |
-
{
|
| 201 |
-
move = pick_best(cur++, endMoves);
|
| 202 |
-
if (move != ttMove)
|
| 203 |
-
{
|
| 204 |
-
if (pos.see_ge(move, VALUE_ZERO))
|
| 205 |
-
return move;
|
| 206 |
-
|
| 207 |
-
// Losing capture, move it to the beginning of the array
|
| 208 |
-
*endBadCaptures++ = move;
|
| 209 |
-
}
|
| 210 |
-
}
|
| 211 |
-
|
| 212 |
-
++stage;
|
| 213 |
-
move = ss->killers[0]; // First killer move
|
| 214 |
-
if ( move != MOVE_NONE
|
| 215 |
-
&& move != ttMove
|
| 216 |
-
&& pos.pseudo_legal(move)
|
| 217 |
-
&& !pos.capture(move))
|
| 218 |
-
return move;
|
| 219 |
-
|
| 220 |
-
case KILLERS:
|
| 221 |
-
++stage;
|
| 222 |
-
move = ss->killers[1]; // Second killer move
|
| 223 |
-
if ( move != MOVE_NONE
|
| 224 |
-
&& move != ttMove
|
| 225 |
-
&& pos.pseudo_legal(move)
|
| 226 |
-
&& !pos.capture(move))
|
| 227 |
-
return move;
|
| 228 |
-
|
| 229 |
-
case COUNTERMOVE:
|
| 230 |
-
++stage;
|
| 231 |
-
move = countermove;
|
| 232 |
-
if ( move != MOVE_NONE
|
| 233 |
-
&& move != ttMove
|
| 234 |
-
&& move != ss->killers[0]
|
| 235 |
-
&& move != ss->killers[1]
|
| 236 |
-
&& pos.pseudo_legal(move)
|
| 237 |
-
&& !pos.capture(move))
|
| 238 |
-
return move;
|
| 239 |
-
|
| 240 |
-
case QUIET_INIT:
|
| 241 |
-
cur = endBadCaptures;
|
| 242 |
-
endMoves = generate<QUIETS>(pos, cur);
|
| 243 |
-
score<QUIETS>();
|
| 244 |
-
if (depth < 3 * ONE_PLY)
|
| 245 |
-
{
|
| 246 |
-
ExtMove* goodQuiet = std::partition(cur, endMoves, [](const ExtMove& m)
|
| 247 |
-
{ return m.value > VALUE_ZERO; });
|
| 248 |
-
insertion_sort(cur, goodQuiet);
|
| 249 |
-
} else
|
| 250 |
-
insertion_sort(cur, endMoves);
|
| 251 |
-
++stage;
|
| 252 |
-
|
| 253 |
-
case QUIET:
|
| 254 |
-
while (cur < endMoves)
|
| 255 |
-
{
|
| 256 |
-
move = *cur++;
|
| 257 |
-
if ( move != ttMove
|
| 258 |
-
&& move != ss->killers[0]
|
| 259 |
-
&& move != ss->killers[1]
|
| 260 |
-
&& move != countermove)
|
| 261 |
-
return move;
|
| 262 |
-
}
|
| 263 |
-
++stage;
|
| 264 |
-
cur = moves; // Point to beginning of bad captures
|
| 265 |
-
|
| 266 |
-
case BAD_CAPTURES:
|
| 267 |
-
if (cur < endBadCaptures)
|
| 268 |
-
return *cur++;
|
| 269 |
-
break;
|
| 270 |
-
|
| 271 |
-
case EVASIONS_INIT:
|
| 272 |
-
cur = moves;
|
| 273 |
-
endMoves = generate<EVASIONS>(pos, cur);
|
| 274 |
-
score<EVASIONS>();
|
| 275 |
-
++stage;
|
| 276 |
-
|
| 277 |
-
case ALL_EVASIONS:
|
| 278 |
-
while (cur < endMoves)
|
| 279 |
-
{
|
| 280 |
-
move = pick_best(cur++, endMoves);
|
| 281 |
-
if (move != ttMove)
|
| 282 |
-
return move;
|
| 283 |
-
}
|
| 284 |
-
break;
|
| 285 |
-
|
| 286 |
-
case PROBCUT_INIT:
|
| 287 |
-
cur = moves;
|
| 288 |
-
endMoves = generate<CAPTURES>(pos, cur);
|
| 289 |
-
score<CAPTURES>();
|
| 290 |
-
++stage;
|
| 291 |
-
|
| 292 |
-
case PROBCUT_CAPTURES:
|
| 293 |
-
while (cur < endMoves)
|
| 294 |
-
{
|
| 295 |
-
move = pick_best(cur++, endMoves);
|
| 296 |
-
if ( move != ttMove
|
| 297 |
-
&& pos.see_ge(move, threshold + 1))
|
| 298 |
-
return move;
|
| 299 |
-
}
|
| 300 |
-
break;
|
| 301 |
-
|
| 302 |
-
case QCAPTURES_1_INIT: case QCAPTURES_2_INIT:
|
| 303 |
-
cur = moves;
|
| 304 |
-
endMoves = generate<CAPTURES>(pos, cur);
|
| 305 |
-
score<CAPTURES>();
|
| 306 |
-
++stage;
|
| 307 |
-
|
| 308 |
-
case QCAPTURES_1: case QCAPTURES_2:
|
| 309 |
-
while (cur < endMoves)
|
| 310 |
-
{
|
| 311 |
-
move = pick_best(cur++, endMoves);
|
| 312 |
-
if (move != ttMove)
|
| 313 |
-
return move;
|
| 314 |
-
}
|
| 315 |
-
if (stage == QCAPTURES_2)
|
| 316 |
-
break;
|
| 317 |
-
cur = moves;
|
| 318 |
-
endMoves = generate<QUIET_CHECKS>(pos, cur);
|
| 319 |
-
++stage;
|
| 320 |
-
|
| 321 |
-
case QCHECKS:
|
| 322 |
-
while (cur < endMoves)
|
| 323 |
-
{
|
| 324 |
-
move = cur++->move;
|
| 325 |
-
if (move != ttMove)
|
| 326 |
-
return move;
|
| 327 |
-
}
|
| 328 |
-
break;
|
| 329 |
-
|
| 330 |
-
case QSEARCH_RECAPTURES:
|
| 331 |
-
cur = moves;
|
| 332 |
-
endMoves = generate<CAPTURES>(pos, cur);
|
| 333 |
-
score<CAPTURES>();
|
| 334 |
-
++stage;
|
| 335 |
-
|
| 336 |
-
case QRECAPTURES:
|
| 337 |
-
while (cur < endMoves)
|
| 338 |
-
{
|
| 339 |
-
move = pick_best(cur++, endMoves);
|
| 340 |
-
if (to_sq(move) == recaptureSquare)
|
| 341 |
-
return move;
|
| 342 |
-
}
|
| 343 |
-
break;
|
| 344 |
-
|
| 345 |
-
default:
|
| 346 |
-
assert(false);
|
| 347 |
-
}
|
| 348 |
-
|
| 349 |
-
return MOVE_NONE;
|
| 350 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/movepick.h
DELETED
|
@@ -1,123 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef MOVEPICK_H_INCLUDED
|
| 22 |
-
#define MOVEPICK_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include <algorithm> // For std::max
|
| 25 |
-
#include <cstring> // For std::memset
|
| 26 |
-
|
| 27 |
-
#include "movegen.h"
|
| 28 |
-
#include "position.h"
|
| 29 |
-
#include "types.h"
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
/// The Stats struct stores moves statistics. According to the template parameter
|
| 33 |
-
/// the class can store History and Countermoves. History records how often
|
| 34 |
-
/// different moves have been successful or unsuccessful during the current search
|
| 35 |
-
/// and is used for reduction and move ordering decisions.
|
| 36 |
-
/// Countermoves store the move that refute a previous one. Entries are stored
|
| 37 |
-
/// using only the moving piece and destination square, hence two moves with
|
| 38 |
-
/// different origin but same destination and piece will be considered identical.
|
| 39 |
-
template<typename T, bool CM = false>
|
| 40 |
-
struct Stats {
|
| 41 |
-
|
| 42 |
-
static const Value Max = Value(1 << 28);
|
| 43 |
-
|
| 44 |
-
const T* operator[](Piece pc) const { return table[pc]; }
|
| 45 |
-
T* operator[](Piece pc) { return table[pc]; }
|
| 46 |
-
void clear() { std::memset(table, 0, sizeof(table)); }
|
| 47 |
-
void update(Piece pc, Square to, Move m) { table[pc][to] = m; }
|
| 48 |
-
void update(Piece pc, Square to, Value v) {
|
| 49 |
-
|
| 50 |
-
if (abs(int(v)) >= 324)
|
| 51 |
-
return;
|
| 52 |
-
|
| 53 |
-
table[pc][to] -= table[pc][to] * abs(int(v)) / (CM ? 936 : 324);
|
| 54 |
-
table[pc][to] += int(v) * 32;
|
| 55 |
-
}
|
| 56 |
-
|
| 57 |
-
private:
|
| 58 |
-
T table[PIECE_NB][SQUARE_NB];
|
| 59 |
-
};
|
| 60 |
-
|
| 61 |
-
typedef Stats<Move> MoveStats;
|
| 62 |
-
typedef Stats<Value, false> HistoryStats;
|
| 63 |
-
typedef Stats<Value, true> CounterMoveStats;
|
| 64 |
-
typedef Stats<CounterMoveStats> CounterMoveHistoryStats;
|
| 65 |
-
|
| 66 |
-
struct FromToStats {
|
| 67 |
-
|
| 68 |
-
Value get(Color c, Move m) const { return table[c][from_sq(m)][to_sq(m)]; }
|
| 69 |
-
void clear() { std::memset(table, 0, sizeof(table)); }
|
| 70 |
-
void update(Color c, Move m, Value v) {
|
| 71 |
-
|
| 72 |
-
if (abs(int(v)) >= 324)
|
| 73 |
-
return;
|
| 74 |
-
|
| 75 |
-
Square from = from_sq(m);
|
| 76 |
-
Square to = to_sq(m);
|
| 77 |
-
|
| 78 |
-
table[c][from][to] -= table[c][from][to] * abs(int(v)) / 324;
|
| 79 |
-
table[c][from][to] += int(v) * 32;
|
| 80 |
-
}
|
| 81 |
-
|
| 82 |
-
private:
|
| 83 |
-
Value table[COLOR_NB][SQUARE_NB][SQUARE_NB];
|
| 84 |
-
};
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
/// MovePicker class is used to pick one pseudo legal move at a time from the
|
| 88 |
-
/// current position. The most important method is next_move(), which returns a
|
| 89 |
-
/// new pseudo legal move each time it is called, until there are no moves left,
|
| 90 |
-
/// when MOVE_NONE is returned. In order to improve the efficiency of the alpha
|
| 91 |
-
/// beta algorithm, MovePicker attempts to return the moves which are most likely
|
| 92 |
-
/// to get a cut-off first.
|
| 93 |
-
namespace Search { struct Stack; }
|
| 94 |
-
|
| 95 |
-
class MovePicker {
|
| 96 |
-
public:
|
| 97 |
-
MovePicker(const MovePicker&) = delete;
|
| 98 |
-
MovePicker& operator=(const MovePicker&) = delete;
|
| 99 |
-
|
| 100 |
-
MovePicker(const Position&, Move, Value);
|
| 101 |
-
MovePicker(const Position&, Move, Depth, Square);
|
| 102 |
-
MovePicker(const Position&, Move, Depth, Search::Stack*);
|
| 103 |
-
|
| 104 |
-
Move next_move();
|
| 105 |
-
|
| 106 |
-
private:
|
| 107 |
-
template<GenType> void score();
|
| 108 |
-
ExtMove* begin() { return cur; }
|
| 109 |
-
ExtMove* end() { return endMoves; }
|
| 110 |
-
|
| 111 |
-
const Position& pos;
|
| 112 |
-
const Search::Stack* ss;
|
| 113 |
-
Move countermove;
|
| 114 |
-
Depth depth;
|
| 115 |
-
Move ttMove;
|
| 116 |
-
Square recaptureSquare;
|
| 117 |
-
Value threshold;
|
| 118 |
-
int stage;
|
| 119 |
-
ExtMove *cur, *endMoves, *endBadCaptures;
|
| 120 |
-
ExtMove moves[MAX_MOVES];
|
| 121 |
-
};
|
| 122 |
-
|
| 123 |
-
#endif // #ifndef MOVEPICK_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/pawns.cpp
DELETED
|
@@ -1,291 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm>
|
| 22 |
-
#include <cassert>
|
| 23 |
-
|
| 24 |
-
#include "bitboard.h"
|
| 25 |
-
#include "pawns.h"
|
| 26 |
-
#include "position.h"
|
| 27 |
-
#include "thread.h"
|
| 28 |
-
|
| 29 |
-
namespace {
|
| 30 |
-
|
| 31 |
-
#define V Value
|
| 32 |
-
#define S(mg, eg) make_score(mg, eg)
|
| 33 |
-
|
| 34 |
-
// Isolated pawn penalty by opposed flag
|
| 35 |
-
const Score Isolated[2] = { S(45, 40), S(30, 27) };
|
| 36 |
-
|
| 37 |
-
// Backward pawn penalty by opposed flag
|
| 38 |
-
const Score Backward[2] = { S(56, 33), S(41, 19) };
|
| 39 |
-
|
| 40 |
-
// Unsupported pawn penalty for pawns which are neither isolated or backward
|
| 41 |
-
const Score Unsupported = S(17, 8);
|
| 42 |
-
|
| 43 |
-
// Connected pawn bonus by opposed, phalanx, twice supported and rank
|
| 44 |
-
Score Connected[2][2][2][RANK_NB];
|
| 45 |
-
|
| 46 |
-
// Doubled pawn penalty
|
| 47 |
-
const Score Doubled = S(18,38);
|
| 48 |
-
|
| 49 |
-
// Lever bonus by rank
|
| 50 |
-
const Score Lever[RANK_NB] = {
|
| 51 |
-
S( 0, 0), S( 0, 0), S(0, 0), S(0, 0),
|
| 52 |
-
S(17, 16), S(33, 32), S(0, 0), S(0, 0)
|
| 53 |
-
};
|
| 54 |
-
|
| 55 |
-
// Weakness of our pawn shelter in front of the king by [distance from edge][rank]
|
| 56 |
-
const Value ShelterWeakness[][RANK_NB] = {
|
| 57 |
-
{ V( 97), V(21), V(26), V(51), V(87), V( 89), V( 99) },
|
| 58 |
-
{ V(120), V( 0), V(28), V(76), V(88), V(103), V(104) },
|
| 59 |
-
{ V(101), V( 7), V(54), V(78), V(77), V( 92), V(101) },
|
| 60 |
-
{ V( 80), V(11), V(44), V(68), V(87), V( 90), V(119) }
|
| 61 |
-
};
|
| 62 |
-
|
| 63 |
-
// Danger of enemy pawns moving toward our king by [type][distance from edge][rank]
|
| 64 |
-
const Value StormDanger[][4][RANK_NB] = {
|
| 65 |
-
{ { V( 0), V( 67), V( 134), V(38), V(32) },
|
| 66 |
-
{ V( 0), V( 57), V( 139), V(37), V(22) },
|
| 67 |
-
{ V( 0), V( 43), V( 115), V(43), V(27) },
|
| 68 |
-
{ V( 0), V( 68), V( 124), V(57), V(32) } },
|
| 69 |
-
{ { V(20), V( 43), V( 100), V(56), V(20) },
|
| 70 |
-
{ V(23), V( 20), V( 98), V(40), V(15) },
|
| 71 |
-
{ V(23), V( 39), V( 103), V(36), V(18) },
|
| 72 |
-
{ V(28), V( 19), V( 108), V(42), V(26) } },
|
| 73 |
-
{ { V( 0), V( 0), V( 75), V(14), V( 2) },
|
| 74 |
-
{ V( 0), V( 0), V( 150), V(30), V( 4) },
|
| 75 |
-
{ V( 0), V( 0), V( 160), V(22), V( 5) },
|
| 76 |
-
{ V( 0), V( 0), V( 166), V(24), V(13) } },
|
| 77 |
-
{ { V( 0), V(-283), V(-281), V(57), V(31) },
|
| 78 |
-
{ V( 0), V( 58), V( 141), V(39), V(18) },
|
| 79 |
-
{ V( 0), V( 65), V( 142), V(48), V(32) },
|
| 80 |
-
{ V( 0), V( 60), V( 126), V(51), V(19) } }
|
| 81 |
-
};
|
| 82 |
-
|
| 83 |
-
// Max bonus for king safety. Corresponds to start position with all the pawns
|
| 84 |
-
// in front of the king and no enemy pawn on the horizon.
|
| 85 |
-
const Value MaxSafetyBonus = V(258);
|
| 86 |
-
|
| 87 |
-
#undef S
|
| 88 |
-
#undef V
|
| 89 |
-
|
| 90 |
-
template<Color Us>
|
| 91 |
-
Score evaluate(const Position& pos, Pawns::Entry* e) {
|
| 92 |
-
|
| 93 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 94 |
-
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
| 95 |
-
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
| 96 |
-
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
| 97 |
-
|
| 98 |
-
Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
|
| 99 |
-
Square s;
|
| 100 |
-
bool opposed, lever, connected, backward;
|
| 101 |
-
Score score = SCORE_ZERO;
|
| 102 |
-
const Square* pl = pos.squares<PAWN>(Us);
|
| 103 |
-
const Bitboard* pawnAttacksBB = StepAttacksBB[make_piece(Us, PAWN)];
|
| 104 |
-
|
| 105 |
-
Bitboard ourPawns = pos.pieces(Us , PAWN);
|
| 106 |
-
Bitboard theirPawns = pos.pieces(Them, PAWN);
|
| 107 |
-
|
| 108 |
-
e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0;
|
| 109 |
-
e->semiopenFiles[Us] = 0xFF;
|
| 110 |
-
e->kingSquares[Us] = SQ_NONE;
|
| 111 |
-
e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns);
|
| 112 |
-
e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares);
|
| 113 |
-
e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
|
| 114 |
-
|
| 115 |
-
// Loop through all pawns of the current color and score each pawn
|
| 116 |
-
while ((s = *pl++) != SQ_NONE)
|
| 117 |
-
{
|
| 118 |
-
assert(pos.piece_on(s) == make_piece(Us, PAWN));
|
| 119 |
-
|
| 120 |
-
File f = file_of(s);
|
| 121 |
-
|
| 122 |
-
e->semiopenFiles[Us] &= ~(1 << f);
|
| 123 |
-
e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s);
|
| 124 |
-
|
| 125 |
-
// Flag the pawn
|
| 126 |
-
opposed = theirPawns & forward_bb(Us, s);
|
| 127 |
-
stoppers = theirPawns & passed_pawn_mask(Us, s);
|
| 128 |
-
lever = theirPawns & pawnAttacksBB[s];
|
| 129 |
-
doubled = ourPawns & (s + Up);
|
| 130 |
-
neighbours = ourPawns & adjacent_files_bb(f);
|
| 131 |
-
phalanx = neighbours & rank_bb(s);
|
| 132 |
-
supported = neighbours & rank_bb(s - Up);
|
| 133 |
-
connected = supported | phalanx;
|
| 134 |
-
|
| 135 |
-
// A pawn is backward when it is behind all pawns of the same color on the
|
| 136 |
-
// adjacent files and cannot be safely advanced.
|
| 137 |
-
if (!neighbours || lever || relative_rank(Us, s) >= RANK_5)
|
| 138 |
-
backward = false;
|
| 139 |
-
else
|
| 140 |
-
{
|
| 141 |
-
// Find the backmost rank with neighbours or stoppers
|
| 142 |
-
b = rank_bb(backmost_sq(Us, neighbours | stoppers));
|
| 143 |
-
|
| 144 |
-
// The pawn is backward when it cannot safely progress to that rank:
|
| 145 |
-
// either there is a stopper in the way on this rank, or there is a
|
| 146 |
-
// stopper on adjacent file which controls the way to that rank.
|
| 147 |
-
backward = (b | shift<Up>(b & adjacent_files_bb(f))) & stoppers;
|
| 148 |
-
|
| 149 |
-
assert(!backward || !(pawn_attack_span(Them, s + Up) & neighbours));
|
| 150 |
-
}
|
| 151 |
-
|
| 152 |
-
// Passed pawns will be properly scored in evaluation because we need
|
| 153 |
-
// full attack info to evaluate them.
|
| 154 |
-
if (!stoppers && !(ourPawns & forward_bb(Us, s)))
|
| 155 |
-
e->passedPawns[Us] |= s;
|
| 156 |
-
|
| 157 |
-
// Score this pawn
|
| 158 |
-
if (!neighbours)
|
| 159 |
-
score -= Isolated[opposed];
|
| 160 |
-
|
| 161 |
-
else if (backward)
|
| 162 |
-
score -= Backward[opposed];
|
| 163 |
-
|
| 164 |
-
else if (!supported)
|
| 165 |
-
score -= Unsupported;
|
| 166 |
-
|
| 167 |
-
if (connected)
|
| 168 |
-
score += Connected[opposed][!!phalanx][more_than_one(supported)][relative_rank(Us, s)];
|
| 169 |
-
|
| 170 |
-
if (doubled)
|
| 171 |
-
score -= Doubled;
|
| 172 |
-
|
| 173 |
-
if (lever)
|
| 174 |
-
score += Lever[relative_rank(Us, s)];
|
| 175 |
-
}
|
| 176 |
-
|
| 177 |
-
return score;
|
| 178 |
-
}
|
| 179 |
-
|
| 180 |
-
} // namespace
|
| 181 |
-
|
| 182 |
-
namespace Pawns {
|
| 183 |
-
|
| 184 |
-
/// Pawns::init() initializes some tables needed by evaluation. Instead of using
|
| 185 |
-
/// hard-coded tables, when makes sense, we prefer to calculate them with a formula
|
| 186 |
-
/// to reduce independent parameters and to allow easier tuning and better insight.
|
| 187 |
-
|
| 188 |
-
void init() {
|
| 189 |
-
|
| 190 |
-
static const int Seed[RANK_NB] = { 0, 8, 19, 13, 71, 94, 169, 324 };
|
| 191 |
-
|
| 192 |
-
for (int opposed = 0; opposed <= 1; ++opposed)
|
| 193 |
-
for (int phalanx = 0; phalanx <= 1; ++phalanx)
|
| 194 |
-
for (int apex = 0; apex <= 1; ++apex)
|
| 195 |
-
for (Rank r = RANK_2; r < RANK_8; ++r)
|
| 196 |
-
{
|
| 197 |
-
int v = (Seed[r] + (phalanx ? (Seed[r + 1] - Seed[r]) / 2 : 0)) >> opposed;
|
| 198 |
-
v += (apex ? v / 2 : 0);
|
| 199 |
-
Connected[opposed][phalanx][apex][r] = make_score(v, v * 5 / 8);
|
| 200 |
-
}
|
| 201 |
-
}
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
/// Pawns::probe() looks up the current position's pawns configuration in
|
| 205 |
-
/// the pawns hash table. It returns a pointer to the Entry if the position
|
| 206 |
-
/// is found. Otherwise a new Entry is computed and stored there, so we don't
|
| 207 |
-
/// have to recompute all when the same pawns configuration occurs again.
|
| 208 |
-
|
| 209 |
-
Entry* probe(const Position& pos) {
|
| 210 |
-
|
| 211 |
-
Key key = pos.pawn_key();
|
| 212 |
-
Entry* e = pos.this_thread()->pawnsTable[key];
|
| 213 |
-
|
| 214 |
-
if (e->key == key)
|
| 215 |
-
return e;
|
| 216 |
-
|
| 217 |
-
e->key = key;
|
| 218 |
-
e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e);
|
| 219 |
-
e->asymmetry = popcount(e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK]);
|
| 220 |
-
e->openFiles = popcount(e->semiopenFiles[WHITE] & e->semiopenFiles[BLACK]);
|
| 221 |
-
return e;
|
| 222 |
-
}
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
/// Entry::shelter_storm() calculates shelter and storm penalties for the file
|
| 226 |
-
/// the king is on, as well as the two adjacent files.
|
| 227 |
-
|
| 228 |
-
template<Color Us>
|
| 229 |
-
Value Entry::shelter_storm(const Position& pos, Square ksq) {
|
| 230 |
-
|
| 231 |
-
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 232 |
-
|
| 233 |
-
enum { NoFriendlyPawn, Unblocked, BlockedByPawn, BlockedByKing };
|
| 234 |
-
|
| 235 |
-
Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq));
|
| 236 |
-
Bitboard ourPawns = b & pos.pieces(Us);
|
| 237 |
-
Bitboard theirPawns = b & pos.pieces(Them);
|
| 238 |
-
Value safety = MaxSafetyBonus;
|
| 239 |
-
File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
|
| 240 |
-
|
| 241 |
-
for (File f = center - File(1); f <= center + File(1); ++f)
|
| 242 |
-
{
|
| 243 |
-
b = ourPawns & file_bb(f);
|
| 244 |
-
Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
|
| 245 |
-
|
| 246 |
-
b = theirPawns & file_bb(f);
|
| 247 |
-
Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
|
| 248 |
-
|
| 249 |
-
safety -= ShelterWeakness[std::min(f, FILE_H - f)][rkUs]
|
| 250 |
-
+ StormDanger
|
| 251 |
-
[f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing :
|
| 252 |
-
rkUs == RANK_1 ? NoFriendlyPawn :
|
| 253 |
-
rkThem == rkUs + 1 ? BlockedByPawn : Unblocked]
|
| 254 |
-
[std::min(f, FILE_H - f)][rkThem];
|
| 255 |
-
}
|
| 256 |
-
|
| 257 |
-
return safety;
|
| 258 |
-
}
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
/// Entry::do_king_safety() calculates a bonus for king safety. It is called only
|
| 262 |
-
/// when king square changes, which is about 20% of total king_safety() calls.
|
| 263 |
-
|
| 264 |
-
template<Color Us>
|
| 265 |
-
Score Entry::do_king_safety(const Position& pos, Square ksq) {
|
| 266 |
-
|
| 267 |
-
kingSquares[Us] = ksq;
|
| 268 |
-
castlingRights[Us] = pos.can_castle(Us);
|
| 269 |
-
int minKingPawnDistance = 0;
|
| 270 |
-
|
| 271 |
-
Bitboard pawns = pos.pieces(Us, PAWN);
|
| 272 |
-
if (pawns)
|
| 273 |
-
while (!(DistanceRingBB[ksq][minKingPawnDistance++] & pawns)) {}
|
| 274 |
-
|
| 275 |
-
Value bonus = shelter_storm<Us>(pos, ksq);
|
| 276 |
-
|
| 277 |
-
// If we can castle use the bonus after the castling if it is bigger
|
| 278 |
-
if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right))
|
| 279 |
-
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_G1)));
|
| 280 |
-
|
| 281 |
-
if (pos.can_castle(MakeCastling<Us, QUEEN_SIDE>::right))
|
| 282 |
-
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1)));
|
| 283 |
-
|
| 284 |
-
return make_score(bonus, -16 * minKingPawnDistance);
|
| 285 |
-
}
|
| 286 |
-
|
| 287 |
-
// Explicit template instantiation
|
| 288 |
-
template Score Entry::do_king_safety<WHITE>(const Position& pos, Square ksq);
|
| 289 |
-
template Score Entry::do_king_safety<BLACK>(const Position& pos, Square ksq);
|
| 290 |
-
|
| 291 |
-
} // namespace Pawns
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/pawns.h
DELETED
|
@@ -1,88 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef PAWNS_H_INCLUDED
|
| 22 |
-
#define PAWNS_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include "misc.h"
|
| 25 |
-
#include "position.h"
|
| 26 |
-
#include "types.h"
|
| 27 |
-
|
| 28 |
-
namespace Pawns {
|
| 29 |
-
|
| 30 |
-
/// Pawns::Entry contains various information about a pawn structure. A lookup
|
| 31 |
-
/// to the pawn hash table (performed by calling the probe function) returns a
|
| 32 |
-
/// pointer to an Entry object.
|
| 33 |
-
|
| 34 |
-
struct Entry {
|
| 35 |
-
|
| 36 |
-
Score pawns_score() const { return score; }
|
| 37 |
-
Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
|
| 38 |
-
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
|
| 39 |
-
Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; }
|
| 40 |
-
int pawn_asymmetry() const { return asymmetry; }
|
| 41 |
-
int open_files() const { return openFiles; }
|
| 42 |
-
|
| 43 |
-
int semiopen_file(Color c, File f) const {
|
| 44 |
-
return semiopenFiles[c] & (1 << f);
|
| 45 |
-
}
|
| 46 |
-
|
| 47 |
-
int semiopen_side(Color c, File f, bool leftSide) const {
|
| 48 |
-
return semiopenFiles[c] & (leftSide ? (1 << f) - 1 : ~((1 << (f + 1)) - 1));
|
| 49 |
-
}
|
| 50 |
-
|
| 51 |
-
int pawns_on_same_color_squares(Color c, Square s) const {
|
| 52 |
-
return pawnsOnSquares[c][!!(DarkSquares & s)];
|
| 53 |
-
}
|
| 54 |
-
|
| 55 |
-
template<Color Us>
|
| 56 |
-
Score king_safety(const Position& pos, Square ksq) {
|
| 57 |
-
return kingSquares[Us] == ksq && castlingRights[Us] == pos.can_castle(Us)
|
| 58 |
-
? kingSafety[Us] : (kingSafety[Us] = do_king_safety<Us>(pos, ksq));
|
| 59 |
-
}
|
| 60 |
-
|
| 61 |
-
template<Color Us>
|
| 62 |
-
Score do_king_safety(const Position& pos, Square ksq);
|
| 63 |
-
|
| 64 |
-
template<Color Us>
|
| 65 |
-
Value shelter_storm(const Position& pos, Square ksq);
|
| 66 |
-
|
| 67 |
-
Key key;
|
| 68 |
-
Score score;
|
| 69 |
-
Bitboard passedPawns[COLOR_NB];
|
| 70 |
-
Bitboard pawnAttacks[COLOR_NB];
|
| 71 |
-
Bitboard pawnAttacksSpan[COLOR_NB];
|
| 72 |
-
Square kingSquares[COLOR_NB];
|
| 73 |
-
Score kingSafety[COLOR_NB];
|
| 74 |
-
int castlingRights[COLOR_NB];
|
| 75 |
-
int semiopenFiles[COLOR_NB];
|
| 76 |
-
int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
|
| 77 |
-
int asymmetry;
|
| 78 |
-
int openFiles;
|
| 79 |
-
};
|
| 80 |
-
|
| 81 |
-
typedef HashTable<Entry, 16384> Table;
|
| 82 |
-
|
| 83 |
-
void init();
|
| 84 |
-
Entry* probe(const Position& pos);
|
| 85 |
-
|
| 86 |
-
} // namespace Pawns
|
| 87 |
-
|
| 88 |
-
#endif // #ifndef PAWNS_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/position.cpp
DELETED
|
@@ -1,1168 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm>
|
| 22 |
-
#include <cassert>
|
| 23 |
-
#include <cstddef> // For offsetof()
|
| 24 |
-
#include <cstring> // For std::memset, std::memcmp
|
| 25 |
-
#include <iomanip>
|
| 26 |
-
#include <sstream>
|
| 27 |
-
|
| 28 |
-
#include "bitboard.h"
|
| 29 |
-
#include "misc.h"
|
| 30 |
-
#include "movegen.h"
|
| 31 |
-
#include "position.h"
|
| 32 |
-
#include "thread.h"
|
| 33 |
-
#include "tt.h"
|
| 34 |
-
#include "uci.h"
|
| 35 |
-
|
| 36 |
-
using std::string;
|
| 37 |
-
|
| 38 |
-
namespace PSQT {
|
| 39 |
-
extern Score psq[PIECE_NB][SQUARE_NB];
|
| 40 |
-
}
|
| 41 |
-
|
| 42 |
-
namespace Zobrist {
|
| 43 |
-
|
| 44 |
-
Key psq[PIECE_NB][SQUARE_NB];
|
| 45 |
-
Key enpassant[FILE_NB];
|
| 46 |
-
Key castling[CASTLING_RIGHT_NB];
|
| 47 |
-
Key side;
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
namespace {
|
| 51 |
-
|
| 52 |
-
const string PieceToChar(" PNBRQK pnbrqk");
|
| 53 |
-
|
| 54 |
-
// min_attacker() is a helper function used by see() to locate the least
|
| 55 |
-
// valuable attacker for the side to move, remove the attacker we just found
|
| 56 |
-
// from the bitboards and scan for new X-ray attacks behind it.
|
| 57 |
-
|
| 58 |
-
template<int Pt>
|
| 59 |
-
PieceType min_attacker(const Bitboard* bb, Square to, Bitboard stmAttackers,
|
| 60 |
-
Bitboard& occupied, Bitboard& attackers) {
|
| 61 |
-
|
| 62 |
-
Bitboard b = stmAttackers & bb[Pt];
|
| 63 |
-
if (!b)
|
| 64 |
-
return min_attacker<Pt+1>(bb, to, stmAttackers, occupied, attackers);
|
| 65 |
-
|
| 66 |
-
occupied ^= b & ~(b - 1);
|
| 67 |
-
|
| 68 |
-
if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN)
|
| 69 |
-
attackers |= attacks_bb<BISHOP>(to, occupied) & (bb[BISHOP] | bb[QUEEN]);
|
| 70 |
-
|
| 71 |
-
if (Pt == ROOK || Pt == QUEEN)
|
| 72 |
-
attackers |= attacks_bb<ROOK>(to, occupied) & (bb[ROOK] | bb[QUEEN]);
|
| 73 |
-
|
| 74 |
-
attackers &= occupied; // After X-ray that may add already processed pieces
|
| 75 |
-
return (PieceType)Pt;
|
| 76 |
-
}
|
| 77 |
-
|
| 78 |
-
template<>
|
| 79 |
-
PieceType min_attacker<KING>(const Bitboard*, Square, Bitboard, Bitboard&, Bitboard&) {
|
| 80 |
-
return KING; // No need to update bitboards: it is the last cycle
|
| 81 |
-
}
|
| 82 |
-
|
| 83 |
-
} // namespace
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
/// operator<<(Position) returns an ASCII representation of the position
|
| 87 |
-
|
| 88 |
-
std::ostream& operator<<(std::ostream& os, const Position& pos) {
|
| 89 |
-
|
| 90 |
-
os << "\n +---+---+---+---+---+---+---+---+\n";
|
| 91 |
-
|
| 92 |
-
for (Rank r = RANK_8; r >= RANK_1; --r)
|
| 93 |
-
{
|
| 94 |
-
for (File f = FILE_A; f <= FILE_H; ++f)
|
| 95 |
-
os << " | " << PieceToChar[pos.piece_on(make_square(f, r))];
|
| 96 |
-
|
| 97 |
-
os << " |\n +---+---+---+---+---+---+---+---+\n";
|
| 98 |
-
}
|
| 99 |
-
|
| 100 |
-
os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase
|
| 101 |
-
<< std::setfill('0') << std::setw(16) << pos.key() << std::dec << "\nCheckers: ";
|
| 102 |
-
|
| 103 |
-
for (Bitboard b = pos.checkers(); b; )
|
| 104 |
-
os << UCI::square(pop_lsb(&b)) << " ";
|
| 105 |
-
|
| 106 |
-
return os;
|
| 107 |
-
}
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
/// Position::init() initializes at startup the various arrays used to compute
|
| 111 |
-
/// hash keys.
|
| 112 |
-
|
| 113 |
-
void Position::init() {
|
| 114 |
-
|
| 115 |
-
PRNG rng(1070372);
|
| 116 |
-
|
| 117 |
-
for (Piece pc : Pieces)
|
| 118 |
-
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
| 119 |
-
Zobrist::psq[pc][s] = rng.rand<Key>();
|
| 120 |
-
|
| 121 |
-
for (File f = FILE_A; f <= FILE_H; ++f)
|
| 122 |
-
Zobrist::enpassant[f] = rng.rand<Key>();
|
| 123 |
-
|
| 124 |
-
for (int cr = NO_CASTLING; cr <= ANY_CASTLING; ++cr)
|
| 125 |
-
{
|
| 126 |
-
Zobrist::castling[cr] = 0;
|
| 127 |
-
Bitboard b = cr;
|
| 128 |
-
while (b)
|
| 129 |
-
{
|
| 130 |
-
Key k = Zobrist::castling[1ULL << pop_lsb(&b)];
|
| 131 |
-
Zobrist::castling[cr] ^= k ? k : rng.rand<Key>();
|
| 132 |
-
}
|
| 133 |
-
}
|
| 134 |
-
|
| 135 |
-
Zobrist::side = rng.rand<Key>();
|
| 136 |
-
}
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
/// Position::set() initializes the position object with the given FEN string.
|
| 140 |
-
/// This function is not very robust - make sure that input FENs are correct,
|
| 141 |
-
/// this is assumed to be the responsibility of the GUI.
|
| 142 |
-
|
| 143 |
-
Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Thread* th) {
|
| 144 |
-
/*
|
| 145 |
-
A FEN string defines a particular position using only the ASCII character set.
|
| 146 |
-
|
| 147 |
-
A FEN string contains six fields separated by a space. The fields are:
|
| 148 |
-
|
| 149 |
-
1) Piece placement (from white's perspective). Each rank is described, starting
|
| 150 |
-
with rank 8 and ending with rank 1. Within each rank, the contents of each
|
| 151 |
-
square are described from file A through file H. Following the Standard
|
| 152 |
-
Algebraic Notation (SAN), each piece is identified by a single letter taken
|
| 153 |
-
from the standard English names. White pieces are designated using upper-case
|
| 154 |
-
letters ("PNBRQK") whilst Black uses lowercase ("pnbrqk"). Blank squares are
|
| 155 |
-
noted using digits 1 through 8 (the number of blank squares), and "/"
|
| 156 |
-
separates ranks.
|
| 157 |
-
|
| 158 |
-
2) Active color. "w" means white moves next, "b" means black.
|
| 159 |
-
|
| 160 |
-
3) Castling availability. If neither side can castle, this is "-". Otherwise,
|
| 161 |
-
this has one or more letters: "K" (White can castle kingside), "Q" (White
|
| 162 |
-
can castle queenside), "k" (Black can castle kingside), and/or "q" (Black
|
| 163 |
-
can castle queenside).
|
| 164 |
-
|
| 165 |
-
4) En passant target square (in algebraic notation). If there's no en passant
|
| 166 |
-
target square, this is "-". If a pawn has just made a 2-square move, this
|
| 167 |
-
is the position "behind" the pawn. This is recorded regardless of whether
|
| 168 |
-
there is a pawn in position to make an en passant capture.
|
| 169 |
-
|
| 170 |
-
5) Halfmove clock. This is the number of halfmoves since the last pawn advance
|
| 171 |
-
or capture. This is used to determine if a draw can be claimed under the
|
| 172 |
-
fifty-move rule.
|
| 173 |
-
|
| 174 |
-
6) Fullmove number. The number of the full move. It starts at 1, and is
|
| 175 |
-
incremented after Black's move.
|
| 176 |
-
*/
|
| 177 |
-
|
| 178 |
-
unsigned char col, row, token;
|
| 179 |
-
size_t idx;
|
| 180 |
-
Square sq = SQ_A8;
|
| 181 |
-
std::istringstream ss(fenStr);
|
| 182 |
-
|
| 183 |
-
std::memset(this, 0, sizeof(Position));
|
| 184 |
-
std::memset(si, 0, sizeof(StateInfo));
|
| 185 |
-
std::fill_n(&pieceList[0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE);
|
| 186 |
-
st = si;
|
| 187 |
-
|
| 188 |
-
ss >> std::noskipws;
|
| 189 |
-
|
| 190 |
-
// 1. Piece placement
|
| 191 |
-
while ((ss >> token) && !isspace(token))
|
| 192 |
-
{
|
| 193 |
-
if (isdigit(token))
|
| 194 |
-
sq += Square(token - '0'); // Advance the given number of files
|
| 195 |
-
|
| 196 |
-
else if (token == '/')
|
| 197 |
-
sq -= Square(16);
|
| 198 |
-
|
| 199 |
-
else if ((idx = PieceToChar.find(token)) != string::npos)
|
| 200 |
-
{
|
| 201 |
-
put_piece(Piece(idx), sq);
|
| 202 |
-
++sq;
|
| 203 |
-
}
|
| 204 |
-
}
|
| 205 |
-
|
| 206 |
-
// 2. Active color
|
| 207 |
-
ss >> token;
|
| 208 |
-
sideToMove = (token == 'w' ? WHITE : BLACK);
|
| 209 |
-
ss >> token;
|
| 210 |
-
|
| 211 |
-
// 3. Castling availability. Compatible with 3 standards: Normal FEN standard,
|
| 212 |
-
// Shredder-FEN that uses the letters of the columns on which the rooks began
|
| 213 |
-
// the game instead of KQkq and also X-FEN standard that, in case of Chess960,
|
| 214 |
-
// if an inner rook is associated with the castling right, the castling tag is
|
| 215 |
-
// replaced by the file letter of the involved rook, as for the Shredder-FEN.
|
| 216 |
-
while ((ss >> token) && !isspace(token))
|
| 217 |
-
{
|
| 218 |
-
Square rsq;
|
| 219 |
-
Color c = islower(token) ? BLACK : WHITE;
|
| 220 |
-
Piece rook = make_piece(c, ROOK);
|
| 221 |
-
|
| 222 |
-
token = char(toupper(token));
|
| 223 |
-
|
| 224 |
-
if (token == 'K')
|
| 225 |
-
for (rsq = relative_square(c, SQ_H1); piece_on(rsq) != rook; --rsq) {}
|
| 226 |
-
|
| 227 |
-
else if (token == 'Q')
|
| 228 |
-
for (rsq = relative_square(c, SQ_A1); piece_on(rsq) != rook; ++rsq) {}
|
| 229 |
-
|
| 230 |
-
else if (token >= 'A' && token <= 'H')
|
| 231 |
-
rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1));
|
| 232 |
-
|
| 233 |
-
else
|
| 234 |
-
continue;
|
| 235 |
-
|
| 236 |
-
set_castling_right(c, rsq);
|
| 237 |
-
}
|
| 238 |
-
|
| 239 |
-
// 4. En passant square. Ignore if no pawn capture is possible
|
| 240 |
-
if ( ((ss >> col) && (col >= 'a' && col <= 'h'))
|
| 241 |
-
&& ((ss >> row) && (row == '3' || row == '6')))
|
| 242 |
-
{
|
| 243 |
-
st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
|
| 244 |
-
|
| 245 |
-
if (!(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)))
|
| 246 |
-
st->epSquare = SQ_NONE;
|
| 247 |
-
}
|
| 248 |
-
else
|
| 249 |
-
st->epSquare = SQ_NONE;
|
| 250 |
-
|
| 251 |
-
// 5-6. Halfmove clock and fullmove number
|
| 252 |
-
ss >> std::skipws >> st->rule50 >> gamePly;
|
| 253 |
-
|
| 254 |
-
// Convert from fullmove starting from 1 to ply starting from 0,
|
| 255 |
-
// handle also common incorrect FEN with fullmove = 0.
|
| 256 |
-
gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK);
|
| 257 |
-
|
| 258 |
-
chess960 = isChess960;
|
| 259 |
-
thisThread = th;
|
| 260 |
-
set_state(st);
|
| 261 |
-
|
| 262 |
-
assert(pos_is_ok());
|
| 263 |
-
|
| 264 |
-
return *this;
|
| 265 |
-
}
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
/// Position::set_castling_right() is a helper function used to set castling
|
| 269 |
-
/// rights given the corresponding color and the rook starting square.
|
| 270 |
-
|
| 271 |
-
void Position::set_castling_right(Color c, Square rfrom) {
|
| 272 |
-
|
| 273 |
-
Square kfrom = square<KING>(c);
|
| 274 |
-
CastlingSide cs = kfrom < rfrom ? KING_SIDE : QUEEN_SIDE;
|
| 275 |
-
CastlingRight cr = (c | cs);
|
| 276 |
-
|
| 277 |
-
st->castlingRights |= cr;
|
| 278 |
-
castlingRightsMask[kfrom] |= cr;
|
| 279 |
-
castlingRightsMask[rfrom] |= cr;
|
| 280 |
-
castlingRookSquare[cr] = rfrom;
|
| 281 |
-
|
| 282 |
-
Square kto = relative_square(c, cs == KING_SIDE ? SQ_G1 : SQ_C1);
|
| 283 |
-
Square rto = relative_square(c, cs == KING_SIDE ? SQ_F1 : SQ_D1);
|
| 284 |
-
|
| 285 |
-
for (Square s = std::min(rfrom, rto); s <= std::max(rfrom, rto); ++s)
|
| 286 |
-
if (s != kfrom && s != rfrom)
|
| 287 |
-
castlingPath[cr] |= s;
|
| 288 |
-
|
| 289 |
-
for (Square s = std::min(kfrom, kto); s <= std::max(kfrom, kto); ++s)
|
| 290 |
-
if (s != kfrom && s != rfrom)
|
| 291 |
-
castlingPath[cr] |= s;
|
| 292 |
-
}
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
/// Position::set_check_info() sets king attacks to detect if a move gives check
|
| 296 |
-
|
| 297 |
-
void Position::set_check_info(StateInfo* si) const {
|
| 298 |
-
|
| 299 |
-
si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE), si->pinnersForKing[WHITE]);
|
| 300 |
-
si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), si->pinnersForKing[BLACK]);
|
| 301 |
-
|
| 302 |
-
Square ksq = square<KING>(~sideToMove);
|
| 303 |
-
|
| 304 |
-
si->checkSquares[PAWN] = attacks_from<PAWN>(ksq, ~sideToMove);
|
| 305 |
-
si->checkSquares[KNIGHT] = attacks_from<KNIGHT>(ksq);
|
| 306 |
-
si->checkSquares[BISHOP] = attacks_from<BISHOP>(ksq);
|
| 307 |
-
si->checkSquares[ROOK] = attacks_from<ROOK>(ksq);
|
| 308 |
-
si->checkSquares[QUEEN] = si->checkSquares[BISHOP] | si->checkSquares[ROOK];
|
| 309 |
-
si->checkSquares[KING] = 0;
|
| 310 |
-
}
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
/// Position::set_state() computes the hash keys of the position, and other
|
| 314 |
-
/// data that once computed is updated incrementally as moves are made.
|
| 315 |
-
/// The function is only used when a new position is set up, and to verify
|
| 316 |
-
/// the correctness of the StateInfo data when running in debug mode.
|
| 317 |
-
|
| 318 |
-
void Position::set_state(StateInfo* si) const {
|
| 319 |
-
|
| 320 |
-
si->key = si->pawnKey = si->materialKey = 0;
|
| 321 |
-
si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO;
|
| 322 |
-
si->psq = SCORE_ZERO;
|
| 323 |
-
si->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove);
|
| 324 |
-
|
| 325 |
-
set_check_info(si);
|
| 326 |
-
|
| 327 |
-
for (Bitboard b = pieces(); b; )
|
| 328 |
-
{
|
| 329 |
-
Square s = pop_lsb(&b);
|
| 330 |
-
Piece pc = piece_on(s);
|
| 331 |
-
si->key ^= Zobrist::psq[pc][s];
|
| 332 |
-
si->psq += PSQT::psq[pc][s];
|
| 333 |
-
}
|
| 334 |
-
|
| 335 |
-
if (si->epSquare != SQ_NONE)
|
| 336 |
-
si->key ^= Zobrist::enpassant[file_of(si->epSquare)];
|
| 337 |
-
|
| 338 |
-
if (sideToMove == BLACK)
|
| 339 |
-
si->key ^= Zobrist::side;
|
| 340 |
-
|
| 341 |
-
si->key ^= Zobrist::castling[si->castlingRights];
|
| 342 |
-
|
| 343 |
-
for (Bitboard b = pieces(PAWN); b; )
|
| 344 |
-
{
|
| 345 |
-
Square s = pop_lsb(&b);
|
| 346 |
-
si->pawnKey ^= Zobrist::psq[piece_on(s)][s];
|
| 347 |
-
}
|
| 348 |
-
|
| 349 |
-
for (Piece pc : Pieces)
|
| 350 |
-
{
|
| 351 |
-
if (type_of(pc) != PAWN && type_of(pc) != KING)
|
| 352 |
-
si->nonPawnMaterial[color_of(pc)] += pieceCount[pc] * PieceValue[MG][pc];
|
| 353 |
-
|
| 354 |
-
for (int cnt = 0; cnt < pieceCount[pc]; ++cnt)
|
| 355 |
-
si->materialKey ^= Zobrist::psq[pc][cnt];
|
| 356 |
-
}
|
| 357 |
-
}
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
/// Position::fen() returns a FEN representation of the position. In case of
|
| 361 |
-
/// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.
|
| 362 |
-
|
| 363 |
-
const string Position::fen() const {
|
| 364 |
-
|
| 365 |
-
int emptyCnt;
|
| 366 |
-
std::ostringstream ss;
|
| 367 |
-
|
| 368 |
-
for (Rank r = RANK_8; r >= RANK_1; --r)
|
| 369 |
-
{
|
| 370 |
-
for (File f = FILE_A; f <= FILE_H; ++f)
|
| 371 |
-
{
|
| 372 |
-
for (emptyCnt = 0; f <= FILE_H && empty(make_square(f, r)); ++f)
|
| 373 |
-
++emptyCnt;
|
| 374 |
-
|
| 375 |
-
if (emptyCnt)
|
| 376 |
-
ss << emptyCnt;
|
| 377 |
-
|
| 378 |
-
if (f <= FILE_H)
|
| 379 |
-
ss << PieceToChar[piece_on(make_square(f, r))];
|
| 380 |
-
}
|
| 381 |
-
|
| 382 |
-
if (r > RANK_1)
|
| 383 |
-
ss << '/';
|
| 384 |
-
}
|
| 385 |
-
|
| 386 |
-
ss << (sideToMove == WHITE ? " w " : " b ");
|
| 387 |
-
|
| 388 |
-
if (can_castle(WHITE_OO))
|
| 389 |
-
ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE | KING_SIDE))) : 'K');
|
| 390 |
-
|
| 391 |
-
if (can_castle(WHITE_OOO))
|
| 392 |
-
ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE | QUEEN_SIDE))) : 'Q');
|
| 393 |
-
|
| 394 |
-
if (can_castle(BLACK_OO))
|
| 395 |
-
ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK | KING_SIDE))) : 'k');
|
| 396 |
-
|
| 397 |
-
if (can_castle(BLACK_OOO))
|
| 398 |
-
ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK | QUEEN_SIDE))) : 'q');
|
| 399 |
-
|
| 400 |
-
if (!can_castle(WHITE) && !can_castle(BLACK))
|
| 401 |
-
ss << '-';
|
| 402 |
-
|
| 403 |
-
ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::square(ep_square()) + " ")
|
| 404 |
-
<< st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
|
| 405 |
-
|
| 406 |
-
return ss.str();
|
| 407 |
-
}
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
/// Position::game_phase() calculates the game phase interpolating total non-pawn
|
| 411 |
-
/// material between endgame and midgame limits.
|
| 412 |
-
|
| 413 |
-
Phase Position::game_phase() const {
|
| 414 |
-
|
| 415 |
-
Value npm = st->nonPawnMaterial[WHITE] + st->nonPawnMaterial[BLACK];
|
| 416 |
-
|
| 417 |
-
npm = std::max(EndgameLimit, std::min(npm, MidgameLimit));
|
| 418 |
-
|
| 419 |
-
return Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit));
|
| 420 |
-
}
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
/// Position::slider_blockers() returns a bitboard of all the pieces (both colors)
|
| 424 |
-
/// that are blocking attacks on the square 's' from 'sliders'. A piece blocks a
|
| 425 |
-
/// slider if removing that piece from the board would result in a position where
|
| 426 |
-
/// square 's' is attacked. For example, a king-attack blocking piece can be either
|
| 427 |
-
/// a pinned or a discovered check piece, according if its color is the opposite
|
| 428 |
-
/// or the same of the color of the slider.
|
| 429 |
-
|
| 430 |
-
Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const {
|
| 431 |
-
|
| 432 |
-
Bitboard result = 0;
|
| 433 |
-
pinners = 0;
|
| 434 |
-
|
| 435 |
-
// Snipers are sliders that attack 's' when a piece is removed
|
| 436 |
-
Bitboard snipers = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK))
|
| 437 |
-
| (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
|
| 438 |
-
|
| 439 |
-
while (snipers)
|
| 440 |
-
{
|
| 441 |
-
Square sniperSq = pop_lsb(&snipers);
|
| 442 |
-
Bitboard b = between_bb(s, sniperSq) & pieces();
|
| 443 |
-
|
| 444 |
-
if (!more_than_one(b))
|
| 445 |
-
{
|
| 446 |
-
result |= b;
|
| 447 |
-
if (b & pieces(color_of(piece_on(s))))
|
| 448 |
-
pinners |= sniperSq;
|
| 449 |
-
}
|
| 450 |
-
}
|
| 451 |
-
return result;
|
| 452 |
-
}
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
/// Position::attackers_to() computes a bitboard of all pieces which attack a
|
| 456 |
-
/// given square. Slider attacks use the occupied bitboard to indicate occupancy.
|
| 457 |
-
|
| 458 |
-
Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
|
| 459 |
-
|
| 460 |
-
return (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
|
| 461 |
-
| (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
|
| 462 |
-
| (attacks_from<KNIGHT>(s) & pieces(KNIGHT))
|
| 463 |
-
| (attacks_bb<ROOK >(s, occupied) & pieces(ROOK, QUEEN))
|
| 464 |
-
| (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
|
| 465 |
-
| (attacks_from<KING>(s) & pieces(KING));
|
| 466 |
-
}
|
| 467 |
-
|
| 468 |
-
|
| 469 |
-
/// Position::legal() tests whether a pseudo-legal move is legal
|
| 470 |
-
|
| 471 |
-
bool Position::legal(Move m) const {
|
| 472 |
-
|
| 473 |
-
assert(is_ok(m));
|
| 474 |
-
|
| 475 |
-
Color us = sideToMove;
|
| 476 |
-
Square from = from_sq(m);
|
| 477 |
-
|
| 478 |
-
assert(color_of(moved_piece(m)) == us);
|
| 479 |
-
assert(piece_on(square<KING>(us)) == make_piece(us, KING));
|
| 480 |
-
|
| 481 |
-
// En passant captures are a tricky special case. Because they are rather
|
| 482 |
-
// uncommon, we do it simply by testing whether the king is attacked after
|
| 483 |
-
// the move is made.
|
| 484 |
-
if (type_of(m) == ENPASSANT)
|
| 485 |
-
{
|
| 486 |
-
Square ksq = square<KING>(us);
|
| 487 |
-
Square to = to_sq(m);
|
| 488 |
-
Square capsq = to - pawn_push(us);
|
| 489 |
-
Bitboard occupied = (pieces() ^ from ^ capsq) | to;
|
| 490 |
-
|
| 491 |
-
assert(to == ep_square());
|
| 492 |
-
assert(moved_piece(m) == make_piece(us, PAWN));
|
| 493 |
-
assert(piece_on(capsq) == make_piece(~us, PAWN));
|
| 494 |
-
assert(piece_on(to) == NO_PIECE);
|
| 495 |
-
|
| 496 |
-
return !(attacks_bb< ROOK>(ksq, occupied) & pieces(~us, QUEEN, ROOK))
|
| 497 |
-
&& !(attacks_bb<BISHOP>(ksq, occupied) & pieces(~us, QUEEN, BISHOP));
|
| 498 |
-
}
|
| 499 |
-
|
| 500 |
-
// If the moving piece is a king, check whether the destination
|
| 501 |
-
// square is attacked by the opponent. Castling moves are checked
|
| 502 |
-
// for legality during move generation.
|
| 503 |
-
if (type_of(piece_on(from)) == KING)
|
| 504 |
-
return type_of(m) == CASTLING || !(attackers_to(to_sq(m)) & pieces(~us));
|
| 505 |
-
|
| 506 |
-
// A non-king move is legal if and only if it is not pinned or it
|
| 507 |
-
// is moving along the ray towards or away from the king.
|
| 508 |
-
return !(pinned_pieces(us) & from)
|
| 509 |
-
|| aligned(from, to_sq(m), square<KING>(us));
|
| 510 |
-
}
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
/// Position::pseudo_legal() takes a random move and tests whether the move is
|
| 514 |
-
/// pseudo legal. It is used to validate moves from TT that can be corrupted
|
| 515 |
-
/// due to SMP concurrent access or hash position key aliasing.
|
| 516 |
-
|
| 517 |
-
bool Position::pseudo_legal(const Move m) const {
|
| 518 |
-
|
| 519 |
-
Color us = sideToMove;
|
| 520 |
-
Square from = from_sq(m);
|
| 521 |
-
Square to = to_sq(m);
|
| 522 |
-
Piece pc = moved_piece(m);
|
| 523 |
-
|
| 524 |
-
// Use a slower but simpler function for uncommon cases
|
| 525 |
-
if (type_of(m) != NORMAL)
|
| 526 |
-
return MoveList<LEGAL>(*this).contains(m);
|
| 527 |
-
|
| 528 |
-
// Is not a promotion, so promotion piece must be empty
|
| 529 |
-
if (promotion_type(m) - KNIGHT != NO_PIECE_TYPE)
|
| 530 |
-
return false;
|
| 531 |
-
|
| 532 |
-
// If the 'from' square is not occupied by a piece belonging to the side to
|
| 533 |
-
// move, the move is obviously not legal.
|
| 534 |
-
if (pc == NO_PIECE || color_of(pc) != us)
|
| 535 |
-
return false;
|
| 536 |
-
|
| 537 |
-
// The destination square cannot be occupied by a friendly piece
|
| 538 |
-
if (pieces(us) & to)
|
| 539 |
-
return false;
|
| 540 |
-
|
| 541 |
-
// Handle the special case of a pawn move
|
| 542 |
-
if (type_of(pc) == PAWN)
|
| 543 |
-
{
|
| 544 |
-
// We have already handled promotion moves, so destination
|
| 545 |
-
// cannot be on the 8th/1st rank.
|
| 546 |
-
if (rank_of(to) == relative_rank(us, RANK_8))
|
| 547 |
-
return false;
|
| 548 |
-
|
| 549 |
-
if ( !(attacks_from<PAWN>(from, us) & pieces(~us) & to) // Not a capture
|
| 550 |
-
&& !((from + pawn_push(us) == to) && empty(to)) // Not a single push
|
| 551 |
-
&& !( (from + 2 * pawn_push(us) == to) // Not a double push
|
| 552 |
-
&& (rank_of(from) == relative_rank(us, RANK_2))
|
| 553 |
-
&& empty(to)
|
| 554 |
-
&& empty(to - pawn_push(us))))
|
| 555 |
-
return false;
|
| 556 |
-
}
|
| 557 |
-
else if (!(attacks_from(pc, from) & to))
|
| 558 |
-
return false;
|
| 559 |
-
|
| 560 |
-
// Evasions generator already takes care to avoid some kind of illegal moves
|
| 561 |
-
// and legal() relies on this. We therefore have to take care that the same
|
| 562 |
-
// kind of moves are filtered out here.
|
| 563 |
-
if (checkers())
|
| 564 |
-
{
|
| 565 |
-
if (type_of(pc) != KING)
|
| 566 |
-
{
|
| 567 |
-
// Double check? In this case a king move is required
|
| 568 |
-
if (more_than_one(checkers()))
|
| 569 |
-
return false;
|
| 570 |
-
|
| 571 |
-
// Our move must be a blocking evasion or a capture of the checking piece
|
| 572 |
-
if (!((between_bb(lsb(checkers()), square<KING>(us)) | checkers()) & to))
|
| 573 |
-
return false;
|
| 574 |
-
}
|
| 575 |
-
// In case of king moves under check we have to remove king so as to catch
|
| 576 |
-
// invalid moves like b1a1 when opposite queen is on c1.
|
| 577 |
-
else if (attackers_to(to, pieces() ^ from) & pieces(~us))
|
| 578 |
-
return false;
|
| 579 |
-
}
|
| 580 |
-
|
| 581 |
-
return true;
|
| 582 |
-
}
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
/// Position::gives_check() tests whether a pseudo-legal move gives a check
|
| 586 |
-
|
| 587 |
-
bool Position::gives_check(Move m) const {
|
| 588 |
-
|
| 589 |
-
assert(is_ok(m));
|
| 590 |
-
assert(color_of(moved_piece(m)) == sideToMove);
|
| 591 |
-
|
| 592 |
-
Square from = from_sq(m);
|
| 593 |
-
Square to = to_sq(m);
|
| 594 |
-
|
| 595 |
-
// Is there a direct check?
|
| 596 |
-
if (st->checkSquares[type_of(piece_on(from))] & to)
|
| 597 |
-
return true;
|
| 598 |
-
|
| 599 |
-
// Is there a discovered check?
|
| 600 |
-
if ( (discovered_check_candidates() & from)
|
| 601 |
-
&& !aligned(from, to, square<KING>(~sideToMove)))
|
| 602 |
-
return true;
|
| 603 |
-
|
| 604 |
-
switch (type_of(m))
|
| 605 |
-
{
|
| 606 |
-
case NORMAL:
|
| 607 |
-
return false;
|
| 608 |
-
|
| 609 |
-
case PROMOTION:
|
| 610 |
-
return attacks_bb(Piece(promotion_type(m)), to, pieces() ^ from) & square<KING>(~sideToMove);
|
| 611 |
-
|
| 612 |
-
// En passant capture with check? We have already handled the case
|
| 613 |
-
// of direct checks and ordinary discovered check, so the only case we
|
| 614 |
-
// need to handle is the unusual case of a discovered check through
|
| 615 |
-
// the captured pawn.
|
| 616 |
-
case ENPASSANT:
|
| 617 |
-
{
|
| 618 |
-
Square capsq = make_square(file_of(to), rank_of(from));
|
| 619 |
-
Bitboard b = (pieces() ^ from ^ capsq) | to;
|
| 620 |
-
|
| 621 |
-
return (attacks_bb< ROOK>(square<KING>(~sideToMove), b) & pieces(sideToMove, QUEEN, ROOK))
|
| 622 |
-
| (attacks_bb<BISHOP>(square<KING>(~sideToMove), b) & pieces(sideToMove, QUEEN, BISHOP));
|
| 623 |
-
}
|
| 624 |
-
case CASTLING:
|
| 625 |
-
{
|
| 626 |
-
Square kfrom = from;
|
| 627 |
-
Square rfrom = to; // Castling is encoded as 'King captures the rook'
|
| 628 |
-
Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1);
|
| 629 |
-
Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1);
|
| 630 |
-
|
| 631 |
-
return (PseudoAttacks[ROOK][rto] & square<KING>(~sideToMove))
|
| 632 |
-
&& (attacks_bb<ROOK>(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & square<KING>(~sideToMove));
|
| 633 |
-
}
|
| 634 |
-
default:
|
| 635 |
-
assert(false);
|
| 636 |
-
return false;
|
| 637 |
-
}
|
| 638 |
-
}
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
/// Position::do_move() makes a move, and saves all information necessary
|
| 642 |
-
/// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
|
| 643 |
-
/// moves should be filtered out before this function is called.
|
| 644 |
-
|
| 645 |
-
void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
| 646 |
-
|
| 647 |
-
assert(is_ok(m));
|
| 648 |
-
assert(&newSt != st);
|
| 649 |
-
|
| 650 |
-
++nodes;
|
| 651 |
-
Key k = st->key ^ Zobrist::side;
|
| 652 |
-
|
| 653 |
-
// Copy some fields of the old state to our new StateInfo object except the
|
| 654 |
-
// ones which are going to be recalculated from scratch anyway and then switch
|
| 655 |
-
// our state pointer to point to the new (ready to be updated) state.
|
| 656 |
-
std::memcpy(&newSt, st, offsetof(StateInfo, key));
|
| 657 |
-
newSt.previous = st;
|
| 658 |
-
st = &newSt;
|
| 659 |
-
|
| 660 |
-
// Increment ply counters. In particular, rule50 will be reset to zero later on
|
| 661 |
-
// in case of a capture or a pawn move.
|
| 662 |
-
++gamePly;
|
| 663 |
-
++st->rule50;
|
| 664 |
-
++st->pliesFromNull;
|
| 665 |
-
|
| 666 |
-
Color us = sideToMove;
|
| 667 |
-
Color them = ~us;
|
| 668 |
-
Square from = from_sq(m);
|
| 669 |
-
Square to = to_sq(m);
|
| 670 |
-
Piece pc = piece_on(from);
|
| 671 |
-
Piece captured = type_of(m) == ENPASSANT ? make_piece(them, PAWN) : piece_on(to);
|
| 672 |
-
|
| 673 |
-
assert(color_of(pc) == us);
|
| 674 |
-
assert(captured == NO_PIECE || color_of(captured) == (type_of(m) != CASTLING ? them : us));
|
| 675 |
-
assert(type_of(captured) != KING);
|
| 676 |
-
|
| 677 |
-
if (type_of(m) == CASTLING)
|
| 678 |
-
{
|
| 679 |
-
assert(pc == make_piece(us, KING));
|
| 680 |
-
assert(captured == make_piece(us, ROOK));
|
| 681 |
-
|
| 682 |
-
Square rfrom, rto;
|
| 683 |
-
do_castling<true>(us, from, to, rfrom, rto);
|
| 684 |
-
|
| 685 |
-
st->psq += PSQT::psq[captured][rto] - PSQT::psq[captured][rfrom];
|
| 686 |
-
k ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
|
| 687 |
-
captured = NO_PIECE;
|
| 688 |
-
}
|
| 689 |
-
|
| 690 |
-
if (captured)
|
| 691 |
-
{
|
| 692 |
-
Square capsq = to;
|
| 693 |
-
|
| 694 |
-
// If the captured piece is a pawn, update pawn hash key, otherwise
|
| 695 |
-
// update non-pawn material.
|
| 696 |
-
if (type_of(captured) == PAWN)
|
| 697 |
-
{
|
| 698 |
-
if (type_of(m) == ENPASSANT)
|
| 699 |
-
{
|
| 700 |
-
capsq -= pawn_push(us);
|
| 701 |
-
|
| 702 |
-
assert(pc == make_piece(us, PAWN));
|
| 703 |
-
assert(to == st->epSquare);
|
| 704 |
-
assert(relative_rank(us, to) == RANK_6);
|
| 705 |
-
assert(piece_on(to) == NO_PIECE);
|
| 706 |
-
assert(piece_on(capsq) == make_piece(them, PAWN));
|
| 707 |
-
|
| 708 |
-
board[capsq] = NO_PIECE; // Not done by remove_piece()
|
| 709 |
-
}
|
| 710 |
-
|
| 711 |
-
st->pawnKey ^= Zobrist::psq[captured][capsq];
|
| 712 |
-
}
|
| 713 |
-
else
|
| 714 |
-
st->nonPawnMaterial[them] -= PieceValue[MG][captured];
|
| 715 |
-
|
| 716 |
-
// Update board and piece lists
|
| 717 |
-
remove_piece(captured, capsq);
|
| 718 |
-
|
| 719 |
-
// Update material hash key and prefetch access to materialTable
|
| 720 |
-
k ^= Zobrist::psq[captured][capsq];
|
| 721 |
-
st->materialKey ^= Zobrist::psq[captured][pieceCount[captured]];
|
| 722 |
-
prefetch(thisThread->materialTable[st->materialKey]);
|
| 723 |
-
|
| 724 |
-
// Update incremental scores
|
| 725 |
-
st->psq -= PSQT::psq[captured][capsq];
|
| 726 |
-
|
| 727 |
-
// Reset rule 50 counter
|
| 728 |
-
st->rule50 = 0;
|
| 729 |
-
}
|
| 730 |
-
|
| 731 |
-
// Update hash key
|
| 732 |
-
k ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
| 733 |
-
|
| 734 |
-
// Reset en passant square
|
| 735 |
-
if (st->epSquare != SQ_NONE)
|
| 736 |
-
{
|
| 737 |
-
k ^= Zobrist::enpassant[file_of(st->epSquare)];
|
| 738 |
-
st->epSquare = SQ_NONE;
|
| 739 |
-
}
|
| 740 |
-
|
| 741 |
-
// Update castling rights if needed
|
| 742 |
-
if (st->castlingRights && (castlingRightsMask[from] | castlingRightsMask[to]))
|
| 743 |
-
{
|
| 744 |
-
int cr = castlingRightsMask[from] | castlingRightsMask[to];
|
| 745 |
-
k ^= Zobrist::castling[st->castlingRights & cr];
|
| 746 |
-
st->castlingRights &= ~cr;
|
| 747 |
-
}
|
| 748 |
-
|
| 749 |
-
// Move the piece. The tricky Chess960 castling is handled earlier
|
| 750 |
-
if (type_of(m) != CASTLING)
|
| 751 |
-
move_piece(pc, from, to);
|
| 752 |
-
|
| 753 |
-
// If the moving piece is a pawn do some special extra work
|
| 754 |
-
if (type_of(pc) == PAWN)
|
| 755 |
-
{
|
| 756 |
-
// Set en-passant square if the moved pawn can be captured
|
| 757 |
-
if ( (int(to) ^ int(from)) == 16
|
| 758 |
-
&& (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN)))
|
| 759 |
-
{
|
| 760 |
-
st->epSquare = (from + to) / 2;
|
| 761 |
-
k ^= Zobrist::enpassant[file_of(st->epSquare)];
|
| 762 |
-
}
|
| 763 |
-
|
| 764 |
-
else if (type_of(m) == PROMOTION)
|
| 765 |
-
{
|
| 766 |
-
Piece promotion = make_piece(us, promotion_type(m));
|
| 767 |
-
|
| 768 |
-
assert(relative_rank(us, to) == RANK_8);
|
| 769 |
-
assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN);
|
| 770 |
-
|
| 771 |
-
remove_piece(pc, to);
|
| 772 |
-
put_piece(promotion, to);
|
| 773 |
-
|
| 774 |
-
// Update hash keys
|
| 775 |
-
k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to];
|
| 776 |
-
st->pawnKey ^= Zobrist::psq[pc][to];
|
| 777 |
-
st->materialKey ^= Zobrist::psq[promotion][pieceCount[promotion]-1]
|
| 778 |
-
^ Zobrist::psq[pc][pieceCount[pc]];
|
| 779 |
-
|
| 780 |
-
// Update incremental score
|
| 781 |
-
st->psq += PSQT::psq[promotion][to] - PSQT::psq[pc][to];
|
| 782 |
-
|
| 783 |
-
// Update material
|
| 784 |
-
st->nonPawnMaterial[us] += PieceValue[MG][promotion];
|
| 785 |
-
}
|
| 786 |
-
|
| 787 |
-
// Update pawn hash key and prefetch access to pawnsTable
|
| 788 |
-
st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
| 789 |
-
prefetch(thisThread->pawnsTable[st->pawnKey]);
|
| 790 |
-
|
| 791 |
-
// Reset rule 50 draw counter
|
| 792 |
-
st->rule50 = 0;
|
| 793 |
-
}
|
| 794 |
-
|
| 795 |
-
// Update incremental scores
|
| 796 |
-
st->psq += PSQT::psq[pc][to] - PSQT::psq[pc][from];
|
| 797 |
-
|
| 798 |
-
// Set capture piece
|
| 799 |
-
st->capturedPiece = captured;
|
| 800 |
-
|
| 801 |
-
// Update the key with the final value
|
| 802 |
-
st->key = k;
|
| 803 |
-
|
| 804 |
-
// Calculate checkers bitboard (if move gives check)
|
| 805 |
-
st->checkersBB = givesCheck ? attackers_to(square<KING>(them)) & pieces(us) : 0;
|
| 806 |
-
|
| 807 |
-
sideToMove = ~sideToMove;
|
| 808 |
-
|
| 809 |
-
// Update king attacks used for fast check detection
|
| 810 |
-
set_check_info(st);
|
| 811 |
-
|
| 812 |
-
assert(pos_is_ok());
|
| 813 |
-
}
|
| 814 |
-
|
| 815 |
-
|
| 816 |
-
/// Position::undo_move() unmakes a move. When it returns, the position should
|
| 817 |
-
/// be restored to exactly the same state as before the move was made.
|
| 818 |
-
|
| 819 |
-
void Position::undo_move(Move m) {
|
| 820 |
-
|
| 821 |
-
assert(is_ok(m));
|
| 822 |
-
|
| 823 |
-
sideToMove = ~sideToMove;
|
| 824 |
-
|
| 825 |
-
Color us = sideToMove;
|
| 826 |
-
Square from = from_sq(m);
|
| 827 |
-
Square to = to_sq(m);
|
| 828 |
-
Piece pc = piece_on(to);
|
| 829 |
-
|
| 830 |
-
assert(empty(from) || type_of(m) == CASTLING);
|
| 831 |
-
assert(type_of(st->capturedPiece) != KING);
|
| 832 |
-
|
| 833 |
-
if (type_of(m) == PROMOTION)
|
| 834 |
-
{
|
| 835 |
-
assert(relative_rank(us, to) == RANK_8);
|
| 836 |
-
assert(type_of(pc) == promotion_type(m));
|
| 837 |
-
assert(type_of(pc) >= KNIGHT && type_of(pc) <= QUEEN);
|
| 838 |
-
|
| 839 |
-
remove_piece(pc, to);
|
| 840 |
-
pc = make_piece(us, PAWN);
|
| 841 |
-
put_piece(pc, to);
|
| 842 |
-
}
|
| 843 |
-
|
| 844 |
-
if (type_of(m) == CASTLING)
|
| 845 |
-
{
|
| 846 |
-
Square rfrom, rto;
|
| 847 |
-
do_castling<false>(us, from, to, rfrom, rto);
|
| 848 |
-
}
|
| 849 |
-
else
|
| 850 |
-
{
|
| 851 |
-
move_piece(pc, to, from); // Put the piece back at the source square
|
| 852 |
-
|
| 853 |
-
if (st->capturedPiece)
|
| 854 |
-
{
|
| 855 |
-
Square capsq = to;
|
| 856 |
-
|
| 857 |
-
if (type_of(m) == ENPASSANT)
|
| 858 |
-
{
|
| 859 |
-
capsq -= pawn_push(us);
|
| 860 |
-
|
| 861 |
-
assert(type_of(pc) == PAWN);
|
| 862 |
-
assert(to == st->previous->epSquare);
|
| 863 |
-
assert(relative_rank(us, to) == RANK_6);
|
| 864 |
-
assert(piece_on(capsq) == NO_PIECE);
|
| 865 |
-
assert(st->capturedPiece == make_piece(~us, PAWN));
|
| 866 |
-
}
|
| 867 |
-
|
| 868 |
-
put_piece(st->capturedPiece, capsq); // Restore the captured piece
|
| 869 |
-
}
|
| 870 |
-
}
|
| 871 |
-
|
| 872 |
-
// Finally point our state pointer back to the previous state
|
| 873 |
-
st = st->previous;
|
| 874 |
-
--gamePly;
|
| 875 |
-
|
| 876 |
-
assert(pos_is_ok());
|
| 877 |
-
}
|
| 878 |
-
|
| 879 |
-
|
| 880 |
-
/// Position::do_castling() is a helper used to do/undo a castling move. This
|
| 881 |
-
/// is a bit tricky in Chess960 where from/to squares can overlap.
|
| 882 |
-
template<bool Do>
|
| 883 |
-
void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto) {
|
| 884 |
-
|
| 885 |
-
bool kingSide = to > from;
|
| 886 |
-
rfrom = to; // Castling is encoded as "king captures friendly rook"
|
| 887 |
-
rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
|
| 888 |
-
to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
|
| 889 |
-
|
| 890 |
-
// Remove both pieces first since squares could overlap in Chess960
|
| 891 |
-
remove_piece(make_piece(us, KING), Do ? from : to);
|
| 892 |
-
remove_piece(make_piece(us, ROOK), Do ? rfrom : rto);
|
| 893 |
-
board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us
|
| 894 |
-
put_piece(make_piece(us, KING), Do ? to : from);
|
| 895 |
-
put_piece(make_piece(us, ROOK), Do ? rto : rfrom);
|
| 896 |
-
}
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
/// Position::do(undo)_null_move() is used to do(undo) a "null move": It flips
|
| 900 |
-
/// the side to move without executing any move on the board.
|
| 901 |
-
|
| 902 |
-
void Position::do_null_move(StateInfo& newSt) {
|
| 903 |
-
|
| 904 |
-
assert(!checkers());
|
| 905 |
-
assert(&newSt != st);
|
| 906 |
-
|
| 907 |
-
std::memcpy(&newSt, st, sizeof(StateInfo));
|
| 908 |
-
newSt.previous = st;
|
| 909 |
-
st = &newSt;
|
| 910 |
-
|
| 911 |
-
if (st->epSquare != SQ_NONE)
|
| 912 |
-
{
|
| 913 |
-
st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
|
| 914 |
-
st->epSquare = SQ_NONE;
|
| 915 |
-
}
|
| 916 |
-
|
| 917 |
-
st->key ^= Zobrist::side;
|
| 918 |
-
prefetch(TT.first_entry(st->key));
|
| 919 |
-
|
| 920 |
-
++st->rule50;
|
| 921 |
-
st->pliesFromNull = 0;
|
| 922 |
-
|
| 923 |
-
sideToMove = ~sideToMove;
|
| 924 |
-
|
| 925 |
-
set_check_info(st);
|
| 926 |
-
|
| 927 |
-
assert(pos_is_ok());
|
| 928 |
-
}
|
| 929 |
-
|
| 930 |
-
void Position::undo_null_move() {
|
| 931 |
-
|
| 932 |
-
assert(!checkers());
|
| 933 |
-
|
| 934 |
-
st = st->previous;
|
| 935 |
-
sideToMove = ~sideToMove;
|
| 936 |
-
}
|
| 937 |
-
|
| 938 |
-
|
| 939 |
-
/// Position::key_after() computes the new hash key after the given move. Needed
|
| 940 |
-
/// for speculative prefetch. It doesn't recognize special moves like castling,
|
| 941 |
-
/// en-passant and promotions.
|
| 942 |
-
|
| 943 |
-
Key Position::key_after(Move m) const {
|
| 944 |
-
|
| 945 |
-
Square from = from_sq(m);
|
| 946 |
-
Square to = to_sq(m);
|
| 947 |
-
Piece pc = piece_on(from);
|
| 948 |
-
Piece captured = piece_on(to);
|
| 949 |
-
Key k = st->key ^ Zobrist::side;
|
| 950 |
-
|
| 951 |
-
if (captured)
|
| 952 |
-
k ^= Zobrist::psq[captured][to];
|
| 953 |
-
|
| 954 |
-
return k ^ Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from];
|
| 955 |
-
}
|
| 956 |
-
|
| 957 |
-
|
| 958 |
-
/// Position::see_ge (Static Exchange Evaluation Greater or Equal) tests if the
|
| 959 |
-
/// SEE value of move is greater or equal to the given value. We'll use an
|
| 960 |
-
/// algorithm similar to alpha-beta pruning with a null window.
|
| 961 |
-
|
| 962 |
-
bool Position::see_ge(Move m, Value v) const {
|
| 963 |
-
|
| 964 |
-
assert(is_ok(m));
|
| 965 |
-
|
| 966 |
-
// Castling moves are implemented as king capturing the rook so cannot be
|
| 967 |
-
// handled correctly. Simply assume the SEE value is VALUE_ZERO that is always
|
| 968 |
-
// correct unless in the rare case the rook ends up under attack.
|
| 969 |
-
if (type_of(m) == CASTLING)
|
| 970 |
-
return VALUE_ZERO >= v;
|
| 971 |
-
|
| 972 |
-
Square from = from_sq(m), to = to_sq(m);
|
| 973 |
-
PieceType nextVictim = type_of(piece_on(from));
|
| 974 |
-
Color stm = ~color_of(piece_on(from)); // First consider opponent's move
|
| 975 |
-
Value balance; // Values of the pieces taken by us minus opponent's ones
|
| 976 |
-
Bitboard occupied, stmAttackers;
|
| 977 |
-
|
| 978 |
-
if (type_of(m) == ENPASSANT)
|
| 979 |
-
{
|
| 980 |
-
occupied = SquareBB[to - pawn_push(~stm)]; // Remove the captured pawn
|
| 981 |
-
balance = PieceValue[MG][PAWN];
|
| 982 |
-
}
|
| 983 |
-
else
|
| 984 |
-
{
|
| 985 |
-
balance = PieceValue[MG][piece_on(to)];
|
| 986 |
-
occupied = 0;
|
| 987 |
-
}
|
| 988 |
-
|
| 989 |
-
if (balance < v)
|
| 990 |
-
return false;
|
| 991 |
-
|
| 992 |
-
if (nextVictim == KING)
|
| 993 |
-
return true;
|
| 994 |
-
|
| 995 |
-
balance -= PieceValue[MG][nextVictim];
|
| 996 |
-
|
| 997 |
-
if (balance >= v)
|
| 998 |
-
return true;
|
| 999 |
-
|
| 1000 |
-
bool relativeStm = true; // True if the opponent is to move
|
| 1001 |
-
occupied ^= pieces() ^ from ^ to;
|
| 1002 |
-
|
| 1003 |
-
// Find all attackers to the destination square, with the moving piece removed,
|
| 1004 |
-
// but possibly an X-ray attacker added behind it.
|
| 1005 |
-
Bitboard attackers = attackers_to(to, occupied) & occupied;
|
| 1006 |
-
|
| 1007 |
-
while (true)
|
| 1008 |
-
{
|
| 1009 |
-
stmAttackers = attackers & pieces(stm);
|
| 1010 |
-
|
| 1011 |
-
// Don't allow pinned pieces to attack pieces except the king as long all
|
| 1012 |
-
// pinners are on their original square.
|
| 1013 |
-
if (!(st->pinnersForKing[stm] & ~occupied))
|
| 1014 |
-
stmAttackers &= ~st->blockersForKing[stm];
|
| 1015 |
-
|
| 1016 |
-
if (!stmAttackers)
|
| 1017 |
-
return relativeStm;
|
| 1018 |
-
|
| 1019 |
-
// Locate and remove the next least valuable attacker
|
| 1020 |
-
nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
|
| 1021 |
-
|
| 1022 |
-
if (nextVictim == KING)
|
| 1023 |
-
return relativeStm == bool(attackers & pieces(~stm));
|
| 1024 |
-
|
| 1025 |
-
balance += relativeStm ? PieceValue[MG][nextVictim]
|
| 1026 |
-
: -PieceValue[MG][nextVictim];
|
| 1027 |
-
|
| 1028 |
-
relativeStm = !relativeStm;
|
| 1029 |
-
|
| 1030 |
-
if (relativeStm == (balance >= v))
|
| 1031 |
-
return relativeStm;
|
| 1032 |
-
|
| 1033 |
-
stm = ~stm;
|
| 1034 |
-
}
|
| 1035 |
-
}
|
| 1036 |
-
|
| 1037 |
-
|
| 1038 |
-
/// Position::is_draw() tests whether the position is drawn by 50-move rule
|
| 1039 |
-
/// or by repetition. It does not detect stalemates.
|
| 1040 |
-
|
| 1041 |
-
bool Position::is_draw() const {
|
| 1042 |
-
|
| 1043 |
-
if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
|
| 1044 |
-
return true;
|
| 1045 |
-
|
| 1046 |
-
StateInfo* stp = st;
|
| 1047 |
-
for (int i = 2, e = std::min(st->rule50, st->pliesFromNull); i <= e; i += 2)
|
| 1048 |
-
{
|
| 1049 |
-
stp = stp->previous->previous;
|
| 1050 |
-
|
| 1051 |
-
if (stp->key == st->key)
|
| 1052 |
-
return true; // Draw at first repetition
|
| 1053 |
-
}
|
| 1054 |
-
|
| 1055 |
-
return false;
|
| 1056 |
-
}
|
| 1057 |
-
|
| 1058 |
-
|
| 1059 |
-
/// Position::flip() flips position with the white and black sides reversed. This
|
| 1060 |
-
/// is only useful for debugging e.g. for finding evaluation symmetry bugs.
|
| 1061 |
-
|
| 1062 |
-
void Position::flip() {
|
| 1063 |
-
|
| 1064 |
-
string f, token;
|
| 1065 |
-
std::stringstream ss(fen());
|
| 1066 |
-
|
| 1067 |
-
for (Rank r = RANK_8; r >= RANK_1; --r) // Piece placement
|
| 1068 |
-
{
|
| 1069 |
-
std::getline(ss, token, r > RANK_1 ? '/' : ' ');
|
| 1070 |
-
f.insert(0, token + (f.empty() ? " " : "/"));
|
| 1071 |
-
}
|
| 1072 |
-
|
| 1073 |
-
ss >> token; // Active color
|
| 1074 |
-
f += (token == "w" ? "B " : "W "); // Will be lowercased later
|
| 1075 |
-
|
| 1076 |
-
ss >> token; // Castling availability
|
| 1077 |
-
f += token + " ";
|
| 1078 |
-
|
| 1079 |
-
std::transform(f.begin(), f.end(), f.begin(),
|
| 1080 |
-
[](char c) { return char(islower(c) ? toupper(c) : tolower(c)); });
|
| 1081 |
-
|
| 1082 |
-
ss >> token; // En passant square
|
| 1083 |
-
f += (token == "-" ? token : token.replace(1, 1, token[1] == '3' ? "6" : "3"));
|
| 1084 |
-
|
| 1085 |
-
std::getline(ss, token); // Half and full moves
|
| 1086 |
-
f += token;
|
| 1087 |
-
|
| 1088 |
-
set(f, is_chess960(), st, this_thread());
|
| 1089 |
-
|
| 1090 |
-
assert(pos_is_ok());
|
| 1091 |
-
}
|
| 1092 |
-
|
| 1093 |
-
|
| 1094 |
-
/// Position::pos_is_ok() performs some consistency checks for the position object.
|
| 1095 |
-
/// This is meant to be helpful when debugging.
|
| 1096 |
-
|
| 1097 |
-
bool Position::pos_is_ok(int* failedStep) const {
|
| 1098 |
-
|
| 1099 |
-
const bool Fast = true; // Quick (default) or full check?
|
| 1100 |
-
|
| 1101 |
-
enum { Default, King, Bitboards, State, Lists, Castling };
|
| 1102 |
-
|
| 1103 |
-
for (int step = Default; step <= (Fast ? Default : Castling); step++)
|
| 1104 |
-
{
|
| 1105 |
-
if (failedStep)
|
| 1106 |
-
*failedStep = step;
|
| 1107 |
-
|
| 1108 |
-
if (step == Default)
|
| 1109 |
-
if ( (sideToMove != WHITE && sideToMove != BLACK)
|
| 1110 |
-
|| piece_on(square<KING>(WHITE)) != W_KING
|
| 1111 |
-
|| piece_on(square<KING>(BLACK)) != B_KING
|
| 1112 |
-
|| ( ep_square() != SQ_NONE
|
| 1113 |
-
&& relative_rank(sideToMove, ep_square()) != RANK_6))
|
| 1114 |
-
return false;
|
| 1115 |
-
|
| 1116 |
-
if (step == King)
|
| 1117 |
-
if ( std::count(board, board + SQUARE_NB, W_KING) != 1
|
| 1118 |
-
|| std::count(board, board + SQUARE_NB, B_KING) != 1
|
| 1119 |
-
|| attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove))
|
| 1120 |
-
return false;
|
| 1121 |
-
|
| 1122 |
-
if (step == Bitboards)
|
| 1123 |
-
{
|
| 1124 |
-
if ( (pieces(WHITE) & pieces(BLACK))
|
| 1125 |
-
||(pieces(WHITE) | pieces(BLACK)) != pieces())
|
| 1126 |
-
return false;
|
| 1127 |
-
|
| 1128 |
-
for (PieceType p1 = PAWN; p1 <= KING; ++p1)
|
| 1129 |
-
for (PieceType p2 = PAWN; p2 <= KING; ++p2)
|
| 1130 |
-
if (p1 != p2 && (pieces(p1) & pieces(p2)))
|
| 1131 |
-
return false;
|
| 1132 |
-
}
|
| 1133 |
-
|
| 1134 |
-
if (step == State)
|
| 1135 |
-
{
|
| 1136 |
-
StateInfo si = *st;
|
| 1137 |
-
set_state(&si);
|
| 1138 |
-
if (std::memcmp(&si, st, sizeof(StateInfo)))
|
| 1139 |
-
return false;
|
| 1140 |
-
}
|
| 1141 |
-
|
| 1142 |
-
if (step == Lists)
|
| 1143 |
-
for (Piece pc : Pieces)
|
| 1144 |
-
{
|
| 1145 |
-
if (pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc))))
|
| 1146 |
-
return false;
|
| 1147 |
-
|
| 1148 |
-
for (int i = 0; i < pieceCount[pc]; ++i)
|
| 1149 |
-
if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i)
|
| 1150 |
-
return false;
|
| 1151 |
-
}
|
| 1152 |
-
|
| 1153 |
-
if (step == Castling)
|
| 1154 |
-
for (Color c = WHITE; c <= BLACK; ++c)
|
| 1155 |
-
for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1))
|
| 1156 |
-
{
|
| 1157 |
-
if (!can_castle(c | s))
|
| 1158 |
-
continue;
|
| 1159 |
-
|
| 1160 |
-
if ( piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK)
|
| 1161 |
-
|| castlingRightsMask[castlingRookSquare[c | s]] != (c | s)
|
| 1162 |
-
||(castlingRightsMask[square<KING>(c)] & (c | s)) != (c | s))
|
| 1163 |
-
return false;
|
| 1164 |
-
}
|
| 1165 |
-
}
|
| 1166 |
-
|
| 1167 |
-
return true;
|
| 1168 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/position.h
DELETED
|
@@ -1,414 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef POSITION_H_INCLUDED
|
| 22 |
-
#define POSITION_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include <cassert>
|
| 25 |
-
#include <deque>
|
| 26 |
-
#include <memory> // For std::unique_ptr
|
| 27 |
-
#include <string>
|
| 28 |
-
|
| 29 |
-
#include "bitboard.h"
|
| 30 |
-
#include "types.h"
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
/// StateInfo struct stores information needed to restore a Position object to
|
| 34 |
-
/// its previous state when we retract a move. Whenever a move is made on the
|
| 35 |
-
/// board (by calling Position::do_move), a StateInfo object must be passed.
|
| 36 |
-
|
| 37 |
-
struct StateInfo {
|
| 38 |
-
|
| 39 |
-
// Copied when making a move
|
| 40 |
-
Key pawnKey;
|
| 41 |
-
Key materialKey;
|
| 42 |
-
Value nonPawnMaterial[COLOR_NB];
|
| 43 |
-
int castlingRights;
|
| 44 |
-
int rule50;
|
| 45 |
-
int pliesFromNull;
|
| 46 |
-
Score psq;
|
| 47 |
-
Square epSquare;
|
| 48 |
-
|
| 49 |
-
// Not copied when making a move (will be recomputed anyhow)
|
| 50 |
-
Key key;
|
| 51 |
-
Bitboard checkersBB;
|
| 52 |
-
Piece capturedPiece;
|
| 53 |
-
StateInfo* previous;
|
| 54 |
-
Bitboard blockersForKing[COLOR_NB];
|
| 55 |
-
Bitboard pinnersForKing[COLOR_NB];
|
| 56 |
-
Bitboard checkSquares[PIECE_TYPE_NB];
|
| 57 |
-
};
|
| 58 |
-
|
| 59 |
-
// In a std::deque references to elements are unaffected upon resizing
|
| 60 |
-
typedef std::unique_ptr<std::deque<StateInfo>> StateListPtr;
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
/// Position class stores information regarding the board representation as
|
| 64 |
-
/// pieces, side to move, hash keys, castling info, etc. Important methods are
|
| 65 |
-
/// do_move() and undo_move(), used by the search to update node info when
|
| 66 |
-
/// traversing the search tree.
|
| 67 |
-
class Thread;
|
| 68 |
-
|
| 69 |
-
class Position {
|
| 70 |
-
public:
|
| 71 |
-
static void init();
|
| 72 |
-
|
| 73 |
-
Position() = default;
|
| 74 |
-
Position(const Position&) = delete;
|
| 75 |
-
Position& operator=(const Position&) = delete;
|
| 76 |
-
|
| 77 |
-
// FEN string input/output
|
| 78 |
-
Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th);
|
| 79 |
-
const std::string fen() const;
|
| 80 |
-
|
| 81 |
-
// Position representation
|
| 82 |
-
Bitboard pieces() const;
|
| 83 |
-
Bitboard pieces(PieceType pt) const;
|
| 84 |
-
Bitboard pieces(PieceType pt1, PieceType pt2) const;
|
| 85 |
-
Bitboard pieces(Color c) const;
|
| 86 |
-
Bitboard pieces(Color c, PieceType pt) const;
|
| 87 |
-
Bitboard pieces(Color c, PieceType pt1, PieceType pt2) const;
|
| 88 |
-
Piece piece_on(Square s) const;
|
| 89 |
-
Square ep_square() const;
|
| 90 |
-
bool empty(Square s) const;
|
| 91 |
-
template<PieceType Pt> int count(Color c) const;
|
| 92 |
-
template<PieceType Pt> const Square* squares(Color c) const;
|
| 93 |
-
template<PieceType Pt> Square square(Color c) const;
|
| 94 |
-
|
| 95 |
-
// Castling
|
| 96 |
-
int can_castle(Color c) const;
|
| 97 |
-
int can_castle(CastlingRight cr) const;
|
| 98 |
-
bool castling_impeded(CastlingRight cr) const;
|
| 99 |
-
Square castling_rook_square(CastlingRight cr) const;
|
| 100 |
-
|
| 101 |
-
// Checking
|
| 102 |
-
Bitboard checkers() const;
|
| 103 |
-
Bitboard discovered_check_candidates() const;
|
| 104 |
-
Bitboard pinned_pieces(Color c) const;
|
| 105 |
-
Bitboard check_squares(PieceType pt) const;
|
| 106 |
-
|
| 107 |
-
// Attacks to/from a given square
|
| 108 |
-
Bitboard attackers_to(Square s) const;
|
| 109 |
-
Bitboard attackers_to(Square s, Bitboard occupied) const;
|
| 110 |
-
Bitboard attacks_from(Piece pc, Square s) const;
|
| 111 |
-
template<PieceType> Bitboard attacks_from(Square s) const;
|
| 112 |
-
template<PieceType> Bitboard attacks_from(Square s, Color c) const;
|
| 113 |
-
Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const;
|
| 114 |
-
|
| 115 |
-
// Properties of moves
|
| 116 |
-
bool legal(Move m) const;
|
| 117 |
-
bool pseudo_legal(const Move m) const;
|
| 118 |
-
bool capture(Move m) const;
|
| 119 |
-
bool capture_or_promotion(Move m) const;
|
| 120 |
-
bool gives_check(Move m) const;
|
| 121 |
-
bool advanced_pawn_push(Move m) const;
|
| 122 |
-
Piece moved_piece(Move m) const;
|
| 123 |
-
Piece captured_piece() const;
|
| 124 |
-
|
| 125 |
-
// Piece specific
|
| 126 |
-
bool pawn_passed(Color c, Square s) const;
|
| 127 |
-
bool opposite_bishops() const;
|
| 128 |
-
|
| 129 |
-
// Doing and undoing moves
|
| 130 |
-
void do_move(Move m, StateInfo& st, bool givesCheck);
|
| 131 |
-
void undo_move(Move m);
|
| 132 |
-
void do_null_move(StateInfo& st);
|
| 133 |
-
void undo_null_move();
|
| 134 |
-
|
| 135 |
-
// Static Exchange Evaluation
|
| 136 |
-
bool see_ge(Move m, Value value) const;
|
| 137 |
-
|
| 138 |
-
// Accessing hash keys
|
| 139 |
-
Key key() const;
|
| 140 |
-
Key key_after(Move m) const;
|
| 141 |
-
Key material_key() const;
|
| 142 |
-
Key pawn_key() const;
|
| 143 |
-
|
| 144 |
-
// Other properties of the position
|
| 145 |
-
Color side_to_move() const;
|
| 146 |
-
Phase game_phase() const;
|
| 147 |
-
int game_ply() const;
|
| 148 |
-
bool is_chess960() const;
|
| 149 |
-
Thread* this_thread() const;
|
| 150 |
-
uint64_t nodes_searched() const;
|
| 151 |
-
bool is_draw() const;
|
| 152 |
-
int rule50_count() const;
|
| 153 |
-
Score psq_score() const;
|
| 154 |
-
Value non_pawn_material(Color c) const;
|
| 155 |
-
|
| 156 |
-
// Position consistency check, for debugging
|
| 157 |
-
bool pos_is_ok(int* failedStep = nullptr) const;
|
| 158 |
-
void flip();
|
| 159 |
-
|
| 160 |
-
private:
|
| 161 |
-
// Initialization helpers (used while setting up a position)
|
| 162 |
-
void set_castling_right(Color c, Square rfrom);
|
| 163 |
-
void set_state(StateInfo* si) const;
|
| 164 |
-
void set_check_info(StateInfo* si) const;
|
| 165 |
-
|
| 166 |
-
// Other helpers
|
| 167 |
-
void put_piece(Piece pc, Square s);
|
| 168 |
-
void remove_piece(Piece pc, Square s);
|
| 169 |
-
void move_piece(Piece pc, Square from, Square to);
|
| 170 |
-
template<bool Do>
|
| 171 |
-
void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto);
|
| 172 |
-
|
| 173 |
-
// Data members
|
| 174 |
-
Piece board[SQUARE_NB];
|
| 175 |
-
Bitboard byTypeBB[PIECE_TYPE_NB];
|
| 176 |
-
Bitboard byColorBB[COLOR_NB];
|
| 177 |
-
int pieceCount[PIECE_NB];
|
| 178 |
-
Square pieceList[PIECE_NB][16];
|
| 179 |
-
int index[SQUARE_NB];
|
| 180 |
-
int castlingRightsMask[SQUARE_NB];
|
| 181 |
-
Square castlingRookSquare[CASTLING_RIGHT_NB];
|
| 182 |
-
Bitboard castlingPath[CASTLING_RIGHT_NB];
|
| 183 |
-
uint64_t nodes;
|
| 184 |
-
int gamePly;
|
| 185 |
-
Color sideToMove;
|
| 186 |
-
Thread* thisThread;
|
| 187 |
-
StateInfo* st;
|
| 188 |
-
bool chess960;
|
| 189 |
-
};
|
| 190 |
-
|
| 191 |
-
extern std::ostream& operator<<(std::ostream& os, const Position& pos);
|
| 192 |
-
|
| 193 |
-
inline Color Position::side_to_move() const {
|
| 194 |
-
return sideToMove;
|
| 195 |
-
}
|
| 196 |
-
|
| 197 |
-
inline bool Position::empty(Square s) const {
|
| 198 |
-
return board[s] == NO_PIECE;
|
| 199 |
-
}
|
| 200 |
-
|
| 201 |
-
inline Piece Position::piece_on(Square s) const {
|
| 202 |
-
return board[s];
|
| 203 |
-
}
|
| 204 |
-
|
| 205 |
-
inline Piece Position::moved_piece(Move m) const {
|
| 206 |
-
return board[from_sq(m)];
|
| 207 |
-
}
|
| 208 |
-
|
| 209 |
-
inline Bitboard Position::pieces() const {
|
| 210 |
-
return byTypeBB[ALL_PIECES];
|
| 211 |
-
}
|
| 212 |
-
|
| 213 |
-
inline Bitboard Position::pieces(PieceType pt) const {
|
| 214 |
-
return byTypeBB[pt];
|
| 215 |
-
}
|
| 216 |
-
|
| 217 |
-
inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const {
|
| 218 |
-
return byTypeBB[pt1] | byTypeBB[pt2];
|
| 219 |
-
}
|
| 220 |
-
|
| 221 |
-
inline Bitboard Position::pieces(Color c) const {
|
| 222 |
-
return byColorBB[c];
|
| 223 |
-
}
|
| 224 |
-
|
| 225 |
-
inline Bitboard Position::pieces(Color c, PieceType pt) const {
|
| 226 |
-
return byColorBB[c] & byTypeBB[pt];
|
| 227 |
-
}
|
| 228 |
-
|
| 229 |
-
inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
|
| 230 |
-
return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]);
|
| 231 |
-
}
|
| 232 |
-
|
| 233 |
-
template<PieceType Pt> inline int Position::count(Color c) const {
|
| 234 |
-
return pieceCount[make_piece(c, Pt)];
|
| 235 |
-
}
|
| 236 |
-
|
| 237 |
-
template<PieceType Pt> inline const Square* Position::squares(Color c) const {
|
| 238 |
-
return pieceList[make_piece(c, Pt)];
|
| 239 |
-
}
|
| 240 |
-
|
| 241 |
-
template<PieceType Pt> inline Square Position::square(Color c) const {
|
| 242 |
-
assert(pieceCount[make_piece(c, Pt)] == 1);
|
| 243 |
-
return pieceList[make_piece(c, Pt)][0];
|
| 244 |
-
}
|
| 245 |
-
|
| 246 |
-
inline Square Position::ep_square() const {
|
| 247 |
-
return st->epSquare;
|
| 248 |
-
}
|
| 249 |
-
|
| 250 |
-
inline int Position::can_castle(CastlingRight cr) const {
|
| 251 |
-
return st->castlingRights & cr;
|
| 252 |
-
}
|
| 253 |
-
|
| 254 |
-
inline int Position::can_castle(Color c) const {
|
| 255 |
-
return st->castlingRights & ((WHITE_OO | WHITE_OOO) << (2 * c));
|
| 256 |
-
}
|
| 257 |
-
|
| 258 |
-
inline bool Position::castling_impeded(CastlingRight cr) const {
|
| 259 |
-
return byTypeBB[ALL_PIECES] & castlingPath[cr];
|
| 260 |
-
}
|
| 261 |
-
|
| 262 |
-
inline Square Position::castling_rook_square(CastlingRight cr) const {
|
| 263 |
-
return castlingRookSquare[cr];
|
| 264 |
-
}
|
| 265 |
-
|
| 266 |
-
template<PieceType Pt>
|
| 267 |
-
inline Bitboard Position::attacks_from(Square s) const {
|
| 268 |
-
return Pt == BISHOP || Pt == ROOK ? attacks_bb<Pt>(s, byTypeBB[ALL_PIECES])
|
| 269 |
-
: Pt == QUEEN ? attacks_from<ROOK>(s) | attacks_from<BISHOP>(s)
|
| 270 |
-
: StepAttacksBB[Pt][s];
|
| 271 |
-
}
|
| 272 |
-
|
| 273 |
-
template<>
|
| 274 |
-
inline Bitboard Position::attacks_from<PAWN>(Square s, Color c) const {
|
| 275 |
-
return StepAttacksBB[make_piece(c, PAWN)][s];
|
| 276 |
-
}
|
| 277 |
-
|
| 278 |
-
inline Bitboard Position::attacks_from(Piece pc, Square s) const {
|
| 279 |
-
return attacks_bb(pc, s, byTypeBB[ALL_PIECES]);
|
| 280 |
-
}
|
| 281 |
-
|
| 282 |
-
inline Bitboard Position::attackers_to(Square s) const {
|
| 283 |
-
return attackers_to(s, byTypeBB[ALL_PIECES]);
|
| 284 |
-
}
|
| 285 |
-
|
| 286 |
-
inline Bitboard Position::checkers() const {
|
| 287 |
-
return st->checkersBB;
|
| 288 |
-
}
|
| 289 |
-
|
| 290 |
-
inline Bitboard Position::discovered_check_candidates() const {
|
| 291 |
-
return st->blockersForKing[~sideToMove] & pieces(sideToMove);
|
| 292 |
-
}
|
| 293 |
-
|
| 294 |
-
inline Bitboard Position::pinned_pieces(Color c) const {
|
| 295 |
-
return st->blockersForKing[c] & pieces(c);
|
| 296 |
-
}
|
| 297 |
-
|
| 298 |
-
inline Bitboard Position::check_squares(PieceType pt) const {
|
| 299 |
-
return st->checkSquares[pt];
|
| 300 |
-
}
|
| 301 |
-
|
| 302 |
-
inline bool Position::pawn_passed(Color c, Square s) const {
|
| 303 |
-
return !(pieces(~c, PAWN) & passed_pawn_mask(c, s));
|
| 304 |
-
}
|
| 305 |
-
|
| 306 |
-
inline bool Position::advanced_pawn_push(Move m) const {
|
| 307 |
-
return type_of(moved_piece(m)) == PAWN
|
| 308 |
-
&& relative_rank(sideToMove, from_sq(m)) > RANK_4;
|
| 309 |
-
}
|
| 310 |
-
|
| 311 |
-
inline Key Position::key() const {
|
| 312 |
-
return st->key;
|
| 313 |
-
}
|
| 314 |
-
|
| 315 |
-
inline Key Position::pawn_key() const {
|
| 316 |
-
return st->pawnKey;
|
| 317 |
-
}
|
| 318 |
-
|
| 319 |
-
inline Key Position::material_key() const {
|
| 320 |
-
return st->materialKey;
|
| 321 |
-
}
|
| 322 |
-
|
| 323 |
-
inline Score Position::psq_score() const {
|
| 324 |
-
return st->psq;
|
| 325 |
-
}
|
| 326 |
-
|
| 327 |
-
inline Value Position::non_pawn_material(Color c) const {
|
| 328 |
-
return st->nonPawnMaterial[c];
|
| 329 |
-
}
|
| 330 |
-
|
| 331 |
-
inline int Position::game_ply() const {
|
| 332 |
-
return gamePly;
|
| 333 |
-
}
|
| 334 |
-
|
| 335 |
-
inline int Position::rule50_count() const {
|
| 336 |
-
return st->rule50;
|
| 337 |
-
}
|
| 338 |
-
|
| 339 |
-
inline uint64_t Position::nodes_searched() const {
|
| 340 |
-
return nodes;
|
| 341 |
-
}
|
| 342 |
-
|
| 343 |
-
inline bool Position::opposite_bishops() const {
|
| 344 |
-
return pieceCount[W_BISHOP] == 1
|
| 345 |
-
&& pieceCount[B_BISHOP] == 1
|
| 346 |
-
&& opposite_colors(square<BISHOP>(WHITE), square<BISHOP>(BLACK));
|
| 347 |
-
}
|
| 348 |
-
|
| 349 |
-
inline bool Position::is_chess960() const {
|
| 350 |
-
return chess960;
|
| 351 |
-
}
|
| 352 |
-
|
| 353 |
-
inline bool Position::capture_or_promotion(Move m) const {
|
| 354 |
-
assert(is_ok(m));
|
| 355 |
-
return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m));
|
| 356 |
-
}
|
| 357 |
-
|
| 358 |
-
inline bool Position::capture(Move m) const {
|
| 359 |
-
assert(is_ok(m));
|
| 360 |
-
// Castling is encoded as "king captures rook"
|
| 361 |
-
return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT;
|
| 362 |
-
}
|
| 363 |
-
|
| 364 |
-
inline Piece Position::captured_piece() const {
|
| 365 |
-
return st->capturedPiece;
|
| 366 |
-
}
|
| 367 |
-
|
| 368 |
-
inline Thread* Position::this_thread() const {
|
| 369 |
-
return thisThread;
|
| 370 |
-
}
|
| 371 |
-
|
| 372 |
-
inline void Position::put_piece(Piece pc, Square s) {
|
| 373 |
-
|
| 374 |
-
board[s] = pc;
|
| 375 |
-
byTypeBB[ALL_PIECES] |= s;
|
| 376 |
-
byTypeBB[type_of(pc)] |= s;
|
| 377 |
-
byColorBB[color_of(pc)] |= s;
|
| 378 |
-
index[s] = pieceCount[pc]++;
|
| 379 |
-
pieceList[pc][index[s]] = s;
|
| 380 |
-
pieceCount[make_piece(color_of(pc), ALL_PIECES)]++;
|
| 381 |
-
}
|
| 382 |
-
|
| 383 |
-
inline void Position::remove_piece(Piece pc, Square s) {
|
| 384 |
-
|
| 385 |
-
// WARNING: This is not a reversible operation. If we remove a piece in
|
| 386 |
-
// do_move() and then replace it in undo_move() we will put it at the end of
|
| 387 |
-
// the list and not in its original place, it means index[] and pieceList[]
|
| 388 |
-
// are not invariant to a do_move() + undo_move() sequence.
|
| 389 |
-
byTypeBB[ALL_PIECES] ^= s;
|
| 390 |
-
byTypeBB[type_of(pc)] ^= s;
|
| 391 |
-
byColorBB[color_of(pc)] ^= s;
|
| 392 |
-
/* board[s] = NO_PIECE; Not needed, overwritten by the capturing one */
|
| 393 |
-
Square lastSquare = pieceList[pc][--pieceCount[pc]];
|
| 394 |
-
index[lastSquare] = index[s];
|
| 395 |
-
pieceList[pc][index[lastSquare]] = lastSquare;
|
| 396 |
-
pieceList[pc][pieceCount[pc]] = SQ_NONE;
|
| 397 |
-
pieceCount[make_piece(color_of(pc), ALL_PIECES)]--;
|
| 398 |
-
}
|
| 399 |
-
|
| 400 |
-
inline void Position::move_piece(Piece pc, Square from, Square to) {
|
| 401 |
-
|
| 402 |
-
// index[from] is not updated and becomes stale. This works as long as index[]
|
| 403 |
-
// is accessed just by known occupied squares.
|
| 404 |
-
Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
|
| 405 |
-
byTypeBB[ALL_PIECES] ^= from_to_bb;
|
| 406 |
-
byTypeBB[type_of(pc)] ^= from_to_bb;
|
| 407 |
-
byColorBB[color_of(pc)] ^= from_to_bb;
|
| 408 |
-
board[from] = NO_PIECE;
|
| 409 |
-
board[to] = pc;
|
| 410 |
-
index[to] = index[from];
|
| 411 |
-
pieceList[pc][index[to]] = to;
|
| 412 |
-
}
|
| 413 |
-
|
| 414 |
-
#endif // #ifndef POSITION_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/psqt.cpp
DELETED
|
@@ -1,126 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm>
|
| 22 |
-
|
| 23 |
-
#include "types.h"
|
| 24 |
-
|
| 25 |
-
Value PieceValue[PHASE_NB][PIECE_NB] = {
|
| 26 |
-
{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg },
|
| 27 |
-
{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg }
|
| 28 |
-
};
|
| 29 |
-
|
| 30 |
-
namespace PSQT {
|
| 31 |
-
|
| 32 |
-
#define S(mg, eg) make_score(mg, eg)
|
| 33 |
-
|
| 34 |
-
// Bonus[PieceType][Square / 2] contains Piece-Square scores. For each piece
|
| 35 |
-
// type on a given square a (middlegame, endgame) score pair is assigned. Table
|
| 36 |
-
// is defined for files A..D and white side: it is symmetric for black side and
|
| 37 |
-
// second half of the files.
|
| 38 |
-
const Score Bonus[][RANK_NB][int(FILE_NB) / 2] = {
|
| 39 |
-
{ },
|
| 40 |
-
{ // Pawn
|
| 41 |
-
{ S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0) },
|
| 42 |
-
{ S(-16, 7), S( 1,-4), S( 7, 8), S( 3,-2) },
|
| 43 |
-
{ S(-23,-4), S( -7,-5), S( 19, 5), S(24, 4) },
|
| 44 |
-
{ S(-22, 3), S(-14, 3), S( 20,-8), S(35,-3) },
|
| 45 |
-
{ S(-11, 8), S( 0, 9), S( 3, 7), S(21,-6) },
|
| 46 |
-
{ S(-11, 8), S(-13,-5), S( -6, 2), S(-2, 4) },
|
| 47 |
-
{ S( -9, 3), S( 15,-9), S( -8, 1), S(-4,18) }
|
| 48 |
-
},
|
| 49 |
-
{ // Knight
|
| 50 |
-
{ S(-143, -97), S(-96,-82), S(-80,-46), S(-73,-14) },
|
| 51 |
-
{ S( -83, -69), S(-43,-55), S(-21,-17), S(-10, 9) },
|
| 52 |
-
{ S( -71, -50), S(-22,-39), S( 0, -8), S( 9, 28) },
|
| 53 |
-
{ S( -25, -41), S( 18,-25), S( 43, 7), S( 47, 38) },
|
| 54 |
-
{ S( -26, -46), S( 16,-25), S( 38, 2), S( 50, 41) },
|
| 55 |
-
{ S( -11, -55), S( 37,-38), S( 56, -8), S( 71, 27) },
|
| 56 |
-
{ S( -62, -64), S(-17,-50), S( 5,-24), S( 14, 13) },
|
| 57 |
-
{ S(-195,-110), S(-66,-90), S(-42,-50), S(-29,-13) }
|
| 58 |
-
},
|
| 59 |
-
{ // Bishop
|
| 60 |
-
{ S(-54,-68), S(-23,-40), S(-35,-46), S(-44,-28) },
|
| 61 |
-
{ S(-30,-43), S( 10,-17), S( 2,-23), S( -9, -5) },
|
| 62 |
-
{ S(-19,-32), S( 17, -9), S( 11,-13), S( 1, 8) },
|
| 63 |
-
{ S(-21,-36), S( 18,-13), S( 11,-15), S( 0, 7) },
|
| 64 |
-
{ S(-21,-36), S( 14,-14), S( 6,-17), S( -1, 3) },
|
| 65 |
-
{ S(-27,-35), S( 6,-13), S( 2,-10), S( -8, 1) },
|
| 66 |
-
{ S(-33,-44), S( 7,-21), S( -4,-22), S(-12, -4) },
|
| 67 |
-
{ S(-45,-65), S(-21,-42), S(-29,-46), S(-39,-27) }
|
| 68 |
-
},
|
| 69 |
-
{ // Rook
|
| 70 |
-
{ S(-25, 0), S(-16, 0), S(-16, 0), S(-9, 0) },
|
| 71 |
-
{ S(-21, 0), S( -8, 0), S( -3, 0), S( 0, 0) },
|
| 72 |
-
{ S(-21, 0), S( -9, 0), S( -4, 0), S( 2, 0) },
|
| 73 |
-
{ S(-22, 0), S( -6, 0), S( -1, 0), S( 2, 0) },
|
| 74 |
-
{ S(-22, 0), S( -7, 0), S( 0, 0), S( 1, 0) },
|
| 75 |
-
{ S(-21, 0), S( -7, 0), S( 0, 0), S( 2, 0) },
|
| 76 |
-
{ S(-12, 0), S( 4, 0), S( 8, 0), S(12, 0) },
|
| 77 |
-
{ S(-23, 0), S(-15, 0), S(-11, 0), S(-5, 0) }
|
| 78 |
-
},
|
| 79 |
-
{ // Queen
|
| 80 |
-
{ S( 0,-70), S(-3,-57), S(-4,-41), S(-1,-29) },
|
| 81 |
-
{ S(-4,-58), S( 6,-30), S( 9,-21), S( 8, -4) },
|
| 82 |
-
{ S(-2,-39), S( 6,-17), S( 9, -7), S( 9, 5) },
|
| 83 |
-
{ S(-1,-29), S( 8, -5), S(10, 9), S( 7, 17) },
|
| 84 |
-
{ S(-3,-27), S( 9, -5), S( 8, 10), S( 7, 23) },
|
| 85 |
-
{ S(-2,-40), S( 6,-16), S( 8,-11), S(10, 3) },
|
| 86 |
-
{ S(-2,-54), S( 7,-30), S( 7,-21), S( 6, -7) },
|
| 87 |
-
{ S(-1,-75), S(-4,-54), S(-1,-44), S( 0,-30) }
|
| 88 |
-
},
|
| 89 |
-
{ // King
|
| 90 |
-
{ S(291, 28), S(344, 76), S(294,103), S(219,112) },
|
| 91 |
-
{ S(289, 70), S(329,119), S(263,170), S(205,159) },
|
| 92 |
-
{ S(226,109), S(271,164), S(202,195), S(136,191) },
|
| 93 |
-
{ S(204,131), S(212,194), S(175,194), S(137,204) },
|
| 94 |
-
{ S(177,132), S(205,187), S(143,224), S( 94,227) },
|
| 95 |
-
{ S(147,118), S(188,178), S(113,199), S( 70,197) },
|
| 96 |
-
{ S(116, 72), S(158,121), S( 93,142), S( 48,161) },
|
| 97 |
-
{ S( 94, 30), S(120, 76), S( 78,101), S( 31,111) }
|
| 98 |
-
}
|
| 99 |
-
};
|
| 100 |
-
|
| 101 |
-
#undef S
|
| 102 |
-
|
| 103 |
-
Score psq[PIECE_NB][SQUARE_NB];
|
| 104 |
-
|
| 105 |
-
// init() initializes piece-square tables: the white halves of the tables are
|
| 106 |
-
// copied from Bonus[] adding the piece value, then the black halves of the
|
| 107 |
-
// tables are initialized by flipping and changing the sign of the white scores.
|
| 108 |
-
void init() {
|
| 109 |
-
|
| 110 |
-
for (Piece pc = W_PAWN; pc <= W_KING; ++pc)
|
| 111 |
-
{
|
| 112 |
-
PieceValue[MG][~pc] = PieceValue[MG][pc];
|
| 113 |
-
PieceValue[EG][~pc] = PieceValue[EG][pc];
|
| 114 |
-
|
| 115 |
-
Score v = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
|
| 116 |
-
|
| 117 |
-
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
| 118 |
-
{
|
| 119 |
-
File f = std::min(file_of(s), FILE_H - file_of(s));
|
| 120 |
-
psq[ pc][ s] = v + Bonus[pc][rank_of(s)][f];
|
| 121 |
-
psq[~pc][~s] = -psq[pc][s];
|
| 122 |
-
}
|
| 123 |
-
}
|
| 124 |
-
}
|
| 125 |
-
|
| 126 |
-
} // namespace PSQT
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/search.cpp
DELETED
|
@@ -1,1656 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm>
|
| 22 |
-
#include <cassert>
|
| 23 |
-
#include <cmath>
|
| 24 |
-
#include <cstring> // For std::memset
|
| 25 |
-
#include <iostream>
|
| 26 |
-
#include <sstream>
|
| 27 |
-
|
| 28 |
-
#include "evaluate.h"
|
| 29 |
-
#include "misc.h"
|
| 30 |
-
#include "movegen.h"
|
| 31 |
-
#include "movepick.h"
|
| 32 |
-
#include "position.h"
|
| 33 |
-
#include "search.h"
|
| 34 |
-
#include "timeman.h"
|
| 35 |
-
#include "thread.h"
|
| 36 |
-
#include "tt.h"
|
| 37 |
-
#include "uci.h"
|
| 38 |
-
#include "syzygy/tbprobe.h"
|
| 39 |
-
|
| 40 |
-
namespace Search {
|
| 41 |
-
|
| 42 |
-
SignalsType Signals;
|
| 43 |
-
LimitsType Limits;
|
| 44 |
-
}
|
| 45 |
-
|
| 46 |
-
namespace Tablebases {
|
| 47 |
-
|
| 48 |
-
int Cardinality;
|
| 49 |
-
bool RootInTB;
|
| 50 |
-
bool UseRule50;
|
| 51 |
-
Depth ProbeDepth;
|
| 52 |
-
Value Score;
|
| 53 |
-
}
|
| 54 |
-
|
| 55 |
-
namespace TB = Tablebases;
|
| 56 |
-
|
| 57 |
-
using std::string;
|
| 58 |
-
using Eval::evaluate;
|
| 59 |
-
using namespace Search;
|
| 60 |
-
|
| 61 |
-
namespace {
|
| 62 |
-
|
| 63 |
-
// Different node types, used as a template parameter
|
| 64 |
-
enum NodeType { NonPV, PV };
|
| 65 |
-
|
| 66 |
-
// Razoring and futility margin based on depth
|
| 67 |
-
const int razor_margin[4] = { 483, 570, 603, 554 };
|
| 68 |
-
Value futility_margin(Depth d) { return Value(150 * d / ONE_PLY); }
|
| 69 |
-
|
| 70 |
-
// Futility and reductions lookup tables, initialized at startup
|
| 71 |
-
int FutilityMoveCounts[2][16]; // [improving][depth]
|
| 72 |
-
int Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber]
|
| 73 |
-
|
| 74 |
-
template <bool PvNode> Depth reduction(bool i, Depth d, int mn) {
|
| 75 |
-
return Reductions[PvNode][i][std::min(d / ONE_PLY, 63)][std::min(mn, 63)] * ONE_PLY;
|
| 76 |
-
}
|
| 77 |
-
|
| 78 |
-
// Skill structure is used to implement strength limit
|
| 79 |
-
struct Skill {
|
| 80 |
-
Skill(int l) : level(l) {}
|
| 81 |
-
bool enabled() const { return level < 20; }
|
| 82 |
-
bool time_to_pick(Depth depth) const { return depth / ONE_PLY == 1 + level; }
|
| 83 |
-
Move best_move(size_t multiPV) { return best ? best : pick_best(multiPV); }
|
| 84 |
-
Move pick_best(size_t multiPV);
|
| 85 |
-
|
| 86 |
-
int level;
|
| 87 |
-
Move best = MOVE_NONE;
|
| 88 |
-
};
|
| 89 |
-
|
| 90 |
-
// EasyMoveManager structure is used to detect an 'easy move'. When the PV is
|
| 91 |
-
// stable across multiple search iterations, we can quickly return the best move.
|
| 92 |
-
struct EasyMoveManager {
|
| 93 |
-
|
| 94 |
-
void clear() {
|
| 95 |
-
stableCnt = 0;
|
| 96 |
-
expectedPosKey = 0;
|
| 97 |
-
pv[0] = pv[1] = pv[2] = MOVE_NONE;
|
| 98 |
-
}
|
| 99 |
-
|
| 100 |
-
Move get(Key key) const {
|
| 101 |
-
return expectedPosKey == key ? pv[2] : MOVE_NONE;
|
| 102 |
-
}
|
| 103 |
-
|
| 104 |
-
void update(Position& pos, const std::vector<Move>& newPv) {
|
| 105 |
-
|
| 106 |
-
assert(newPv.size() >= 3);
|
| 107 |
-
|
| 108 |
-
// Keep track of how many times in a row the 3rd ply remains stable
|
| 109 |
-
stableCnt = (newPv[2] == pv[2]) ? stableCnt + 1 : 0;
|
| 110 |
-
|
| 111 |
-
if (!std::equal(newPv.begin(), newPv.begin() + 3, pv))
|
| 112 |
-
{
|
| 113 |
-
std::copy(newPv.begin(), newPv.begin() + 3, pv);
|
| 114 |
-
|
| 115 |
-
StateInfo st[2];
|
| 116 |
-
pos.do_move(newPv[0], st[0], pos.gives_check(newPv[0]));
|
| 117 |
-
pos.do_move(newPv[1], st[1], pos.gives_check(newPv[1]));
|
| 118 |
-
expectedPosKey = pos.key();
|
| 119 |
-
pos.undo_move(newPv[1]);
|
| 120 |
-
pos.undo_move(newPv[0]);
|
| 121 |
-
}
|
| 122 |
-
}
|
| 123 |
-
|
| 124 |
-
int stableCnt;
|
| 125 |
-
Key expectedPosKey;
|
| 126 |
-
Move pv[3];
|
| 127 |
-
};
|
| 128 |
-
|
| 129 |
-
// Set of rows with half bits set to 1 and half to 0. It is used to allocate
|
| 130 |
-
// the search depths across the threads.
|
| 131 |
-
typedef std::vector<int> Row;
|
| 132 |
-
|
| 133 |
-
const Row HalfDensity[] = {
|
| 134 |
-
{0, 1},
|
| 135 |
-
{1, 0},
|
| 136 |
-
{0, 0, 1, 1},
|
| 137 |
-
{0, 1, 1, 0},
|
| 138 |
-
{1, 1, 0, 0},
|
| 139 |
-
{1, 0, 0, 1},
|
| 140 |
-
{0, 0, 0, 1, 1, 1},
|
| 141 |
-
{0, 0, 1, 1, 1, 0},
|
| 142 |
-
{0, 1, 1, 1, 0, 0},
|
| 143 |
-
{1, 1, 1, 0, 0, 0},
|
| 144 |
-
{1, 1, 0, 0, 0, 1},
|
| 145 |
-
{1, 0, 0, 0, 1, 1},
|
| 146 |
-
{0, 0, 0, 0, 1, 1, 1, 1},
|
| 147 |
-
{0, 0, 0, 1, 1, 1, 1, 0},
|
| 148 |
-
{0, 0, 1, 1, 1, 1, 0 ,0},
|
| 149 |
-
{0, 1, 1, 1, 1, 0, 0 ,0},
|
| 150 |
-
{1, 1, 1, 1, 0, 0, 0 ,0},
|
| 151 |
-
{1, 1, 1, 0, 0, 0, 0 ,1},
|
| 152 |
-
{1, 1, 0, 0, 0, 0, 1 ,1},
|
| 153 |
-
{1, 0, 0, 0, 0, 1, 1 ,1},
|
| 154 |
-
};
|
| 155 |
-
|
| 156 |
-
const size_t HalfDensitySize = std::extent<decltype(HalfDensity)>::value;
|
| 157 |
-
|
| 158 |
-
EasyMoveManager EasyMove;
|
| 159 |
-
Value DrawValue[COLOR_NB];
|
| 160 |
-
|
| 161 |
-
template <NodeType NT>
|
| 162 |
-
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
|
| 163 |
-
|
| 164 |
-
template <NodeType NT, bool InCheck>
|
| 165 |
-
Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth);
|
| 166 |
-
|
| 167 |
-
Value value_to_tt(Value v, int ply);
|
| 168 |
-
Value value_from_tt(Value v, int ply);
|
| 169 |
-
void update_pv(Move* pv, Move move, Move* childPv);
|
| 170 |
-
void update_cm_stats(Stack* ss, Piece pc, Square s, Value bonus);
|
| 171 |
-
void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, Value bonus);
|
| 172 |
-
void check_time();
|
| 173 |
-
|
| 174 |
-
} // namespace
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
/// Search::init() is called during startup to initialize various lookup tables
|
| 178 |
-
|
| 179 |
-
void Search::init() {
|
| 180 |
-
|
| 181 |
-
for (int imp = 0; imp <= 1; ++imp)
|
| 182 |
-
for (int d = 1; d < 64; ++d)
|
| 183 |
-
for (int mc = 1; mc < 64; ++mc)
|
| 184 |
-
{
|
| 185 |
-
double r = log(d) * log(mc) / 2;
|
| 186 |
-
if (r < 0.80)
|
| 187 |
-
continue;
|
| 188 |
-
|
| 189 |
-
Reductions[NonPV][imp][d][mc] = int(std::round(r));
|
| 190 |
-
Reductions[PV][imp][d][mc] = std::max(Reductions[NonPV][imp][d][mc] - 1, 0);
|
| 191 |
-
|
| 192 |
-
// Increase reduction for non-PV nodes when eval is not improving
|
| 193 |
-
if (!imp && Reductions[NonPV][imp][d][mc] >= 2)
|
| 194 |
-
Reductions[NonPV][imp][d][mc]++;
|
| 195 |
-
}
|
| 196 |
-
|
| 197 |
-
for (int d = 0; d < 16; ++d)
|
| 198 |
-
{
|
| 199 |
-
FutilityMoveCounts[0][d] = int(2.4 + 0.773 * pow(d + 0.00, 1.8));
|
| 200 |
-
FutilityMoveCounts[1][d] = int(2.9 + 1.045 * pow(d + 0.49, 1.8));
|
| 201 |
-
}
|
| 202 |
-
}
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
/// Search::clear() resets search state to zero, to obtain reproducible results
|
| 206 |
-
|
| 207 |
-
void Search::clear() {
|
| 208 |
-
|
| 209 |
-
TT.clear();
|
| 210 |
-
|
| 211 |
-
for (Thread* th : Threads)
|
| 212 |
-
{
|
| 213 |
-
th->history.clear();
|
| 214 |
-
th->counterMoves.clear();
|
| 215 |
-
th->fromTo.clear();
|
| 216 |
-
th->counterMoveHistory.clear();
|
| 217 |
-
}
|
| 218 |
-
|
| 219 |
-
Threads.main()->previousScore = VALUE_INFINITE;
|
| 220 |
-
}
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
/// Search::perft() is our utility to verify move generation. All the leaf nodes
|
| 224 |
-
/// up to the given depth are generated and counted, and the sum is returned.
|
| 225 |
-
template<bool Root>
|
| 226 |
-
uint64_t Search::perft(Position& pos, Depth depth) {
|
| 227 |
-
|
| 228 |
-
StateInfo st;
|
| 229 |
-
uint64_t cnt, nodes = 0;
|
| 230 |
-
const bool leaf = (depth == 2 * ONE_PLY);
|
| 231 |
-
|
| 232 |
-
for (const auto& m : MoveList<LEGAL>(pos))
|
| 233 |
-
{
|
| 234 |
-
if (Root && depth <= ONE_PLY)
|
| 235 |
-
cnt = 1, nodes++;
|
| 236 |
-
else
|
| 237 |
-
{
|
| 238 |
-
pos.do_move(m, st, pos.gives_check(m));
|
| 239 |
-
cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - ONE_PLY);
|
| 240 |
-
nodes += cnt;
|
| 241 |
-
pos.undo_move(m);
|
| 242 |
-
}
|
| 243 |
-
if (Root)
|
| 244 |
-
sync_cout << UCI::move(m, pos.is_chess960()) << ": " << cnt << sync_endl;
|
| 245 |
-
}
|
| 246 |
-
return nodes;
|
| 247 |
-
}
|
| 248 |
-
|
| 249 |
-
template uint64_t Search::perft<true>(Position&, Depth);
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
/// MainThread::search() is called by the main thread when the program receives
|
| 253 |
-
/// the UCI 'go' command. It searches from the root position and outputs the "bestmove".
|
| 254 |
-
|
| 255 |
-
void MainThread::search() {
|
| 256 |
-
|
| 257 |
-
Color us = rootPos.side_to_move();
|
| 258 |
-
Time.init(Limits, us, rootPos.game_ply());
|
| 259 |
-
|
| 260 |
-
int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
|
| 261 |
-
DrawValue[ us] = VALUE_DRAW - Value(contempt);
|
| 262 |
-
DrawValue[~us] = VALUE_DRAW + Value(contempt);
|
| 263 |
-
|
| 264 |
-
if (rootMoves.empty())
|
| 265 |
-
{
|
| 266 |
-
rootMoves.push_back(RootMove(MOVE_NONE));
|
| 267 |
-
sync_cout << "info depth 0 score "
|
| 268 |
-
<< UCI::value(rootPos.checkers() ? -VALUE_MATE : VALUE_DRAW)
|
| 269 |
-
<< sync_endl;
|
| 270 |
-
}
|
| 271 |
-
else
|
| 272 |
-
{
|
| 273 |
-
for (Thread* th : Threads)
|
| 274 |
-
if (th != this)
|
| 275 |
-
th->start_searching();
|
| 276 |
-
|
| 277 |
-
Thread::search(); // Let's start searching!
|
| 278 |
-
}
|
| 279 |
-
|
| 280 |
-
// When playing in 'nodes as time' mode, subtract the searched nodes from
|
| 281 |
-
// the available ones before exiting.
|
| 282 |
-
if (Limits.npmsec)
|
| 283 |
-
Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
|
| 284 |
-
|
| 285 |
-
// When we reach the maximum depth, we can arrive here without a raise of
|
| 286 |
-
// Signals.stop. However, if we are pondering or in an infinite search,
|
| 287 |
-
// the UCI protocol states that we shouldn't print the best move before the
|
| 288 |
-
// GUI sends a "stop" or "ponderhit" command. We therefore simply wait here
|
| 289 |
-
// until the GUI sends one of those commands (which also raises Signals.stop).
|
| 290 |
-
if (!Signals.stop && (Limits.ponder || Limits.infinite))
|
| 291 |
-
{
|
| 292 |
-
Signals.stopOnPonderhit = true;
|
| 293 |
-
wait(Signals.stop);
|
| 294 |
-
}
|
| 295 |
-
|
| 296 |
-
// Stop the threads if not already stopped
|
| 297 |
-
Signals.stop = true;
|
| 298 |
-
|
| 299 |
-
// Wait until all threads have finished
|
| 300 |
-
for (Thread* th : Threads)
|
| 301 |
-
if (th != this)
|
| 302 |
-
th->wait_for_search_finished();
|
| 303 |
-
|
| 304 |
-
// Check if there are threads with a better score than main thread
|
| 305 |
-
Thread* bestThread = this;
|
| 306 |
-
if ( !this->easyMovePlayed
|
| 307 |
-
&& Options["MultiPV"] == 1
|
| 308 |
-
&& !Limits.depth
|
| 309 |
-
&& !Skill(Options["Skill Level"]).enabled()
|
| 310 |
-
&& rootMoves[0].pv[0] != MOVE_NONE)
|
| 311 |
-
{
|
| 312 |
-
for (Thread* th : Threads)
|
| 313 |
-
if ( th->completedDepth > bestThread->completedDepth
|
| 314 |
-
&& th->rootMoves[0].score > bestThread->rootMoves[0].score)
|
| 315 |
-
bestThread = th;
|
| 316 |
-
}
|
| 317 |
-
|
| 318 |
-
previousScore = bestThread->rootMoves[0].score;
|
| 319 |
-
|
| 320 |
-
// Send new PV when needed
|
| 321 |
-
if (bestThread != this)
|
| 322 |
-
sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE) << sync_endl;
|
| 323 |
-
|
| 324 |
-
sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960());
|
| 325 |
-
|
| 326 |
-
if (bestThread->rootMoves[0].pv.size() > 1 || bestThread->rootMoves[0].extract_ponder_from_tt(rootPos))
|
| 327 |
-
std::cout << " ponder " << UCI::move(bestThread->rootMoves[0].pv[1], rootPos.is_chess960());
|
| 328 |
-
|
| 329 |
-
std::cout << sync_endl;
|
| 330 |
-
}
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
// Thread::search() is the main iterative deepening loop. It calls search()
|
| 334 |
-
// repeatedly with increasing depth until the allocated thinking time has been
|
| 335 |
-
// consumed, the user stops the search, or the maximum search depth is reached.
|
| 336 |
-
|
| 337 |
-
void Thread::search() {
|
| 338 |
-
|
| 339 |
-
Stack stack[MAX_PLY+7], *ss = stack+5; // To allow referencing (ss-5) and (ss+2)
|
| 340 |
-
Value bestValue, alpha, beta, delta;
|
| 341 |
-
Move easyMove = MOVE_NONE;
|
| 342 |
-
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
|
| 343 |
-
|
| 344 |
-
std::memset(ss-5, 0, 8 * sizeof(Stack));
|
| 345 |
-
|
| 346 |
-
bestValue = delta = alpha = -VALUE_INFINITE;
|
| 347 |
-
beta = VALUE_INFINITE;
|
| 348 |
-
completedDepth = DEPTH_ZERO;
|
| 349 |
-
|
| 350 |
-
if (mainThread)
|
| 351 |
-
{
|
| 352 |
-
easyMove = EasyMove.get(rootPos.key());
|
| 353 |
-
EasyMove.clear();
|
| 354 |
-
mainThread->easyMovePlayed = mainThread->failedLow = false;
|
| 355 |
-
mainThread->bestMoveChanges = 0;
|
| 356 |
-
TT.new_search();
|
| 357 |
-
}
|
| 358 |
-
|
| 359 |
-
size_t multiPV = Options["MultiPV"];
|
| 360 |
-
Skill skill(Options["Skill Level"]);
|
| 361 |
-
|
| 362 |
-
// When playing with strength handicap enable MultiPV search that we will
|
| 363 |
-
// use behind the scenes to retrieve a set of possible moves.
|
| 364 |
-
if (skill.enabled())
|
| 365 |
-
multiPV = std::max(multiPV, (size_t)4);
|
| 366 |
-
|
| 367 |
-
multiPV = std::min(multiPV, rootMoves.size());
|
| 368 |
-
|
| 369 |
-
// Iterative deepening loop until requested to stop or the target depth is reached
|
| 370 |
-
while ( (rootDepth += ONE_PLY) < DEPTH_MAX
|
| 371 |
-
&& !Signals.stop
|
| 372 |
-
&& (!Limits.depth || Threads.main()->rootDepth / ONE_PLY <= Limits.depth))
|
| 373 |
-
{
|
| 374 |
-
// Set up the new depths for the helper threads skipping on average every
|
| 375 |
-
// 2nd ply (using a half-density matrix).
|
| 376 |
-
if (!mainThread)
|
| 377 |
-
{
|
| 378 |
-
const Row& row = HalfDensity[(idx - 1) % HalfDensitySize];
|
| 379 |
-
if (row[(rootDepth / ONE_PLY + rootPos.game_ply()) % row.size()])
|
| 380 |
-
continue;
|
| 381 |
-
}
|
| 382 |
-
|
| 383 |
-
// Age out PV variability metric
|
| 384 |
-
if (mainThread)
|
| 385 |
-
mainThread->bestMoveChanges *= 0.505, mainThread->failedLow = false;
|
| 386 |
-
|
| 387 |
-
// Save the last iteration's scores before first PV line is searched and
|
| 388 |
-
// all the move scores except the (new) PV are set to -VALUE_INFINITE.
|
| 389 |
-
for (RootMove& rm : rootMoves)
|
| 390 |
-
rm.previousScore = rm.score;
|
| 391 |
-
|
| 392 |
-
// MultiPV loop. We perform a full root search for each PV line
|
| 393 |
-
for (PVIdx = 0; PVIdx < multiPV && !Signals.stop; ++PVIdx)
|
| 394 |
-
{
|
| 395 |
-
// Reset aspiration window starting size
|
| 396 |
-
if (rootDepth >= 5 * ONE_PLY)
|
| 397 |
-
{
|
| 398 |
-
delta = Value(18);
|
| 399 |
-
alpha = std::max(rootMoves[PVIdx].previousScore - delta,-VALUE_INFINITE);
|
| 400 |
-
beta = std::min(rootMoves[PVIdx].previousScore + delta, VALUE_INFINITE);
|
| 401 |
-
}
|
| 402 |
-
|
| 403 |
-
// Start with a small aspiration window and, in the case of a fail
|
| 404 |
-
// high/low, re-search with a bigger window until we're not failing
|
| 405 |
-
// high/low anymore.
|
| 406 |
-
while (true)
|
| 407 |
-
{
|
| 408 |
-
bestValue = ::search<PV>(rootPos, ss, alpha, beta, rootDepth, false);
|
| 409 |
-
|
| 410 |
-
// Bring the best move to the front. It is critical that sorting
|
| 411 |
-
// is done with a stable algorithm because all the values but the
|
| 412 |
-
// first and eventually the new best one are set to -VALUE_INFINITE
|
| 413 |
-
// and we want to keep the same order for all the moves except the
|
| 414 |
-
// new PV that goes to the front. Note that in case of MultiPV
|
| 415 |
-
// search the already searched PV lines are preserved.
|
| 416 |
-
std::stable_sort(rootMoves.begin() + PVIdx, rootMoves.end());
|
| 417 |
-
|
| 418 |
-
// If search has been stopped, break immediately. Sorting and
|
| 419 |
-
// writing PV back to TT is safe because RootMoves is still
|
| 420 |
-
// valid, although it refers to the previous iteration.
|
| 421 |
-
if (Signals.stop)
|
| 422 |
-
break;
|
| 423 |
-
|
| 424 |
-
// When failing high/low give some update (without cluttering
|
| 425 |
-
// the UI) before a re-search.
|
| 426 |
-
if ( mainThread
|
| 427 |
-
&& multiPV == 1
|
| 428 |
-
&& (bestValue <= alpha || bestValue >= beta)
|
| 429 |
-
&& Time.elapsed() > 3000)
|
| 430 |
-
sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
|
| 431 |
-
|
| 432 |
-
// In case of failing low/high increase aspiration window and
|
| 433 |
-
// re-search, otherwise exit the loop.
|
| 434 |
-
if (bestValue <= alpha)
|
| 435 |
-
{
|
| 436 |
-
beta = (alpha + beta) / 2;
|
| 437 |
-
alpha = std::max(bestValue - delta, -VALUE_INFINITE);
|
| 438 |
-
|
| 439 |
-
if (mainThread)
|
| 440 |
-
{
|
| 441 |
-
mainThread->failedLow = true;
|
| 442 |
-
Signals.stopOnPonderhit = false;
|
| 443 |
-
}
|
| 444 |
-
}
|
| 445 |
-
else if (bestValue >= beta)
|
| 446 |
-
{
|
| 447 |
-
alpha = (alpha + beta) / 2;
|
| 448 |
-
beta = std::min(bestValue + delta, VALUE_INFINITE);
|
| 449 |
-
}
|
| 450 |
-
else
|
| 451 |
-
break;
|
| 452 |
-
|
| 453 |
-
delta += delta / 4 + 5;
|
| 454 |
-
|
| 455 |
-
assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
|
| 456 |
-
}
|
| 457 |
-
|
| 458 |
-
// Sort the PV lines searched so far and update the GUI
|
| 459 |
-
std::stable_sort(rootMoves.begin(), rootMoves.begin() + PVIdx + 1);
|
| 460 |
-
|
| 461 |
-
if (!mainThread)
|
| 462 |
-
continue;
|
| 463 |
-
|
| 464 |
-
if (Signals.stop || PVIdx + 1 == multiPV || Time.elapsed() > 3000)
|
| 465 |
-
sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
|
| 466 |
-
}
|
| 467 |
-
|
| 468 |
-
if (!Signals.stop)
|
| 469 |
-
completedDepth = rootDepth;
|
| 470 |
-
|
| 471 |
-
if (!mainThread)
|
| 472 |
-
continue;
|
| 473 |
-
|
| 474 |
-
// If skill level is enabled and time is up, pick a sub-optimal best move
|
| 475 |
-
if (skill.enabled() && skill.time_to_pick(rootDepth))
|
| 476 |
-
skill.pick_best(multiPV);
|
| 477 |
-
|
| 478 |
-
// Have we found a "mate in x"?
|
| 479 |
-
if ( Limits.mate
|
| 480 |
-
&& bestValue >= VALUE_MATE_IN_MAX_PLY
|
| 481 |
-
&& VALUE_MATE - bestValue <= 2 * Limits.mate)
|
| 482 |
-
Signals.stop = true;
|
| 483 |
-
|
| 484 |
-
// Do we have time for the next iteration? Can we stop searching now?
|
| 485 |
-
if (Limits.use_time_management())
|
| 486 |
-
{
|
| 487 |
-
if (!Signals.stop && !Signals.stopOnPonderhit)
|
| 488 |
-
{
|
| 489 |
-
// Stop the search if only one legal move is available, or if all
|
| 490 |
-
// of the available time has been used, or if we matched an easyMove
|
| 491 |
-
// from the previous search and just did a fast verification.
|
| 492 |
-
const int F[] = { mainThread->failedLow,
|
| 493 |
-
bestValue - mainThread->previousScore };
|
| 494 |
-
|
| 495 |
-
int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1]));
|
| 496 |
-
double unstablePvFactor = 1 + mainThread->bestMoveChanges;
|
| 497 |
-
|
| 498 |
-
bool doEasyMove = rootMoves[0].pv[0] == easyMove
|
| 499 |
-
&& mainThread->bestMoveChanges < 0.03
|
| 500 |
-
&& Time.elapsed() > Time.optimum() * 5 / 42;
|
| 501 |
-
|
| 502 |
-
if ( rootMoves.size() == 1
|
| 503 |
-
|| Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628
|
| 504 |
-
|| (mainThread->easyMovePlayed = doEasyMove, doEasyMove))
|
| 505 |
-
{
|
| 506 |
-
// If we are allowed to ponder do not stop the search now but
|
| 507 |
-
// keep pondering until the GUI sends "ponderhit" or "stop".
|
| 508 |
-
if (Limits.ponder)
|
| 509 |
-
Signals.stopOnPonderhit = true;
|
| 510 |
-
else
|
| 511 |
-
Signals.stop = true;
|
| 512 |
-
}
|
| 513 |
-
}
|
| 514 |
-
|
| 515 |
-
if (rootMoves[0].pv.size() >= 3)
|
| 516 |
-
EasyMove.update(rootPos, rootMoves[0].pv);
|
| 517 |
-
else
|
| 518 |
-
EasyMove.clear();
|
| 519 |
-
}
|
| 520 |
-
}
|
| 521 |
-
|
| 522 |
-
if (!mainThread)
|
| 523 |
-
return;
|
| 524 |
-
|
| 525 |
-
// Clear any candidate easy move that wasn't stable for the last search
|
| 526 |
-
// iterations; the second condition prevents consecutive fast moves.
|
| 527 |
-
if (EasyMove.stableCnt < 6 || mainThread->easyMovePlayed)
|
| 528 |
-
EasyMove.clear();
|
| 529 |
-
|
| 530 |
-
// If skill level is enabled, swap best PV line with the sub-optimal one
|
| 531 |
-
if (skill.enabled())
|
| 532 |
-
std::swap(rootMoves[0], *std::find(rootMoves.begin(),
|
| 533 |
-
rootMoves.end(), skill.best_move(multiPV)));
|
| 534 |
-
}
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
namespace {
|
| 538 |
-
|
| 539 |
-
// search<>() is the main search function for both PV and non-PV nodes
|
| 540 |
-
|
| 541 |
-
template <NodeType NT>
|
| 542 |
-
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode) {
|
| 543 |
-
|
| 544 |
-
const bool PvNode = NT == PV;
|
| 545 |
-
const bool rootNode = PvNode && (ss-1)->ply == 0;
|
| 546 |
-
|
| 547 |
-
assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE);
|
| 548 |
-
assert(PvNode || (alpha == beta - 1));
|
| 549 |
-
assert(DEPTH_ZERO < depth && depth < DEPTH_MAX);
|
| 550 |
-
assert(!(PvNode && cutNode));
|
| 551 |
-
assert(depth / ONE_PLY * ONE_PLY == depth);
|
| 552 |
-
|
| 553 |
-
Move pv[MAX_PLY+1], quietsSearched[64];
|
| 554 |
-
StateInfo st;
|
| 555 |
-
TTEntry* tte;
|
| 556 |
-
Key posKey;
|
| 557 |
-
Move ttMove, move, excludedMove, bestMove;
|
| 558 |
-
Depth extension, newDepth;
|
| 559 |
-
Value bestValue, value, ttValue, eval, nullValue;
|
| 560 |
-
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
|
| 561 |
-
bool captureOrPromotion, doFullDepthSearch, moveCountPruning;
|
| 562 |
-
Piece moved_piece;
|
| 563 |
-
int moveCount, quietCount;
|
| 564 |
-
|
| 565 |
-
// Step 1. Initialize node
|
| 566 |
-
Thread* thisThread = pos.this_thread();
|
| 567 |
-
inCheck = pos.checkers();
|
| 568 |
-
moveCount = quietCount = ss->moveCount = 0;
|
| 569 |
-
ss->history = VALUE_ZERO;
|
| 570 |
-
bestValue = -VALUE_INFINITE;
|
| 571 |
-
ss->ply = (ss-1)->ply + 1;
|
| 572 |
-
|
| 573 |
-
// Check for the available remaining time
|
| 574 |
-
if (thisThread->resetCalls.load(std::memory_order_relaxed))
|
| 575 |
-
{
|
| 576 |
-
thisThread->resetCalls = false;
|
| 577 |
-
thisThread->callsCnt = 0;
|
| 578 |
-
}
|
| 579 |
-
if (++thisThread->callsCnt > 4096)
|
| 580 |
-
{
|
| 581 |
-
for (Thread* th : Threads)
|
| 582 |
-
th->resetCalls = true;
|
| 583 |
-
|
| 584 |
-
check_time();
|
| 585 |
-
}
|
| 586 |
-
|
| 587 |
-
// Used to send selDepth info to GUI
|
| 588 |
-
if (PvNode && thisThread->maxPly < ss->ply)
|
| 589 |
-
thisThread->maxPly = ss->ply;
|
| 590 |
-
|
| 591 |
-
if (!rootNode)
|
| 592 |
-
{
|
| 593 |
-
// Step 2. Check for aborted search and immediate draw
|
| 594 |
-
if (Signals.stop.load(std::memory_order_relaxed) || pos.is_draw() || ss->ply >= MAX_PLY)
|
| 595 |
-
return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos)
|
| 596 |
-
: DrawValue[pos.side_to_move()];
|
| 597 |
-
|
| 598 |
-
// Step 3. Mate distance pruning. Even if we mate at the next move our score
|
| 599 |
-
// would be at best mate_in(ss->ply+1), but if alpha is already bigger because
|
| 600 |
-
// a shorter mate was found upward in the tree then there is no need to search
|
| 601 |
-
// because we will never beat the current alpha. Same logic but with reversed
|
| 602 |
-
// signs applies also in the opposite condition of being mated instead of giving
|
| 603 |
-
// mate. In this case return a fail-high score.
|
| 604 |
-
alpha = std::max(mated_in(ss->ply), alpha);
|
| 605 |
-
beta = std::min(mate_in(ss->ply+1), beta);
|
| 606 |
-
if (alpha >= beta)
|
| 607 |
-
return alpha;
|
| 608 |
-
}
|
| 609 |
-
|
| 610 |
-
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
| 611 |
-
|
| 612 |
-
ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
|
| 613 |
-
ss->counterMoves = nullptr;
|
| 614 |
-
(ss+1)->skipEarlyPruning = false;
|
| 615 |
-
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
|
| 616 |
-
|
| 617 |
-
// Step 4. Transposition table lookup. We don't want the score of a partial
|
| 618 |
-
// search to overwrite a previous full search TT value, so we use a different
|
| 619 |
-
// position key in case of an excluded move.
|
| 620 |
-
excludedMove = ss->excludedMove;
|
| 621 |
-
posKey = pos.key() ^ Key(excludedMove);
|
| 622 |
-
tte = TT.probe(posKey, ttHit);
|
| 623 |
-
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
|
| 624 |
-
ttMove = rootNode ? thisThread->rootMoves[thisThread->PVIdx].pv[0]
|
| 625 |
-
: ttHit ? tte->move() : MOVE_NONE;
|
| 626 |
-
|
| 627 |
-
// At non-PV nodes we check for an early TT cutoff
|
| 628 |
-
if ( !PvNode
|
| 629 |
-
&& ttHit
|
| 630 |
-
&& tte->depth() >= depth
|
| 631 |
-
&& ttValue != VALUE_NONE // Possible in case of TT access race
|
| 632 |
-
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
|
| 633 |
-
: (tte->bound() & BOUND_UPPER)))
|
| 634 |
-
{
|
| 635 |
-
// If ttMove is quiet, update killers, history, counter move on TT hit
|
| 636 |
-
if (ttValue >= beta && ttMove)
|
| 637 |
-
{
|
| 638 |
-
int d = depth / ONE_PLY;
|
| 639 |
-
|
| 640 |
-
if (!pos.capture_or_promotion(ttMove))
|
| 641 |
-
{
|
| 642 |
-
Value bonus = Value(d * d + 2 * d - 2);
|
| 643 |
-
update_stats(pos, ss, ttMove, nullptr, 0, bonus);
|
| 644 |
-
}
|
| 645 |
-
|
| 646 |
-
// Extra penalty for a quiet TT move in previous ply when it gets refuted
|
| 647 |
-
if ((ss-1)->moveCount == 1 && !pos.captured_piece())
|
| 648 |
-
{
|
| 649 |
-
Value penalty = Value(d * d + 4 * d + 1);
|
| 650 |
-
Square prevSq = to_sq((ss-1)->currentMove);
|
| 651 |
-
update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, -penalty);
|
| 652 |
-
}
|
| 653 |
-
}
|
| 654 |
-
return ttValue;
|
| 655 |
-
}
|
| 656 |
-
|
| 657 |
-
// Step 4a. Tablebase probe
|
| 658 |
-
if (!rootNode && TB::Cardinality)
|
| 659 |
-
{
|
| 660 |
-
int piecesCnt = pos.count<ALL_PIECES>(WHITE) + pos.count<ALL_PIECES>(BLACK);
|
| 661 |
-
|
| 662 |
-
if ( piecesCnt <= TB::Cardinality
|
| 663 |
-
&& (piecesCnt < TB::Cardinality || depth >= TB::ProbeDepth)
|
| 664 |
-
&& pos.rule50_count() == 0
|
| 665 |
-
&& !pos.can_castle(ANY_CASTLING))
|
| 666 |
-
{
|
| 667 |
-
int found, v = Tablebases::probe_wdl(pos, &found);
|
| 668 |
-
|
| 669 |
-
if (found)
|
| 670 |
-
{
|
| 671 |
-
thisThread->tbHits++;
|
| 672 |
-
|
| 673 |
-
int drawScore = TB::UseRule50 ? 1 : 0;
|
| 674 |
-
|
| 675 |
-
value = v < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply
|
| 676 |
-
: v > drawScore ? VALUE_MATE - MAX_PLY - ss->ply
|
| 677 |
-
: VALUE_DRAW + 2 * v * drawScore;
|
| 678 |
-
|
| 679 |
-
tte->save(posKey, value_to_tt(value, ss->ply), BOUND_EXACT,
|
| 680 |
-
std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY),
|
| 681 |
-
MOVE_NONE, VALUE_NONE, TT.generation());
|
| 682 |
-
|
| 683 |
-
return value;
|
| 684 |
-
}
|
| 685 |
-
}
|
| 686 |
-
}
|
| 687 |
-
|
| 688 |
-
// Step 5. Evaluate the position statically
|
| 689 |
-
if (inCheck)
|
| 690 |
-
{
|
| 691 |
-
ss->staticEval = eval = VALUE_NONE;
|
| 692 |
-
goto moves_loop;
|
| 693 |
-
}
|
| 694 |
-
|
| 695 |
-
else if (ttHit)
|
| 696 |
-
{
|
| 697 |
-
// Never assume anything on values stored in TT
|
| 698 |
-
if ((ss->staticEval = eval = tte->eval()) == VALUE_NONE)
|
| 699 |
-
eval = ss->staticEval = evaluate(pos);
|
| 700 |
-
|
| 701 |
-
// Can ttValue be used as a better position evaluation?
|
| 702 |
-
if (ttValue != VALUE_NONE)
|
| 703 |
-
if (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER))
|
| 704 |
-
eval = ttValue;
|
| 705 |
-
}
|
| 706 |
-
else
|
| 707 |
-
{
|
| 708 |
-
eval = ss->staticEval =
|
| 709 |
-
(ss-1)->currentMove != MOVE_NULL ? evaluate(pos)
|
| 710 |
-
: -(ss-1)->staticEval + 2 * Eval::Tempo;
|
| 711 |
-
|
| 712 |
-
tte->save(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE,
|
| 713 |
-
ss->staticEval, TT.generation());
|
| 714 |
-
}
|
| 715 |
-
|
| 716 |
-
if (ss->skipEarlyPruning)
|
| 717 |
-
goto moves_loop;
|
| 718 |
-
|
| 719 |
-
// Step 6. Razoring (skipped when in check)
|
| 720 |
-
if ( !PvNode
|
| 721 |
-
&& depth < 4 * ONE_PLY
|
| 722 |
-
&& ttMove == MOVE_NONE
|
| 723 |
-
&& eval + razor_margin[depth / ONE_PLY] <= alpha)
|
| 724 |
-
{
|
| 725 |
-
if (depth <= ONE_PLY)
|
| 726 |
-
return qsearch<NonPV, false>(pos, ss, alpha, beta, DEPTH_ZERO);
|
| 727 |
-
|
| 728 |
-
Value ralpha = alpha - razor_margin[depth / ONE_PLY];
|
| 729 |
-
Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1, DEPTH_ZERO);
|
| 730 |
-
if (v <= ralpha)
|
| 731 |
-
return v;
|
| 732 |
-
}
|
| 733 |
-
|
| 734 |
-
// Step 7. Futility pruning: child node (skipped when in check)
|
| 735 |
-
if ( !rootNode
|
| 736 |
-
&& depth < 7 * ONE_PLY
|
| 737 |
-
&& eval - futility_margin(depth) >= beta
|
| 738 |
-
&& eval < VALUE_KNOWN_WIN // Do not return unproven wins
|
| 739 |
-
&& pos.non_pawn_material(pos.side_to_move()))
|
| 740 |
-
return eval;
|
| 741 |
-
|
| 742 |
-
// Step 8. Null move search with verification search (is omitted in PV nodes)
|
| 743 |
-
if ( !PvNode
|
| 744 |
-
&& eval >= beta
|
| 745 |
-
&& (ss->staticEval >= beta - 35 * (depth / ONE_PLY - 6) || depth >= 13 * ONE_PLY)
|
| 746 |
-
&& pos.non_pawn_material(pos.side_to_move()))
|
| 747 |
-
{
|
| 748 |
-
ss->currentMove = MOVE_NULL;
|
| 749 |
-
ss->counterMoves = nullptr;
|
| 750 |
-
|
| 751 |
-
assert(eval - beta >= 0);
|
| 752 |
-
|
| 753 |
-
// Null move dynamic reduction based on depth and value
|
| 754 |
-
Depth R = ((823 + 67 * depth / ONE_PLY) / 256 + std::min((eval - beta) / PawnValueMg, 3)) * ONE_PLY;
|
| 755 |
-
|
| 756 |
-
pos.do_null_move(st);
|
| 757 |
-
(ss+1)->skipEarlyPruning = true;
|
| 758 |
-
nullValue = depth-R < ONE_PLY ? -qsearch<NonPV, false>(pos, ss+1, -beta, -beta+1, DEPTH_ZERO)
|
| 759 |
-
: - search<NonPV>(pos, ss+1, -beta, -beta+1, depth-R, !cutNode);
|
| 760 |
-
(ss+1)->skipEarlyPruning = false;
|
| 761 |
-
pos.undo_null_move();
|
| 762 |
-
|
| 763 |
-
if (nullValue >= beta)
|
| 764 |
-
{
|
| 765 |
-
// Do not return unproven mate scores
|
| 766 |
-
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
|
| 767 |
-
nullValue = beta;
|
| 768 |
-
|
| 769 |
-
if (depth < 12 * ONE_PLY && abs(beta) < VALUE_KNOWN_WIN)
|
| 770 |
-
return nullValue;
|
| 771 |
-
|
| 772 |
-
// Do verification search at high depths
|
| 773 |
-
ss->skipEarlyPruning = true;
|
| 774 |
-
Value v = depth-R < ONE_PLY ? qsearch<NonPV, false>(pos, ss, beta-1, beta, DEPTH_ZERO)
|
| 775 |
-
: search<NonPV>(pos, ss, beta-1, beta, depth-R, false);
|
| 776 |
-
ss->skipEarlyPruning = false;
|
| 777 |
-
|
| 778 |
-
if (v >= beta)
|
| 779 |
-
return nullValue;
|
| 780 |
-
}
|
| 781 |
-
}
|
| 782 |
-
|
| 783 |
-
// Step 9. ProbCut (skipped when in check)
|
| 784 |
-
// If we have a good enough capture and a reduced search returns a value
|
| 785 |
-
// much above beta, we can (almost) safely prune the previous move.
|
| 786 |
-
if ( !PvNode
|
| 787 |
-
&& depth >= 5 * ONE_PLY
|
| 788 |
-
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
|
| 789 |
-
{
|
| 790 |
-
Value rbeta = std::min(beta + 200, VALUE_INFINITE);
|
| 791 |
-
Depth rdepth = depth - 4 * ONE_PLY;
|
| 792 |
-
|
| 793 |
-
assert(rdepth >= ONE_PLY);
|
| 794 |
-
assert((ss-1)->currentMove != MOVE_NONE);
|
| 795 |
-
assert((ss-1)->currentMove != MOVE_NULL);
|
| 796 |
-
|
| 797 |
-
MovePicker mp(pos, ttMove, rbeta - ss->staticEval);
|
| 798 |
-
|
| 799 |
-
while ((move = mp.next_move()) != MOVE_NONE)
|
| 800 |
-
if (pos.legal(move))
|
| 801 |
-
{
|
| 802 |
-
ss->currentMove = move;
|
| 803 |
-
ss->counterMoves = &thisThread->counterMoveHistory[pos.moved_piece(move)][to_sq(move)];
|
| 804 |
-
pos.do_move(move, st, pos.gives_check(move));
|
| 805 |
-
value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth, !cutNode);
|
| 806 |
-
pos.undo_move(move);
|
| 807 |
-
if (value >= rbeta)
|
| 808 |
-
return value;
|
| 809 |
-
}
|
| 810 |
-
}
|
| 811 |
-
|
| 812 |
-
// Step 10. Internal iterative deepening (skipped when in check)
|
| 813 |
-
if ( depth >= 6 * ONE_PLY
|
| 814 |
-
&& !ttMove
|
| 815 |
-
&& (PvNode || ss->staticEval + 256 >= beta))
|
| 816 |
-
{
|
| 817 |
-
Depth d = (3 * depth / (4 * ONE_PLY) - 2) * ONE_PLY;
|
| 818 |
-
ss->skipEarlyPruning = true;
|
| 819 |
-
search<NT>(pos, ss, alpha, beta, d, cutNode);
|
| 820 |
-
ss->skipEarlyPruning = false;
|
| 821 |
-
|
| 822 |
-
tte = TT.probe(posKey, ttHit);
|
| 823 |
-
ttMove = ttHit ? tte->move() : MOVE_NONE;
|
| 824 |
-
}
|
| 825 |
-
|
| 826 |
-
moves_loop: // When in check search starts from here
|
| 827 |
-
|
| 828 |
-
const CounterMoveStats* cmh = (ss-1)->counterMoves;
|
| 829 |
-
const CounterMoveStats* fmh = (ss-2)->counterMoves;
|
| 830 |
-
const CounterMoveStats* fmh2 = (ss-4)->counterMoves;
|
| 831 |
-
|
| 832 |
-
MovePicker mp(pos, ttMove, depth, ss);
|
| 833 |
-
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
|
| 834 |
-
improving = ss->staticEval >= (ss-2)->staticEval
|
| 835 |
-
/* || ss->staticEval == VALUE_NONE Already implicit in the previous condition */
|
| 836 |
-
||(ss-2)->staticEval == VALUE_NONE;
|
| 837 |
-
|
| 838 |
-
singularExtensionNode = !rootNode
|
| 839 |
-
&& depth >= 8 * ONE_PLY
|
| 840 |
-
&& ttMove != MOVE_NONE
|
| 841 |
-
&& ttValue != VALUE_NONE
|
| 842 |
-
&& !excludedMove // Recursive singular search is not allowed
|
| 843 |
-
&& (tte->bound() & BOUND_LOWER)
|
| 844 |
-
&& tte->depth() >= depth - 3 * ONE_PLY;
|
| 845 |
-
|
| 846 |
-
// Step 11. Loop through moves
|
| 847 |
-
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
|
| 848 |
-
while ((move = mp.next_move()) != MOVE_NONE)
|
| 849 |
-
{
|
| 850 |
-
assert(is_ok(move));
|
| 851 |
-
|
| 852 |
-
if (move == excludedMove)
|
| 853 |
-
continue;
|
| 854 |
-
|
| 855 |
-
// At root obey the "searchmoves" option and skip moves not listed in Root
|
| 856 |
-
// Move List. As a consequence any illegal move is also skipped. In MultiPV
|
| 857 |
-
// mode we also skip PV moves which have been already searched.
|
| 858 |
-
if (rootNode && !std::count(thisThread->rootMoves.begin() + thisThread->PVIdx,
|
| 859 |
-
thisThread->rootMoves.end(), move))
|
| 860 |
-
continue;
|
| 861 |
-
|
| 862 |
-
ss->moveCount = ++moveCount;
|
| 863 |
-
|
| 864 |
-
if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000)
|
| 865 |
-
sync_cout << "info depth " << depth / ONE_PLY
|
| 866 |
-
<< " currmove " << UCI::move(move, pos.is_chess960())
|
| 867 |
-
<< " currmovenumber " << moveCount + thisThread->PVIdx << sync_endl;
|
| 868 |
-
|
| 869 |
-
if (PvNode)
|
| 870 |
-
(ss+1)->pv = nullptr;
|
| 871 |
-
|
| 872 |
-
extension = DEPTH_ZERO;
|
| 873 |
-
captureOrPromotion = pos.capture_or_promotion(move);
|
| 874 |
-
moved_piece = pos.moved_piece(move);
|
| 875 |
-
|
| 876 |
-
givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates()
|
| 877 |
-
? pos.check_squares(type_of(pos.piece_on(from_sq(move)))) & to_sq(move)
|
| 878 |
-
: pos.gives_check(move);
|
| 879 |
-
|
| 880 |
-
moveCountPruning = depth < 16 * ONE_PLY
|
| 881 |
-
&& moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY];
|
| 882 |
-
|
| 883 |
-
// Step 12. Extend checks
|
| 884 |
-
if ( givesCheck
|
| 885 |
-
&& !moveCountPruning
|
| 886 |
-
&& pos.see_ge(move, VALUE_ZERO))
|
| 887 |
-
extension = ONE_PLY;
|
| 888 |
-
|
| 889 |
-
// Singular extension search. If all moves but one fail low on a search of
|
| 890 |
-
// (alpha-s, beta-s), and just one fails high on (alpha, beta), then that move
|
| 891 |
-
// is singular and should be extended. To verify this we do a reduced search
|
| 892 |
-
// on all the other moves but the ttMove and if the result is lower than
|
| 893 |
-
// ttValue minus a margin then we extend the ttMove.
|
| 894 |
-
if ( singularExtensionNode
|
| 895 |
-
&& move == ttMove
|
| 896 |
-
&& !extension
|
| 897 |
-
&& pos.legal(move))
|
| 898 |
-
{
|
| 899 |
-
Value rBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE);
|
| 900 |
-
Depth d = (depth / (2 * ONE_PLY)) * ONE_PLY;
|
| 901 |
-
ss->excludedMove = move;
|
| 902 |
-
ss->skipEarlyPruning = true;
|
| 903 |
-
value = search<NonPV>(pos, ss, rBeta - 1, rBeta, d, cutNode);
|
| 904 |
-
ss->skipEarlyPruning = false;
|
| 905 |
-
ss->excludedMove = MOVE_NONE;
|
| 906 |
-
|
| 907 |
-
if (value < rBeta)
|
| 908 |
-
extension = ONE_PLY;
|
| 909 |
-
}
|
| 910 |
-
|
| 911 |
-
// Update the current move (this must be done after singular extension search)
|
| 912 |
-
newDepth = depth - ONE_PLY + extension;
|
| 913 |
-
|
| 914 |
-
// Step 13. Pruning at shallow depth
|
| 915 |
-
if ( !rootNode
|
| 916 |
-
&& bestValue > VALUE_MATED_IN_MAX_PLY)
|
| 917 |
-
{
|
| 918 |
-
if ( !captureOrPromotion
|
| 919 |
-
&& !givesCheck
|
| 920 |
-
&& !pos.advanced_pawn_push(move))
|
| 921 |
-
{
|
| 922 |
-
// Move count based pruning
|
| 923 |
-
if (moveCountPruning)
|
| 924 |
-
continue;
|
| 925 |
-
|
| 926 |
-
// Reduced depth of the next LMR search
|
| 927 |
-
int lmrDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO) / ONE_PLY;
|
| 928 |
-
|
| 929 |
-
// Countermoves based pruning
|
| 930 |
-
if ( lmrDepth < 3
|
| 931 |
-
&& (!cmh || (*cmh )[moved_piece][to_sq(move)] < VALUE_ZERO)
|
| 932 |
-
&& (!fmh || (*fmh )[moved_piece][to_sq(move)] < VALUE_ZERO)
|
| 933 |
-
&& (!fmh2 || (*fmh2)[moved_piece][to_sq(move)] < VALUE_ZERO || (cmh && fmh)))
|
| 934 |
-
continue;
|
| 935 |
-
|
| 936 |
-
// Futility pruning: parent node
|
| 937 |
-
if ( lmrDepth < 7
|
| 938 |
-
&& !inCheck
|
| 939 |
-
&& ss->staticEval + 256 + 200 * lmrDepth <= alpha)
|
| 940 |
-
continue;
|
| 941 |
-
|
| 942 |
-
// Prune moves with negative SEE
|
| 943 |
-
if ( lmrDepth < 8
|
| 944 |
-
&& !pos.see_ge(move, Value(-35 * lmrDepth * lmrDepth)))
|
| 945 |
-
continue;
|
| 946 |
-
}
|
| 947 |
-
else if ( depth < 7 * ONE_PLY
|
| 948 |
-
&& !extension
|
| 949 |
-
&& !pos.see_ge(move, Value(-35 * depth / ONE_PLY * depth / ONE_PLY)))
|
| 950 |
-
continue;
|
| 951 |
-
}
|
| 952 |
-
|
| 953 |
-
// Speculative prefetch as early as possible
|
| 954 |
-
prefetch(TT.first_entry(pos.key_after(move)));
|
| 955 |
-
|
| 956 |
-
// Check for legality just before making the move
|
| 957 |
-
if (!rootNode && !pos.legal(move))
|
| 958 |
-
{
|
| 959 |
-
ss->moveCount = --moveCount;
|
| 960 |
-
continue;
|
| 961 |
-
}
|
| 962 |
-
|
| 963 |
-
ss->currentMove = move;
|
| 964 |
-
ss->counterMoves = &thisThread->counterMoveHistory[moved_piece][to_sq(move)];
|
| 965 |
-
|
| 966 |
-
// Step 14. Make the move
|
| 967 |
-
pos.do_move(move, st, givesCheck);
|
| 968 |
-
|
| 969 |
-
// Step 15. Reduced depth search (LMR). If the move fails high it will be
|
| 970 |
-
// re-searched at full depth.
|
| 971 |
-
if ( depth >= 3 * ONE_PLY
|
| 972 |
-
&& moveCount > 1
|
| 973 |
-
&& (!captureOrPromotion || moveCountPruning))
|
| 974 |
-
{
|
| 975 |
-
Depth r = reduction<PvNode>(improving, depth, moveCount);
|
| 976 |
-
|
| 977 |
-
if (captureOrPromotion)
|
| 978 |
-
r -= r ? ONE_PLY : DEPTH_ZERO;
|
| 979 |
-
else
|
| 980 |
-
{
|
| 981 |
-
// Increase reduction for cut nodes
|
| 982 |
-
if (cutNode)
|
| 983 |
-
r += 2 * ONE_PLY;
|
| 984 |
-
|
| 985 |
-
// Decrease reduction for moves that escape a capture. Filter out
|
| 986 |
-
// castling moves, because they are coded as "king captures rook" and
|
| 987 |
-
// hence break make_move(). Also use see() instead of see_sign(),
|
| 988 |
-
// because the destination square is empty.
|
| 989 |
-
else if ( type_of(move) == NORMAL
|
| 990 |
-
&& type_of(pos.piece_on(to_sq(move))) != PAWN
|
| 991 |
-
&& !pos.see_ge(make_move(to_sq(move), from_sq(move)), VALUE_ZERO))
|
| 992 |
-
r -= 2 * ONE_PLY;
|
| 993 |
-
|
| 994 |
-
ss->history = thisThread->history[moved_piece][to_sq(move)]
|
| 995 |
-
+ (cmh ? (*cmh )[moved_piece][to_sq(move)] : VALUE_ZERO)
|
| 996 |
-
+ (fmh ? (*fmh )[moved_piece][to_sq(move)] : VALUE_ZERO)
|
| 997 |
-
+ (fmh2 ? (*fmh2)[moved_piece][to_sq(move)] : VALUE_ZERO)
|
| 998 |
-
+ thisThread->fromTo.get(~pos.side_to_move(), move)
|
| 999 |
-
- 8000; // Correction factor
|
| 1000 |
-
|
| 1001 |
-
// Decrease/increase reduction by comparing opponent's stat score
|
| 1002 |
-
if (ss->history > VALUE_ZERO && (ss-1)->history < VALUE_ZERO)
|
| 1003 |
-
r -= ONE_PLY;
|
| 1004 |
-
|
| 1005 |
-
else if (ss->history < VALUE_ZERO && (ss-1)->history > VALUE_ZERO)
|
| 1006 |
-
r += ONE_PLY;
|
| 1007 |
-
|
| 1008 |
-
// Decrease/increase reduction for moves with a good/bad history
|
| 1009 |
-
r = std::max(DEPTH_ZERO, (r / ONE_PLY - ss->history / 20000) * ONE_PLY);
|
| 1010 |
-
}
|
| 1011 |
-
|
| 1012 |
-
Depth d = std::max(newDepth - r, ONE_PLY);
|
| 1013 |
-
|
| 1014 |
-
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true);
|
| 1015 |
-
|
| 1016 |
-
doFullDepthSearch = (value > alpha && d != newDepth);
|
| 1017 |
-
}
|
| 1018 |
-
else
|
| 1019 |
-
doFullDepthSearch = !PvNode || moveCount > 1;
|
| 1020 |
-
|
| 1021 |
-
// Step 16. Full depth search when LMR is skipped or fails high
|
| 1022 |
-
if (doFullDepthSearch)
|
| 1023 |
-
value = newDepth < ONE_PLY ?
|
| 1024 |
-
givesCheck ? -qsearch<NonPV, true>(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
|
| 1025 |
-
: -qsearch<NonPV, false>(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
|
| 1026 |
-
: - search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
|
| 1027 |
-
|
| 1028 |
-
// For PV nodes only, do a full PV search on the first move or after a fail
|
| 1029 |
-
// high (in the latter case search only if value < beta), otherwise let the
|
| 1030 |
-
// parent node fail low with value <= alpha and try another move.
|
| 1031 |
-
if (PvNode && (moveCount == 1 || (value > alpha && (rootNode || value < beta))))
|
| 1032 |
-
{
|
| 1033 |
-
(ss+1)->pv = pv;
|
| 1034 |
-
(ss+1)->pv[0] = MOVE_NONE;
|
| 1035 |
-
|
| 1036 |
-
value = newDepth < ONE_PLY ?
|
| 1037 |
-
givesCheck ? -qsearch<PV, true>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
|
| 1038 |
-
: -qsearch<PV, false>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
|
| 1039 |
-
: - search<PV>(pos, ss+1, -beta, -alpha, newDepth, false);
|
| 1040 |
-
}
|
| 1041 |
-
|
| 1042 |
-
// Step 17. Undo move
|
| 1043 |
-
pos.undo_move(move);
|
| 1044 |
-
|
| 1045 |
-
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
| 1046 |
-
|
| 1047 |
-
// Step 18. Check for a new best move
|
| 1048 |
-
// Finished searching the move. If a stop occurred, the return value of
|
| 1049 |
-
// the search cannot be trusted, and we return immediately without
|
| 1050 |
-
// updating best move, PV and TT.
|
| 1051 |
-
if (Signals.stop.load(std::memory_order_relaxed))
|
| 1052 |
-
return VALUE_ZERO;
|
| 1053 |
-
|
| 1054 |
-
if (rootNode)
|
| 1055 |
-
{
|
| 1056 |
-
RootMove& rm = *std::find(thisThread->rootMoves.begin(),
|
| 1057 |
-
thisThread->rootMoves.end(), move);
|
| 1058 |
-
|
| 1059 |
-
// PV move or new best move ?
|
| 1060 |
-
if (moveCount == 1 || value > alpha)
|
| 1061 |
-
{
|
| 1062 |
-
rm.score = value;
|
| 1063 |
-
rm.pv.resize(1);
|
| 1064 |
-
|
| 1065 |
-
assert((ss+1)->pv);
|
| 1066 |
-
|
| 1067 |
-
for (Move* m = (ss+1)->pv; *m != MOVE_NONE; ++m)
|
| 1068 |
-
rm.pv.push_back(*m);
|
| 1069 |
-
|
| 1070 |
-
// We record how often the best move has been changed in each
|
| 1071 |
-
// iteration. This information is used for time management: When
|
| 1072 |
-
// the best move changes frequently, we allocate some more time.
|
| 1073 |
-
if (moveCount > 1 && thisThread == Threads.main())
|
| 1074 |
-
++static_cast<MainThread*>(thisThread)->bestMoveChanges;
|
| 1075 |
-
}
|
| 1076 |
-
else
|
| 1077 |
-
// All other moves but the PV are set to the lowest value: this is
|
| 1078 |
-
// not a problem when sorting because the sort is stable and the
|
| 1079 |
-
// move position in the list is preserved - just the PV is pushed up.
|
| 1080 |
-
rm.score = -VALUE_INFINITE;
|
| 1081 |
-
}
|
| 1082 |
-
|
| 1083 |
-
if (value > bestValue)
|
| 1084 |
-
{
|
| 1085 |
-
bestValue = value;
|
| 1086 |
-
|
| 1087 |
-
if (value > alpha)
|
| 1088 |
-
{
|
| 1089 |
-
// If there is an easy move for this position, clear it if unstable
|
| 1090 |
-
if ( PvNode
|
| 1091 |
-
&& thisThread == Threads.main()
|
| 1092 |
-
&& EasyMove.get(pos.key())
|
| 1093 |
-
&& (move != EasyMove.get(pos.key()) || moveCount > 1))
|
| 1094 |
-
EasyMove.clear();
|
| 1095 |
-
|
| 1096 |
-
bestMove = move;
|
| 1097 |
-
|
| 1098 |
-
if (PvNode && !rootNode) // Update pv even in fail-high case
|
| 1099 |
-
update_pv(ss->pv, move, (ss+1)->pv);
|
| 1100 |
-
|
| 1101 |
-
if (PvNode && value < beta) // Update alpha! Always alpha < beta
|
| 1102 |
-
alpha = value;
|
| 1103 |
-
else
|
| 1104 |
-
{
|
| 1105 |
-
assert(value >= beta); // Fail high
|
| 1106 |
-
break;
|
| 1107 |
-
}
|
| 1108 |
-
}
|
| 1109 |
-
}
|
| 1110 |
-
|
| 1111 |
-
if (!captureOrPromotion && move != bestMove && quietCount < 64)
|
| 1112 |
-
quietsSearched[quietCount++] = move;
|
| 1113 |
-
}
|
| 1114 |
-
|
| 1115 |
-
// The following condition would detect a stop only after move loop has been
|
| 1116 |
-
// completed. But in this case bestValue is valid because we have fully
|
| 1117 |
-
// searched our subtree, and we can anyhow save the result in TT.
|
| 1118 |
-
/*
|
| 1119 |
-
if (Signals.stop)
|
| 1120 |
-
return VALUE_DRAW;
|
| 1121 |
-
*/
|
| 1122 |
-
|
| 1123 |
-
// Step 20. Check for mate and stalemate
|
| 1124 |
-
// All legal moves have been searched and if there are no legal moves, it
|
| 1125 |
-
// must be a mate or a stalemate. If we are in a singular extension search then
|
| 1126 |
-
// return a fail low score.
|
| 1127 |
-
|
| 1128 |
-
assert(moveCount || !inCheck || excludedMove || !MoveList<LEGAL>(pos).size());
|
| 1129 |
-
|
| 1130 |
-
if (!moveCount)
|
| 1131 |
-
bestValue = excludedMove ? alpha
|
| 1132 |
-
: inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()];
|
| 1133 |
-
else if (bestMove)
|
| 1134 |
-
{
|
| 1135 |
-
int d = depth / ONE_PLY;
|
| 1136 |
-
|
| 1137 |
-
// Quiet best move: update killers, history and countermoves
|
| 1138 |
-
if (!pos.capture_or_promotion(bestMove))
|
| 1139 |
-
{
|
| 1140 |
-
Value bonus = Value(d * d + 2 * d - 2);
|
| 1141 |
-
update_stats(pos, ss, bestMove, quietsSearched, quietCount, bonus);
|
| 1142 |
-
}
|
| 1143 |
-
|
| 1144 |
-
// Extra penalty for a quiet TT move in previous ply when it gets refuted
|
| 1145 |
-
if ((ss-1)->moveCount == 1 && !pos.captured_piece())
|
| 1146 |
-
{
|
| 1147 |
-
Value penalty = Value(d * d + 4 * d + 1);
|
| 1148 |
-
Square prevSq = to_sq((ss-1)->currentMove);
|
| 1149 |
-
update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, -penalty);
|
| 1150 |
-
}
|
| 1151 |
-
}
|
| 1152 |
-
// Bonus for prior countermove that caused the fail low
|
| 1153 |
-
else if ( depth >= 3 * ONE_PLY
|
| 1154 |
-
&& !pos.captured_piece()
|
| 1155 |
-
&& is_ok((ss-1)->currentMove))
|
| 1156 |
-
{
|
| 1157 |
-
int d = depth / ONE_PLY;
|
| 1158 |
-
Value bonus = Value(d * d + 2 * d - 2);
|
| 1159 |
-
Square prevSq = to_sq((ss-1)->currentMove);
|
| 1160 |
-
update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, bonus);
|
| 1161 |
-
}
|
| 1162 |
-
|
| 1163 |
-
tte->save(posKey, value_to_tt(bestValue, ss->ply),
|
| 1164 |
-
bestValue >= beta ? BOUND_LOWER :
|
| 1165 |
-
PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
|
| 1166 |
-
depth, bestMove, ss->staticEval, TT.generation());
|
| 1167 |
-
|
| 1168 |
-
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
|
| 1169 |
-
|
| 1170 |
-
return bestValue;
|
| 1171 |
-
}
|
| 1172 |
-
|
| 1173 |
-
|
| 1174 |
-
// qsearch() is the quiescence search function, which is called by the main
|
| 1175 |
-
// search function when the remaining depth is zero (or, to be more precise,
|
| 1176 |
-
// less than ONE_PLY).
|
| 1177 |
-
|
| 1178 |
-
template <NodeType NT, bool InCheck>
|
| 1179 |
-
Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
| 1180 |
-
|
| 1181 |
-
const bool PvNode = NT == PV;
|
| 1182 |
-
|
| 1183 |
-
assert(InCheck == !!pos.checkers());
|
| 1184 |
-
assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
|
| 1185 |
-
assert(PvNode || (alpha == beta - 1));
|
| 1186 |
-
assert(depth <= DEPTH_ZERO);
|
| 1187 |
-
assert(depth / ONE_PLY * ONE_PLY == depth);
|
| 1188 |
-
|
| 1189 |
-
Move pv[MAX_PLY+1];
|
| 1190 |
-
StateInfo st;
|
| 1191 |
-
TTEntry* tte;
|
| 1192 |
-
Key posKey;
|
| 1193 |
-
Move ttMove, move, bestMove;
|
| 1194 |
-
Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha;
|
| 1195 |
-
bool ttHit, givesCheck, evasionPrunable;
|
| 1196 |
-
Depth ttDepth;
|
| 1197 |
-
|
| 1198 |
-
if (PvNode)
|
| 1199 |
-
{
|
| 1200 |
-
oldAlpha = alpha; // To flag BOUND_EXACT when eval above alpha and no available moves
|
| 1201 |
-
(ss+1)->pv = pv;
|
| 1202 |
-
ss->pv[0] = MOVE_NONE;
|
| 1203 |
-
}
|
| 1204 |
-
|
| 1205 |
-
ss->currentMove = bestMove = MOVE_NONE;
|
| 1206 |
-
ss->ply = (ss-1)->ply + 1;
|
| 1207 |
-
|
| 1208 |
-
// Check for an instant draw or if the maximum ply has been reached
|
| 1209 |
-
if (pos.is_draw() || ss->ply >= MAX_PLY)
|
| 1210 |
-
return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos)
|
| 1211 |
-
: DrawValue[pos.side_to_move()];
|
| 1212 |
-
|
| 1213 |
-
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
| 1214 |
-
|
| 1215 |
-
// Decide whether or not to include checks: this fixes also the type of
|
| 1216 |
-
// TT entry depth that we are going to use. Note that in qsearch we use
|
| 1217 |
-
// only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
|
| 1218 |
-
ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
|
| 1219 |
-
: DEPTH_QS_NO_CHECKS;
|
| 1220 |
-
|
| 1221 |
-
// Transposition table lookup
|
| 1222 |
-
posKey = pos.key();
|
| 1223 |
-
tte = TT.probe(posKey, ttHit);
|
| 1224 |
-
ttMove = ttHit ? tte->move() : MOVE_NONE;
|
| 1225 |
-
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
|
| 1226 |
-
|
| 1227 |
-
if ( !PvNode
|
| 1228 |
-
&& ttHit
|
| 1229 |
-
&& tte->depth() >= ttDepth
|
| 1230 |
-
&& ttValue != VALUE_NONE // Only in case of TT access race
|
| 1231 |
-
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
|
| 1232 |
-
: (tte->bound() & BOUND_UPPER)))
|
| 1233 |
-
return ttValue;
|
| 1234 |
-
|
| 1235 |
-
// Evaluate the position statically
|
| 1236 |
-
if (InCheck)
|
| 1237 |
-
{
|
| 1238 |
-
ss->staticEval = VALUE_NONE;
|
| 1239 |
-
bestValue = futilityBase = -VALUE_INFINITE;
|
| 1240 |
-
}
|
| 1241 |
-
else
|
| 1242 |
-
{
|
| 1243 |
-
if (ttHit)
|
| 1244 |
-
{
|
| 1245 |
-
// Never assume anything on values stored in TT
|
| 1246 |
-
if ((ss->staticEval = bestValue = tte->eval()) == VALUE_NONE)
|
| 1247 |
-
ss->staticEval = bestValue = evaluate(pos);
|
| 1248 |
-
|
| 1249 |
-
// Can ttValue be used as a better position evaluation?
|
| 1250 |
-
if (ttValue != VALUE_NONE)
|
| 1251 |
-
if (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER))
|
| 1252 |
-
bestValue = ttValue;
|
| 1253 |
-
}
|
| 1254 |
-
else
|
| 1255 |
-
ss->staticEval = bestValue =
|
| 1256 |
-
(ss-1)->currentMove != MOVE_NULL ? evaluate(pos)
|
| 1257 |
-
: -(ss-1)->staticEval + 2 * Eval::Tempo;
|
| 1258 |
-
|
| 1259 |
-
// Stand pat. Return immediately if static value is at least beta
|
| 1260 |
-
if (bestValue >= beta)
|
| 1261 |
-
{
|
| 1262 |
-
if (!ttHit)
|
| 1263 |
-
tte->save(pos.key(), value_to_tt(bestValue, ss->ply), BOUND_LOWER,
|
| 1264 |
-
DEPTH_NONE, MOVE_NONE, ss->staticEval, TT.generation());
|
| 1265 |
-
|
| 1266 |
-
return bestValue;
|
| 1267 |
-
}
|
| 1268 |
-
|
| 1269 |
-
if (PvNode && bestValue > alpha)
|
| 1270 |
-
alpha = bestValue;
|
| 1271 |
-
|
| 1272 |
-
futilityBase = bestValue + 128;
|
| 1273 |
-
}
|
| 1274 |
-
|
| 1275 |
-
// Initialize a MovePicker object for the current position, and prepare
|
| 1276 |
-
// to search the moves. Because the depth is <= 0 here, only captures,
|
| 1277 |
-
// queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
|
| 1278 |
-
// be generated.
|
| 1279 |
-
MovePicker mp(pos, ttMove, depth, to_sq((ss-1)->currentMove));
|
| 1280 |
-
|
| 1281 |
-
// Loop through the moves until no moves remain or a beta cutoff occurs
|
| 1282 |
-
while ((move = mp.next_move()) != MOVE_NONE)
|
| 1283 |
-
{
|
| 1284 |
-
assert(is_ok(move));
|
| 1285 |
-
|
| 1286 |
-
givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates()
|
| 1287 |
-
? pos.check_squares(type_of(pos.piece_on(from_sq(move)))) & to_sq(move)
|
| 1288 |
-
: pos.gives_check(move);
|
| 1289 |
-
|
| 1290 |
-
// Futility pruning
|
| 1291 |
-
if ( !InCheck
|
| 1292 |
-
&& !givesCheck
|
| 1293 |
-
&& futilityBase > -VALUE_KNOWN_WIN
|
| 1294 |
-
&& !pos.advanced_pawn_push(move))
|
| 1295 |
-
{
|
| 1296 |
-
assert(type_of(move) != ENPASSANT); // Due to !pos.advanced_pawn_push
|
| 1297 |
-
|
| 1298 |
-
futilityValue = futilityBase + PieceValue[EG][pos.piece_on(to_sq(move))];
|
| 1299 |
-
|
| 1300 |
-
if (futilityValue <= alpha)
|
| 1301 |
-
{
|
| 1302 |
-
bestValue = std::max(bestValue, futilityValue);
|
| 1303 |
-
continue;
|
| 1304 |
-
}
|
| 1305 |
-
|
| 1306 |
-
if (futilityBase <= alpha && !pos.see_ge(move, VALUE_ZERO + 1))
|
| 1307 |
-
{
|
| 1308 |
-
bestValue = std::max(bestValue, futilityBase);
|
| 1309 |
-
continue;
|
| 1310 |
-
}
|
| 1311 |
-
}
|
| 1312 |
-
|
| 1313 |
-
// Detect non-capture evasions that are candidates to be pruned
|
| 1314 |
-
evasionPrunable = InCheck
|
| 1315 |
-
&& bestValue > VALUE_MATED_IN_MAX_PLY
|
| 1316 |
-
&& !pos.capture(move);
|
| 1317 |
-
|
| 1318 |
-
// Don't search moves with negative SEE values
|
| 1319 |
-
if ( (!InCheck || evasionPrunable)
|
| 1320 |
-
&& type_of(move) != PROMOTION
|
| 1321 |
-
&& !pos.see_ge(move, VALUE_ZERO))
|
| 1322 |
-
continue;
|
| 1323 |
-
|
| 1324 |
-
// Speculative prefetch as early as possible
|
| 1325 |
-
prefetch(TT.first_entry(pos.key_after(move)));
|
| 1326 |
-
|
| 1327 |
-
// Check for legality just before making the move
|
| 1328 |
-
if (!pos.legal(move))
|
| 1329 |
-
continue;
|
| 1330 |
-
|
| 1331 |
-
ss->currentMove = move;
|
| 1332 |
-
|
| 1333 |
-
// Make and search the move
|
| 1334 |
-
pos.do_move(move, st, givesCheck);
|
| 1335 |
-
value = givesCheck ? -qsearch<NT, true>(pos, ss+1, -beta, -alpha, depth - ONE_PLY)
|
| 1336 |
-
: -qsearch<NT, false>(pos, ss+1, -beta, -alpha, depth - ONE_PLY);
|
| 1337 |
-
pos.undo_move(move);
|
| 1338 |
-
|
| 1339 |
-
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
| 1340 |
-
|
| 1341 |
-
// Check for a new best move
|
| 1342 |
-
if (value > bestValue)
|
| 1343 |
-
{
|
| 1344 |
-
bestValue = value;
|
| 1345 |
-
|
| 1346 |
-
if (value > alpha)
|
| 1347 |
-
{
|
| 1348 |
-
if (PvNode) // Update pv even in fail-high case
|
| 1349 |
-
update_pv(ss->pv, move, (ss+1)->pv);
|
| 1350 |
-
|
| 1351 |
-
if (PvNode && value < beta) // Update alpha here!
|
| 1352 |
-
{
|
| 1353 |
-
alpha = value;
|
| 1354 |
-
bestMove = move;
|
| 1355 |
-
}
|
| 1356 |
-
else // Fail high
|
| 1357 |
-
{
|
| 1358 |
-
tte->save(posKey, value_to_tt(value, ss->ply), BOUND_LOWER,
|
| 1359 |
-
ttDepth, move, ss->staticEval, TT.generation());
|
| 1360 |
-
|
| 1361 |
-
return value;
|
| 1362 |
-
}
|
| 1363 |
-
}
|
| 1364 |
-
}
|
| 1365 |
-
}
|
| 1366 |
-
|
| 1367 |
-
// All legal moves have been searched. A special case: If we're in check
|
| 1368 |
-
// and no legal moves were found, it is checkmate.
|
| 1369 |
-
if (InCheck && bestValue == -VALUE_INFINITE)
|
| 1370 |
-
return mated_in(ss->ply); // Plies to mate from the root
|
| 1371 |
-
|
| 1372 |
-
tte->save(posKey, value_to_tt(bestValue, ss->ply),
|
| 1373 |
-
PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER,
|
| 1374 |
-
ttDepth, bestMove, ss->staticEval, TT.generation());
|
| 1375 |
-
|
| 1376 |
-
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
|
| 1377 |
-
|
| 1378 |
-
return bestValue;
|
| 1379 |
-
}
|
| 1380 |
-
|
| 1381 |
-
|
| 1382 |
-
// value_to_tt() adjusts a mate score from "plies to mate from the root" to
|
| 1383 |
-
// "plies to mate from the current position". Non-mate scores are unchanged.
|
| 1384 |
-
// The function is called before storing a value in the transposition table.
|
| 1385 |
-
|
| 1386 |
-
Value value_to_tt(Value v, int ply) {
|
| 1387 |
-
|
| 1388 |
-
assert(v != VALUE_NONE);
|
| 1389 |
-
|
| 1390 |
-
return v >= VALUE_MATE_IN_MAX_PLY ? v + ply
|
| 1391 |
-
: v <= VALUE_MATED_IN_MAX_PLY ? v - ply : v;
|
| 1392 |
-
}
|
| 1393 |
-
|
| 1394 |
-
|
| 1395 |
-
// value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score
|
| 1396 |
-
// from the transposition table (which refers to the plies to mate/be mated
|
| 1397 |
-
// from current position) to "plies to mate/be mated from the root".
|
| 1398 |
-
|
| 1399 |
-
Value value_from_tt(Value v, int ply) {
|
| 1400 |
-
|
| 1401 |
-
return v == VALUE_NONE ? VALUE_NONE
|
| 1402 |
-
: v >= VALUE_MATE_IN_MAX_PLY ? v - ply
|
| 1403 |
-
: v <= VALUE_MATED_IN_MAX_PLY ? v + ply : v;
|
| 1404 |
-
}
|
| 1405 |
-
|
| 1406 |
-
|
| 1407 |
-
// update_pv() adds current move and appends child pv[]
|
| 1408 |
-
|
| 1409 |
-
void update_pv(Move* pv, Move move, Move* childPv) {
|
| 1410 |
-
|
| 1411 |
-
for (*pv++ = move; childPv && *childPv != MOVE_NONE; )
|
| 1412 |
-
*pv++ = *childPv++;
|
| 1413 |
-
*pv = MOVE_NONE;
|
| 1414 |
-
}
|
| 1415 |
-
|
| 1416 |
-
|
| 1417 |
-
// update_cm_stats() updates countermove and follow-up move history
|
| 1418 |
-
|
| 1419 |
-
void update_cm_stats(Stack* ss, Piece pc, Square s, Value bonus) {
|
| 1420 |
-
|
| 1421 |
-
CounterMoveStats* cmh = (ss-1)->counterMoves;
|
| 1422 |
-
CounterMoveStats* fmh1 = (ss-2)->counterMoves;
|
| 1423 |
-
CounterMoveStats* fmh2 = (ss-4)->counterMoves;
|
| 1424 |
-
|
| 1425 |
-
if (cmh)
|
| 1426 |
-
cmh->update(pc, s, bonus);
|
| 1427 |
-
|
| 1428 |
-
if (fmh1)
|
| 1429 |
-
fmh1->update(pc, s, bonus);
|
| 1430 |
-
|
| 1431 |
-
if (fmh2)
|
| 1432 |
-
fmh2->update(pc, s, bonus);
|
| 1433 |
-
}
|
| 1434 |
-
|
| 1435 |
-
|
| 1436 |
-
// update_stats() updates killers, history, countermove and countermove plus
|
| 1437 |
-
// follow-up move history when a new quiet best move is found.
|
| 1438 |
-
|
| 1439 |
-
void update_stats(const Position& pos, Stack* ss, Move move,
|
| 1440 |
-
Move* quiets, int quietsCnt, Value bonus) {
|
| 1441 |
-
|
| 1442 |
-
if (ss->killers[0] != move)
|
| 1443 |
-
{
|
| 1444 |
-
ss->killers[1] = ss->killers[0];
|
| 1445 |
-
ss->killers[0] = move;
|
| 1446 |
-
}
|
| 1447 |
-
|
| 1448 |
-
Color c = pos.side_to_move();
|
| 1449 |
-
Thread* thisThread = pos.this_thread();
|
| 1450 |
-
thisThread->fromTo.update(c, move, bonus);
|
| 1451 |
-
thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus);
|
| 1452 |
-
update_cm_stats(ss, pos.moved_piece(move), to_sq(move), bonus);
|
| 1453 |
-
|
| 1454 |
-
if ((ss-1)->counterMoves)
|
| 1455 |
-
{
|
| 1456 |
-
Square prevSq = to_sq((ss-1)->currentMove);
|
| 1457 |
-
thisThread->counterMoves.update(pos.piece_on(prevSq), prevSq, move);
|
| 1458 |
-
}
|
| 1459 |
-
|
| 1460 |
-
// Decrease all the other played quiet moves
|
| 1461 |
-
for (int i = 0; i < quietsCnt; ++i)
|
| 1462 |
-
{
|
| 1463 |
-
thisThread->fromTo.update(c, quiets[i], -bonus);
|
| 1464 |
-
thisThread->history.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
| 1465 |
-
update_cm_stats(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
| 1466 |
-
}
|
| 1467 |
-
}
|
| 1468 |
-
|
| 1469 |
-
|
| 1470 |
-
// When playing with strength handicap, choose best move among a set of RootMoves
|
| 1471 |
-
// using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
|
| 1472 |
-
|
| 1473 |
-
Move Skill::pick_best(size_t multiPV) {
|
| 1474 |
-
|
| 1475 |
-
const RootMoves& rootMoves = Threads.main()->rootMoves;
|
| 1476 |
-
static PRNG rng(now()); // PRNG sequence should be non-deterministic
|
| 1477 |
-
|
| 1478 |
-
// RootMoves are already sorted by score in descending order
|
| 1479 |
-
Value topScore = rootMoves[0].score;
|
| 1480 |
-
int delta = std::min(topScore - rootMoves[multiPV - 1].score, PawnValueMg);
|
| 1481 |
-
int weakness = 120 - 2 * level;
|
| 1482 |
-
int maxScore = -VALUE_INFINITE;
|
| 1483 |
-
|
| 1484 |
-
// Choose best move. For each move score we add two terms, both dependent on
|
| 1485 |
-
// weakness. One is deterministic and bigger for weaker levels, and one is
|
| 1486 |
-
// random. Then we choose the move with the resulting highest score.
|
| 1487 |
-
for (size_t i = 0; i < multiPV; ++i)
|
| 1488 |
-
{
|
| 1489 |
-
// This is our magic formula
|
| 1490 |
-
int push = ( weakness * int(topScore - rootMoves[i].score)
|
| 1491 |
-
+ delta * (rng.rand<unsigned>() % weakness)) / 128;
|
| 1492 |
-
|
| 1493 |
-
if (rootMoves[i].score + push > maxScore)
|
| 1494 |
-
{
|
| 1495 |
-
maxScore = rootMoves[i].score + push;
|
| 1496 |
-
best = rootMoves[i].pv[0];
|
| 1497 |
-
}
|
| 1498 |
-
}
|
| 1499 |
-
|
| 1500 |
-
return best;
|
| 1501 |
-
}
|
| 1502 |
-
|
| 1503 |
-
|
| 1504 |
-
// check_time() is used to print debug info and, more importantly, to detect
|
| 1505 |
-
// when we are out of available time and thus stop the search.
|
| 1506 |
-
|
| 1507 |
-
void check_time() {
|
| 1508 |
-
|
| 1509 |
-
static TimePoint lastInfoTime = now();
|
| 1510 |
-
|
| 1511 |
-
int elapsed = Time.elapsed();
|
| 1512 |
-
TimePoint tick = Limits.startTime + elapsed;
|
| 1513 |
-
|
| 1514 |
-
if (tick - lastInfoTime >= 1000)
|
| 1515 |
-
{
|
| 1516 |
-
lastInfoTime = tick;
|
| 1517 |
-
dbg_print();
|
| 1518 |
-
}
|
| 1519 |
-
|
| 1520 |
-
// An engine may not stop pondering until told so by the GUI
|
| 1521 |
-
if (Limits.ponder)
|
| 1522 |
-
return;
|
| 1523 |
-
|
| 1524 |
-
if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10)
|
| 1525 |
-
|| (Limits.movetime && elapsed >= Limits.movetime)
|
| 1526 |
-
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
|
| 1527 |
-
Signals.stop = true;
|
| 1528 |
-
}
|
| 1529 |
-
|
| 1530 |
-
} // namespace
|
| 1531 |
-
|
| 1532 |
-
|
| 1533 |
-
/// UCI::pv() formats PV information according to the UCI protocol. UCI requires
|
| 1534 |
-
/// that all (if any) unsearched PV lines are sent using a previous search score.
|
| 1535 |
-
|
| 1536 |
-
string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) {
|
| 1537 |
-
|
| 1538 |
-
std::stringstream ss;
|
| 1539 |
-
int elapsed = Time.elapsed() + 1;
|
| 1540 |
-
const RootMoves& rootMoves = pos.this_thread()->rootMoves;
|
| 1541 |
-
size_t PVIdx = pos.this_thread()->PVIdx;
|
| 1542 |
-
size_t multiPV = std::min((size_t)Options["MultiPV"], rootMoves.size());
|
| 1543 |
-
uint64_t nodesSearched = Threads.nodes_searched();
|
| 1544 |
-
uint64_t tbHits = Threads.tb_hits() + (TB::RootInTB ? rootMoves.size() : 0);
|
| 1545 |
-
|
| 1546 |
-
for (size_t i = 0; i < multiPV; ++i)
|
| 1547 |
-
{
|
| 1548 |
-
bool updated = (i <= PVIdx);
|
| 1549 |
-
|
| 1550 |
-
if (depth == ONE_PLY && !updated)
|
| 1551 |
-
continue;
|
| 1552 |
-
|
| 1553 |
-
Depth d = updated ? depth : depth - ONE_PLY;
|
| 1554 |
-
Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore;
|
| 1555 |
-
|
| 1556 |
-
bool tb = TB::RootInTB && abs(v) < VALUE_MATE - MAX_PLY;
|
| 1557 |
-
v = tb ? TB::Score : v;
|
| 1558 |
-
|
| 1559 |
-
if (ss.rdbuf()->in_avail()) // Not at first line
|
| 1560 |
-
ss << "\n";
|
| 1561 |
-
|
| 1562 |
-
ss << "info"
|
| 1563 |
-
<< " depth " << d / ONE_PLY
|
| 1564 |
-
<< " seldepth " << pos.this_thread()->maxPly
|
| 1565 |
-
<< " multipv " << i + 1
|
| 1566 |
-
<< " score " << UCI::value(v);
|
| 1567 |
-
|
| 1568 |
-
if (!tb && i == PVIdx)
|
| 1569 |
-
ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : "");
|
| 1570 |
-
|
| 1571 |
-
ss << " nodes " << nodesSearched
|
| 1572 |
-
<< " nps " << nodesSearched * 1000 / elapsed;
|
| 1573 |
-
|
| 1574 |
-
if (elapsed > 1000) // Earlier makes little sense
|
| 1575 |
-
ss << " hashfull " << TT.hashfull();
|
| 1576 |
-
|
| 1577 |
-
ss << " tbhits " << tbHits
|
| 1578 |
-
<< " time " << elapsed
|
| 1579 |
-
<< " pv";
|
| 1580 |
-
|
| 1581 |
-
for (Move m : rootMoves[i].pv)
|
| 1582 |
-
ss << " " << UCI::move(m, pos.is_chess960());
|
| 1583 |
-
}
|
| 1584 |
-
|
| 1585 |
-
return ss.str();
|
| 1586 |
-
}
|
| 1587 |
-
|
| 1588 |
-
|
| 1589 |
-
/// RootMove::extract_ponder_from_tt() is called in case we have no ponder move
|
| 1590 |
-
/// before exiting the search, for instance, in case we stop the search during a
|
| 1591 |
-
/// fail high at root. We try hard to have a ponder move to return to the GUI,
|
| 1592 |
-
/// otherwise in case of 'ponder on' we have nothing to think on.
|
| 1593 |
-
|
| 1594 |
-
bool RootMove::extract_ponder_from_tt(Position& pos) {
|
| 1595 |
-
|
| 1596 |
-
StateInfo st;
|
| 1597 |
-
bool ttHit;
|
| 1598 |
-
|
| 1599 |
-
assert(pv.size() == 1);
|
| 1600 |
-
|
| 1601 |
-
if (!pv[0])
|
| 1602 |
-
return false;
|
| 1603 |
-
|
| 1604 |
-
pos.do_move(pv[0], st, pos.gives_check(pv[0]));
|
| 1605 |
-
TTEntry* tte = TT.probe(pos.key(), ttHit);
|
| 1606 |
-
|
| 1607 |
-
if (ttHit)
|
| 1608 |
-
{
|
| 1609 |
-
Move m = tte->move(); // Local copy to be SMP safe
|
| 1610 |
-
if (MoveList<LEGAL>(pos).contains(m))
|
| 1611 |
-
pv.push_back(m);
|
| 1612 |
-
}
|
| 1613 |
-
|
| 1614 |
-
pos.undo_move(pv[0]);
|
| 1615 |
-
return pv.size() > 1;
|
| 1616 |
-
}
|
| 1617 |
-
|
| 1618 |
-
void Tablebases::filter_root_moves(Position& pos, Search::RootMoves& rootMoves) {
|
| 1619 |
-
|
| 1620 |
-
RootInTB = false;
|
| 1621 |
-
UseRule50 = Options["Syzygy50MoveRule"];
|
| 1622 |
-
ProbeDepth = Options["SyzygyProbeDepth"] * ONE_PLY;
|
| 1623 |
-
Cardinality = Options["SyzygyProbeLimit"];
|
| 1624 |
-
|
| 1625 |
-
// Skip TB probing when no TB found: !TBLargest -> !TB::Cardinality
|
| 1626 |
-
if (Cardinality > MaxCardinality)
|
| 1627 |
-
{
|
| 1628 |
-
Cardinality = MaxCardinality;
|
| 1629 |
-
ProbeDepth = DEPTH_ZERO;
|
| 1630 |
-
}
|
| 1631 |
-
|
| 1632 |
-
if (Cardinality < popcount(pos.pieces()) || pos.can_castle(ANY_CASTLING))
|
| 1633 |
-
return;
|
| 1634 |
-
|
| 1635 |
-
// If the current root position is in the tablebases, then RootMoves
|
| 1636 |
-
// contains only moves that preserve the draw or the win.
|
| 1637 |
-
RootInTB = root_probe(pos, rootMoves, TB::Score);
|
| 1638 |
-
|
| 1639 |
-
if (RootInTB)
|
| 1640 |
-
Cardinality = 0; // Do not probe tablebases during the search
|
| 1641 |
-
|
| 1642 |
-
else // If DTZ tables are missing, use WDL tables as a fallback
|
| 1643 |
-
{
|
| 1644 |
-
// Filter out moves that do not preserve the draw or the win.
|
| 1645 |
-
RootInTB = root_probe_wdl(pos, rootMoves, TB::Score);
|
| 1646 |
-
|
| 1647 |
-
// Only probe during search if winning
|
| 1648 |
-
if (RootInTB && TB::Score <= VALUE_DRAW)
|
| 1649 |
-
Cardinality = 0;
|
| 1650 |
-
}
|
| 1651 |
-
|
| 1652 |
-
if (RootInTB && !UseRule50)
|
| 1653 |
-
TB::Score = TB::Score > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1
|
| 1654 |
-
: TB::Score < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1
|
| 1655 |
-
: VALUE_DRAW;
|
| 1656 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/search.h
DELETED
|
@@ -1,111 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef SEARCH_H_INCLUDED
|
| 22 |
-
#define SEARCH_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include <atomic>
|
| 25 |
-
#include <vector>
|
| 26 |
-
|
| 27 |
-
#include "misc.h"
|
| 28 |
-
#include "movepick.h"
|
| 29 |
-
#include "types.h"
|
| 30 |
-
|
| 31 |
-
class Position;
|
| 32 |
-
|
| 33 |
-
namespace Search {
|
| 34 |
-
|
| 35 |
-
/// Stack struct keeps track of the information we need to remember from nodes
|
| 36 |
-
/// shallower and deeper in the tree during the search. Each search thread has
|
| 37 |
-
/// its own array of Stack objects, indexed by the current ply.
|
| 38 |
-
|
| 39 |
-
struct Stack {
|
| 40 |
-
Move* pv;
|
| 41 |
-
int ply;
|
| 42 |
-
Move currentMove;
|
| 43 |
-
Move excludedMove;
|
| 44 |
-
Move killers[2];
|
| 45 |
-
Value staticEval;
|
| 46 |
-
Value history;
|
| 47 |
-
bool skipEarlyPruning;
|
| 48 |
-
int moveCount;
|
| 49 |
-
CounterMoveStats* counterMoves;
|
| 50 |
-
};
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
/// RootMove struct is used for moves at the root of the tree. For each root move
|
| 54 |
-
/// we store a score and a PV (really a refutation in the case of moves which
|
| 55 |
-
/// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves.
|
| 56 |
-
|
| 57 |
-
struct RootMove {
|
| 58 |
-
|
| 59 |
-
explicit RootMove(Move m) : pv(1, m) {}
|
| 60 |
-
|
| 61 |
-
bool operator<(const RootMove& m) const { return m.score < score; } // Descending sort
|
| 62 |
-
bool operator==(const Move& m) const { return pv[0] == m; }
|
| 63 |
-
bool extract_ponder_from_tt(Position& pos);
|
| 64 |
-
|
| 65 |
-
Value score = -VALUE_INFINITE;
|
| 66 |
-
Value previousScore = -VALUE_INFINITE;
|
| 67 |
-
std::vector<Move> pv;
|
| 68 |
-
};
|
| 69 |
-
|
| 70 |
-
typedef std::vector<RootMove> RootMoves;
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
/// LimitsType struct stores information sent by GUI about available time to
|
| 74 |
-
/// search the current move, maximum depth/time, if we are in analysis mode or
|
| 75 |
-
/// if we have to ponder while it's our opponent's turn to move.
|
| 76 |
-
|
| 77 |
-
struct LimitsType {
|
| 78 |
-
|
| 79 |
-
LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
|
| 80 |
-
nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] =
|
| 81 |
-
npmsec = movestogo = depth = movetime = mate = infinite = ponder = 0;
|
| 82 |
-
}
|
| 83 |
-
|
| 84 |
-
bool use_time_management() const {
|
| 85 |
-
return !(mate | movetime | depth | nodes | infinite);
|
| 86 |
-
}
|
| 87 |
-
|
| 88 |
-
std::vector<Move> searchmoves;
|
| 89 |
-
int time[COLOR_NB], inc[COLOR_NB], npmsec, movestogo, depth, movetime, mate, infinite, ponder;
|
| 90 |
-
int64_t nodes;
|
| 91 |
-
TimePoint startTime;
|
| 92 |
-
};
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
/// SignalsType struct stores atomic flags updated during the search, typically
|
| 96 |
-
/// in an async fashion e.g. to stop the search by the GUI.
|
| 97 |
-
|
| 98 |
-
struct SignalsType {
|
| 99 |
-
std::atomic_bool stop, stopOnPonderhit;
|
| 100 |
-
};
|
| 101 |
-
|
| 102 |
-
extern SignalsType Signals;
|
| 103 |
-
extern LimitsType Limits;
|
| 104 |
-
|
| 105 |
-
void init();
|
| 106 |
-
void clear();
|
| 107 |
-
template<bool Root = true> uint64_t perft(Position& pos, Depth depth);
|
| 108 |
-
|
| 109 |
-
} // namespace Search
|
| 110 |
-
|
| 111 |
-
#endif // #ifndef SEARCH_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/syzygy/tbcore.cpp
DELETED
|
@@ -1,1378 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Copyright (c) 2011-2013 Ronald de Man
|
| 3 |
-
This file may be redistributed and/or modified without restrictions.
|
| 4 |
-
|
| 5 |
-
tbcore.c contains engine-independent routines of the tablebase probing code.
|
| 6 |
-
This file should not need too much adaptation to add tablebase probing to
|
| 7 |
-
a particular engine, provided the engine is written in C or C++.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#include <stdio.h>
|
| 11 |
-
#include <stdint.h>
|
| 12 |
-
#include <stdlib.h>
|
| 13 |
-
#include <string.h>
|
| 14 |
-
#include <sys/stat.h>
|
| 15 |
-
#include <fcntl.h>
|
| 16 |
-
#ifndef _WIN32
|
| 17 |
-
#include <unistd.h>
|
| 18 |
-
#include <sys/mman.h>
|
| 19 |
-
#endif
|
| 20 |
-
#include "tbcore.h"
|
| 21 |
-
|
| 22 |
-
#define TBMAX_PIECE 254
|
| 23 |
-
#define TBMAX_PAWN 256
|
| 24 |
-
#define HSHMAX 5
|
| 25 |
-
|
| 26 |
-
#define Swap(a,b) {int tmp=a;a=b;b=tmp;}
|
| 27 |
-
|
| 28 |
-
#define TB_PAWN 1
|
| 29 |
-
#define TB_KNIGHT 2
|
| 30 |
-
#define TB_BISHOP 3
|
| 31 |
-
#define TB_ROOK 4
|
| 32 |
-
#define TB_QUEEN 5
|
| 33 |
-
#define TB_KING 6
|
| 34 |
-
|
| 35 |
-
#define TB_WPAWN TB_PAWN
|
| 36 |
-
#define TB_BPAWN (TB_PAWN | 8)
|
| 37 |
-
|
| 38 |
-
static LOCK_T TB_mutex;
|
| 39 |
-
|
| 40 |
-
static bool initialized = false;
|
| 41 |
-
static int num_paths = 0;
|
| 42 |
-
static char *path_string = NULL;
|
| 43 |
-
static char **paths = NULL;
|
| 44 |
-
|
| 45 |
-
static int TBnum_piece, TBnum_pawn;
|
| 46 |
-
static struct TBEntry_piece TB_piece[TBMAX_PIECE];
|
| 47 |
-
static struct TBEntry_pawn TB_pawn[TBMAX_PAWN];
|
| 48 |
-
|
| 49 |
-
static struct TBHashEntry TB_hash[1 << TBHASHBITS][HSHMAX];
|
| 50 |
-
|
| 51 |
-
#define DTZ_ENTRIES 64
|
| 52 |
-
|
| 53 |
-
static struct DTZTableEntry DTZ_table[DTZ_ENTRIES];
|
| 54 |
-
|
| 55 |
-
static void init_indices(void);
|
| 56 |
-
static uint64 calc_key_from_pcs(int *pcs, int mirror);
|
| 57 |
-
static void free_wdl_entry(struct TBEntry *entry);
|
| 58 |
-
static void free_dtz_entry(struct TBEntry *entry);
|
| 59 |
-
|
| 60 |
-
static FD open_tb(const char *str, const char *suffix)
|
| 61 |
-
{
|
| 62 |
-
int i;
|
| 63 |
-
FD fd;
|
| 64 |
-
char file[256];
|
| 65 |
-
|
| 66 |
-
for (i = 0; i < num_paths; i++) {
|
| 67 |
-
strcpy(file, paths[i]);
|
| 68 |
-
strcat(file, "/");
|
| 69 |
-
strcat(file, str);
|
| 70 |
-
strcat(file, suffix);
|
| 71 |
-
#ifndef _WIN32
|
| 72 |
-
fd = open(file, O_RDONLY);
|
| 73 |
-
#else
|
| 74 |
-
fd = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL,
|
| 75 |
-
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
| 76 |
-
#endif
|
| 77 |
-
if (fd != FD_ERR) return fd;
|
| 78 |
-
}
|
| 79 |
-
return FD_ERR;
|
| 80 |
-
}
|
| 81 |
-
|
| 82 |
-
static void close_tb(FD fd)
|
| 83 |
-
{
|
| 84 |
-
#ifndef _WIN32
|
| 85 |
-
close(fd);
|
| 86 |
-
#else
|
| 87 |
-
CloseHandle(fd);
|
| 88 |
-
#endif
|
| 89 |
-
}
|
| 90 |
-
|
| 91 |
-
static char *map_file(const char *name, const char *suffix, uint64 *mapping)
|
| 92 |
-
{
|
| 93 |
-
FD fd = open_tb(name, suffix);
|
| 94 |
-
if (fd == FD_ERR)
|
| 95 |
-
return NULL;
|
| 96 |
-
#ifndef _WIN32
|
| 97 |
-
struct stat statbuf;
|
| 98 |
-
fstat(fd, &statbuf);
|
| 99 |
-
*mapping = statbuf.st_size;
|
| 100 |
-
char *data = (char *)mmap(NULL, statbuf.st_size, PROT_READ,
|
| 101 |
-
MAP_SHARED, fd, 0);
|
| 102 |
-
if (data == (char *)(-1)) {
|
| 103 |
-
printf("Could not mmap() %s.\n", name);
|
| 104 |
-
exit(1);
|
| 105 |
-
}
|
| 106 |
-
#else
|
| 107 |
-
DWORD size_low, size_high;
|
| 108 |
-
size_low = GetFileSize(fd, &size_high);
|
| 109 |
-
// *size = ((uint64)size_high) << 32 | ((uint64)size_low);
|
| 110 |
-
HANDLE map = CreateFileMapping(fd, NULL, PAGE_READONLY, size_high, size_low,
|
| 111 |
-
NULL);
|
| 112 |
-
if (map == NULL) {
|
| 113 |
-
printf("CreateFileMapping() failed.\n");
|
| 114 |
-
exit(1);
|
| 115 |
-
}
|
| 116 |
-
*mapping = (uint64)map;
|
| 117 |
-
char *data = (char *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
|
| 118 |
-
if (data == NULL) {
|
| 119 |
-
printf("MapViewOfFile() failed, name = %s%s, error = %lu.\n", name, suffix, GetLastError());
|
| 120 |
-
exit(1);
|
| 121 |
-
}
|
| 122 |
-
#endif
|
| 123 |
-
close_tb(fd);
|
| 124 |
-
return data;
|
| 125 |
-
}
|
| 126 |
-
|
| 127 |
-
#ifndef _WIN32
|
| 128 |
-
static void unmap_file(char *data, uint64 size)
|
| 129 |
-
{
|
| 130 |
-
if (!data) return;
|
| 131 |
-
munmap(data, size);
|
| 132 |
-
}
|
| 133 |
-
#else
|
| 134 |
-
static void unmap_file(char *data, uint64 mapping)
|
| 135 |
-
{
|
| 136 |
-
if (!data) return;
|
| 137 |
-
UnmapViewOfFile(data);
|
| 138 |
-
CloseHandle((HANDLE)mapping);
|
| 139 |
-
}
|
| 140 |
-
#endif
|
| 141 |
-
|
| 142 |
-
static void add_to_hash(struct TBEntry *ptr, uint64 key)
|
| 143 |
-
{
|
| 144 |
-
int i, hshidx;
|
| 145 |
-
|
| 146 |
-
hshidx = key >> (64 - TBHASHBITS);
|
| 147 |
-
i = 0;
|
| 148 |
-
while (i < HSHMAX && TB_hash[hshidx][i].ptr)
|
| 149 |
-
i++;
|
| 150 |
-
if (i == HSHMAX) {
|
| 151 |
-
printf("HSHMAX too low!\n");
|
| 152 |
-
exit(1);
|
| 153 |
-
} else {
|
| 154 |
-
TB_hash[hshidx][i].key = key;
|
| 155 |
-
TB_hash[hshidx][i].ptr = ptr;
|
| 156 |
-
}
|
| 157 |
-
}
|
| 158 |
-
|
| 159 |
-
static char pchr[] = {'K', 'Q', 'R', 'B', 'N', 'P'};
|
| 160 |
-
|
| 161 |
-
static void init_tb(char *str)
|
| 162 |
-
{
|
| 163 |
-
FD fd;
|
| 164 |
-
struct TBEntry *entry;
|
| 165 |
-
int i, j, pcs[16];
|
| 166 |
-
uint64 key, key2;
|
| 167 |
-
int color;
|
| 168 |
-
char *s;
|
| 169 |
-
|
| 170 |
-
fd = open_tb(str, WDLSUFFIX);
|
| 171 |
-
if (fd == FD_ERR) return;
|
| 172 |
-
close_tb(fd);
|
| 173 |
-
|
| 174 |
-
for (i = 0; i < 16; i++)
|
| 175 |
-
pcs[i] = 0;
|
| 176 |
-
color = 0;
|
| 177 |
-
for (s = str; *s; s++)
|
| 178 |
-
switch (*s) {
|
| 179 |
-
case 'P':
|
| 180 |
-
pcs[TB_PAWN | color]++;
|
| 181 |
-
break;
|
| 182 |
-
case 'N':
|
| 183 |
-
pcs[TB_KNIGHT | color]++;
|
| 184 |
-
break;
|
| 185 |
-
case 'B':
|
| 186 |
-
pcs[TB_BISHOP | color]++;
|
| 187 |
-
break;
|
| 188 |
-
case 'R':
|
| 189 |
-
pcs[TB_ROOK | color]++;
|
| 190 |
-
break;
|
| 191 |
-
case 'Q':
|
| 192 |
-
pcs[TB_QUEEN | color]++;
|
| 193 |
-
break;
|
| 194 |
-
case 'K':
|
| 195 |
-
pcs[TB_KING | color]++;
|
| 196 |
-
break;
|
| 197 |
-
case 'v':
|
| 198 |
-
color = 0x08;
|
| 199 |
-
break;
|
| 200 |
-
}
|
| 201 |
-
for (i = 0; i < 8; i++)
|
| 202 |
-
if (pcs[i] != pcs[i+8])
|
| 203 |
-
break;
|
| 204 |
-
key = calc_key_from_pcs(pcs, 0);
|
| 205 |
-
key2 = calc_key_from_pcs(pcs, 1);
|
| 206 |
-
if (pcs[TB_WPAWN] + pcs[TB_BPAWN] == 0) {
|
| 207 |
-
if (TBnum_piece == TBMAX_PIECE) {
|
| 208 |
-
printf("TBMAX_PIECE limit too low!\n");
|
| 209 |
-
exit(1);
|
| 210 |
-
}
|
| 211 |
-
entry = (struct TBEntry *)&TB_piece[TBnum_piece++];
|
| 212 |
-
} else {
|
| 213 |
-
if (TBnum_pawn == TBMAX_PAWN) {
|
| 214 |
-
printf("TBMAX_PAWN limit too low!\n");
|
| 215 |
-
exit(1);
|
| 216 |
-
}
|
| 217 |
-
entry = (struct TBEntry *)&TB_pawn[TBnum_pawn++];
|
| 218 |
-
}
|
| 219 |
-
entry->key = key;
|
| 220 |
-
entry->ready = 0;
|
| 221 |
-
entry->num = 0;
|
| 222 |
-
for (i = 0; i < 16; i++)
|
| 223 |
-
entry->num += (ubyte)pcs[i];
|
| 224 |
-
entry->symmetric = (key == key2);
|
| 225 |
-
entry->has_pawns = (pcs[TB_WPAWN] + pcs[TB_BPAWN] > 0);
|
| 226 |
-
if (entry->num > Tablebases::MaxCardinality)
|
| 227 |
-
Tablebases::MaxCardinality = entry->num;
|
| 228 |
-
|
| 229 |
-
if (entry->has_pawns) {
|
| 230 |
-
struct TBEntry_pawn *ptr = (struct TBEntry_pawn *)entry;
|
| 231 |
-
ptr->pawns[0] = (ubyte)pcs[TB_WPAWN];
|
| 232 |
-
ptr->pawns[1] = (ubyte)pcs[TB_BPAWN];
|
| 233 |
-
if (pcs[TB_BPAWN] > 0
|
| 234 |
-
&& (pcs[TB_WPAWN] == 0 || pcs[TB_BPAWN] < pcs[TB_WPAWN])) {
|
| 235 |
-
ptr->pawns[0] = (ubyte)pcs[TB_BPAWN];
|
| 236 |
-
ptr->pawns[1] = (ubyte)pcs[TB_WPAWN];
|
| 237 |
-
}
|
| 238 |
-
} else {
|
| 239 |
-
struct TBEntry_piece *ptr = (struct TBEntry_piece *)entry;
|
| 240 |
-
for (i = 0, j = 0; i < 16; i++)
|
| 241 |
-
if (pcs[i] == 1) j++;
|
| 242 |
-
if (j >= 3) ptr->enc_type = 0;
|
| 243 |
-
else if (j == 2) ptr->enc_type = 2;
|
| 244 |
-
else { /* only for suicide */
|
| 245 |
-
j = 16;
|
| 246 |
-
for (i = 0; i < 16; i++) {
|
| 247 |
-
if (pcs[i] < j && pcs[i] > 1) j = pcs[i];
|
| 248 |
-
ptr->enc_type = ubyte(1 + j);
|
| 249 |
-
}
|
| 250 |
-
}
|
| 251 |
-
}
|
| 252 |
-
add_to_hash(entry, key);
|
| 253 |
-
if (key2 != key) add_to_hash(entry, key2);
|
| 254 |
-
}
|
| 255 |
-
|
| 256 |
-
void Tablebases::init(const std::string& path)
|
| 257 |
-
{
|
| 258 |
-
char str[16];
|
| 259 |
-
int i, j, k, l;
|
| 260 |
-
|
| 261 |
-
if (initialized) {
|
| 262 |
-
free(path_string);
|
| 263 |
-
free(paths);
|
| 264 |
-
struct TBEntry *entry;
|
| 265 |
-
for (i = 0; i < TBnum_piece; i++) {
|
| 266 |
-
entry = (struct TBEntry *)&TB_piece[i];
|
| 267 |
-
free_wdl_entry(entry);
|
| 268 |
-
}
|
| 269 |
-
for (i = 0; i < TBnum_pawn; i++) {
|
| 270 |
-
entry = (struct TBEntry *)&TB_pawn[i];
|
| 271 |
-
free_wdl_entry(entry);
|
| 272 |
-
}
|
| 273 |
-
for (i = 0; i < DTZ_ENTRIES; i++)
|
| 274 |
-
if (DTZ_table[i].entry)
|
| 275 |
-
free_dtz_entry(DTZ_table[i].entry);
|
| 276 |
-
} else {
|
| 277 |
-
init_indices();
|
| 278 |
-
initialized = true;
|
| 279 |
-
}
|
| 280 |
-
|
| 281 |
-
const char *p = path.c_str();
|
| 282 |
-
if (strlen(p) == 0 || !strcmp(p, "<empty>")) return;
|
| 283 |
-
path_string = (char *)malloc(strlen(p) + 1);
|
| 284 |
-
strcpy(path_string, p);
|
| 285 |
-
num_paths = 0;
|
| 286 |
-
for (i = 0;; i++) {
|
| 287 |
-
if (path_string[i] != SEP_CHAR)
|
| 288 |
-
num_paths++;
|
| 289 |
-
while (path_string[i] && path_string[i] != SEP_CHAR)
|
| 290 |
-
i++;
|
| 291 |
-
if (!path_string[i]) break;
|
| 292 |
-
path_string[i] = 0;
|
| 293 |
-
}
|
| 294 |
-
paths = (char **)malloc(num_paths * sizeof(char *));
|
| 295 |
-
for (i = j = 0; i < num_paths; i++) {
|
| 296 |
-
while (!path_string[j]) j++;
|
| 297 |
-
paths[i] = &path_string[j];
|
| 298 |
-
while (path_string[j]) j++;
|
| 299 |
-
}
|
| 300 |
-
|
| 301 |
-
LOCK_INIT(TB_mutex);
|
| 302 |
-
|
| 303 |
-
TBnum_piece = TBnum_pawn = 0;
|
| 304 |
-
MaxCardinality = 0;
|
| 305 |
-
|
| 306 |
-
for (i = 0; i < (1 << TBHASHBITS); i++)
|
| 307 |
-
for (j = 0; j < HSHMAX; j++) {
|
| 308 |
-
TB_hash[i][j].key = 0ULL;
|
| 309 |
-
TB_hash[i][j].ptr = NULL;
|
| 310 |
-
}
|
| 311 |
-
|
| 312 |
-
for (i = 0; i < DTZ_ENTRIES; i++)
|
| 313 |
-
DTZ_table[i].entry = NULL;
|
| 314 |
-
|
| 315 |
-
for (i = 1; i < 6; i++) {
|
| 316 |
-
sprintf(str, "K%cvK", pchr[i]);
|
| 317 |
-
init_tb(str);
|
| 318 |
-
}
|
| 319 |
-
|
| 320 |
-
for (i = 1; i < 6; i++)
|
| 321 |
-
for (j = i; j < 6; j++) {
|
| 322 |
-
sprintf(str, "K%cvK%c", pchr[i], pchr[j]);
|
| 323 |
-
init_tb(str);
|
| 324 |
-
}
|
| 325 |
-
|
| 326 |
-
for (i = 1; i < 6; i++)
|
| 327 |
-
for (j = i; j < 6; j++) {
|
| 328 |
-
sprintf(str, "K%c%cvK", pchr[i], pchr[j]);
|
| 329 |
-
init_tb(str);
|
| 330 |
-
}
|
| 331 |
-
|
| 332 |
-
for (i = 1; i < 6; i++)
|
| 333 |
-
for (j = i; j < 6; j++)
|
| 334 |
-
for (k = 1; k < 6; k++) {
|
| 335 |
-
sprintf(str, "K%c%cvK%c", pchr[i], pchr[j], pchr[k]);
|
| 336 |
-
init_tb(str);
|
| 337 |
-
}
|
| 338 |
-
|
| 339 |
-
for (i = 1; i < 6; i++)
|
| 340 |
-
for (j = i; j < 6; j++)
|
| 341 |
-
for (k = j; k < 6; k++) {
|
| 342 |
-
sprintf(str, "K%c%c%cvK", pchr[i], pchr[j], pchr[k]);
|
| 343 |
-
init_tb(str);
|
| 344 |
-
}
|
| 345 |
-
|
| 346 |
-
for (i = 1; i < 6; i++)
|
| 347 |
-
for (j = i; j < 6; j++)
|
| 348 |
-
for (k = i; k < 6; k++)
|
| 349 |
-
for (l = (i == k) ? j : k; l < 6; l++) {
|
| 350 |
-
sprintf(str, "K%c%cvK%c%c", pchr[i], pchr[j], pchr[k], pchr[l]);
|
| 351 |
-
init_tb(str);
|
| 352 |
-
}
|
| 353 |
-
|
| 354 |
-
for (i = 1; i < 6; i++)
|
| 355 |
-
for (j = i; j < 6; j++)
|
| 356 |
-
for (k = j; k < 6; k++)
|
| 357 |
-
for (l = 1; l < 6; l++) {
|
| 358 |
-
sprintf(str, "K%c%c%cvK%c", pchr[i], pchr[j], pchr[k], pchr[l]);
|
| 359 |
-
init_tb(str);
|
| 360 |
-
}
|
| 361 |
-
|
| 362 |
-
for (i = 1; i < 6; i++)
|
| 363 |
-
for (j = i; j < 6; j++)
|
| 364 |
-
for (k = j; k < 6; k++)
|
| 365 |
-
for (l = k; l < 6; l++) {
|
| 366 |
-
sprintf(str, "K%c%c%c%cvK", pchr[i], pchr[j], pchr[k], pchr[l]);
|
| 367 |
-
init_tb(str);
|
| 368 |
-
}
|
| 369 |
-
|
| 370 |
-
printf("info string Found %d tablebases.\n", TBnum_piece + TBnum_pawn);
|
| 371 |
-
}
|
| 372 |
-
|
| 373 |
-
static const signed char offdiag[] = {
|
| 374 |
-
0,-1,-1,-1,-1,-1,-1,-1,
|
| 375 |
-
1, 0,-1,-1,-1,-1,-1,-1,
|
| 376 |
-
1, 1, 0,-1,-1,-1,-1,-1,
|
| 377 |
-
1, 1, 1, 0,-1,-1,-1,-1,
|
| 378 |
-
1, 1, 1, 1, 0,-1,-1,-1,
|
| 379 |
-
1, 1, 1, 1, 1, 0,-1,-1,
|
| 380 |
-
1, 1, 1, 1, 1, 1, 0,-1,
|
| 381 |
-
1, 1, 1, 1, 1, 1, 1, 0
|
| 382 |
-
};
|
| 383 |
-
|
| 384 |
-
static const ubyte triangle[] = {
|
| 385 |
-
6, 0, 1, 2, 2, 1, 0, 6,
|
| 386 |
-
0, 7, 3, 4, 4, 3, 7, 0,
|
| 387 |
-
1, 3, 8, 5, 5, 8, 3, 1,
|
| 388 |
-
2, 4, 5, 9, 9, 5, 4, 2,
|
| 389 |
-
2, 4, 5, 9, 9, 5, 4, 2,
|
| 390 |
-
1, 3, 8, 5, 5, 8, 3, 1,
|
| 391 |
-
0, 7, 3, 4, 4, 3, 7, 0,
|
| 392 |
-
6, 0, 1, 2, 2, 1, 0, 6
|
| 393 |
-
};
|
| 394 |
-
|
| 395 |
-
static const ubyte invtriangle[] = {
|
| 396 |
-
1, 2, 3, 10, 11, 19, 0, 9, 18, 27
|
| 397 |
-
};
|
| 398 |
-
|
| 399 |
-
static const ubyte invdiag[] = {
|
| 400 |
-
0, 9, 18, 27, 36, 45, 54, 63,
|
| 401 |
-
7, 14, 21, 28, 35, 42, 49, 56
|
| 402 |
-
};
|
| 403 |
-
|
| 404 |
-
static const ubyte flipdiag[] = {
|
| 405 |
-
0, 8, 16, 24, 32, 40, 48, 56,
|
| 406 |
-
1, 9, 17, 25, 33, 41, 49, 57,
|
| 407 |
-
2, 10, 18, 26, 34, 42, 50, 58,
|
| 408 |
-
3, 11, 19, 27, 35, 43, 51, 59,
|
| 409 |
-
4, 12, 20, 28, 36, 44, 52, 60,
|
| 410 |
-
5, 13, 21, 29, 37, 45, 53, 61,
|
| 411 |
-
6, 14, 22, 30, 38, 46, 54, 62,
|
| 412 |
-
7, 15, 23, 31, 39, 47, 55, 63
|
| 413 |
-
};
|
| 414 |
-
|
| 415 |
-
static const ubyte lower[] = {
|
| 416 |
-
28, 0, 1, 2, 3, 4, 5, 6,
|
| 417 |
-
0, 29, 7, 8, 9, 10, 11, 12,
|
| 418 |
-
1, 7, 30, 13, 14, 15, 16, 17,
|
| 419 |
-
2, 8, 13, 31, 18, 19, 20, 21,
|
| 420 |
-
3, 9, 14, 18, 32, 22, 23, 24,
|
| 421 |
-
4, 10, 15, 19, 22, 33, 25, 26,
|
| 422 |
-
5, 11, 16, 20, 23, 25, 34, 27,
|
| 423 |
-
6, 12, 17, 21, 24, 26, 27, 35
|
| 424 |
-
};
|
| 425 |
-
|
| 426 |
-
static const ubyte diag[] = {
|
| 427 |
-
0, 0, 0, 0, 0, 0, 0, 8,
|
| 428 |
-
0, 1, 0, 0, 0, 0, 9, 0,
|
| 429 |
-
0, 0, 2, 0, 0, 10, 0, 0,
|
| 430 |
-
0, 0, 0, 3, 11, 0, 0, 0,
|
| 431 |
-
0, 0, 0, 12, 4, 0, 0, 0,
|
| 432 |
-
0, 0, 13, 0, 0, 5, 0, 0,
|
| 433 |
-
0, 14, 0, 0, 0, 0, 6, 0,
|
| 434 |
-
15, 0, 0, 0, 0, 0, 0, 7
|
| 435 |
-
};
|
| 436 |
-
|
| 437 |
-
static const ubyte flap[] = {
|
| 438 |
-
0, 0, 0, 0, 0, 0, 0, 0,
|
| 439 |
-
0, 6, 12, 18, 18, 12, 6, 0,
|
| 440 |
-
1, 7, 13, 19, 19, 13, 7, 1,
|
| 441 |
-
2, 8, 14, 20, 20, 14, 8, 2,
|
| 442 |
-
3, 9, 15, 21, 21, 15, 9, 3,
|
| 443 |
-
4, 10, 16, 22, 22, 16, 10, 4,
|
| 444 |
-
5, 11, 17, 23, 23, 17, 11, 5,
|
| 445 |
-
0, 0, 0, 0, 0, 0, 0, 0
|
| 446 |
-
};
|
| 447 |
-
|
| 448 |
-
static const ubyte ptwist[] = {
|
| 449 |
-
0, 0, 0, 0, 0, 0, 0, 0,
|
| 450 |
-
47, 35, 23, 11, 10, 22, 34, 46,
|
| 451 |
-
45, 33, 21, 9, 8, 20, 32, 44,
|
| 452 |
-
43, 31, 19, 7, 6, 18, 30, 42,
|
| 453 |
-
41, 29, 17, 5, 4, 16, 28, 40,
|
| 454 |
-
39, 27, 15, 3, 2, 14, 26, 38,
|
| 455 |
-
37, 25, 13, 1, 0, 12, 24, 36,
|
| 456 |
-
0, 0, 0, 0, 0, 0, 0, 0
|
| 457 |
-
};
|
| 458 |
-
|
| 459 |
-
static const ubyte invflap[] = {
|
| 460 |
-
8, 16, 24, 32, 40, 48,
|
| 461 |
-
9, 17, 25, 33, 41, 49,
|
| 462 |
-
10, 18, 26, 34, 42, 50,
|
| 463 |
-
11, 19, 27, 35, 43, 51
|
| 464 |
-
};
|
| 465 |
-
|
| 466 |
-
static const ubyte invptwist[] = {
|
| 467 |
-
52, 51, 44, 43, 36, 35, 28, 27, 20, 19, 12, 11,
|
| 468 |
-
53, 50, 45, 42, 37, 34, 29, 26, 21, 18, 13, 10,
|
| 469 |
-
54, 49, 46, 41, 38, 33, 30, 25, 22, 17, 14, 9,
|
| 470 |
-
55, 48, 47, 40, 39, 32, 31, 24, 23, 16, 15, 8
|
| 471 |
-
};
|
| 472 |
-
|
| 473 |
-
static const ubyte file_to_file[] = {
|
| 474 |
-
0, 1, 2, 3, 3, 2, 1, 0
|
| 475 |
-
};
|
| 476 |
-
|
| 477 |
-
static const short KK_idx[10][64] = {
|
| 478 |
-
{ -1, -1, -1, 0, 1, 2, 3, 4,
|
| 479 |
-
-1, -1, -1, 5, 6, 7, 8, 9,
|
| 480 |
-
10, 11, 12, 13, 14, 15, 16, 17,
|
| 481 |
-
18, 19, 20, 21, 22, 23, 24, 25,
|
| 482 |
-
26, 27, 28, 29, 30, 31, 32, 33,
|
| 483 |
-
34, 35, 36, 37, 38, 39, 40, 41,
|
| 484 |
-
42, 43, 44, 45, 46, 47, 48, 49,
|
| 485 |
-
50, 51, 52, 53, 54, 55, 56, 57 },
|
| 486 |
-
{ 58, -1, -1, -1, 59, 60, 61, 62,
|
| 487 |
-
63, -1, -1, -1, 64, 65, 66, 67,
|
| 488 |
-
68, 69, 70, 71, 72, 73, 74, 75,
|
| 489 |
-
76, 77, 78, 79, 80, 81, 82, 83,
|
| 490 |
-
84, 85, 86, 87, 88, 89, 90, 91,
|
| 491 |
-
92, 93, 94, 95, 96, 97, 98, 99,
|
| 492 |
-
100,101,102,103,104,105,106,107,
|
| 493 |
-
108,109,110,111,112,113,114,115},
|
| 494 |
-
{116,117, -1, -1, -1,118,119,120,
|
| 495 |
-
121,122, -1, -1, -1,123,124,125,
|
| 496 |
-
126,127,128,129,130,131,132,133,
|
| 497 |
-
134,135,136,137,138,139,140,141,
|
| 498 |
-
142,143,144,145,146,147,148,149,
|
| 499 |
-
150,151,152,153,154,155,156,157,
|
| 500 |
-
158,159,160,161,162,163,164,165,
|
| 501 |
-
166,167,168,169,170,171,172,173 },
|
| 502 |
-
{174, -1, -1, -1,175,176,177,178,
|
| 503 |
-
179, -1, -1, -1,180,181,182,183,
|
| 504 |
-
184, -1, -1, -1,185,186,187,188,
|
| 505 |
-
189,190,191,192,193,194,195,196,
|
| 506 |
-
197,198,199,200,201,202,203,204,
|
| 507 |
-
205,206,207,208,209,210,211,212,
|
| 508 |
-
213,214,215,216,217,218,219,220,
|
| 509 |
-
221,222,223,224,225,226,227,228 },
|
| 510 |
-
{229,230, -1, -1, -1,231,232,233,
|
| 511 |
-
234,235, -1, -1, -1,236,237,238,
|
| 512 |
-
239,240, -1, -1, -1,241,242,243,
|
| 513 |
-
244,245,246,247,248,249,250,251,
|
| 514 |
-
252,253,254,255,256,257,258,259,
|
| 515 |
-
260,261,262,263,264,265,266,267,
|
| 516 |
-
268,269,270,271,272,273,274,275,
|
| 517 |
-
276,277,278,279,280,281,282,283 },
|
| 518 |
-
{284,285,286,287,288,289,290,291,
|
| 519 |
-
292,293, -1, -1, -1,294,295,296,
|
| 520 |
-
297,298, -1, -1, -1,299,300,301,
|
| 521 |
-
302,303, -1, -1, -1,304,305,306,
|
| 522 |
-
307,308,309,310,311,312,313,314,
|
| 523 |
-
315,316,317,318,319,320,321,322,
|
| 524 |
-
323,324,325,326,327,328,329,330,
|
| 525 |
-
331,332,333,334,335,336,337,338 },
|
| 526 |
-
{ -1, -1,339,340,341,342,343,344,
|
| 527 |
-
-1, -1,345,346,347,348,349,350,
|
| 528 |
-
-1, -1,441,351,352,353,354,355,
|
| 529 |
-
-1, -1, -1,442,356,357,358,359,
|
| 530 |
-
-1, -1, -1, -1,443,360,361,362,
|
| 531 |
-
-1, -1, -1, -1, -1,444,363,364,
|
| 532 |
-
-1, -1, -1, -1, -1, -1,445,365,
|
| 533 |
-
-1, -1, -1, -1, -1, -1, -1,446 },
|
| 534 |
-
{ -1, -1, -1,366,367,368,369,370,
|
| 535 |
-
-1, -1, -1,371,372,373,374,375,
|
| 536 |
-
-1, -1, -1,376,377,378,379,380,
|
| 537 |
-
-1, -1, -1,447,381,382,383,384,
|
| 538 |
-
-1, -1, -1, -1,448,385,386,387,
|
| 539 |
-
-1, -1, -1, -1, -1,449,388,389,
|
| 540 |
-
-1, -1, -1, -1, -1, -1,450,390,
|
| 541 |
-
-1, -1, -1, -1, -1, -1, -1,451 },
|
| 542 |
-
{452,391,392,393,394,395,396,397,
|
| 543 |
-
-1, -1, -1, -1,398,399,400,401,
|
| 544 |
-
-1, -1, -1, -1,402,403,404,405,
|
| 545 |
-
-1, -1, -1, -1,406,407,408,409,
|
| 546 |
-
-1, -1, -1, -1,453,410,411,412,
|
| 547 |
-
-1, -1, -1, -1, -1,454,413,414,
|
| 548 |
-
-1, -1, -1, -1, -1, -1,455,415,
|
| 549 |
-
-1, -1, -1, -1, -1, -1, -1,456 },
|
| 550 |
-
{457,416,417,418,419,420,421,422,
|
| 551 |
-
-1,458,423,424,425,426,427,428,
|
| 552 |
-
-1, -1, -1, -1, -1,429,430,431,
|
| 553 |
-
-1, -1, -1, -1, -1,432,433,434,
|
| 554 |
-
-1, -1, -1, -1, -1,435,436,437,
|
| 555 |
-
-1, -1, -1, -1, -1,459,438,439,
|
| 556 |
-
-1, -1, -1, -1, -1, -1,460,440,
|
| 557 |
-
-1, -1, -1, -1, -1, -1, -1,461 }
|
| 558 |
-
};
|
| 559 |
-
|
| 560 |
-
static int binomial[5][64];
|
| 561 |
-
static int pawnidx[5][24];
|
| 562 |
-
static int pfactor[5][4];
|
| 563 |
-
|
| 564 |
-
static void init_indices(void)
|
| 565 |
-
{
|
| 566 |
-
int i, j, k;
|
| 567 |
-
|
| 568 |
-
// binomial[k-1][n] = Bin(n, k)
|
| 569 |
-
for (i = 0; i < 5; i++)
|
| 570 |
-
for (j = 0; j < 64; j++) {
|
| 571 |
-
int f = j;
|
| 572 |
-
int l = 1;
|
| 573 |
-
for (k = 1; k <= i; k++) {
|
| 574 |
-
f *= (j - k);
|
| 575 |
-
l *= (k + 1);
|
| 576 |
-
}
|
| 577 |
-
binomial[i][j] = f / l;
|
| 578 |
-
}
|
| 579 |
-
|
| 580 |
-
for (i = 0; i < 5; i++) {
|
| 581 |
-
int s = 0;
|
| 582 |
-
for (j = 0; j < 6; j++) {
|
| 583 |
-
pawnidx[i][j] = s;
|
| 584 |
-
s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
|
| 585 |
-
}
|
| 586 |
-
pfactor[i][0] = s;
|
| 587 |
-
s = 0;
|
| 588 |
-
for (; j < 12; j++) {
|
| 589 |
-
pawnidx[i][j] = s;
|
| 590 |
-
s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
|
| 591 |
-
}
|
| 592 |
-
pfactor[i][1] = s;
|
| 593 |
-
s = 0;
|
| 594 |
-
for (; j < 18; j++) {
|
| 595 |
-
pawnidx[i][j] = s;
|
| 596 |
-
s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
|
| 597 |
-
}
|
| 598 |
-
pfactor[i][2] = s;
|
| 599 |
-
s = 0;
|
| 600 |
-
for (; j < 24; j++) {
|
| 601 |
-
pawnidx[i][j] = s;
|
| 602 |
-
s += (i == 0) ? 1 : binomial[i - 1][ptwist[invflap[j]]];
|
| 603 |
-
}
|
| 604 |
-
pfactor[i][3] = s;
|
| 605 |
-
}
|
| 606 |
-
}
|
| 607 |
-
|
| 608 |
-
static uint64 encode_piece(struct TBEntry_piece *ptr, ubyte *norm, int *pos, int *factor)
|
| 609 |
-
{
|
| 610 |
-
uint64 idx;
|
| 611 |
-
int i, j, k, m, l, p;
|
| 612 |
-
int n = ptr->num;
|
| 613 |
-
|
| 614 |
-
if (pos[0] & 0x04) {
|
| 615 |
-
for (i = 0; i < n; i++)
|
| 616 |
-
pos[i] ^= 0x07;
|
| 617 |
-
}
|
| 618 |
-
if (pos[0] & 0x20) {
|
| 619 |
-
for (i = 0; i < n; i++)
|
| 620 |
-
pos[i] ^= 0x38;
|
| 621 |
-
}
|
| 622 |
-
|
| 623 |
-
for (i = 0; i < n; i++)
|
| 624 |
-
if (offdiag[pos[i]]) break;
|
| 625 |
-
if (i < (ptr->enc_type == 0 ? 3 : 2) && offdiag[pos[i]] > 0)
|
| 626 |
-
for (i = 0; i < n; i++)
|
| 627 |
-
pos[i] = flipdiag[pos[i]];
|
| 628 |
-
|
| 629 |
-
switch (ptr->enc_type) {
|
| 630 |
-
|
| 631 |
-
case 0: /* 111 */
|
| 632 |
-
i = (pos[1] > pos[0]);
|
| 633 |
-
j = (pos[2] > pos[0]) + (pos[2] > pos[1]);
|
| 634 |
-
|
| 635 |
-
if (offdiag[pos[0]])
|
| 636 |
-
idx = triangle[pos[0]] * 63*62 + (pos[1] - i) * 62 + (pos[2] - j);
|
| 637 |
-
else if (offdiag[pos[1]])
|
| 638 |
-
idx = 6*63*62 + diag[pos[0]] * 28*62 + lower[pos[1]] * 62 + pos[2] - j;
|
| 639 |
-
else if (offdiag[pos[2]])
|
| 640 |
-
idx = 6*63*62 + 4*28*62 + (diag[pos[0]]) * 7*28 + (diag[pos[1]] - i) * 28 + lower[pos[2]];
|
| 641 |
-
else
|
| 642 |
-
idx = 6*63*62 + 4*28*62 + 4*7*28 + (diag[pos[0]] * 7*6) + (diag[pos[1]] - i) * 6 + (diag[pos[2]] - j);
|
| 643 |
-
i = 3;
|
| 644 |
-
break;
|
| 645 |
-
|
| 646 |
-
case 1: /* K3 */
|
| 647 |
-
j = (pos[2] > pos[0]) + (pos[2] > pos[1]);
|
| 648 |
-
|
| 649 |
-
idx = KK_idx[triangle[pos[0]]][pos[1]];
|
| 650 |
-
if (idx < 441)
|
| 651 |
-
idx = idx + 441 * (pos[2] - j);
|
| 652 |
-
else {
|
| 653 |
-
idx = 441*62 + (idx - 441) + 21 * lower[pos[2]];
|
| 654 |
-
if (!offdiag[pos[2]])
|
| 655 |
-
idx -= j * 21;
|
| 656 |
-
}
|
| 657 |
-
i = 3;
|
| 658 |
-
break;
|
| 659 |
-
|
| 660 |
-
default: /* K2 */
|
| 661 |
-
idx = KK_idx[triangle[pos[0]]][pos[1]];
|
| 662 |
-
i = 2;
|
| 663 |
-
break;
|
| 664 |
-
}
|
| 665 |
-
idx *= factor[0];
|
| 666 |
-
|
| 667 |
-
for (; i < n;) {
|
| 668 |
-
int t = norm[i];
|
| 669 |
-
for (j = i; j < i + t; j++)
|
| 670 |
-
for (k = j + 1; k < i + t; k++)
|
| 671 |
-
if (pos[j] > pos[k]) Swap(pos[j], pos[k]);
|
| 672 |
-
int s = 0;
|
| 673 |
-
for (m = i; m < i + t; m++) {
|
| 674 |
-
p = pos[m];
|
| 675 |
-
for (l = 0, j = 0; l < i; l++)
|
| 676 |
-
j += (p > pos[l]);
|
| 677 |
-
s += binomial[m - i][p - j];
|
| 678 |
-
}
|
| 679 |
-
idx += ((uint64)s) * ((uint64)factor[i]);
|
| 680 |
-
i += t;
|
| 681 |
-
}
|
| 682 |
-
|
| 683 |
-
return idx;
|
| 684 |
-
}
|
| 685 |
-
|
| 686 |
-
// determine file of leftmost pawn and sort pawns
|
| 687 |
-
static int pawn_file(struct TBEntry_pawn *ptr, int *pos)
|
| 688 |
-
{
|
| 689 |
-
int i;
|
| 690 |
-
|
| 691 |
-
for (i = 1; i < ptr->pawns[0]; i++)
|
| 692 |
-
if (flap[pos[0]] > flap[pos[i]])
|
| 693 |
-
Swap(pos[0], pos[i]);
|
| 694 |
-
|
| 695 |
-
return file_to_file[pos[0] & 0x07];
|
| 696 |
-
}
|
| 697 |
-
|
| 698 |
-
static uint64 encode_pawn(struct TBEntry_pawn *ptr, ubyte *norm, int *pos, int *factor)
|
| 699 |
-
{
|
| 700 |
-
uint64 idx;
|
| 701 |
-
int i, j, k, m, s, t;
|
| 702 |
-
int n = ptr->num;
|
| 703 |
-
|
| 704 |
-
if (pos[0] & 0x04)
|
| 705 |
-
for (i = 0; i < n; i++)
|
| 706 |
-
pos[i] ^= 0x07;
|
| 707 |
-
|
| 708 |
-
for (i = 1; i < ptr->pawns[0]; i++)
|
| 709 |
-
for (j = i + 1; j < ptr->pawns[0]; j++)
|
| 710 |
-
if (ptwist[pos[i]] < ptwist[pos[j]])
|
| 711 |
-
Swap(pos[i], pos[j]);
|
| 712 |
-
|
| 713 |
-
t = ptr->pawns[0] - 1;
|
| 714 |
-
idx = pawnidx[t][flap[pos[0]]];
|
| 715 |
-
for (i = t; i > 0; i--)
|
| 716 |
-
idx += binomial[t - i][ptwist[pos[i]]];
|
| 717 |
-
idx *= factor[0];
|
| 718 |
-
|
| 719 |
-
// remaining pawns
|
| 720 |
-
i = ptr->pawns[0];
|
| 721 |
-
t = i + ptr->pawns[1];
|
| 722 |
-
if (t > i) {
|
| 723 |
-
for (j = i; j < t; j++)
|
| 724 |
-
for (k = j + 1; k < t; k++)
|
| 725 |
-
if (pos[j] > pos[k]) Swap(pos[j], pos[k]);
|
| 726 |
-
s = 0;
|
| 727 |
-
for (m = i; m < t; m++) {
|
| 728 |
-
int p = pos[m];
|
| 729 |
-
for (k = 0, j = 0; k < i; k++)
|
| 730 |
-
j += (p > pos[k]);
|
| 731 |
-
s += binomial[m - i][p - j - 8];
|
| 732 |
-
}
|
| 733 |
-
idx += ((uint64)s) * ((uint64)factor[i]);
|
| 734 |
-
i = t;
|
| 735 |
-
}
|
| 736 |
-
|
| 737 |
-
for (; i < n;) {
|
| 738 |
-
t = norm[i];
|
| 739 |
-
for (j = i; j < i + t; j++)
|
| 740 |
-
for (k = j + 1; k < i + t; k++)
|
| 741 |
-
if (pos[j] > pos[k]) Swap(pos[j], pos[k]);
|
| 742 |
-
s = 0;
|
| 743 |
-
for (m = i; m < i + t; m++) {
|
| 744 |
-
int p = pos[m];
|
| 745 |
-
for (k = 0, j = 0; k < i; k++)
|
| 746 |
-
j += (p > pos[k]);
|
| 747 |
-
s += binomial[m - i][p - j];
|
| 748 |
-
}
|
| 749 |
-
idx += ((uint64)s) * ((uint64)factor[i]);
|
| 750 |
-
i += t;
|
| 751 |
-
}
|
| 752 |
-
|
| 753 |
-
return idx;
|
| 754 |
-
}
|
| 755 |
-
|
| 756 |
-
// place k like pieces on n squares
|
| 757 |
-
static int subfactor(int k, int n)
|
| 758 |
-
{
|
| 759 |
-
int i, f, l;
|
| 760 |
-
|
| 761 |
-
f = n;
|
| 762 |
-
l = 1;
|
| 763 |
-
for (i = 1; i < k; i++) {
|
| 764 |
-
f *= n - i;
|
| 765 |
-
l *= i + 1;
|
| 766 |
-
}
|
| 767 |
-
|
| 768 |
-
return f / l;
|
| 769 |
-
}
|
| 770 |
-
|
| 771 |
-
static uint64 calc_factors_piece(int *factor, int num, int order, ubyte *norm, ubyte enc_type)
|
| 772 |
-
{
|
| 773 |
-
int i, k, n;
|
| 774 |
-
uint64 f;
|
| 775 |
-
static int pivfac[] = { 31332, 28056, 462 };
|
| 776 |
-
|
| 777 |
-
n = 64 - norm[0];
|
| 778 |
-
|
| 779 |
-
f = 1;
|
| 780 |
-
for (i = norm[0], k = 0; i < num || k == order; k++) {
|
| 781 |
-
if (k == order) {
|
| 782 |
-
factor[0] = static_cast<int>(f);
|
| 783 |
-
f *= pivfac[enc_type];
|
| 784 |
-
} else {
|
| 785 |
-
factor[i] = static_cast<int>(f);
|
| 786 |
-
f *= subfactor(norm[i], n);
|
| 787 |
-
n -= norm[i];
|
| 788 |
-
i += norm[i];
|
| 789 |
-
}
|
| 790 |
-
}
|
| 791 |
-
|
| 792 |
-
return f;
|
| 793 |
-
}
|
| 794 |
-
|
| 795 |
-
static uint64 calc_factors_pawn(int *factor, int num, int order, int order2, ubyte *norm, int file)
|
| 796 |
-
{
|
| 797 |
-
int i, k, n;
|
| 798 |
-
uint64 f;
|
| 799 |
-
|
| 800 |
-
i = norm[0];
|
| 801 |
-
if (order2 < 0x0f) i += norm[i];
|
| 802 |
-
n = 64 - i;
|
| 803 |
-
|
| 804 |
-
f = 1;
|
| 805 |
-
for (k = 0; i < num || k == order || k == order2; k++) {
|
| 806 |
-
if (k == order) {
|
| 807 |
-
factor[0] = static_cast<int>(f);
|
| 808 |
-
f *= pfactor[norm[0] - 1][file];
|
| 809 |
-
} else if (k == order2) {
|
| 810 |
-
factor[norm[0]] = static_cast<int>(f);
|
| 811 |
-
f *= subfactor(norm[norm[0]], 48 - norm[0]);
|
| 812 |
-
} else {
|
| 813 |
-
factor[i] = static_cast<int>(f);
|
| 814 |
-
f *= subfactor(norm[i], n);
|
| 815 |
-
n -= norm[i];
|
| 816 |
-
i += norm[i];
|
| 817 |
-
}
|
| 818 |
-
}
|
| 819 |
-
|
| 820 |
-
return f;
|
| 821 |
-
}
|
| 822 |
-
|
| 823 |
-
static void set_norm_piece(struct TBEntry_piece *ptr, ubyte *norm, ubyte *pieces)
|
| 824 |
-
{
|
| 825 |
-
int i, j;
|
| 826 |
-
|
| 827 |
-
for (i = 0; i < ptr->num; i++)
|
| 828 |
-
norm[i] = 0;
|
| 829 |
-
|
| 830 |
-
switch (ptr->enc_type) {
|
| 831 |
-
case 0:
|
| 832 |
-
norm[0] = 3;
|
| 833 |
-
break;
|
| 834 |
-
case 2:
|
| 835 |
-
norm[0] = 2;
|
| 836 |
-
break;
|
| 837 |
-
default:
|
| 838 |
-
norm[0] = ubyte(ptr->enc_type - 1);
|
| 839 |
-
break;
|
| 840 |
-
}
|
| 841 |
-
|
| 842 |
-
for (i = norm[0]; i < ptr->num; i += norm[i])
|
| 843 |
-
for (j = i; j < ptr->num && pieces[j] == pieces[i]; j++)
|
| 844 |
-
norm[i]++;
|
| 845 |
-
}
|
| 846 |
-
|
| 847 |
-
static void set_norm_pawn(struct TBEntry_pawn *ptr, ubyte *norm, ubyte *pieces)
|
| 848 |
-
{
|
| 849 |
-
int i, j;
|
| 850 |
-
|
| 851 |
-
for (i = 0; i < ptr->num; i++)
|
| 852 |
-
norm[i] = 0;
|
| 853 |
-
|
| 854 |
-
norm[0] = ptr->pawns[0];
|
| 855 |
-
if (ptr->pawns[1]) norm[ptr->pawns[0]] = ptr->pawns[1];
|
| 856 |
-
|
| 857 |
-
for (i = ptr->pawns[0] + ptr->pawns[1]; i < ptr->num; i += norm[i])
|
| 858 |
-
for (j = i; j < ptr->num && pieces[j] == pieces[i]; j++)
|
| 859 |
-
norm[i]++;
|
| 860 |
-
}
|
| 861 |
-
|
| 862 |
-
static void setup_pieces_piece(struct TBEntry_piece *ptr, unsigned char *data, uint64 *tb_size)
|
| 863 |
-
{
|
| 864 |
-
int i;
|
| 865 |
-
int order;
|
| 866 |
-
|
| 867 |
-
for (i = 0; i < ptr->num; i++)
|
| 868 |
-
ptr->pieces[0][i] = ubyte(data[i + 1] & 0x0f);
|
| 869 |
-
order = data[0] & 0x0f;
|
| 870 |
-
set_norm_piece(ptr, ptr->norm[0], ptr->pieces[0]);
|
| 871 |
-
tb_size[0] = calc_factors_piece(ptr->factor[0], ptr->num, order, ptr->norm[0], ptr->enc_type);
|
| 872 |
-
|
| 873 |
-
for (i = 0; i < ptr->num; i++)
|
| 874 |
-
ptr->pieces[1][i] = ubyte(data[i + 1] >> 4);
|
| 875 |
-
order = data[0] >> 4;
|
| 876 |
-
set_norm_piece(ptr, ptr->norm[1], ptr->pieces[1]);
|
| 877 |
-
tb_size[1] = calc_factors_piece(ptr->factor[1], ptr->num, order, ptr->norm[1], ptr->enc_type);
|
| 878 |
-
}
|
| 879 |
-
|
| 880 |
-
static void setup_pieces_piece_dtz(struct DTZEntry_piece *ptr, unsigned char *data, uint64 *tb_size)
|
| 881 |
-
{
|
| 882 |
-
int i;
|
| 883 |
-
int order;
|
| 884 |
-
|
| 885 |
-
for (i = 0; i < ptr->num; i++)
|
| 886 |
-
ptr->pieces[i] = ubyte(data[i + 1] & 0x0f);
|
| 887 |
-
order = data[0] & 0x0f;
|
| 888 |
-
set_norm_piece((struct TBEntry_piece *)ptr, ptr->norm, ptr->pieces);
|
| 889 |
-
tb_size[0] = calc_factors_piece(ptr->factor, ptr->num, order, ptr->norm, ptr->enc_type);
|
| 890 |
-
}
|
| 891 |
-
|
| 892 |
-
static void setup_pieces_pawn(struct TBEntry_pawn *ptr, unsigned char *data, uint64 *tb_size, int f)
|
| 893 |
-
{
|
| 894 |
-
int i, j;
|
| 895 |
-
int order, order2;
|
| 896 |
-
|
| 897 |
-
j = 1 + (ptr->pawns[1] > 0);
|
| 898 |
-
order = data[0] & 0x0f;
|
| 899 |
-
order2 = ptr->pawns[1] ? (data[1] & 0x0f) : 0x0f;
|
| 900 |
-
for (i = 0; i < ptr->num; i++)
|
| 901 |
-
ptr->file[f].pieces[0][i] = ubyte(data[i + j] & 0x0f);
|
| 902 |
-
set_norm_pawn(ptr, ptr->file[f].norm[0], ptr->file[f].pieces[0]);
|
| 903 |
-
tb_size[0] = calc_factors_pawn(ptr->file[f].factor[0], ptr->num, order, order2, ptr->file[f].norm[0], f);
|
| 904 |
-
|
| 905 |
-
order = data[0] >> 4;
|
| 906 |
-
order2 = ptr->pawns[1] ? (data[1] >> 4) : 0x0f;
|
| 907 |
-
for (i = 0; i < ptr->num; i++)
|
| 908 |
-
ptr->file[f].pieces[1][i] = ubyte(data[i + j] >> 4);
|
| 909 |
-
set_norm_pawn(ptr, ptr->file[f].norm[1], ptr->file[f].pieces[1]);
|
| 910 |
-
tb_size[1] = calc_factors_pawn(ptr->file[f].factor[1], ptr->num, order, order2, ptr->file[f].norm[1], f);
|
| 911 |
-
}
|
| 912 |
-
|
| 913 |
-
static void setup_pieces_pawn_dtz(struct DTZEntry_pawn *ptr, unsigned char *data, uint64 *tb_size, int f)
|
| 914 |
-
{
|
| 915 |
-
int i, j;
|
| 916 |
-
int order, order2;
|
| 917 |
-
|
| 918 |
-
j = 1 + (ptr->pawns[1] > 0);
|
| 919 |
-
order = data[0] & 0x0f;
|
| 920 |
-
order2 = ptr->pawns[1] ? (data[1] & 0x0f) : 0x0f;
|
| 921 |
-
for (i = 0; i < ptr->num; i++)
|
| 922 |
-
ptr->file[f].pieces[i] = ubyte(data[i + j] & 0x0f);
|
| 923 |
-
set_norm_pawn((struct TBEntry_pawn *)ptr, ptr->file[f].norm, ptr->file[f].pieces);
|
| 924 |
-
tb_size[0] = calc_factors_pawn(ptr->file[f].factor, ptr->num, order, order2, ptr->file[f].norm, f);
|
| 925 |
-
}
|
| 926 |
-
|
| 927 |
-
static void calc_symlen(struct PairsData *d, int s, char *tmp)
|
| 928 |
-
{
|
| 929 |
-
int s1, s2;
|
| 930 |
-
|
| 931 |
-
ubyte* w = d->sympat + 3 * s;
|
| 932 |
-
s2 = (w[2] << 4) | (w[1] >> 4);
|
| 933 |
-
if (s2 == 0x0fff)
|
| 934 |
-
d->symlen[s] = 0;
|
| 935 |
-
else {
|
| 936 |
-
s1 = ((w[1] & 0xf) << 8) | w[0];
|
| 937 |
-
if (!tmp[s1]) calc_symlen(d, s1, tmp);
|
| 938 |
-
if (!tmp[s2]) calc_symlen(d, s2, tmp);
|
| 939 |
-
d->symlen[s] = ubyte(d->symlen[s1] + d->symlen[s2] + 1);
|
| 940 |
-
}
|
| 941 |
-
tmp[s] = 1;
|
| 942 |
-
}
|
| 943 |
-
|
| 944 |
-
ushort ReadUshort(ubyte* d) {
|
| 945 |
-
return ushort(d[0] | (d[1] << 8));
|
| 946 |
-
}
|
| 947 |
-
|
| 948 |
-
uint32 ReadUint32(ubyte* d) {
|
| 949 |
-
return d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
|
| 950 |
-
}
|
| 951 |
-
|
| 952 |
-
static struct PairsData *setup_pairs(unsigned char *data, uint64 tb_size, uint64 *size, unsigned char **next, ubyte *flags, int wdl)
|
| 953 |
-
{
|
| 954 |
-
struct PairsData *d;
|
| 955 |
-
int i;
|
| 956 |
-
|
| 957 |
-
*flags = data[0];
|
| 958 |
-
if (data[0] & 0x80) {
|
| 959 |
-
d = (struct PairsData *)malloc(sizeof(struct PairsData));
|
| 960 |
-
d->idxbits = 0;
|
| 961 |
-
if (wdl)
|
| 962 |
-
d->min_len = data[1];
|
| 963 |
-
else
|
| 964 |
-
d->min_len = 0;
|
| 965 |
-
*next = data + 2;
|
| 966 |
-
size[0] = size[1] = size[2] = 0;
|
| 967 |
-
return d;
|
| 968 |
-
}
|
| 969 |
-
|
| 970 |
-
int blocksize = data[1];
|
| 971 |
-
int idxbits = data[2];
|
| 972 |
-
int real_num_blocks = ReadUint32(&data[4]);
|
| 973 |
-
int num_blocks = real_num_blocks + *(ubyte *)(&data[3]);
|
| 974 |
-
int max_len = data[8];
|
| 975 |
-
int min_len = data[9];
|
| 976 |
-
int h = max_len - min_len + 1;
|
| 977 |
-
int num_syms = ReadUshort(&data[10 + 2 * h]);
|
| 978 |
-
d = (struct PairsData *)malloc(sizeof(struct PairsData) + (h - 1) * sizeof(base_t) + num_syms);
|
| 979 |
-
d->blocksize = blocksize;
|
| 980 |
-
d->idxbits = idxbits;
|
| 981 |
-
d->offset = (ushort*)(&data[10]);
|
| 982 |
-
d->symlen = ((ubyte *)d) + sizeof(struct PairsData) + (h - 1) * sizeof(base_t);
|
| 983 |
-
d->sympat = &data[12 + 2 * h];
|
| 984 |
-
d->min_len = min_len;
|
| 985 |
-
*next = &data[12 + 2 * h + 3 * num_syms + (num_syms & 1)];
|
| 986 |
-
|
| 987 |
-
uint64 num_indices = (tb_size + (1ULL << idxbits) - 1) >> idxbits;
|
| 988 |
-
size[0] = 6ULL * num_indices;
|
| 989 |
-
size[1] = 2ULL * num_blocks;
|
| 990 |
-
size[2] = (1ULL << blocksize) * real_num_blocks;
|
| 991 |
-
|
| 992 |
-
// char tmp[num_syms];
|
| 993 |
-
char tmp[4096];
|
| 994 |
-
for (i = 0; i < num_syms; i++)
|
| 995 |
-
tmp[i] = 0;
|
| 996 |
-
for (i = 0; i < num_syms; i++)
|
| 997 |
-
if (!tmp[i])
|
| 998 |
-
calc_symlen(d, i, tmp);
|
| 999 |
-
|
| 1000 |
-
d->base[h - 1] = 0;
|
| 1001 |
-
for (i = h - 2; i >= 0; i--)
|
| 1002 |
-
d->base[i] = (d->base[i + 1] + ReadUshort((ubyte*)(d->offset + i)) - ReadUshort((ubyte*)(d->offset + i + 1))) / 2;
|
| 1003 |
-
for (i = 0; i < h; i++)
|
| 1004 |
-
d->base[i] <<= 64 - (min_len + i);
|
| 1005 |
-
|
| 1006 |
-
d->offset -= d->min_len;
|
| 1007 |
-
|
| 1008 |
-
return d;
|
| 1009 |
-
}
|
| 1010 |
-
|
| 1011 |
-
static int init_table_wdl(struct TBEntry *entry, char *str)
|
| 1012 |
-
{
|
| 1013 |
-
ubyte *next;
|
| 1014 |
-
int f, s;
|
| 1015 |
-
uint64 tb_size[8];
|
| 1016 |
-
uint64 size[8 * 3];
|
| 1017 |
-
ubyte flags;
|
| 1018 |
-
|
| 1019 |
-
// first mmap the table into memory
|
| 1020 |
-
|
| 1021 |
-
entry->data = map_file(str, WDLSUFFIX, &entry->mapping);
|
| 1022 |
-
if (!entry->data) {
|
| 1023 |
-
printf("Could not find %s" WDLSUFFIX, str);
|
| 1024 |
-
return 0;
|
| 1025 |
-
}
|
| 1026 |
-
|
| 1027 |
-
ubyte *data = (ubyte *)entry->data;
|
| 1028 |
-
if (data[0] != WDL_MAGIC[0] ||
|
| 1029 |
-
data[1] != WDL_MAGIC[1] ||
|
| 1030 |
-
data[2] != WDL_MAGIC[2] ||
|
| 1031 |
-
data[3] != WDL_MAGIC[3]) {
|
| 1032 |
-
printf("Corrupted table.\n");
|
| 1033 |
-
unmap_file(entry->data, entry->mapping);
|
| 1034 |
-
entry->data = 0;
|
| 1035 |
-
return 0;
|
| 1036 |
-
}
|
| 1037 |
-
|
| 1038 |
-
int split = data[4] & 0x01;
|
| 1039 |
-
int files = data[4] & 0x02 ? 4 : 1;
|
| 1040 |
-
|
| 1041 |
-
data += 5;
|
| 1042 |
-
|
| 1043 |
-
if (!entry->has_pawns) {
|
| 1044 |
-
struct TBEntry_piece *ptr = (struct TBEntry_piece *)entry;
|
| 1045 |
-
setup_pieces_piece(ptr, data, &tb_size[0]);
|
| 1046 |
-
data += ptr->num + 1;
|
| 1047 |
-
data += ((uintptr_t)data) & 0x01;
|
| 1048 |
-
|
| 1049 |
-
ptr->precomp[0] = setup_pairs(data, tb_size[0], &size[0], &next, &flags, 1);
|
| 1050 |
-
data = next;
|
| 1051 |
-
if (split) {
|
| 1052 |
-
ptr->precomp[1] = setup_pairs(data, tb_size[1], &size[3], &next, &flags, 1);
|
| 1053 |
-
data = next;
|
| 1054 |
-
} else
|
| 1055 |
-
ptr->precomp[1] = NULL;
|
| 1056 |
-
|
| 1057 |
-
ptr->precomp[0]->indextable = (char *)data;
|
| 1058 |
-
data += size[0];
|
| 1059 |
-
if (split) {
|
| 1060 |
-
ptr->precomp[1]->indextable = (char *)data;
|
| 1061 |
-
data += size[3];
|
| 1062 |
-
}
|
| 1063 |
-
|
| 1064 |
-
ptr->precomp[0]->sizetable = (ushort *)data;
|
| 1065 |
-
data += size[1];
|
| 1066 |
-
if (split) {
|
| 1067 |
-
ptr->precomp[1]->sizetable = (ushort *)data;
|
| 1068 |
-
data += size[4];
|
| 1069 |
-
}
|
| 1070 |
-
|
| 1071 |
-
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
| 1072 |
-
ptr->precomp[0]->data = data;
|
| 1073 |
-
data += size[2];
|
| 1074 |
-
if (split) {
|
| 1075 |
-
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
| 1076 |
-
ptr->precomp[1]->data = data;
|
| 1077 |
-
}
|
| 1078 |
-
} else {
|
| 1079 |
-
struct TBEntry_pawn *ptr = (struct TBEntry_pawn *)entry;
|
| 1080 |
-
s = 1 + (ptr->pawns[1] > 0);
|
| 1081 |
-
for (f = 0; f < 4; f++) {
|
| 1082 |
-
setup_pieces_pawn((struct TBEntry_pawn *)ptr, data, &tb_size[2 * f], f);
|
| 1083 |
-
data += ptr->num + s;
|
| 1084 |
-
}
|
| 1085 |
-
data += ((uintptr_t)data) & 0x01;
|
| 1086 |
-
|
| 1087 |
-
for (f = 0; f < files; f++) {
|
| 1088 |
-
ptr->file[f].precomp[0] = setup_pairs(data, tb_size[2 * f], &size[6 * f], &next, &flags, 1);
|
| 1089 |
-
data = next;
|
| 1090 |
-
if (split) {
|
| 1091 |
-
ptr->file[f].precomp[1] = setup_pairs(data, tb_size[2 * f + 1], &size[6 * f + 3], &next, &flags, 1);
|
| 1092 |
-
data = next;
|
| 1093 |
-
} else
|
| 1094 |
-
ptr->file[f].precomp[1] = NULL;
|
| 1095 |
-
}
|
| 1096 |
-
|
| 1097 |
-
for (f = 0; f < files; f++) {
|
| 1098 |
-
ptr->file[f].precomp[0]->indextable = (char *)data;
|
| 1099 |
-
data += size[6 * f];
|
| 1100 |
-
if (split) {
|
| 1101 |
-
ptr->file[f].precomp[1]->indextable = (char *)data;
|
| 1102 |
-
data += size[6 * f + 3];
|
| 1103 |
-
}
|
| 1104 |
-
}
|
| 1105 |
-
|
| 1106 |
-
for (f = 0; f < files; f++) {
|
| 1107 |
-
ptr->file[f].precomp[0]->sizetable = (ushort *)data;
|
| 1108 |
-
data += size[6 * f + 1];
|
| 1109 |
-
if (split) {
|
| 1110 |
-
ptr->file[f].precomp[1]->sizetable = (ushort *)data;
|
| 1111 |
-
data += size[6 * f + 4];
|
| 1112 |
-
}
|
| 1113 |
-
}
|
| 1114 |
-
|
| 1115 |
-
for (f = 0; f < files; f++) {
|
| 1116 |
-
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
| 1117 |
-
ptr->file[f].precomp[0]->data = data;
|
| 1118 |
-
data += size[6 * f + 2];
|
| 1119 |
-
if (split) {
|
| 1120 |
-
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
| 1121 |
-
ptr->file[f].precomp[1]->data = data;
|
| 1122 |
-
data += size[6 * f + 5];
|
| 1123 |
-
}
|
| 1124 |
-
}
|
| 1125 |
-
}
|
| 1126 |
-
|
| 1127 |
-
return 1;
|
| 1128 |
-
}
|
| 1129 |
-
|
| 1130 |
-
static int init_table_dtz(struct TBEntry *entry)
|
| 1131 |
-
{
|
| 1132 |
-
ubyte *data = (ubyte *)entry->data;
|
| 1133 |
-
ubyte *next;
|
| 1134 |
-
int f, s;
|
| 1135 |
-
uint64 tb_size[4];
|
| 1136 |
-
uint64 size[4 * 3];
|
| 1137 |
-
|
| 1138 |
-
if (!data)
|
| 1139 |
-
return 0;
|
| 1140 |
-
|
| 1141 |
-
if (data[0] != DTZ_MAGIC[0] ||
|
| 1142 |
-
data[1] != DTZ_MAGIC[1] ||
|
| 1143 |
-
data[2] != DTZ_MAGIC[2] ||
|
| 1144 |
-
data[3] != DTZ_MAGIC[3]) {
|
| 1145 |
-
printf("Corrupted table.\n");
|
| 1146 |
-
return 0;
|
| 1147 |
-
}
|
| 1148 |
-
|
| 1149 |
-
int files = data[4] & 0x02 ? 4 : 1;
|
| 1150 |
-
|
| 1151 |
-
data += 5;
|
| 1152 |
-
|
| 1153 |
-
if (!entry->has_pawns) {
|
| 1154 |
-
struct DTZEntry_piece *ptr = (struct DTZEntry_piece *)entry;
|
| 1155 |
-
setup_pieces_piece_dtz(ptr, data, &tb_size[0]);
|
| 1156 |
-
data += ptr->num + 1;
|
| 1157 |
-
data += ((uintptr_t)data) & 0x01;
|
| 1158 |
-
|
| 1159 |
-
ptr->precomp = setup_pairs(data, tb_size[0], &size[0], &next, &(ptr->flags), 0);
|
| 1160 |
-
data = next;
|
| 1161 |
-
|
| 1162 |
-
ptr->map = data;
|
| 1163 |
-
if (ptr->flags & 2) {
|
| 1164 |
-
int i;
|
| 1165 |
-
for (i = 0; i < 4; i++) {
|
| 1166 |
-
ptr->map_idx[i] = static_cast<ushort>(data + 1 - ptr->map);
|
| 1167 |
-
data += 1 + data[0];
|
| 1168 |
-
}
|
| 1169 |
-
data += ((uintptr_t)data) & 0x01;
|
| 1170 |
-
}
|
| 1171 |
-
|
| 1172 |
-
ptr->precomp->indextable = (char *)data;
|
| 1173 |
-
data += size[0];
|
| 1174 |
-
|
| 1175 |
-
ptr->precomp->sizetable = (ushort *)data;
|
| 1176 |
-
data += size[1];
|
| 1177 |
-
|
| 1178 |
-
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
| 1179 |
-
ptr->precomp->data = data;
|
| 1180 |
-
data += size[2];
|
| 1181 |
-
} else {
|
| 1182 |
-
struct DTZEntry_pawn *ptr = (struct DTZEntry_pawn *)entry;
|
| 1183 |
-
s = 1 + (ptr->pawns[1] > 0);
|
| 1184 |
-
for (f = 0; f < 4; f++) {
|
| 1185 |
-
setup_pieces_pawn_dtz(ptr, data, &tb_size[f], f);
|
| 1186 |
-
data += ptr->num + s;
|
| 1187 |
-
}
|
| 1188 |
-
data += ((uintptr_t)data) & 0x01;
|
| 1189 |
-
|
| 1190 |
-
for (f = 0; f < files; f++) {
|
| 1191 |
-
ptr->file[f].precomp = setup_pairs(data, tb_size[f], &size[3 * f], &next, &(ptr->flags[f]), 0);
|
| 1192 |
-
data = next;
|
| 1193 |
-
}
|
| 1194 |
-
|
| 1195 |
-
ptr->map = data;
|
| 1196 |
-
for (f = 0; f < files; f++) {
|
| 1197 |
-
if (ptr->flags[f] & 2) {
|
| 1198 |
-
int i;
|
| 1199 |
-
for (i = 0; i < 4; i++) {
|
| 1200 |
-
ptr->map_idx[f][i] = static_cast<ushort>(data + 1 - ptr->map);
|
| 1201 |
-
data += 1 + data[0];
|
| 1202 |
-
}
|
| 1203 |
-
}
|
| 1204 |
-
}
|
| 1205 |
-
data += ((uintptr_t)data) & 0x01;
|
| 1206 |
-
|
| 1207 |
-
for (f = 0; f < files; f++) {
|
| 1208 |
-
ptr->file[f].precomp->indextable = (char *)data;
|
| 1209 |
-
data += size[3 * f];
|
| 1210 |
-
}
|
| 1211 |
-
|
| 1212 |
-
for (f = 0; f < files; f++) {
|
| 1213 |
-
ptr->file[f].precomp->sizetable = (ushort *)data;
|
| 1214 |
-
data += size[3 * f + 1];
|
| 1215 |
-
}
|
| 1216 |
-
|
| 1217 |
-
for (f = 0; f < files; f++) {
|
| 1218 |
-
data = (ubyte *)((((uintptr_t)data) + 0x3f) & ~0x3f);
|
| 1219 |
-
ptr->file[f].precomp->data = data;
|
| 1220 |
-
data += size[3 * f + 2];
|
| 1221 |
-
}
|
| 1222 |
-
}
|
| 1223 |
-
|
| 1224 |
-
return 1;
|
| 1225 |
-
}
|
| 1226 |
-
|
| 1227 |
-
template<bool LittleEndian>
|
| 1228 |
-
static ubyte decompress_pairs(struct PairsData *d, uint64 idx)
|
| 1229 |
-
{
|
| 1230 |
-
if (!d->idxbits)
|
| 1231 |
-
return ubyte(d->min_len);
|
| 1232 |
-
|
| 1233 |
-
uint32 mainidx = static_cast<uint32>(idx >> d->idxbits);
|
| 1234 |
-
int litidx = (idx & ((1ULL << d->idxbits) - 1)) - (1ULL << (d->idxbits - 1));
|
| 1235 |
-
uint32 block = *(uint32 *)(d->indextable + 6 * mainidx);
|
| 1236 |
-
if (!LittleEndian)
|
| 1237 |
-
block = BSWAP32(block);
|
| 1238 |
-
|
| 1239 |
-
ushort idxOffset = *(ushort *)(d->indextable + 6 * mainidx + 4);
|
| 1240 |
-
if (!LittleEndian)
|
| 1241 |
-
idxOffset = ushort((idxOffset << 8) | (idxOffset >> 8));
|
| 1242 |
-
litidx += idxOffset;
|
| 1243 |
-
|
| 1244 |
-
if (litidx < 0) {
|
| 1245 |
-
do {
|
| 1246 |
-
litidx += d->sizetable[--block] + 1;
|
| 1247 |
-
} while (litidx < 0);
|
| 1248 |
-
} else {
|
| 1249 |
-
while (litidx > d->sizetable[block])
|
| 1250 |
-
litidx -= d->sizetable[block++] + 1;
|
| 1251 |
-
}
|
| 1252 |
-
|
| 1253 |
-
uint32 *ptr = (uint32 *)(d->data + (block << d->blocksize));
|
| 1254 |
-
|
| 1255 |
-
int m = d->min_len;
|
| 1256 |
-
ushort *offset = d->offset;
|
| 1257 |
-
base_t *base = d->base - m;
|
| 1258 |
-
ubyte *symlen = d->symlen;
|
| 1259 |
-
int sym, bitcnt;
|
| 1260 |
-
|
| 1261 |
-
uint64 code = *((uint64 *)ptr);
|
| 1262 |
-
if (LittleEndian)
|
| 1263 |
-
code = BSWAP64(code);
|
| 1264 |
-
|
| 1265 |
-
ptr += 2;
|
| 1266 |
-
bitcnt = 0; // number of "empty bits" in code
|
| 1267 |
-
for (;;) {
|
| 1268 |
-
int l = m;
|
| 1269 |
-
while (code < base[l]) l++;
|
| 1270 |
-
sym = offset[l];
|
| 1271 |
-
if (!LittleEndian)
|
| 1272 |
-
sym = ((sym & 0xff) << 8) | (sym >> 8);
|
| 1273 |
-
sym += static_cast<int>((code - base[l]) >> (64 - l));
|
| 1274 |
-
if (litidx < (int)symlen[sym] + 1) break;
|
| 1275 |
-
litidx -= (int)symlen[sym] + 1;
|
| 1276 |
-
code <<= l;
|
| 1277 |
-
bitcnt += l;
|
| 1278 |
-
if (bitcnt >= 32) {
|
| 1279 |
-
bitcnt -= 32;
|
| 1280 |
-
uint32 tmp = *ptr++;
|
| 1281 |
-
if (LittleEndian)
|
| 1282 |
-
tmp = BSWAP32(tmp);
|
| 1283 |
-
code |= ((uint64)tmp) << bitcnt;
|
| 1284 |
-
}
|
| 1285 |
-
}
|
| 1286 |
-
|
| 1287 |
-
ubyte *sympat = d->sympat;
|
| 1288 |
-
while (symlen[sym] != 0) {
|
| 1289 |
-
ubyte* w = sympat + (3 * sym);
|
| 1290 |
-
int s1 = ((w[1] & 0xf) << 8) | w[0];
|
| 1291 |
-
if (litidx < (int)symlen[s1] + 1)
|
| 1292 |
-
sym = s1;
|
| 1293 |
-
else {
|
| 1294 |
-
litidx -= (int)symlen[s1] + 1;
|
| 1295 |
-
sym = (w[2] << 4) | (w[1] >> 4);
|
| 1296 |
-
}
|
| 1297 |
-
}
|
| 1298 |
-
|
| 1299 |
-
return sympat[3 * sym];
|
| 1300 |
-
}
|
| 1301 |
-
|
| 1302 |
-
void load_dtz_table(char *str, uint64 key1, uint64 key2)
|
| 1303 |
-
{
|
| 1304 |
-
int i;
|
| 1305 |
-
struct TBEntry *ptr, *ptr3;
|
| 1306 |
-
struct TBHashEntry *ptr2;
|
| 1307 |
-
|
| 1308 |
-
DTZ_table[0].key1 = key1;
|
| 1309 |
-
DTZ_table[0].key2 = key2;
|
| 1310 |
-
DTZ_table[0].entry = NULL;
|
| 1311 |
-
|
| 1312 |
-
// find corresponding WDL entry
|
| 1313 |
-
ptr2 = TB_hash[key1 >> (64 - TBHASHBITS)];
|
| 1314 |
-
for (i = 0; i < HSHMAX; i++)
|
| 1315 |
-
if (ptr2[i].key == key1) break;
|
| 1316 |
-
if (i == HSHMAX) return;
|
| 1317 |
-
ptr = ptr2[i].ptr;
|
| 1318 |
-
|
| 1319 |
-
ptr3 = (struct TBEntry *)malloc(ptr->has_pawns
|
| 1320 |
-
? sizeof(struct DTZEntry_pawn)
|
| 1321 |
-
: sizeof(struct DTZEntry_piece));
|
| 1322 |
-
|
| 1323 |
-
ptr3->data = map_file(str, DTZSUFFIX, &ptr3->mapping);
|
| 1324 |
-
ptr3->key = ptr->key;
|
| 1325 |
-
ptr3->num = ptr->num;
|
| 1326 |
-
ptr3->symmetric = ptr->symmetric;
|
| 1327 |
-
ptr3->has_pawns = ptr->has_pawns;
|
| 1328 |
-
if (ptr3->has_pawns) {
|
| 1329 |
-
struct DTZEntry_pawn *entry = (struct DTZEntry_pawn *)ptr3;
|
| 1330 |
-
entry->pawns[0] = ((struct TBEntry_pawn *)ptr)->pawns[0];
|
| 1331 |
-
entry->pawns[1] = ((struct TBEntry_pawn *)ptr)->pawns[1];
|
| 1332 |
-
} else {
|
| 1333 |
-
struct DTZEntry_piece *entry = (struct DTZEntry_piece *)ptr3;
|
| 1334 |
-
entry->enc_type = ((struct TBEntry_piece *)ptr)->enc_type;
|
| 1335 |
-
}
|
| 1336 |
-
if (!init_table_dtz(ptr3))
|
| 1337 |
-
free(ptr3);
|
| 1338 |
-
else
|
| 1339 |
-
DTZ_table[0].entry = ptr3;
|
| 1340 |
-
}
|
| 1341 |
-
|
| 1342 |
-
static void free_wdl_entry(struct TBEntry *entry)
|
| 1343 |
-
{
|
| 1344 |
-
unmap_file(entry->data, entry->mapping);
|
| 1345 |
-
if (!entry->has_pawns) {
|
| 1346 |
-
struct TBEntry_piece *ptr = (struct TBEntry_piece *)entry;
|
| 1347 |
-
free(ptr->precomp[0]);
|
| 1348 |
-
if (ptr->precomp[1])
|
| 1349 |
-
free(ptr->precomp[1]);
|
| 1350 |
-
} else {
|
| 1351 |
-
struct TBEntry_pawn *ptr = (struct TBEntry_pawn *)entry;
|
| 1352 |
-
int f;
|
| 1353 |
-
for (f = 0; f < 4; f++) {
|
| 1354 |
-
free(ptr->file[f].precomp[0]);
|
| 1355 |
-
if (ptr->file[f].precomp[1])
|
| 1356 |
-
free(ptr->file[f].precomp[1]);
|
| 1357 |
-
}
|
| 1358 |
-
}
|
| 1359 |
-
}
|
| 1360 |
-
|
| 1361 |
-
static void free_dtz_entry(struct TBEntry *entry)
|
| 1362 |
-
{
|
| 1363 |
-
unmap_file(entry->data, entry->mapping);
|
| 1364 |
-
if (!entry->has_pawns) {
|
| 1365 |
-
struct DTZEntry_piece *ptr = (struct DTZEntry_piece *)entry;
|
| 1366 |
-
free(ptr->precomp);
|
| 1367 |
-
} else {
|
| 1368 |
-
struct DTZEntry_pawn *ptr = (struct DTZEntry_pawn *)entry;
|
| 1369 |
-
int f;
|
| 1370 |
-
for (f = 0; f < 4; f++)
|
| 1371 |
-
free(ptr->file[f].precomp);
|
| 1372 |
-
}
|
| 1373 |
-
free(entry);
|
| 1374 |
-
}
|
| 1375 |
-
|
| 1376 |
-
static int wdl_to_map[5] = { 1, 3, 0, 2, 0 };
|
| 1377 |
-
static ubyte pa_flags[5] = { 8, 0, 0, 0, 4 };
|
| 1378 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/syzygy/tbcore.h
DELETED
|
@@ -1,169 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Copyright (c) 2011-2013 Ronald de Man
|
| 3 |
-
*/
|
| 4 |
-
|
| 5 |
-
#ifndef TBCORE_H
|
| 6 |
-
#define TBCORE_H
|
| 7 |
-
|
| 8 |
-
#ifndef _WIN32
|
| 9 |
-
#include <pthread.h>
|
| 10 |
-
#define SEP_CHAR ':'
|
| 11 |
-
#define FD int
|
| 12 |
-
#define FD_ERR -1
|
| 13 |
-
#else
|
| 14 |
-
#include <windows.h>
|
| 15 |
-
#define SEP_CHAR ';'
|
| 16 |
-
#define FD HANDLE
|
| 17 |
-
#define FD_ERR INVALID_HANDLE_VALUE
|
| 18 |
-
#endif
|
| 19 |
-
|
| 20 |
-
#ifndef _WIN32
|
| 21 |
-
#define LOCK_T pthread_mutex_t
|
| 22 |
-
#define LOCK_INIT(x) pthread_mutex_init(&(x), NULL)
|
| 23 |
-
#define LOCK(x) pthread_mutex_lock(&(x))
|
| 24 |
-
#define UNLOCK(x) pthread_mutex_unlock(&(x))
|
| 25 |
-
#else
|
| 26 |
-
#define LOCK_T HANDLE
|
| 27 |
-
#define LOCK_INIT(x) do { x = CreateMutex(NULL, FALSE, NULL); } while (0)
|
| 28 |
-
#define LOCK(x) WaitForSingleObject(x, INFINITE)
|
| 29 |
-
#define UNLOCK(x) ReleaseMutex(x)
|
| 30 |
-
#endif
|
| 31 |
-
|
| 32 |
-
#ifndef _MSC_VER
|
| 33 |
-
#define BSWAP32(v) __builtin_bswap32(v)
|
| 34 |
-
#define BSWAP64(v) __builtin_bswap64(v)
|
| 35 |
-
#else
|
| 36 |
-
#define BSWAP32(v) _byteswap_ulong(v)
|
| 37 |
-
#define BSWAP64(v) _byteswap_uint64(v)
|
| 38 |
-
#endif
|
| 39 |
-
|
| 40 |
-
#define WDLSUFFIX ".rtbw"
|
| 41 |
-
#define DTZSUFFIX ".rtbz"
|
| 42 |
-
#define WDLDIR "RTBWDIR"
|
| 43 |
-
#define DTZDIR "RTBZDIR"
|
| 44 |
-
#define TBPIECES 6
|
| 45 |
-
|
| 46 |
-
typedef unsigned long long uint64;
|
| 47 |
-
typedef unsigned int uint32;
|
| 48 |
-
typedef unsigned char ubyte;
|
| 49 |
-
typedef unsigned short ushort;
|
| 50 |
-
|
| 51 |
-
const ubyte WDL_MAGIC[4] = { 0x71, 0xe8, 0x23, 0x5d };
|
| 52 |
-
const ubyte DTZ_MAGIC[4] = { 0xd7, 0x66, 0x0c, 0xa5 };
|
| 53 |
-
|
| 54 |
-
#define TBHASHBITS 10
|
| 55 |
-
|
| 56 |
-
struct TBHashEntry;
|
| 57 |
-
|
| 58 |
-
typedef uint64 base_t;
|
| 59 |
-
|
| 60 |
-
struct PairsData {
|
| 61 |
-
char *indextable;
|
| 62 |
-
ushort *sizetable;
|
| 63 |
-
ubyte *data;
|
| 64 |
-
ushort *offset;
|
| 65 |
-
ubyte *symlen;
|
| 66 |
-
ubyte *sympat;
|
| 67 |
-
int blocksize;
|
| 68 |
-
int idxbits;
|
| 69 |
-
int min_len;
|
| 70 |
-
base_t base[1]; // C++ complains about base[]...
|
| 71 |
-
};
|
| 72 |
-
|
| 73 |
-
struct TBEntry {
|
| 74 |
-
char *data;
|
| 75 |
-
uint64 key;
|
| 76 |
-
uint64 mapping;
|
| 77 |
-
ubyte ready;
|
| 78 |
-
ubyte num;
|
| 79 |
-
ubyte symmetric;
|
| 80 |
-
ubyte has_pawns;
|
| 81 |
-
}
|
| 82 |
-
#ifndef _WIN32
|
| 83 |
-
__attribute__((__may_alias__))
|
| 84 |
-
#endif
|
| 85 |
-
;
|
| 86 |
-
|
| 87 |
-
struct TBEntry_piece {
|
| 88 |
-
char *data;
|
| 89 |
-
uint64 key;
|
| 90 |
-
uint64 mapping;
|
| 91 |
-
ubyte ready;
|
| 92 |
-
ubyte num;
|
| 93 |
-
ubyte symmetric;
|
| 94 |
-
ubyte has_pawns;
|
| 95 |
-
ubyte enc_type;
|
| 96 |
-
struct PairsData *precomp[2];
|
| 97 |
-
int factor[2][TBPIECES];
|
| 98 |
-
ubyte pieces[2][TBPIECES];
|
| 99 |
-
ubyte norm[2][TBPIECES];
|
| 100 |
-
};
|
| 101 |
-
|
| 102 |
-
struct TBEntry_pawn {
|
| 103 |
-
char *data;
|
| 104 |
-
uint64 key;
|
| 105 |
-
uint64 mapping;
|
| 106 |
-
ubyte ready;
|
| 107 |
-
ubyte num;
|
| 108 |
-
ubyte symmetric;
|
| 109 |
-
ubyte has_pawns;
|
| 110 |
-
ubyte pawns[2];
|
| 111 |
-
struct {
|
| 112 |
-
struct PairsData *precomp[2];
|
| 113 |
-
int factor[2][TBPIECES];
|
| 114 |
-
ubyte pieces[2][TBPIECES];
|
| 115 |
-
ubyte norm[2][TBPIECES];
|
| 116 |
-
} file[4];
|
| 117 |
-
};
|
| 118 |
-
|
| 119 |
-
struct DTZEntry_piece {
|
| 120 |
-
char *data;
|
| 121 |
-
uint64 key;
|
| 122 |
-
uint64 mapping;
|
| 123 |
-
ubyte ready;
|
| 124 |
-
ubyte num;
|
| 125 |
-
ubyte symmetric;
|
| 126 |
-
ubyte has_pawns;
|
| 127 |
-
ubyte enc_type;
|
| 128 |
-
struct PairsData *precomp;
|
| 129 |
-
int factor[TBPIECES];
|
| 130 |
-
ubyte pieces[TBPIECES];
|
| 131 |
-
ubyte norm[TBPIECES];
|
| 132 |
-
ubyte flags; // accurate, mapped, side
|
| 133 |
-
ushort map_idx[4];
|
| 134 |
-
ubyte *map;
|
| 135 |
-
};
|
| 136 |
-
|
| 137 |
-
struct DTZEntry_pawn {
|
| 138 |
-
char *data;
|
| 139 |
-
uint64 key;
|
| 140 |
-
uint64 mapping;
|
| 141 |
-
ubyte ready;
|
| 142 |
-
ubyte num;
|
| 143 |
-
ubyte symmetric;
|
| 144 |
-
ubyte has_pawns;
|
| 145 |
-
ubyte pawns[2];
|
| 146 |
-
struct {
|
| 147 |
-
struct PairsData *precomp;
|
| 148 |
-
int factor[TBPIECES];
|
| 149 |
-
ubyte pieces[TBPIECES];
|
| 150 |
-
ubyte norm[TBPIECES];
|
| 151 |
-
} file[4];
|
| 152 |
-
ubyte flags[4];
|
| 153 |
-
ushort map_idx[4][4];
|
| 154 |
-
ubyte *map;
|
| 155 |
-
};
|
| 156 |
-
|
| 157 |
-
struct TBHashEntry {
|
| 158 |
-
uint64 key;
|
| 159 |
-
struct TBEntry *ptr;
|
| 160 |
-
};
|
| 161 |
-
|
| 162 |
-
struct DTZTableEntry {
|
| 163 |
-
uint64 key1;
|
| 164 |
-
uint64 key2;
|
| 165 |
-
struct TBEntry *entry;
|
| 166 |
-
};
|
| 167 |
-
|
| 168 |
-
#endif
|
| 169 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/syzygy/tbprobe.cpp
DELETED
|
@@ -1,824 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Copyright (c) 2013 Ronald de Man
|
| 3 |
-
This file may be redistributed and/or modified without restrictions.
|
| 4 |
-
|
| 5 |
-
tbprobe.cpp contains the Stockfish-specific routines of the
|
| 6 |
-
tablebase probing code. It should be relatively easy to adapt
|
| 7 |
-
this code to other chess engines.
|
| 8 |
-
*/
|
| 9 |
-
|
| 10 |
-
#define NOMINMAX
|
| 11 |
-
|
| 12 |
-
#include <algorithm>
|
| 13 |
-
|
| 14 |
-
#include "../position.h"
|
| 15 |
-
#include "../movegen.h"
|
| 16 |
-
#include "../bitboard.h"
|
| 17 |
-
#include "../search.h"
|
| 18 |
-
|
| 19 |
-
#include "tbprobe.h"
|
| 20 |
-
#include "tbcore.h"
|
| 21 |
-
|
| 22 |
-
#include "tbcore.cpp"
|
| 23 |
-
|
| 24 |
-
namespace Zobrist {
|
| 25 |
-
extern Key psq[PIECE_NB][SQUARE_NB];
|
| 26 |
-
}
|
| 27 |
-
|
| 28 |
-
int Tablebases::MaxCardinality = 0;
|
| 29 |
-
|
| 30 |
-
// Given a position with 6 or fewer pieces, produce a text string
|
| 31 |
-
// of the form KQPvKRP, where "KQP" represents the white pieces if
|
| 32 |
-
// mirror == 0 and the black pieces if mirror == 1.
|
| 33 |
-
static void prt_str(Position& pos, char *str, int mirror)
|
| 34 |
-
{
|
| 35 |
-
Color color;
|
| 36 |
-
PieceType pt;
|
| 37 |
-
int i;
|
| 38 |
-
|
| 39 |
-
color = !mirror ? WHITE : BLACK;
|
| 40 |
-
for (pt = KING; pt >= PAWN; --pt)
|
| 41 |
-
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
| 42 |
-
*str++ = pchr[6 - pt];
|
| 43 |
-
*str++ = 'v';
|
| 44 |
-
color = ~color;
|
| 45 |
-
for (pt = KING; pt >= PAWN; --pt)
|
| 46 |
-
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
| 47 |
-
*str++ = pchr[6 - pt];
|
| 48 |
-
*str++ = 0;
|
| 49 |
-
}
|
| 50 |
-
|
| 51 |
-
// Given a position, produce a 64-bit material signature key.
|
| 52 |
-
// If the engine supports such a key, it should equal the engine's key.
|
| 53 |
-
static uint64 calc_key(Position& pos, int mirror)
|
| 54 |
-
{
|
| 55 |
-
Color color;
|
| 56 |
-
PieceType pt;
|
| 57 |
-
int i;
|
| 58 |
-
uint64 key = 0;
|
| 59 |
-
|
| 60 |
-
color = !mirror ? WHITE : BLACK;
|
| 61 |
-
for (pt = PAWN; pt <= KING; ++pt)
|
| 62 |
-
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
| 63 |
-
key ^= Zobrist::psq[make_piece(WHITE, pt)][i - 1];
|
| 64 |
-
color = ~color;
|
| 65 |
-
for (pt = PAWN; pt <= KING; ++pt)
|
| 66 |
-
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
| 67 |
-
key ^= Zobrist::psq[make_piece(BLACK, pt)][i - 1];
|
| 68 |
-
|
| 69 |
-
return key;
|
| 70 |
-
}
|
| 71 |
-
|
| 72 |
-
// Produce a 64-bit material key corresponding to the material combination
|
| 73 |
-
// defined by pcs[16], where pcs[1], ..., pcs[6] is the number of white
|
| 74 |
-
// pawns, ..., kings and pcs[9], ..., pcs[14] is the number of black
|
| 75 |
-
// pawns, ..., kings.
|
| 76 |
-
static uint64 calc_key_from_pcs(int *pcs, int mirror)
|
| 77 |
-
{
|
| 78 |
-
int color;
|
| 79 |
-
PieceType pt;
|
| 80 |
-
int i;
|
| 81 |
-
uint64 key = 0;
|
| 82 |
-
|
| 83 |
-
color = !mirror ? 0 : 8;
|
| 84 |
-
for (pt = PAWN; pt <= KING; ++pt)
|
| 85 |
-
for (i = 0; i < pcs[color + pt]; i++)
|
| 86 |
-
key ^= Zobrist::psq[make_piece(WHITE, pt)][i];
|
| 87 |
-
color ^= 8;
|
| 88 |
-
for (pt = PAWN; pt <= KING; ++pt)
|
| 89 |
-
for (i = 0; i < pcs[color + pt]; i++)
|
| 90 |
-
key ^= Zobrist::psq[make_piece(BLACK, pt)][i];
|
| 91 |
-
|
| 92 |
-
return key;
|
| 93 |
-
}
|
| 94 |
-
|
| 95 |
-
bool is_little_endian() {
|
| 96 |
-
union {
|
| 97 |
-
int i;
|
| 98 |
-
char c[sizeof(int)];
|
| 99 |
-
} x;
|
| 100 |
-
x.i = 1;
|
| 101 |
-
return x.c[0] == 1;
|
| 102 |
-
}
|
| 103 |
-
|
| 104 |
-
static ubyte decompress_pairs(struct PairsData *d, uint64 idx)
|
| 105 |
-
{
|
| 106 |
-
static const bool isLittleEndian = is_little_endian();
|
| 107 |
-
return isLittleEndian ? decompress_pairs<true >(d, idx)
|
| 108 |
-
: decompress_pairs<false>(d, idx);
|
| 109 |
-
}
|
| 110 |
-
|
| 111 |
-
// probe_wdl_table and probe_dtz_table require similar adaptations.
|
| 112 |
-
static int probe_wdl_table(Position& pos, int *success)
|
| 113 |
-
{
|
| 114 |
-
struct TBEntry *ptr;
|
| 115 |
-
struct TBHashEntry *ptr2;
|
| 116 |
-
uint64 idx;
|
| 117 |
-
uint64 key;
|
| 118 |
-
int i;
|
| 119 |
-
ubyte res;
|
| 120 |
-
int p[TBPIECES];
|
| 121 |
-
|
| 122 |
-
// Obtain the position's material signature key.
|
| 123 |
-
key = pos.material_key();
|
| 124 |
-
|
| 125 |
-
// Test for KvK.
|
| 126 |
-
if (key == (Zobrist::psq[W_KING][0] ^ Zobrist::psq[B_KING][0]))
|
| 127 |
-
return 0;
|
| 128 |
-
|
| 129 |
-
ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
|
| 130 |
-
for (i = 0; i < HSHMAX; i++)
|
| 131 |
-
if (ptr2[i].key == key) break;
|
| 132 |
-
if (i == HSHMAX) {
|
| 133 |
-
*success = 0;
|
| 134 |
-
return 0;
|
| 135 |
-
}
|
| 136 |
-
|
| 137 |
-
ptr = ptr2[i].ptr;
|
| 138 |
-
if (!ptr->ready) {
|
| 139 |
-
LOCK(TB_mutex);
|
| 140 |
-
if (!ptr->ready) {
|
| 141 |
-
char str[16];
|
| 142 |
-
prt_str(pos, str, ptr->key != key);
|
| 143 |
-
if (!init_table_wdl(ptr, str)) {
|
| 144 |
-
ptr2[i].key = 0ULL;
|
| 145 |
-
*success = 0;
|
| 146 |
-
UNLOCK(TB_mutex);
|
| 147 |
-
return 0;
|
| 148 |
-
}
|
| 149 |
-
// Memory barrier to ensure ptr->ready = 1 is not reordered.
|
| 150 |
-
#ifdef _MSC_VER
|
| 151 |
-
_ReadWriteBarrier();
|
| 152 |
-
#else
|
| 153 |
-
__asm__ __volatile__ ("" ::: "memory");
|
| 154 |
-
#endif
|
| 155 |
-
ptr->ready = 1;
|
| 156 |
-
}
|
| 157 |
-
UNLOCK(TB_mutex);
|
| 158 |
-
}
|
| 159 |
-
|
| 160 |
-
int bside, mirror, cmirror;
|
| 161 |
-
if (!ptr->symmetric) {
|
| 162 |
-
if (key != ptr->key) {
|
| 163 |
-
cmirror = 8;
|
| 164 |
-
mirror = 0x38;
|
| 165 |
-
bside = (pos.side_to_move() == WHITE);
|
| 166 |
-
} else {
|
| 167 |
-
cmirror = mirror = 0;
|
| 168 |
-
bside = !(pos.side_to_move() == WHITE);
|
| 169 |
-
}
|
| 170 |
-
} else {
|
| 171 |
-
cmirror = pos.side_to_move() == WHITE ? 0 : 8;
|
| 172 |
-
mirror = pos.side_to_move() == WHITE ? 0 : 0x38;
|
| 173 |
-
bside = 0;
|
| 174 |
-
}
|
| 175 |
-
|
| 176 |
-
// p[i] is to contain the square 0-63 (A1-H8) for a piece of type
|
| 177 |
-
// pc[i] ^ cmirror, where 1 = white pawn, ..., 14 = black king.
|
| 178 |
-
// Pieces of the same type are guaranteed to be consecutive.
|
| 179 |
-
if (!ptr->has_pawns) {
|
| 180 |
-
struct TBEntry_piece *entry = (struct TBEntry_piece *)ptr;
|
| 181 |
-
ubyte *pc = entry->pieces[bside];
|
| 182 |
-
for (i = 0; i < entry->num;) {
|
| 183 |
-
Bitboard bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
|
| 184 |
-
(PieceType)(pc[i] & 0x07));
|
| 185 |
-
do {
|
| 186 |
-
p[i++] = pop_lsb(&bb);
|
| 187 |
-
} while (bb);
|
| 188 |
-
}
|
| 189 |
-
idx = encode_piece(entry, entry->norm[bside], p, entry->factor[bside]);
|
| 190 |
-
res = decompress_pairs(entry->precomp[bside], idx);
|
| 191 |
-
} else {
|
| 192 |
-
struct TBEntry_pawn *entry = (struct TBEntry_pawn *)ptr;
|
| 193 |
-
int k = entry->file[0].pieces[0][0] ^ cmirror;
|
| 194 |
-
Bitboard bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07));
|
| 195 |
-
i = 0;
|
| 196 |
-
do {
|
| 197 |
-
p[i++] = pop_lsb(&bb) ^ mirror;
|
| 198 |
-
} while (bb);
|
| 199 |
-
int f = pawn_file(entry, p);
|
| 200 |
-
ubyte *pc = entry->file[f].pieces[bside];
|
| 201 |
-
for (; i < entry->num;) {
|
| 202 |
-
bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
|
| 203 |
-
(PieceType)(pc[i] & 0x07));
|
| 204 |
-
do {
|
| 205 |
-
p[i++] = pop_lsb(&bb) ^ mirror;
|
| 206 |
-
} while (bb);
|
| 207 |
-
}
|
| 208 |
-
idx = encode_pawn(entry, entry->file[f].norm[bside], p, entry->file[f].factor[bside]);
|
| 209 |
-
res = decompress_pairs(entry->file[f].precomp[bside], idx);
|
| 210 |
-
}
|
| 211 |
-
|
| 212 |
-
return ((int)res) - 2;
|
| 213 |
-
}
|
| 214 |
-
|
| 215 |
-
static int probe_dtz_table(Position& pos, int wdl, int *success)
|
| 216 |
-
{
|
| 217 |
-
struct TBEntry *ptr;
|
| 218 |
-
uint64 idx;
|
| 219 |
-
int i, res;
|
| 220 |
-
int p[TBPIECES];
|
| 221 |
-
|
| 222 |
-
// Obtain the position's material signature key.
|
| 223 |
-
uint64 key = pos.material_key();
|
| 224 |
-
|
| 225 |
-
if (DTZ_table[0].key1 != key && DTZ_table[0].key2 != key) {
|
| 226 |
-
for (i = 1; i < DTZ_ENTRIES; i++)
|
| 227 |
-
if (DTZ_table[i].key1 == key) break;
|
| 228 |
-
if (i < DTZ_ENTRIES) {
|
| 229 |
-
struct DTZTableEntry table_entry = DTZ_table[i];
|
| 230 |
-
for (; i > 0; i--)
|
| 231 |
-
DTZ_table[i] = DTZ_table[i - 1];
|
| 232 |
-
DTZ_table[0] = table_entry;
|
| 233 |
-
} else {
|
| 234 |
-
struct TBHashEntry *ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
|
| 235 |
-
for (i = 0; i < HSHMAX; i++)
|
| 236 |
-
if (ptr2[i].key == key) break;
|
| 237 |
-
if (i == HSHMAX) {
|
| 238 |
-
*success = 0;
|
| 239 |
-
return 0;
|
| 240 |
-
}
|
| 241 |
-
ptr = ptr2[i].ptr;
|
| 242 |
-
char str[16];
|
| 243 |
-
int mirror = (ptr->key != key);
|
| 244 |
-
prt_str(pos, str, mirror);
|
| 245 |
-
if (DTZ_table[DTZ_ENTRIES - 1].entry)
|
| 246 |
-
free_dtz_entry(DTZ_table[DTZ_ENTRIES-1].entry);
|
| 247 |
-
for (i = DTZ_ENTRIES - 1; i > 0; i--)
|
| 248 |
-
DTZ_table[i] = DTZ_table[i - 1];
|
| 249 |
-
load_dtz_table(str, calc_key(pos, mirror), calc_key(pos, !mirror));
|
| 250 |
-
}
|
| 251 |
-
}
|
| 252 |
-
|
| 253 |
-
ptr = DTZ_table[0].entry;
|
| 254 |
-
if (!ptr) {
|
| 255 |
-
*success = 0;
|
| 256 |
-
return 0;
|
| 257 |
-
}
|
| 258 |
-
|
| 259 |
-
int bside, mirror, cmirror;
|
| 260 |
-
if (!ptr->symmetric) {
|
| 261 |
-
if (key != ptr->key) {
|
| 262 |
-
cmirror = 8;
|
| 263 |
-
mirror = 0x38;
|
| 264 |
-
bside = (pos.side_to_move() == WHITE);
|
| 265 |
-
} else {
|
| 266 |
-
cmirror = mirror = 0;
|
| 267 |
-
bside = !(pos.side_to_move() == WHITE);
|
| 268 |
-
}
|
| 269 |
-
} else {
|
| 270 |
-
cmirror = pos.side_to_move() == WHITE ? 0 : 8;
|
| 271 |
-
mirror = pos.side_to_move() == WHITE ? 0 : 0x38;
|
| 272 |
-
bside = 0;
|
| 273 |
-
}
|
| 274 |
-
|
| 275 |
-
if (!ptr->has_pawns) {
|
| 276 |
-
struct DTZEntry_piece *entry = (struct DTZEntry_piece *)ptr;
|
| 277 |
-
if ((entry->flags & 1) != bside && !entry->symmetric) {
|
| 278 |
-
*success = -1;
|
| 279 |
-
return 0;
|
| 280 |
-
}
|
| 281 |
-
ubyte *pc = entry->pieces;
|
| 282 |
-
for (i = 0; i < entry->num;) {
|
| 283 |
-
Bitboard bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
|
| 284 |
-
(PieceType)(pc[i] & 0x07));
|
| 285 |
-
do {
|
| 286 |
-
p[i++] = pop_lsb(&bb);
|
| 287 |
-
} while (bb);
|
| 288 |
-
}
|
| 289 |
-
idx = encode_piece((struct TBEntry_piece *)entry, entry->norm, p, entry->factor);
|
| 290 |
-
res = decompress_pairs(entry->precomp, idx);
|
| 291 |
-
|
| 292 |
-
if (entry->flags & 2)
|
| 293 |
-
res = entry->map[entry->map_idx[wdl_to_map[wdl + 2]] + res];
|
| 294 |
-
|
| 295 |
-
if (!(entry->flags & pa_flags[wdl + 2]) || (wdl & 1))
|
| 296 |
-
res *= 2;
|
| 297 |
-
} else {
|
| 298 |
-
struct DTZEntry_pawn *entry = (struct DTZEntry_pawn *)ptr;
|
| 299 |
-
int k = entry->file[0].pieces[0] ^ cmirror;
|
| 300 |
-
Bitboard bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07));
|
| 301 |
-
i = 0;
|
| 302 |
-
do {
|
| 303 |
-
p[i++] = pop_lsb(&bb) ^ mirror;
|
| 304 |
-
} while (bb);
|
| 305 |
-
int f = pawn_file((struct TBEntry_pawn *)entry, p);
|
| 306 |
-
if ((entry->flags[f] & 1) != bside) {
|
| 307 |
-
*success = -1;
|
| 308 |
-
return 0;
|
| 309 |
-
}
|
| 310 |
-
ubyte *pc = entry->file[f].pieces;
|
| 311 |
-
for (; i < entry->num;) {
|
| 312 |
-
bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
|
| 313 |
-
(PieceType)(pc[i] & 0x07));
|
| 314 |
-
do {
|
| 315 |
-
p[i++] = pop_lsb(&bb) ^ mirror;
|
| 316 |
-
} while (bb);
|
| 317 |
-
}
|
| 318 |
-
idx = encode_pawn((struct TBEntry_pawn *)entry, entry->file[f].norm, p, entry->file[f].factor);
|
| 319 |
-
res = decompress_pairs(entry->file[f].precomp, idx);
|
| 320 |
-
|
| 321 |
-
if (entry->flags[f] & 2)
|
| 322 |
-
res = entry->map[entry->map_idx[f][wdl_to_map[wdl + 2]] + res];
|
| 323 |
-
|
| 324 |
-
if (!(entry->flags[f] & pa_flags[wdl + 2]) || (wdl & 1))
|
| 325 |
-
res *= 2;
|
| 326 |
-
}
|
| 327 |
-
|
| 328 |
-
return res;
|
| 329 |
-
}
|
| 330 |
-
|
| 331 |
-
// Add underpromotion captures to list of captures.
|
| 332 |
-
static ExtMove *add_underprom_caps(Position& pos, ExtMove *stack, ExtMove *end)
|
| 333 |
-
{
|
| 334 |
-
ExtMove *moves, *extra = end;
|
| 335 |
-
|
| 336 |
-
for (moves = stack; moves < end; moves++) {
|
| 337 |
-
Move move = moves->move;
|
| 338 |
-
if (type_of(move) == PROMOTION && !pos.empty(to_sq(move))) {
|
| 339 |
-
(*extra++).move = (Move)(move - (1 << 12));
|
| 340 |
-
(*extra++).move = (Move)(move - (2 << 12));
|
| 341 |
-
(*extra++).move = (Move)(move - (3 << 12));
|
| 342 |
-
}
|
| 343 |
-
}
|
| 344 |
-
|
| 345 |
-
return extra;
|
| 346 |
-
}
|
| 347 |
-
|
| 348 |
-
static int probe_ab(Position& pos, int alpha, int beta, int *success)
|
| 349 |
-
{
|
| 350 |
-
int v;
|
| 351 |
-
ExtMove stack[64];
|
| 352 |
-
ExtMove *moves, *end;
|
| 353 |
-
StateInfo st;
|
| 354 |
-
|
| 355 |
-
// Generate (at least) all legal non-ep captures including (under)promotions.
|
| 356 |
-
// It is OK to generate more, as long as they are filtered out below.
|
| 357 |
-
if (!pos.checkers()) {
|
| 358 |
-
end = generate<CAPTURES>(pos, stack);
|
| 359 |
-
// Since underpromotion captures are not included, we need to add them.
|
| 360 |
-
end = add_underprom_caps(pos, stack, end);
|
| 361 |
-
} else
|
| 362 |
-
end = generate<EVASIONS>(pos, stack);
|
| 363 |
-
|
| 364 |
-
for (moves = stack; moves < end; moves++) {
|
| 365 |
-
Move capture = moves->move;
|
| 366 |
-
if (!pos.capture(capture) || type_of(capture) == ENPASSANT
|
| 367 |
-
|| !pos.legal(capture))
|
| 368 |
-
continue;
|
| 369 |
-
pos.do_move(capture, st, pos.gives_check(capture));
|
| 370 |
-
v = -probe_ab(pos, -beta, -alpha, success);
|
| 371 |
-
pos.undo_move(capture);
|
| 372 |
-
if (*success == 0) return 0;
|
| 373 |
-
if (v > alpha) {
|
| 374 |
-
if (v >= beta) {
|
| 375 |
-
*success = 2;
|
| 376 |
-
return v;
|
| 377 |
-
}
|
| 378 |
-
alpha = v;
|
| 379 |
-
}
|
| 380 |
-
}
|
| 381 |
-
|
| 382 |
-
v = probe_wdl_table(pos, success);
|
| 383 |
-
if (*success == 0) return 0;
|
| 384 |
-
if (alpha >= v) {
|
| 385 |
-
*success = 1 + (alpha > 0);
|
| 386 |
-
return alpha;
|
| 387 |
-
} else {
|
| 388 |
-
*success = 1;
|
| 389 |
-
return v;
|
| 390 |
-
}
|
| 391 |
-
}
|
| 392 |
-
|
| 393 |
-
// Probe the WDL table for a particular position.
|
| 394 |
-
// If *success != 0, the probe was successful.
|
| 395 |
-
// The return value is from the point of view of the side to move:
|
| 396 |
-
// -2 : loss
|
| 397 |
-
// -1 : loss, but draw under 50-move rule
|
| 398 |
-
// 0 : draw
|
| 399 |
-
// 1 : win, but draw under 50-move rule
|
| 400 |
-
// 2 : win
|
| 401 |
-
int Tablebases::probe_wdl(Position& pos, int *success)
|
| 402 |
-
{
|
| 403 |
-
int v;
|
| 404 |
-
|
| 405 |
-
*success = 1;
|
| 406 |
-
v = probe_ab(pos, -2, 2, success);
|
| 407 |
-
|
| 408 |
-
// If en passant is not possible, we are done.
|
| 409 |
-
if (pos.ep_square() == SQ_NONE)
|
| 410 |
-
return v;
|
| 411 |
-
if (!(*success)) return 0;
|
| 412 |
-
|
| 413 |
-
// Now handle en passant.
|
| 414 |
-
int v1 = -3;
|
| 415 |
-
// Generate (at least) all legal en passant captures.
|
| 416 |
-
ExtMove stack[192];
|
| 417 |
-
ExtMove *moves, *end;
|
| 418 |
-
StateInfo st;
|
| 419 |
-
|
| 420 |
-
if (!pos.checkers())
|
| 421 |
-
end = generate<CAPTURES>(pos, stack);
|
| 422 |
-
else
|
| 423 |
-
end = generate<EVASIONS>(pos, stack);
|
| 424 |
-
|
| 425 |
-
for (moves = stack; moves < end; moves++) {
|
| 426 |
-
Move capture = moves->move;
|
| 427 |
-
if (type_of(capture) != ENPASSANT
|
| 428 |
-
|| !pos.legal(capture))
|
| 429 |
-
continue;
|
| 430 |
-
pos.do_move(capture, st, pos.gives_check(capture));
|
| 431 |
-
int v0 = -probe_ab(pos, -2, 2, success);
|
| 432 |
-
pos.undo_move(capture);
|
| 433 |
-
if (*success == 0) return 0;
|
| 434 |
-
if (v0 > v1) v1 = v0;
|
| 435 |
-
}
|
| 436 |
-
if (v1 > -3) {
|
| 437 |
-
if (v1 >= v) v = v1;
|
| 438 |
-
else if (v == 0) {
|
| 439 |
-
// Check whether there is at least one legal non-ep move.
|
| 440 |
-
for (moves = stack; moves < end; moves++) {
|
| 441 |
-
Move capture = moves->move;
|
| 442 |
-
if (type_of(capture) == ENPASSANT) continue;
|
| 443 |
-
if (pos.legal(capture)) break;
|
| 444 |
-
}
|
| 445 |
-
if (moves == end && !pos.checkers()) {
|
| 446 |
-
end = generate<QUIETS>(pos, end);
|
| 447 |
-
for (; moves < end; moves++) {
|
| 448 |
-
Move move = moves->move;
|
| 449 |
-
if (pos.legal(move))
|
| 450 |
-
break;
|
| 451 |
-
}
|
| 452 |
-
}
|
| 453 |
-
// If not, then we are forced to play the losing ep capture.
|
| 454 |
-
if (moves == end)
|
| 455 |
-
v = v1;
|
| 456 |
-
}
|
| 457 |
-
}
|
| 458 |
-
|
| 459 |
-
return v;
|
| 460 |
-
}
|
| 461 |
-
|
| 462 |
-
// This routine treats a position with en passant captures as one without.
|
| 463 |
-
static int probe_dtz_no_ep(Position& pos, int *success)
|
| 464 |
-
{
|
| 465 |
-
int wdl, dtz;
|
| 466 |
-
|
| 467 |
-
wdl = probe_ab(pos, -2, 2, success);
|
| 468 |
-
if (*success == 0) return 0;
|
| 469 |
-
|
| 470 |
-
if (wdl == 0) return 0;
|
| 471 |
-
|
| 472 |
-
if (*success == 2)
|
| 473 |
-
return wdl == 2 ? 1 : 101;
|
| 474 |
-
|
| 475 |
-
ExtMove stack[192];
|
| 476 |
-
ExtMove *moves, *end = NULL;
|
| 477 |
-
StateInfo st;
|
| 478 |
-
|
| 479 |
-
if (wdl > 0) {
|
| 480 |
-
// Generate at least all legal non-capturing pawn moves
|
| 481 |
-
// including non-capturing promotions.
|
| 482 |
-
if (!pos.checkers())
|
| 483 |
-
end = generate<NON_EVASIONS>(pos, stack);
|
| 484 |
-
else
|
| 485 |
-
end = generate<EVASIONS>(pos, stack);
|
| 486 |
-
|
| 487 |
-
for (moves = stack; moves < end; moves++) {
|
| 488 |
-
Move move = moves->move;
|
| 489 |
-
if (type_of(pos.moved_piece(move)) != PAWN || pos.capture(move)
|
| 490 |
-
|| !pos.legal(move))
|
| 491 |
-
continue;
|
| 492 |
-
pos.do_move(move, st, pos.gives_check(move));
|
| 493 |
-
int v = -Tablebases::probe_wdl(pos, success);
|
| 494 |
-
pos.undo_move(move);
|
| 495 |
-
if (*success == 0) return 0;
|
| 496 |
-
if (v == wdl)
|
| 497 |
-
return v == 2 ? 1 : 101;
|
| 498 |
-
}
|
| 499 |
-
}
|
| 500 |
-
|
| 501 |
-
dtz = 1 + probe_dtz_table(pos, wdl, success);
|
| 502 |
-
if (*success >= 0) {
|
| 503 |
-
if (wdl & 1) dtz += 100;
|
| 504 |
-
return wdl >= 0 ? dtz : -dtz;
|
| 505 |
-
}
|
| 506 |
-
|
| 507 |
-
if (wdl > 0) {
|
| 508 |
-
int best = 0xffff;
|
| 509 |
-
for (moves = stack; moves < end; moves++) {
|
| 510 |
-
Move move = moves->move;
|
| 511 |
-
if (pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN
|
| 512 |
-
|| !pos.legal(move))
|
| 513 |
-
continue;
|
| 514 |
-
pos.do_move(move, st, pos.gives_check(move));
|
| 515 |
-
int v = -Tablebases::probe_dtz(pos, success);
|
| 516 |
-
pos.undo_move(move);
|
| 517 |
-
if (*success == 0) return 0;
|
| 518 |
-
if (v > 0 && v + 1 < best)
|
| 519 |
-
best = v + 1;
|
| 520 |
-
}
|
| 521 |
-
return best;
|
| 522 |
-
} else {
|
| 523 |
-
int best = -1;
|
| 524 |
-
if (!pos.checkers())
|
| 525 |
-
end = generate<NON_EVASIONS>(pos, stack);
|
| 526 |
-
else
|
| 527 |
-
end = generate<EVASIONS>(pos, stack);
|
| 528 |
-
for (moves = stack; moves < end; moves++) {
|
| 529 |
-
int v;
|
| 530 |
-
Move move = moves->move;
|
| 531 |
-
if (!pos.legal(move))
|
| 532 |
-
continue;
|
| 533 |
-
pos.do_move(move, st, pos.gives_check(move));
|
| 534 |
-
if (st.rule50 == 0) {
|
| 535 |
-
if (wdl == -2) v = -1;
|
| 536 |
-
else {
|
| 537 |
-
v = probe_ab(pos, 1, 2, success);
|
| 538 |
-
v = (v == 2) ? 0 : -101;
|
| 539 |
-
}
|
| 540 |
-
} else {
|
| 541 |
-
v = -Tablebases::probe_dtz(pos, success) - 1;
|
| 542 |
-
}
|
| 543 |
-
pos.undo_move(move);
|
| 544 |
-
if (*success == 0) return 0;
|
| 545 |
-
if (v < best)
|
| 546 |
-
best = v;
|
| 547 |
-
}
|
| 548 |
-
return best;
|
| 549 |
-
}
|
| 550 |
-
}
|
| 551 |
-
|
| 552 |
-
static int wdl_to_dtz[] = {
|
| 553 |
-
-1, -101, 0, 101, 1
|
| 554 |
-
};
|
| 555 |
-
|
| 556 |
-
// Probe the DTZ table for a particular position.
|
| 557 |
-
// If *success != 0, the probe was successful.
|
| 558 |
-
// The return value is from the point of view of the side to move:
|
| 559 |
-
// n < -100 : loss, but draw under 50-move rule
|
| 560 |
-
// -100 <= n < -1 : loss in n ply (assuming 50-move counter == 0)
|
| 561 |
-
// 0 : draw
|
| 562 |
-
// 1 < n <= 100 : win in n ply (assuming 50-move counter == 0)
|
| 563 |
-
// 100 < n : win, but draw under 50-move rule
|
| 564 |
-
//
|
| 565 |
-
// The return value n can be off by 1: a return value -n can mean a loss
|
| 566 |
-
// in n+1 ply and a return value +n can mean a win in n+1 ply. This
|
| 567 |
-
// cannot happen for tables with positions exactly on the "edge" of
|
| 568 |
-
// the 50-move rule.
|
| 569 |
-
//
|
| 570 |
-
// This implies that if dtz > 0 is returned, the position is certainly
|
| 571 |
-
// a win if dtz + 50-move-counter <= 99. Care must be taken that the engine
|
| 572 |
-
// picks moves that preserve dtz + 50-move-counter <= 99.
|
| 573 |
-
//
|
| 574 |
-
// If n = 100 immediately after a capture or pawn move, then the position
|
| 575 |
-
// is also certainly a win, and during the whole phase until the next
|
| 576 |
-
// capture or pawn move, the inequality to be preserved is
|
| 577 |
-
// dtz + 50-movecounter <= 100.
|
| 578 |
-
//
|
| 579 |
-
// In short, if a move is available resulting in dtz + 50-move-counter <= 99,
|
| 580 |
-
// then do not accept moves leading to dtz + 50-move-counter == 100.
|
| 581 |
-
//
|
| 582 |
-
int Tablebases::probe_dtz(Position& pos, int *success)
|
| 583 |
-
{
|
| 584 |
-
*success = 1;
|
| 585 |
-
int v = probe_dtz_no_ep(pos, success);
|
| 586 |
-
|
| 587 |
-
if (pos.ep_square() == SQ_NONE)
|
| 588 |
-
return v;
|
| 589 |
-
if (*success == 0) return 0;
|
| 590 |
-
|
| 591 |
-
// Now handle en passant.
|
| 592 |
-
int v1 = -3;
|
| 593 |
-
|
| 594 |
-
ExtMove stack[192];
|
| 595 |
-
ExtMove *moves, *end;
|
| 596 |
-
StateInfo st;
|
| 597 |
-
|
| 598 |
-
if (!pos.checkers())
|
| 599 |
-
end = generate<CAPTURES>(pos, stack);
|
| 600 |
-
else
|
| 601 |
-
end = generate<EVASIONS>(pos, stack);
|
| 602 |
-
|
| 603 |
-
for (moves = stack; moves < end; moves++) {
|
| 604 |
-
Move capture = moves->move;
|
| 605 |
-
if (type_of(capture) != ENPASSANT
|
| 606 |
-
|| !pos.legal(capture))
|
| 607 |
-
continue;
|
| 608 |
-
pos.do_move(capture, st, pos.gives_check(capture));
|
| 609 |
-
int v0 = -probe_ab(pos, -2, 2, success);
|
| 610 |
-
pos.undo_move(capture);
|
| 611 |
-
if (*success == 0) return 0;
|
| 612 |
-
if (v0 > v1) v1 = v0;
|
| 613 |
-
}
|
| 614 |
-
if (v1 > -3) {
|
| 615 |
-
v1 = wdl_to_dtz[v1 + 2];
|
| 616 |
-
if (v < -100) {
|
| 617 |
-
if (v1 >= 0)
|
| 618 |
-
v = v1;
|
| 619 |
-
} else if (v < 0) {
|
| 620 |
-
if (v1 >= 0 || v1 < -100)
|
| 621 |
-
v = v1;
|
| 622 |
-
} else if (v > 100) {
|
| 623 |
-
if (v1 > 0)
|
| 624 |
-
v = v1;
|
| 625 |
-
} else if (v > 0) {
|
| 626 |
-
if (v1 == 1)
|
| 627 |
-
v = v1;
|
| 628 |
-
} else if (v1 >= 0) {
|
| 629 |
-
v = v1;
|
| 630 |
-
} else {
|
| 631 |
-
for (moves = stack; moves < end; moves++) {
|
| 632 |
-
Move move = moves->move;
|
| 633 |
-
if (type_of(move) == ENPASSANT) continue;
|
| 634 |
-
if (pos.legal(move)) break;
|
| 635 |
-
}
|
| 636 |
-
if (moves == end && !pos.checkers()) {
|
| 637 |
-
end = generate<QUIETS>(pos, end);
|
| 638 |
-
for (; moves < end; moves++) {
|
| 639 |
-
Move move = moves->move;
|
| 640 |
-
if (pos.legal(move))
|
| 641 |
-
break;
|
| 642 |
-
}
|
| 643 |
-
}
|
| 644 |
-
if (moves == end)
|
| 645 |
-
v = v1;
|
| 646 |
-
}
|
| 647 |
-
}
|
| 648 |
-
|
| 649 |
-
return v;
|
| 650 |
-
}
|
| 651 |
-
|
| 652 |
-
// Check whether there has been at least one repetition of positions
|
| 653 |
-
// since the last capture or pawn move.
|
| 654 |
-
static int has_repeated(StateInfo *st)
|
| 655 |
-
{
|
| 656 |
-
while (1) {
|
| 657 |
-
int i = 4, e = std::min(st->rule50, st->pliesFromNull);
|
| 658 |
-
if (e < i)
|
| 659 |
-
return 0;
|
| 660 |
-
StateInfo *stp = st->previous->previous;
|
| 661 |
-
do {
|
| 662 |
-
stp = stp->previous->previous;
|
| 663 |
-
if (stp->key == st->key)
|
| 664 |
-
return 1;
|
| 665 |
-
i += 2;
|
| 666 |
-
} while (i <= e);
|
| 667 |
-
st = st->previous;
|
| 668 |
-
}
|
| 669 |
-
}
|
| 670 |
-
|
| 671 |
-
static Value wdl_to_Value[5] = {
|
| 672 |
-
-VALUE_MATE + MAX_PLY + 1,
|
| 673 |
-
VALUE_DRAW - 2,
|
| 674 |
-
VALUE_DRAW,
|
| 675 |
-
VALUE_DRAW + 2,
|
| 676 |
-
VALUE_MATE - MAX_PLY - 1
|
| 677 |
-
};
|
| 678 |
-
|
| 679 |
-
// Use the DTZ tables to filter out moves that don't preserve the win or draw.
|
| 680 |
-
// If the position is lost, but DTZ is fairly high, only keep moves that
|
| 681 |
-
// maximise DTZ.
|
| 682 |
-
//
|
| 683 |
-
// A return value false indicates that not all probes were successful and that
|
| 684 |
-
// no moves were filtered out.
|
| 685 |
-
bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score)
|
| 686 |
-
{
|
| 687 |
-
int success;
|
| 688 |
-
|
| 689 |
-
int dtz = probe_dtz(pos, &success);
|
| 690 |
-
if (!success) return false;
|
| 691 |
-
|
| 692 |
-
StateInfo st;
|
| 693 |
-
|
| 694 |
-
// Probe each move.
|
| 695 |
-
for (size_t i = 0; i < rootMoves.size(); i++) {
|
| 696 |
-
Move move = rootMoves[i].pv[0];
|
| 697 |
-
pos.do_move(move, st, pos.gives_check(move));
|
| 698 |
-
int v = 0;
|
| 699 |
-
if (pos.checkers() && dtz > 0) {
|
| 700 |
-
ExtMove s[192];
|
| 701 |
-
if (generate<LEGAL>(pos, s) == s)
|
| 702 |
-
v = 1;
|
| 703 |
-
}
|
| 704 |
-
if (!v) {
|
| 705 |
-
if (st.rule50 != 0) {
|
| 706 |
-
v = -Tablebases::probe_dtz(pos, &success);
|
| 707 |
-
if (v > 0) v++;
|
| 708 |
-
else if (v < 0) v--;
|
| 709 |
-
} else {
|
| 710 |
-
v = -Tablebases::probe_wdl(pos, &success);
|
| 711 |
-
v = wdl_to_dtz[v + 2];
|
| 712 |
-
}
|
| 713 |
-
}
|
| 714 |
-
pos.undo_move(move);
|
| 715 |
-
if (!success) return false;
|
| 716 |
-
rootMoves[i].score = (Value)v;
|
| 717 |
-
}
|
| 718 |
-
|
| 719 |
-
// Obtain 50-move counter for the root position.
|
| 720 |
-
// In Stockfish there seems to be no clean way, so we do it like this:
|
| 721 |
-
int cnt50 = st.previous->rule50;
|
| 722 |
-
|
| 723 |
-
// Use 50-move counter to determine whether the root position is
|
| 724 |
-
// won, lost or drawn.
|
| 725 |
-
int wdl = 0;
|
| 726 |
-
if (dtz > 0)
|
| 727 |
-
wdl = (dtz + cnt50 <= 100) ? 2 : 1;
|
| 728 |
-
else if (dtz < 0)
|
| 729 |
-
wdl = (-dtz + cnt50 <= 100) ? -2 : -1;
|
| 730 |
-
|
| 731 |
-
// Determine the score to report to the user.
|
| 732 |
-
score = wdl_to_Value[wdl + 2];
|
| 733 |
-
// If the position is winning or losing, but too few moves left, adjust the
|
| 734 |
-
// score to show how close it is to winning or losing.
|
| 735 |
-
// NOTE: int(PawnValueEg) is used as scaling factor in score_to_uci().
|
| 736 |
-
if (wdl == 1 && dtz <= 100)
|
| 737 |
-
score = (Value)(((200 - dtz - cnt50) * int(PawnValueEg)) / 200);
|
| 738 |
-
else if (wdl == -1 && dtz >= -100)
|
| 739 |
-
score = -(Value)(((200 + dtz - cnt50) * int(PawnValueEg)) / 200);
|
| 740 |
-
|
| 741 |
-
// Now be a bit smart about filtering out moves.
|
| 742 |
-
size_t j = 0;
|
| 743 |
-
if (dtz > 0) { // winning (or 50-move rule draw)
|
| 744 |
-
int best = 0xffff;
|
| 745 |
-
for (size_t i = 0; i < rootMoves.size(); i++) {
|
| 746 |
-
int v = rootMoves[i].score;
|
| 747 |
-
if (v > 0 && v < best)
|
| 748 |
-
best = v;
|
| 749 |
-
}
|
| 750 |
-
int max = best;
|
| 751 |
-
// If the current phase has not seen repetitions, then try all moves
|
| 752 |
-
// that stay safely within the 50-move budget, if there are any.
|
| 753 |
-
if (!has_repeated(st.previous) && best + cnt50 <= 99)
|
| 754 |
-
max = 99 - cnt50;
|
| 755 |
-
for (size_t i = 0; i < rootMoves.size(); i++) {
|
| 756 |
-
int v = rootMoves[i].score;
|
| 757 |
-
if (v > 0 && v <= max)
|
| 758 |
-
rootMoves[j++] = rootMoves[i];
|
| 759 |
-
}
|
| 760 |
-
} else if (dtz < 0) { // losing (or 50-move rule draw)
|
| 761 |
-
int best = 0;
|
| 762 |
-
for (size_t i = 0; i < rootMoves.size(); i++) {
|
| 763 |
-
int v = rootMoves[i].score;
|
| 764 |
-
if (v < best)
|
| 765 |
-
best = v;
|
| 766 |
-
}
|
| 767 |
-
// Try all moves, unless we approach or have a 50-move rule draw.
|
| 768 |
-
if (-best * 2 + cnt50 < 100)
|
| 769 |
-
return true;
|
| 770 |
-
for (size_t i = 0; i < rootMoves.size(); i++) {
|
| 771 |
-
if (rootMoves[i].score == best)
|
| 772 |
-
rootMoves[j++] = rootMoves[i];
|
| 773 |
-
}
|
| 774 |
-
} else { // drawing
|
| 775 |
-
// Try all moves that preserve the draw.
|
| 776 |
-
for (size_t i = 0; i < rootMoves.size(); i++) {
|
| 777 |
-
if (rootMoves[i].score == 0)
|
| 778 |
-
rootMoves[j++] = rootMoves[i];
|
| 779 |
-
}
|
| 780 |
-
}
|
| 781 |
-
rootMoves.resize(j, Search::RootMove(MOVE_NONE));
|
| 782 |
-
|
| 783 |
-
return true;
|
| 784 |
-
}
|
| 785 |
-
|
| 786 |
-
// Use the WDL tables to filter out moves that don't preserve the win or draw.
|
| 787 |
-
// This is a fallback for the case that some or all DTZ tables are missing.
|
| 788 |
-
//
|
| 789 |
-
// A return value false indicates that not all probes were successful and that
|
| 790 |
-
// no moves were filtered out.
|
| 791 |
-
bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score)
|
| 792 |
-
{
|
| 793 |
-
int success;
|
| 794 |
-
|
| 795 |
-
int wdl = Tablebases::probe_wdl(pos, &success);
|
| 796 |
-
if (!success) return false;
|
| 797 |
-
score = wdl_to_Value[wdl + 2];
|
| 798 |
-
|
| 799 |
-
StateInfo st;
|
| 800 |
-
|
| 801 |
-
int best = -2;
|
| 802 |
-
|
| 803 |
-
// Probe each move.
|
| 804 |
-
for (size_t i = 0; i < rootMoves.size(); i++) {
|
| 805 |
-
Move move = rootMoves[i].pv[0];
|
| 806 |
-
pos.do_move(move, st, pos.gives_check(move));
|
| 807 |
-
int v = -Tablebases::probe_wdl(pos, &success);
|
| 808 |
-
pos.undo_move(move);
|
| 809 |
-
if (!success) return false;
|
| 810 |
-
rootMoves[i].score = (Value)v;
|
| 811 |
-
if (v > best)
|
| 812 |
-
best = v;
|
| 813 |
-
}
|
| 814 |
-
|
| 815 |
-
size_t j = 0;
|
| 816 |
-
for (size_t i = 0; i < rootMoves.size(); i++) {
|
| 817 |
-
if (rootMoves[i].score == best)
|
| 818 |
-
rootMoves[j++] = rootMoves[i];
|
| 819 |
-
}
|
| 820 |
-
rootMoves.resize(j, Search::RootMove(MOVE_NONE));
|
| 821 |
-
|
| 822 |
-
return true;
|
| 823 |
-
}
|
| 824 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/syzygy/tbprobe.h
DELETED
|
@@ -1,19 +0,0 @@
|
|
| 1 |
-
#ifndef TBPROBE_H
|
| 2 |
-
#define TBPROBE_H
|
| 3 |
-
|
| 4 |
-
#include "../search.h"
|
| 5 |
-
|
| 6 |
-
namespace Tablebases {
|
| 7 |
-
|
| 8 |
-
extern int MaxCardinality;
|
| 9 |
-
|
| 10 |
-
void init(const std::string& path);
|
| 11 |
-
int probe_wdl(Position& pos, int *success);
|
| 12 |
-
int probe_dtz(Position& pos, int *success);
|
| 13 |
-
bool root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score);
|
| 14 |
-
bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score);
|
| 15 |
-
void filter_root_moves(Position& pos, Search::RootMoves& rootMoves);
|
| 16 |
-
|
| 17 |
-
}
|
| 18 |
-
|
| 19 |
-
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/thread.cpp
DELETED
|
@@ -1,223 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm> // For std::count
|
| 22 |
-
#include <cassert>
|
| 23 |
-
|
| 24 |
-
#include "movegen.h"
|
| 25 |
-
#include "search.h"
|
| 26 |
-
#include "thread.h"
|
| 27 |
-
#include "uci.h"
|
| 28 |
-
#include "syzygy/tbprobe.h"
|
| 29 |
-
|
| 30 |
-
ThreadPool Threads; // Global object
|
| 31 |
-
|
| 32 |
-
/// Thread constructor launches the thread and then waits until it goes to sleep
|
| 33 |
-
/// in idle_loop().
|
| 34 |
-
|
| 35 |
-
Thread::Thread() {
|
| 36 |
-
|
| 37 |
-
resetCalls = exit = false;
|
| 38 |
-
maxPly = callsCnt = 0;
|
| 39 |
-
tbHits = 0;
|
| 40 |
-
history.clear();
|
| 41 |
-
counterMoves.clear();
|
| 42 |
-
idx = Threads.size(); // Start from 0
|
| 43 |
-
|
| 44 |
-
std::unique_lock<Mutex> lk(mutex);
|
| 45 |
-
searching = true;
|
| 46 |
-
nativeThread = std::thread(&Thread::idle_loop, this);
|
| 47 |
-
sleepCondition.wait(lk, [&]{ return !searching; });
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
/// Thread destructor waits for thread termination before returning
|
| 52 |
-
|
| 53 |
-
Thread::~Thread() {
|
| 54 |
-
|
| 55 |
-
mutex.lock();
|
| 56 |
-
exit = true;
|
| 57 |
-
sleepCondition.notify_one();
|
| 58 |
-
mutex.unlock();
|
| 59 |
-
nativeThread.join();
|
| 60 |
-
}
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
/// Thread::wait_for_search_finished() waits on sleep condition
|
| 64 |
-
/// until not searching
|
| 65 |
-
|
| 66 |
-
void Thread::wait_for_search_finished() {
|
| 67 |
-
|
| 68 |
-
std::unique_lock<Mutex> lk(mutex);
|
| 69 |
-
sleepCondition.wait(lk, [&]{ return !searching; });
|
| 70 |
-
}
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
/// Thread::wait() waits on sleep condition until condition is true
|
| 74 |
-
|
| 75 |
-
void Thread::wait(std::atomic_bool& condition) {
|
| 76 |
-
|
| 77 |
-
std::unique_lock<Mutex> lk(mutex);
|
| 78 |
-
sleepCondition.wait(lk, [&]{ return bool(condition); });
|
| 79 |
-
}
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
/// Thread::start_searching() wakes up the thread that will start the search
|
| 83 |
-
|
| 84 |
-
void Thread::start_searching(bool resume) {
|
| 85 |
-
|
| 86 |
-
std::unique_lock<Mutex> lk(mutex);
|
| 87 |
-
|
| 88 |
-
if (!resume)
|
| 89 |
-
searching = true;
|
| 90 |
-
|
| 91 |
-
sleepCondition.notify_one();
|
| 92 |
-
}
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
/// Thread::idle_loop() is where the thread is parked when it has no work to do
|
| 96 |
-
|
| 97 |
-
void Thread::idle_loop() {
|
| 98 |
-
|
| 99 |
-
while (!exit)
|
| 100 |
-
{
|
| 101 |
-
std::unique_lock<Mutex> lk(mutex);
|
| 102 |
-
|
| 103 |
-
searching = false;
|
| 104 |
-
|
| 105 |
-
while (!searching && !exit)
|
| 106 |
-
{
|
| 107 |
-
sleepCondition.notify_one(); // Wake up any waiting thread
|
| 108 |
-
sleepCondition.wait(lk);
|
| 109 |
-
}
|
| 110 |
-
|
| 111 |
-
lk.unlock();
|
| 112 |
-
|
| 113 |
-
if (!exit)
|
| 114 |
-
search();
|
| 115 |
-
}
|
| 116 |
-
}
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
/// ThreadPool::init() creates and launches requested threads that will go
|
| 120 |
-
/// immediately to sleep. We cannot use a constructor because Threads is a
|
| 121 |
-
/// static object and we need a fully initialized engine at this point due to
|
| 122 |
-
/// allocation of Endgames in the Thread constructor.
|
| 123 |
-
|
| 124 |
-
void ThreadPool::init() {
|
| 125 |
-
|
| 126 |
-
push_back(new MainThread);
|
| 127 |
-
read_uci_options();
|
| 128 |
-
}
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
/// ThreadPool::exit() terminates threads before the program exits. Cannot be
|
| 132 |
-
/// done in destructor because threads must be terminated before deleting any
|
| 133 |
-
/// static objects while still in main().
|
| 134 |
-
|
| 135 |
-
void ThreadPool::exit() {
|
| 136 |
-
|
| 137 |
-
while (size())
|
| 138 |
-
delete back(), pop_back();
|
| 139 |
-
}
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
/// ThreadPool::read_uci_options() updates internal threads parameters from the
|
| 143 |
-
/// corresponding UCI options and creates/destroys threads to match requested
|
| 144 |
-
/// number. Thread objects are dynamically allocated.
|
| 145 |
-
|
| 146 |
-
void ThreadPool::read_uci_options() {
|
| 147 |
-
|
| 148 |
-
size_t requested = Options["Threads"];
|
| 149 |
-
|
| 150 |
-
assert(requested > 0);
|
| 151 |
-
|
| 152 |
-
while (size() < requested)
|
| 153 |
-
push_back(new Thread);
|
| 154 |
-
|
| 155 |
-
while (size() > requested)
|
| 156 |
-
delete back(), pop_back();
|
| 157 |
-
}
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
/// ThreadPool::nodes_searched() returns the number of nodes searched
|
| 161 |
-
|
| 162 |
-
uint64_t ThreadPool::nodes_searched() const {
|
| 163 |
-
|
| 164 |
-
uint64_t nodes = 0;
|
| 165 |
-
for (Thread* th : *this)
|
| 166 |
-
nodes += th->rootPos.nodes_searched();
|
| 167 |
-
return nodes;
|
| 168 |
-
}
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
/// ThreadPool::tb_hits() returns the number of TB hits
|
| 172 |
-
|
| 173 |
-
uint64_t ThreadPool::tb_hits() const {
|
| 174 |
-
|
| 175 |
-
uint64_t hits = 0;
|
| 176 |
-
for (Thread* th : *this)
|
| 177 |
-
hits += th->tbHits;
|
| 178 |
-
return hits;
|
| 179 |
-
}
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
/// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
|
| 183 |
-
/// and starts a new search, then returns immediately.
|
| 184 |
-
|
| 185 |
-
void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
|
| 186 |
-
const Search::LimitsType& limits) {
|
| 187 |
-
|
| 188 |
-
main()->wait_for_search_finished();
|
| 189 |
-
|
| 190 |
-
Search::Signals.stopOnPonderhit = Search::Signals.stop = false;
|
| 191 |
-
Search::Limits = limits;
|
| 192 |
-
Search::RootMoves rootMoves;
|
| 193 |
-
|
| 194 |
-
for (const auto& m : MoveList<LEGAL>(pos))
|
| 195 |
-
if ( limits.searchmoves.empty()
|
| 196 |
-
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
|
| 197 |
-
rootMoves.push_back(Search::RootMove(m));
|
| 198 |
-
|
| 199 |
-
if (!rootMoves.empty())
|
| 200 |
-
Tablebases::filter_root_moves(pos, rootMoves);
|
| 201 |
-
|
| 202 |
-
// After ownership transfer 'states' becomes empty, so if we stop the search
|
| 203 |
-
// and call 'go' again without setting a new position states.get() == NULL.
|
| 204 |
-
assert(states.get() || setupStates.get());
|
| 205 |
-
|
| 206 |
-
if (states.get())
|
| 207 |
-
setupStates = std::move(states); // Ownership transfer, states is now empty
|
| 208 |
-
|
| 209 |
-
StateInfo tmp = setupStates->back();
|
| 210 |
-
|
| 211 |
-
for (Thread* th : Threads)
|
| 212 |
-
{
|
| 213 |
-
th->maxPly = 0;
|
| 214 |
-
th->tbHits = 0;
|
| 215 |
-
th->rootDepth = DEPTH_ZERO;
|
| 216 |
-
th->rootMoves = rootMoves;
|
| 217 |
-
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
|
| 218 |
-
}
|
| 219 |
-
|
| 220 |
-
setupStates->back() = tmp; // Restore st->previous, cleared by Position::set()
|
| 221 |
-
|
| 222 |
-
main()->start_searching();
|
| 223 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/thread.h
DELETED
|
@@ -1,111 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef THREAD_H_INCLUDED
|
| 22 |
-
#define THREAD_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include <atomic>
|
| 25 |
-
#include <bitset>
|
| 26 |
-
#include <condition_variable>
|
| 27 |
-
#include <mutex>
|
| 28 |
-
#include <thread>
|
| 29 |
-
#include <vector>
|
| 30 |
-
|
| 31 |
-
#include "material.h"
|
| 32 |
-
#include "movepick.h"
|
| 33 |
-
#include "pawns.h"
|
| 34 |
-
#include "position.h"
|
| 35 |
-
#include "search.h"
|
| 36 |
-
#include "thread_win32.h"
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
/// Thread struct keeps together all the thread-related stuff. We also use
|
| 40 |
-
/// per-thread pawn and material hash tables so that once we get a pointer to an
|
| 41 |
-
/// entry its life time is unlimited and we don't have to care about someone
|
| 42 |
-
/// changing the entry under our feet.
|
| 43 |
-
|
| 44 |
-
class Thread {
|
| 45 |
-
|
| 46 |
-
std::thread nativeThread;
|
| 47 |
-
Mutex mutex;
|
| 48 |
-
ConditionVariable sleepCondition;
|
| 49 |
-
bool exit, searching;
|
| 50 |
-
|
| 51 |
-
public:
|
| 52 |
-
Thread();
|
| 53 |
-
virtual ~Thread();
|
| 54 |
-
virtual void search();
|
| 55 |
-
void idle_loop();
|
| 56 |
-
void start_searching(bool resume = false);
|
| 57 |
-
void wait_for_search_finished();
|
| 58 |
-
void wait(std::atomic_bool& b);
|
| 59 |
-
|
| 60 |
-
Pawns::Table pawnsTable;
|
| 61 |
-
Material::Table materialTable;
|
| 62 |
-
Endgames endgames;
|
| 63 |
-
size_t idx, PVIdx;
|
| 64 |
-
int maxPly, callsCnt;
|
| 65 |
-
uint64_t tbHits;
|
| 66 |
-
|
| 67 |
-
Position rootPos;
|
| 68 |
-
Search::RootMoves rootMoves;
|
| 69 |
-
Depth rootDepth;
|
| 70 |
-
Depth completedDepth;
|
| 71 |
-
std::atomic_bool resetCalls;
|
| 72 |
-
HistoryStats history;
|
| 73 |
-
MoveStats counterMoves;
|
| 74 |
-
FromToStats fromTo;
|
| 75 |
-
CounterMoveHistoryStats counterMoveHistory;
|
| 76 |
-
};
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
/// MainThread is a derived class with a specific overload for the main thread
|
| 80 |
-
|
| 81 |
-
struct MainThread : public Thread {
|
| 82 |
-
virtual void search();
|
| 83 |
-
|
| 84 |
-
bool easyMovePlayed, failedLow;
|
| 85 |
-
double bestMoveChanges;
|
| 86 |
-
Value previousScore;
|
| 87 |
-
};
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
/// ThreadPool struct handles all the threads-related stuff like init, starting,
|
| 91 |
-
/// parking and, most importantly, launching a thread. All the access to threads
|
| 92 |
-
/// data is done through this class.
|
| 93 |
-
|
| 94 |
-
struct ThreadPool : public std::vector<Thread*> {
|
| 95 |
-
|
| 96 |
-
void init(); // No constructor and destructor, threads rely on globals that should
|
| 97 |
-
void exit(); // be initialized and valid during the whole thread lifetime.
|
| 98 |
-
|
| 99 |
-
MainThread* main() { return static_cast<MainThread*>(at(0)); }
|
| 100 |
-
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&);
|
| 101 |
-
void read_uci_options();
|
| 102 |
-
uint64_t nodes_searched() const;
|
| 103 |
-
uint64_t tb_hits() const;
|
| 104 |
-
|
| 105 |
-
private:
|
| 106 |
-
StateListPtr setupStates;
|
| 107 |
-
};
|
| 108 |
-
|
| 109 |
-
extern ThreadPool Threads;
|
| 110 |
-
|
| 111 |
-
#endif // #ifndef THREAD_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/thread_win32.h
DELETED
|
@@ -1,70 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef THREAD_WIN32_H_INCLUDED
|
| 22 |
-
#define THREAD_WIN32_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
/// STL thread library used by mingw and gcc when cross compiling for Windows
|
| 25 |
-
/// relies on libwinpthread. Currently libwinpthread implements mutexes directly
|
| 26 |
-
/// on top of Windows semaphores. Semaphores, being kernel objects, require kernel
|
| 27 |
-
/// mode transition in order to lock or unlock, which is very slow compared to
|
| 28 |
-
/// interlocked operations (about 30% slower on bench test). To work around this
|
| 29 |
-
/// issue, we define our wrappers to the low level Win32 calls. We use critical
|
| 30 |
-
/// sections to support Windows XP and older versions. Unfortunately, cond_wait()
|
| 31 |
-
/// is racy between unlock() and WaitForSingleObject() but they have the same
|
| 32 |
-
/// speed performance as the SRW locks.
|
| 33 |
-
|
| 34 |
-
#include <condition_variable>
|
| 35 |
-
#include <mutex>
|
| 36 |
-
|
| 37 |
-
#if defined(_WIN32) && !defined(_MSC_VER)
|
| 38 |
-
|
| 39 |
-
#ifndef NOMINMAX
|
| 40 |
-
# define NOMINMAX // Disable macros min() and max()
|
| 41 |
-
#endif
|
| 42 |
-
|
| 43 |
-
#define WIN32_LEAN_AND_MEAN
|
| 44 |
-
#include <windows.h>
|
| 45 |
-
#undef WIN32_LEAN_AND_MEAN
|
| 46 |
-
#undef NOMINMAX
|
| 47 |
-
|
| 48 |
-
/// Mutex and ConditionVariable struct are wrappers of the low level locking
|
| 49 |
-
/// machinery and are modeled after the corresponding C++11 classes.
|
| 50 |
-
|
| 51 |
-
struct Mutex {
|
| 52 |
-
Mutex() { InitializeCriticalSection(&cs); }
|
| 53 |
-
~Mutex() { DeleteCriticalSection(&cs); }
|
| 54 |
-
void lock() { EnterCriticalSection(&cs); }
|
| 55 |
-
void unlock() { LeaveCriticalSection(&cs); }
|
| 56 |
-
|
| 57 |
-
private:
|
| 58 |
-
CRITICAL_SECTION cs;
|
| 59 |
-
};
|
| 60 |
-
|
| 61 |
-
typedef std::condition_variable_any ConditionVariable;
|
| 62 |
-
|
| 63 |
-
#else // Default case: use STL classes
|
| 64 |
-
|
| 65 |
-
typedef std::mutex Mutex;
|
| 66 |
-
typedef std::condition_variable ConditionVariable;
|
| 67 |
-
|
| 68 |
-
#endif
|
| 69 |
-
|
| 70 |
-
#endif // #ifndef THREAD_WIN32_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/timeman.cpp
DELETED
|
@@ -1,132 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm>
|
| 22 |
-
#include <cfloat>
|
| 23 |
-
#include <cmath>
|
| 24 |
-
|
| 25 |
-
#include "search.h"
|
| 26 |
-
#include "timeman.h"
|
| 27 |
-
#include "uci.h"
|
| 28 |
-
|
| 29 |
-
TimeManagement Time; // Our global time management object
|
| 30 |
-
|
| 31 |
-
namespace {
|
| 32 |
-
|
| 33 |
-
enum TimeType { OptimumTime, MaxTime };
|
| 34 |
-
|
| 35 |
-
const int MoveHorizon = 50; // Plan time management at most this many moves ahead
|
| 36 |
-
const double MaxRatio = 7.09; // When in trouble, we can step over reserved time with this ratio
|
| 37 |
-
const double StealRatio = 0.35; // However we must not steal time from remaining moves over this ratio
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
// move_importance() is a skew-logistic function based on naive statistical
|
| 41 |
-
// analysis of "how many games are still undecided after n half-moves". Game
|
| 42 |
-
// is considered "undecided" as long as neither side has >275cp advantage.
|
| 43 |
-
// Data was extracted from the CCRL game database with some simple filtering criteria.
|
| 44 |
-
|
| 45 |
-
double move_importance(int ply) {
|
| 46 |
-
|
| 47 |
-
const double XScale = 7.64;
|
| 48 |
-
const double XShift = 58.4;
|
| 49 |
-
const double Skew = 0.183;
|
| 50 |
-
|
| 51 |
-
return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero
|
| 52 |
-
}
|
| 53 |
-
|
| 54 |
-
template<TimeType T>
|
| 55 |
-
int remaining(int myTime, int movesToGo, int ply, int slowMover) {
|
| 56 |
-
|
| 57 |
-
const double TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
|
| 58 |
-
const double TStealRatio = (T == OptimumTime ? 0 : StealRatio);
|
| 59 |
-
|
| 60 |
-
double moveImportance = (move_importance(ply) * slowMover) / 100;
|
| 61 |
-
double otherMovesImportance = 0;
|
| 62 |
-
|
| 63 |
-
for (int i = 1; i < movesToGo; ++i)
|
| 64 |
-
otherMovesImportance += move_importance(ply + 2 * i);
|
| 65 |
-
|
| 66 |
-
double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance);
|
| 67 |
-
double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance);
|
| 68 |
-
|
| 69 |
-
return int(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast
|
| 70 |
-
}
|
| 71 |
-
|
| 72 |
-
} // namespace
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
/// init() is called at the beginning of the search and calculates the allowed
|
| 76 |
-
/// thinking time out of the time control and current game ply. We support four
|
| 77 |
-
/// different kinds of time controls, passed in 'limits':
|
| 78 |
-
///
|
| 79 |
-
/// inc == 0 && movestogo == 0 means: x basetime [sudden death!]
|
| 80 |
-
/// inc == 0 && movestogo != 0 means: x moves in y minutes
|
| 81 |
-
/// inc > 0 && movestogo == 0 means: x basetime + z increment
|
| 82 |
-
/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment
|
| 83 |
-
|
| 84 |
-
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
| 85 |
-
|
| 86 |
-
int minThinkingTime = Options["Minimum Thinking Time"];
|
| 87 |
-
int moveOverhead = Options["Move Overhead"];
|
| 88 |
-
int slowMover = Options["Slow Mover"];
|
| 89 |
-
int npmsec = Options["nodestime"];
|
| 90 |
-
|
| 91 |
-
// If we have to play in 'nodes as time' mode, then convert from time
|
| 92 |
-
// to nodes, and use resulting values in time management formulas.
|
| 93 |
-
// WARNING: Given npms (nodes per millisecond) must be much lower then
|
| 94 |
-
// the real engine speed to avoid time losses.
|
| 95 |
-
if (npmsec)
|
| 96 |
-
{
|
| 97 |
-
if (!availableNodes) // Only once at game start
|
| 98 |
-
availableNodes = npmsec * limits.time[us]; // Time is in msec
|
| 99 |
-
|
| 100 |
-
// Convert from millisecs to nodes
|
| 101 |
-
limits.time[us] = (int)availableNodes;
|
| 102 |
-
limits.inc[us] *= npmsec;
|
| 103 |
-
limits.npmsec = npmsec;
|
| 104 |
-
}
|
| 105 |
-
|
| 106 |
-
startTime = limits.startTime;
|
| 107 |
-
optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime);
|
| 108 |
-
|
| 109 |
-
const int MaxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon;
|
| 110 |
-
|
| 111 |
-
// We calculate optimum time usage for different hypothetical "moves to go"-values
|
| 112 |
-
// and choose the minimum of calculated search time values. Usually the greatest
|
| 113 |
-
// hypMTG gives the minimum values.
|
| 114 |
-
for (int hypMTG = 1; hypMTG <= MaxMTG; ++hypMTG)
|
| 115 |
-
{
|
| 116 |
-
// Calculate thinking time for hypothetical "moves to go"-value
|
| 117 |
-
int hypMyTime = limits.time[us]
|
| 118 |
-
+ limits.inc[us] * (hypMTG - 1)
|
| 119 |
-
- moveOverhead * (2 + std::min(hypMTG, 40));
|
| 120 |
-
|
| 121 |
-
hypMyTime = std::max(hypMyTime, 0);
|
| 122 |
-
|
| 123 |
-
int t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, ply, slowMover);
|
| 124 |
-
int t2 = minThinkingTime + remaining<MaxTime >(hypMyTime, hypMTG, ply, slowMover);
|
| 125 |
-
|
| 126 |
-
optimumTime = std::min(t1, optimumTime);
|
| 127 |
-
maximumTime = std::min(t2, maximumTime);
|
| 128 |
-
}
|
| 129 |
-
|
| 130 |
-
if (Options["Ponder"])
|
| 131 |
-
optimumTime += optimumTime / 4;
|
| 132 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/timeman.h
DELETED
|
@@ -1,48 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef TIMEMAN_H_INCLUDED
|
| 22 |
-
#define TIMEMAN_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include "misc.h"
|
| 25 |
-
#include "search.h"
|
| 26 |
-
#include "thread.h"
|
| 27 |
-
|
| 28 |
-
/// The TimeManagement class computes the optimal time to think depending on
|
| 29 |
-
/// the maximum available time, the game move number and other parameters.
|
| 30 |
-
|
| 31 |
-
class TimeManagement {
|
| 32 |
-
public:
|
| 33 |
-
void init(Search::LimitsType& limits, Color us, int ply);
|
| 34 |
-
int optimum() const { return optimumTime; }
|
| 35 |
-
int maximum() const { return maximumTime; }
|
| 36 |
-
int elapsed() const { return int(Search::Limits.npmsec ? Threads.nodes_searched() : now() - startTime); }
|
| 37 |
-
|
| 38 |
-
int64_t availableNodes; // When in 'nodes as time' mode
|
| 39 |
-
|
| 40 |
-
private:
|
| 41 |
-
TimePoint startTime;
|
| 42 |
-
int optimumTime;
|
| 43 |
-
int maximumTime;
|
| 44 |
-
};
|
| 45 |
-
|
| 46 |
-
extern TimeManagement Time;
|
| 47 |
-
|
| 48 |
-
#endif // #ifndef TIMEMAN_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/tt.cpp
DELETED
|
@@ -1,117 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <cstring> // For std::memset
|
| 22 |
-
#include <iostream>
|
| 23 |
-
|
| 24 |
-
#include "bitboard.h"
|
| 25 |
-
#include "tt.h"
|
| 26 |
-
|
| 27 |
-
TranspositionTable TT; // Our global transposition table
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
/// TranspositionTable::resize() sets the size of the transposition table,
|
| 31 |
-
/// measured in megabytes. Transposition table consists of a power of 2 number
|
| 32 |
-
/// of clusters and each cluster consists of ClusterSize number of TTEntry.
|
| 33 |
-
|
| 34 |
-
void TranspositionTable::resize(size_t mbSize) {
|
| 35 |
-
|
| 36 |
-
size_t newClusterCount = size_t(1) << msb((mbSize * 1024 * 1024) / sizeof(Cluster));
|
| 37 |
-
|
| 38 |
-
if (newClusterCount == clusterCount)
|
| 39 |
-
return;
|
| 40 |
-
|
| 41 |
-
clusterCount = newClusterCount;
|
| 42 |
-
|
| 43 |
-
free(mem);
|
| 44 |
-
mem = calloc(clusterCount * sizeof(Cluster) + CacheLineSize - 1, 1);
|
| 45 |
-
|
| 46 |
-
if (!mem)
|
| 47 |
-
{
|
| 48 |
-
std::cerr << "Failed to allocate " << mbSize
|
| 49 |
-
<< "MB for transposition table." << std::endl;
|
| 50 |
-
exit(EXIT_FAILURE);
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
table = (Cluster*)((uintptr_t(mem) + CacheLineSize - 1) & ~(CacheLineSize - 1));
|
| 54 |
-
}
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
/// TranspositionTable::clear() overwrites the entire transposition table
|
| 58 |
-
/// with zeros. It is called whenever the table is resized, or when the
|
| 59 |
-
/// user asks the program to clear the table (from the UCI interface).
|
| 60 |
-
|
| 61 |
-
void TranspositionTable::clear() {
|
| 62 |
-
|
| 63 |
-
std::memset(table, 0, clusterCount * sizeof(Cluster));
|
| 64 |
-
}
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
/// TranspositionTable::probe() looks up the current position in the transposition
|
| 68 |
-
/// table. It returns true and a pointer to the TTEntry if the position is found.
|
| 69 |
-
/// Otherwise, it returns false and a pointer to an empty or least valuable TTEntry
|
| 70 |
-
/// to be replaced later. The replace value of an entry is calculated as its depth
|
| 71 |
-
/// minus 8 times its relative age. TTEntry t1 is considered more valuable than
|
| 72 |
-
/// TTEntry t2 if its replace value is greater than that of t2.
|
| 73 |
-
|
| 74 |
-
TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
|
| 75 |
-
|
| 76 |
-
TTEntry* const tte = first_entry(key);
|
| 77 |
-
const uint16_t key16 = key >> 48; // Use the high 16 bits as key inside the cluster
|
| 78 |
-
|
| 79 |
-
for (int i = 0; i < ClusterSize; ++i)
|
| 80 |
-
if (!tte[i].key16 || tte[i].key16 == key16)
|
| 81 |
-
{
|
| 82 |
-
if ((tte[i].genBound8 & 0xFC) != generation8 && tte[i].key16)
|
| 83 |
-
tte[i].genBound8 = uint8_t(generation8 | tte[i].bound()); // Refresh
|
| 84 |
-
|
| 85 |
-
return found = (bool)tte[i].key16, &tte[i];
|
| 86 |
-
}
|
| 87 |
-
|
| 88 |
-
// Find an entry to be replaced according to the replacement strategy
|
| 89 |
-
TTEntry* replace = tte;
|
| 90 |
-
for (int i = 1; i < ClusterSize; ++i)
|
| 91 |
-
// Due to our packed storage format for generation and its cyclic
|
| 92 |
-
// nature we add 259 (256 is the modulus plus 3 to keep the lowest
|
| 93 |
-
// two bound bits from affecting the result) to calculate the entry
|
| 94 |
-
// age correctly even after generation8 overflows into the next cycle.
|
| 95 |
-
if ( replace->depth8 - ((259 + generation8 - replace->genBound8) & 0xFC) * 2
|
| 96 |
-
> tte[i].depth8 - ((259 + generation8 - tte[i].genBound8) & 0xFC) * 2)
|
| 97 |
-
replace = &tte[i];
|
| 98 |
-
|
| 99 |
-
return found = false, replace;
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
/// TranspositionTable::hashfull() returns an approximation of the hashtable
|
| 104 |
-
/// occupation during a search. The hash is x permill full, as per UCI protocol.
|
| 105 |
-
|
| 106 |
-
int TranspositionTable::hashfull() const {
|
| 107 |
-
|
| 108 |
-
int cnt = 0;
|
| 109 |
-
for (int i = 0; i < 1000 / ClusterSize; i++)
|
| 110 |
-
{
|
| 111 |
-
const TTEntry* tte = &table[i].entry[0];
|
| 112 |
-
for (int j = 0; j < ClusterSize; j++)
|
| 113 |
-
if ((tte[j].genBound8 & 0xFC) == generation8)
|
| 114 |
-
cnt++;
|
| 115 |
-
}
|
| 116 |
-
return cnt;
|
| 117 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/tt.h
DELETED
|
@@ -1,121 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef TT_H_INCLUDED
|
| 22 |
-
#define TT_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include "misc.h"
|
| 25 |
-
#include "types.h"
|
| 26 |
-
|
| 27 |
-
/// TTEntry struct is the 10 bytes transposition table entry, defined as below:
|
| 28 |
-
///
|
| 29 |
-
/// key 16 bit
|
| 30 |
-
/// move 16 bit
|
| 31 |
-
/// value 16 bit
|
| 32 |
-
/// eval value 16 bit
|
| 33 |
-
/// generation 6 bit
|
| 34 |
-
/// bound type 2 bit
|
| 35 |
-
/// depth 8 bit
|
| 36 |
-
|
| 37 |
-
struct TTEntry {
|
| 38 |
-
|
| 39 |
-
Move move() const { return (Move )move16; }
|
| 40 |
-
Value value() const { return (Value)value16; }
|
| 41 |
-
Value eval() const { return (Value)eval16; }
|
| 42 |
-
Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)); }
|
| 43 |
-
Bound bound() const { return (Bound)(genBound8 & 0x3); }
|
| 44 |
-
|
| 45 |
-
void save(Key k, Value v, Bound b, Depth d, Move m, Value ev, uint8_t g) {
|
| 46 |
-
|
| 47 |
-
assert(d / ONE_PLY * ONE_PLY == d);
|
| 48 |
-
|
| 49 |
-
// Preserve any existing move for the same position
|
| 50 |
-
if (m || (k >> 48) != key16)
|
| 51 |
-
move16 = (uint16_t)m;
|
| 52 |
-
|
| 53 |
-
// Don't overwrite more valuable entries
|
| 54 |
-
if ( (k >> 48) != key16
|
| 55 |
-
|| d / ONE_PLY > depth8 - 4
|
| 56 |
-
/* || g != (genBound8 & 0xFC) // Matching non-zero keys are already refreshed by probe() */
|
| 57 |
-
|| b == BOUND_EXACT)
|
| 58 |
-
{
|
| 59 |
-
key16 = (uint16_t)(k >> 48);
|
| 60 |
-
value16 = (int16_t)v;
|
| 61 |
-
eval16 = (int16_t)ev;
|
| 62 |
-
genBound8 = (uint8_t)(g | b);
|
| 63 |
-
depth8 = (int8_t)(d / ONE_PLY);
|
| 64 |
-
}
|
| 65 |
-
}
|
| 66 |
-
|
| 67 |
-
private:
|
| 68 |
-
friend class TranspositionTable;
|
| 69 |
-
|
| 70 |
-
uint16_t key16;
|
| 71 |
-
uint16_t move16;
|
| 72 |
-
int16_t value16;
|
| 73 |
-
int16_t eval16;
|
| 74 |
-
uint8_t genBound8;
|
| 75 |
-
int8_t depth8;
|
| 76 |
-
};
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
/// A TranspositionTable consists of a power of 2 number of clusters and each
|
| 80 |
-
/// cluster consists of ClusterSize number of TTEntry. Each non-empty entry
|
| 81 |
-
/// contains information of exactly one position. The size of a cluster should
|
| 82 |
-
/// divide the size of a cache line size, to ensure that clusters never cross
|
| 83 |
-
/// cache lines. This ensures best cache performance, as the cacheline is
|
| 84 |
-
/// prefetched, as soon as possible.
|
| 85 |
-
|
| 86 |
-
class TranspositionTable {
|
| 87 |
-
|
| 88 |
-
static const int CacheLineSize = 64;
|
| 89 |
-
static const int ClusterSize = 3;
|
| 90 |
-
|
| 91 |
-
struct Cluster {
|
| 92 |
-
TTEntry entry[ClusterSize];
|
| 93 |
-
char padding[2]; // Align to a divisor of the cache line size
|
| 94 |
-
};
|
| 95 |
-
|
| 96 |
-
static_assert(CacheLineSize % sizeof(Cluster) == 0, "Cluster size incorrect");
|
| 97 |
-
|
| 98 |
-
public:
|
| 99 |
-
~TranspositionTable() { free(mem); }
|
| 100 |
-
void new_search() { generation8 += 4; } // Lower 2 bits are used by Bound
|
| 101 |
-
uint8_t generation() const { return generation8; }
|
| 102 |
-
TTEntry* probe(const Key key, bool& found) const;
|
| 103 |
-
int hashfull() const;
|
| 104 |
-
void resize(size_t mbSize);
|
| 105 |
-
void clear();
|
| 106 |
-
|
| 107 |
-
// The lowest order bits of the key are used to get the index of the cluster
|
| 108 |
-
TTEntry* first_entry(const Key key) const {
|
| 109 |
-
return &table[(size_t)key & (clusterCount - 1)].entry[0];
|
| 110 |
-
}
|
| 111 |
-
|
| 112 |
-
private:
|
| 113 |
-
size_t clusterCount;
|
| 114 |
-
Cluster* table;
|
| 115 |
-
void* mem;
|
| 116 |
-
uint8_t generation8; // Size must be not bigger than TTEntry::genBound8
|
| 117 |
-
};
|
| 118 |
-
|
| 119 |
-
extern TranspositionTable TT;
|
| 120 |
-
|
| 121 |
-
#endif // #ifndef TT_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/types.h
DELETED
|
@@ -1,435 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef TYPES_H_INCLUDED
|
| 22 |
-
#define TYPES_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
/// When compiling with provided Makefile (e.g. for Linux and OSX), configuration
|
| 25 |
-
/// is done automatically. To get started type 'make help'.
|
| 26 |
-
///
|
| 27 |
-
/// When Makefile is not used (e.g. with Microsoft Visual Studio) some switches
|
| 28 |
-
/// need to be set manually:
|
| 29 |
-
///
|
| 30 |
-
/// -DNDEBUG | Disable debugging mode. Always use this for release.
|
| 31 |
-
///
|
| 32 |
-
/// -DNO_PREFETCH | Disable use of prefetch asm-instruction. You may need this to
|
| 33 |
-
/// | run on some very old machines.
|
| 34 |
-
///
|
| 35 |
-
/// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction. Works
|
| 36 |
-
/// | only in 64-bit mode and requires hardware with popcnt support.
|
| 37 |
-
///
|
| 38 |
-
/// -DUSE_PEXT | Add runtime support for use of pext asm-instruction. Works
|
| 39 |
-
/// | only in 64-bit mode and requires hardware with pext support.
|
| 40 |
-
|
| 41 |
-
#include <cassert>
|
| 42 |
-
#include <cctype>
|
| 43 |
-
#include <climits>
|
| 44 |
-
#include <cstdint>
|
| 45 |
-
#include <cstdlib>
|
| 46 |
-
|
| 47 |
-
#if defined(_MSC_VER)
|
| 48 |
-
// Disable some silly and noisy warning from MSVC compiler
|
| 49 |
-
#pragma warning(disable: 4127) // Conditional expression is constant
|
| 50 |
-
#pragma warning(disable: 4146) // Unary minus operator applied to unsigned type
|
| 51 |
-
#pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false'
|
| 52 |
-
#endif
|
| 53 |
-
|
| 54 |
-
/// Predefined macros hell:
|
| 55 |
-
///
|
| 56 |
-
/// __GNUC__ Compiler is gcc, Clang or Intel on Linux
|
| 57 |
-
/// __INTEL_COMPILER Compiler is Intel
|
| 58 |
-
/// _MSC_VER Compiler is MSVC or Intel on Windows
|
| 59 |
-
/// _WIN32 Building on Windows (any)
|
| 60 |
-
/// _WIN64 Building on Windows 64 bit
|
| 61 |
-
|
| 62 |
-
#if defined(_WIN64) && defined(_MSC_VER) // No Makefile used
|
| 63 |
-
# include <intrin.h> // Microsoft header for _BitScanForward64()
|
| 64 |
-
# define IS_64BIT
|
| 65 |
-
#endif
|
| 66 |
-
|
| 67 |
-
#if defined(USE_POPCNT) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
|
| 68 |
-
# include <nmmintrin.h> // Intel and Microsoft header for _mm_popcnt_u64()
|
| 69 |
-
#endif
|
| 70 |
-
|
| 71 |
-
#if !defined(NO_PREFETCH) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
|
| 72 |
-
# include <xmmintrin.h> // Intel and Microsoft header for _mm_prefetch()
|
| 73 |
-
#endif
|
| 74 |
-
|
| 75 |
-
#if defined(USE_PEXT)
|
| 76 |
-
# include <immintrin.h> // Header for _pext_u64() intrinsic
|
| 77 |
-
# define pext(b, m) _pext_u64(b, m)
|
| 78 |
-
#else
|
| 79 |
-
# define pext(b, m) (0)
|
| 80 |
-
#endif
|
| 81 |
-
|
| 82 |
-
#ifdef USE_POPCNT
|
| 83 |
-
const bool HasPopCnt = true;
|
| 84 |
-
#else
|
| 85 |
-
const bool HasPopCnt = false;
|
| 86 |
-
#endif
|
| 87 |
-
|
| 88 |
-
#ifdef USE_PEXT
|
| 89 |
-
const bool HasPext = true;
|
| 90 |
-
#else
|
| 91 |
-
const bool HasPext = false;
|
| 92 |
-
#endif
|
| 93 |
-
|
| 94 |
-
#ifdef IS_64BIT
|
| 95 |
-
const bool Is64Bit = true;
|
| 96 |
-
#else
|
| 97 |
-
const bool Is64Bit = false;
|
| 98 |
-
#endif
|
| 99 |
-
|
| 100 |
-
typedef uint64_t Key;
|
| 101 |
-
typedef uint64_t Bitboard;
|
| 102 |
-
|
| 103 |
-
const int MAX_MOVES = 256;
|
| 104 |
-
const int MAX_PLY = 128;
|
| 105 |
-
|
| 106 |
-
/// A move needs 16 bits to be stored
|
| 107 |
-
///
|
| 108 |
-
/// bit 0- 5: destination square (from 0 to 63)
|
| 109 |
-
/// bit 6-11: origin square (from 0 to 63)
|
| 110 |
-
/// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2)
|
| 111 |
-
/// bit 14-15: special move flag: promotion (1), en passant (2), castling (3)
|
| 112 |
-
/// NOTE: EN-PASSANT bit is set only when a pawn can be captured
|
| 113 |
-
///
|
| 114 |
-
/// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in because in
|
| 115 |
-
/// any normal move destination square is always different from origin square
|
| 116 |
-
/// while MOVE_NONE and MOVE_NULL have the same origin and destination square.
|
| 117 |
-
|
| 118 |
-
enum Move : int {
|
| 119 |
-
MOVE_NONE,
|
| 120 |
-
MOVE_NULL = 65
|
| 121 |
-
};
|
| 122 |
-
|
| 123 |
-
enum MoveType {
|
| 124 |
-
NORMAL,
|
| 125 |
-
PROMOTION = 1 << 14,
|
| 126 |
-
ENPASSANT = 2 << 14,
|
| 127 |
-
CASTLING = 3 << 14
|
| 128 |
-
};
|
| 129 |
-
|
| 130 |
-
enum Color {
|
| 131 |
-
WHITE, BLACK, NO_COLOR, COLOR_NB = 2
|
| 132 |
-
};
|
| 133 |
-
|
| 134 |
-
enum CastlingSide {
|
| 135 |
-
KING_SIDE, QUEEN_SIDE, CASTLING_SIDE_NB = 2
|
| 136 |
-
};
|
| 137 |
-
|
| 138 |
-
enum CastlingRight {
|
| 139 |
-
NO_CASTLING,
|
| 140 |
-
WHITE_OO,
|
| 141 |
-
WHITE_OOO = WHITE_OO << 1,
|
| 142 |
-
BLACK_OO = WHITE_OO << 2,
|
| 143 |
-
BLACK_OOO = WHITE_OO << 3,
|
| 144 |
-
ANY_CASTLING = WHITE_OO | WHITE_OOO | BLACK_OO | BLACK_OOO,
|
| 145 |
-
CASTLING_RIGHT_NB = 16
|
| 146 |
-
};
|
| 147 |
-
|
| 148 |
-
template<Color C, CastlingSide S> struct MakeCastling {
|
| 149 |
-
static const CastlingRight
|
| 150 |
-
right = C == WHITE ? S == QUEEN_SIDE ? WHITE_OOO : WHITE_OO
|
| 151 |
-
: S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO;
|
| 152 |
-
};
|
| 153 |
-
|
| 154 |
-
enum Phase {
|
| 155 |
-
PHASE_ENDGAME,
|
| 156 |
-
PHASE_MIDGAME = 128,
|
| 157 |
-
MG = 0, EG = 1, PHASE_NB = 2
|
| 158 |
-
};
|
| 159 |
-
|
| 160 |
-
enum ScaleFactor {
|
| 161 |
-
SCALE_FACTOR_DRAW = 0,
|
| 162 |
-
SCALE_FACTOR_ONEPAWN = 48,
|
| 163 |
-
SCALE_FACTOR_NORMAL = 64,
|
| 164 |
-
SCALE_FACTOR_MAX = 128,
|
| 165 |
-
SCALE_FACTOR_NONE = 255
|
| 166 |
-
};
|
| 167 |
-
|
| 168 |
-
enum Bound {
|
| 169 |
-
BOUND_NONE,
|
| 170 |
-
BOUND_UPPER,
|
| 171 |
-
BOUND_LOWER,
|
| 172 |
-
BOUND_EXACT = BOUND_UPPER | BOUND_LOWER
|
| 173 |
-
};
|
| 174 |
-
|
| 175 |
-
enum Value : int {
|
| 176 |
-
VALUE_ZERO = 0,
|
| 177 |
-
VALUE_DRAW = 0,
|
| 178 |
-
VALUE_KNOWN_WIN = 10000,
|
| 179 |
-
VALUE_MATE = 32000,
|
| 180 |
-
VALUE_INFINITE = 32001,
|
| 181 |
-
VALUE_NONE = 32002,
|
| 182 |
-
|
| 183 |
-
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY,
|
| 184 |
-
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY,
|
| 185 |
-
|
| 186 |
-
PawnValueMg = 188, PawnValueEg = 248,
|
| 187 |
-
KnightValueMg = 753, KnightValueEg = 832,
|
| 188 |
-
BishopValueMg = 826, BishopValueEg = 897,
|
| 189 |
-
RookValueMg = 1285, RookValueEg = 1371,
|
| 190 |
-
QueenValueMg = 2513, QueenValueEg = 2650,
|
| 191 |
-
|
| 192 |
-
MidgameLimit = 15258, EndgameLimit = 3915
|
| 193 |
-
};
|
| 194 |
-
|
| 195 |
-
enum PieceType {
|
| 196 |
-
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
|
| 197 |
-
ALL_PIECES = 0,
|
| 198 |
-
PIECE_TYPE_NB = 8
|
| 199 |
-
};
|
| 200 |
-
|
| 201 |
-
enum Piece {
|
| 202 |
-
NO_PIECE,
|
| 203 |
-
W_PAWN = 1, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
|
| 204 |
-
B_PAWN = 9, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING,
|
| 205 |
-
PIECE_NB = 16
|
| 206 |
-
};
|
| 207 |
-
|
| 208 |
-
const Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
|
| 209 |
-
B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING };
|
| 210 |
-
extern Value PieceValue[PHASE_NB][PIECE_NB];
|
| 211 |
-
|
| 212 |
-
enum Depth {
|
| 213 |
-
|
| 214 |
-
ONE_PLY = 1,
|
| 215 |
-
|
| 216 |
-
DEPTH_ZERO = 0 * ONE_PLY,
|
| 217 |
-
DEPTH_QS_CHECKS = 0 * ONE_PLY,
|
| 218 |
-
DEPTH_QS_NO_CHECKS = -1 * ONE_PLY,
|
| 219 |
-
DEPTH_QS_RECAPTURES = -5 * ONE_PLY,
|
| 220 |
-
|
| 221 |
-
DEPTH_NONE = -6 * ONE_PLY,
|
| 222 |
-
DEPTH_MAX = MAX_PLY * ONE_PLY
|
| 223 |
-
};
|
| 224 |
-
|
| 225 |
-
static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2");
|
| 226 |
-
|
| 227 |
-
enum Square {
|
| 228 |
-
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
|
| 229 |
-
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
|
| 230 |
-
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
|
| 231 |
-
SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4,
|
| 232 |
-
SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5,
|
| 233 |
-
SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6,
|
| 234 |
-
SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7,
|
| 235 |
-
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
|
| 236 |
-
SQ_NONE,
|
| 237 |
-
|
| 238 |
-
SQUARE_NB = 64,
|
| 239 |
-
|
| 240 |
-
NORTH = 8,
|
| 241 |
-
EAST = 1,
|
| 242 |
-
SOUTH = -8,
|
| 243 |
-
WEST = -1,
|
| 244 |
-
|
| 245 |
-
NORTH_EAST = NORTH + EAST,
|
| 246 |
-
SOUTH_EAST = SOUTH + EAST,
|
| 247 |
-
SOUTH_WEST = SOUTH + WEST,
|
| 248 |
-
NORTH_WEST = NORTH + WEST
|
| 249 |
-
};
|
| 250 |
-
|
| 251 |
-
enum File : int {
|
| 252 |
-
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB
|
| 253 |
-
};
|
| 254 |
-
|
| 255 |
-
enum Rank : int {
|
| 256 |
-
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB
|
| 257 |
-
};
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
/// Score enum stores a middlegame and an endgame value in a single integer
|
| 261 |
-
/// (enum). The least significant 16 bits are used to store the endgame value
|
| 262 |
-
/// and the upper 16 bits are used to store the middlegame value. Take some
|
| 263 |
-
/// care to avoid left-shifting a signed int to avoid undefined behavior.
|
| 264 |
-
enum Score : int { SCORE_ZERO };
|
| 265 |
-
|
| 266 |
-
inline Score make_score(int mg, int eg) {
|
| 267 |
-
return Score((int)((unsigned int)eg << 16) + mg);
|
| 268 |
-
}
|
| 269 |
-
|
| 270 |
-
/// Extracting the signed lower and upper 16 bits is not so trivial because
|
| 271 |
-
/// according to the standard a simple cast to short is implementation defined
|
| 272 |
-
/// and so is a right shift of a signed integer.
|
| 273 |
-
inline Value eg_value(Score s) {
|
| 274 |
-
|
| 275 |
-
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s + 0x8000) >> 16) };
|
| 276 |
-
return Value(eg.s);
|
| 277 |
-
}
|
| 278 |
-
|
| 279 |
-
inline Value mg_value(Score s) {
|
| 280 |
-
|
| 281 |
-
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
|
| 282 |
-
return Value(mg.s);
|
| 283 |
-
}
|
| 284 |
-
|
| 285 |
-
#define ENABLE_BASE_OPERATORS_ON(T) \
|
| 286 |
-
inline T operator+(T d1, T d2) { return T(int(d1) + int(d2)); } \
|
| 287 |
-
inline T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \
|
| 288 |
-
inline T operator*(int i, T d) { return T(i * int(d)); } \
|
| 289 |
-
inline T operator*(T d, int i) { return T(int(d) * i); } \
|
| 290 |
-
inline T operator-(T d) { return T(-int(d)); } \
|
| 291 |
-
inline T& operator+=(T& d1, T d2) { return d1 = d1 + d2; } \
|
| 292 |
-
inline T& operator-=(T& d1, T d2) { return d1 = d1 - d2; } \
|
| 293 |
-
inline T& operator*=(T& d, int i) { return d = T(int(d) * i); }
|
| 294 |
-
|
| 295 |
-
#define ENABLE_FULL_OPERATORS_ON(T) \
|
| 296 |
-
ENABLE_BASE_OPERATORS_ON(T) \
|
| 297 |
-
inline T& operator++(T& d) { return d = T(int(d) + 1); } \
|
| 298 |
-
inline T& operator--(T& d) { return d = T(int(d) - 1); } \
|
| 299 |
-
inline T operator/(T d, int i) { return T(int(d) / i); } \
|
| 300 |
-
inline int operator/(T d1, T d2) { return int(d1) / int(d2); } \
|
| 301 |
-
inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
|
| 302 |
-
|
| 303 |
-
ENABLE_FULL_OPERATORS_ON(Value)
|
| 304 |
-
ENABLE_FULL_OPERATORS_ON(PieceType)
|
| 305 |
-
ENABLE_FULL_OPERATORS_ON(Piece)
|
| 306 |
-
ENABLE_FULL_OPERATORS_ON(Color)
|
| 307 |
-
ENABLE_FULL_OPERATORS_ON(Depth)
|
| 308 |
-
ENABLE_FULL_OPERATORS_ON(Square)
|
| 309 |
-
ENABLE_FULL_OPERATORS_ON(File)
|
| 310 |
-
ENABLE_FULL_OPERATORS_ON(Rank)
|
| 311 |
-
|
| 312 |
-
ENABLE_BASE_OPERATORS_ON(Score)
|
| 313 |
-
|
| 314 |
-
#undef ENABLE_FULL_OPERATORS_ON
|
| 315 |
-
#undef ENABLE_BASE_OPERATORS_ON
|
| 316 |
-
|
| 317 |
-
/// Additional operators to add integers to a Value
|
| 318 |
-
inline Value operator+(Value v, int i) { return Value(int(v) + i); }
|
| 319 |
-
inline Value operator-(Value v, int i) { return Value(int(v) - i); }
|
| 320 |
-
inline Value& operator+=(Value& v, int i) { return v = v + i; }
|
| 321 |
-
inline Value& operator-=(Value& v, int i) { return v = v - i; }
|
| 322 |
-
|
| 323 |
-
/// Only declared but not defined. We don't want to multiply two scores due to
|
| 324 |
-
/// a very high risk of overflow. So user should explicitly convert to integer.
|
| 325 |
-
inline Score operator*(Score s1, Score s2);
|
| 326 |
-
|
| 327 |
-
/// Division of a Score must be handled separately for each term
|
| 328 |
-
inline Score operator/(Score s, int i) {
|
| 329 |
-
return make_score(mg_value(s) / i, eg_value(s) / i);
|
| 330 |
-
}
|
| 331 |
-
|
| 332 |
-
inline Color operator~(Color c) {
|
| 333 |
-
return Color(c ^ BLACK); // Toggle color
|
| 334 |
-
}
|
| 335 |
-
|
| 336 |
-
inline Square operator~(Square s) {
|
| 337 |
-
return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8
|
| 338 |
-
}
|
| 339 |
-
|
| 340 |
-
inline Piece operator~(Piece pc) {
|
| 341 |
-
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
|
| 342 |
-
}
|
| 343 |
-
|
| 344 |
-
inline CastlingRight operator|(Color c, CastlingSide s) {
|
| 345 |
-
return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c));
|
| 346 |
-
}
|
| 347 |
-
|
| 348 |
-
inline Value mate_in(int ply) {
|
| 349 |
-
return VALUE_MATE - ply;
|
| 350 |
-
}
|
| 351 |
-
|
| 352 |
-
inline Value mated_in(int ply) {
|
| 353 |
-
return -VALUE_MATE + ply;
|
| 354 |
-
}
|
| 355 |
-
|
| 356 |
-
inline Square make_square(File f, Rank r) {
|
| 357 |
-
return Square((r << 3) + f);
|
| 358 |
-
}
|
| 359 |
-
|
| 360 |
-
inline Piece make_piece(Color c, PieceType pt) {
|
| 361 |
-
return Piece((c << 3) + pt);
|
| 362 |
-
}
|
| 363 |
-
|
| 364 |
-
inline PieceType type_of(Piece pc) {
|
| 365 |
-
return PieceType(pc & 7);
|
| 366 |
-
}
|
| 367 |
-
|
| 368 |
-
inline Color color_of(Piece pc) {
|
| 369 |
-
assert(pc != NO_PIECE);
|
| 370 |
-
return Color(pc >> 3);
|
| 371 |
-
}
|
| 372 |
-
|
| 373 |
-
inline bool is_ok(Square s) {
|
| 374 |
-
return s >= SQ_A1 && s <= SQ_H8;
|
| 375 |
-
}
|
| 376 |
-
|
| 377 |
-
inline File file_of(Square s) {
|
| 378 |
-
return File(s & 7);
|
| 379 |
-
}
|
| 380 |
-
|
| 381 |
-
inline Rank rank_of(Square s) {
|
| 382 |
-
return Rank(s >> 3);
|
| 383 |
-
}
|
| 384 |
-
|
| 385 |
-
inline Square relative_square(Color c, Square s) {
|
| 386 |
-
return Square(s ^ (c * 56));
|
| 387 |
-
}
|
| 388 |
-
|
| 389 |
-
inline Rank relative_rank(Color c, Rank r) {
|
| 390 |
-
return Rank(r ^ (c * 7));
|
| 391 |
-
}
|
| 392 |
-
|
| 393 |
-
inline Rank relative_rank(Color c, Square s) {
|
| 394 |
-
return relative_rank(c, rank_of(s));
|
| 395 |
-
}
|
| 396 |
-
|
| 397 |
-
inline bool opposite_colors(Square s1, Square s2) {
|
| 398 |
-
int s = int(s1) ^ int(s2);
|
| 399 |
-
return ((s >> 3) ^ s) & 1;
|
| 400 |
-
}
|
| 401 |
-
|
| 402 |
-
inline Square pawn_push(Color c) {
|
| 403 |
-
return c == WHITE ? NORTH : SOUTH;
|
| 404 |
-
}
|
| 405 |
-
|
| 406 |
-
inline Square from_sq(Move m) {
|
| 407 |
-
return Square((m >> 6) & 0x3F);
|
| 408 |
-
}
|
| 409 |
-
|
| 410 |
-
inline Square to_sq(Move m) {
|
| 411 |
-
return Square(m & 0x3F);
|
| 412 |
-
}
|
| 413 |
-
|
| 414 |
-
inline MoveType type_of(Move m) {
|
| 415 |
-
return MoveType(m & (3 << 14));
|
| 416 |
-
}
|
| 417 |
-
|
| 418 |
-
inline PieceType promotion_type(Move m) {
|
| 419 |
-
return PieceType(((m >> 12) & 3) + KNIGHT);
|
| 420 |
-
}
|
| 421 |
-
|
| 422 |
-
inline Move make_move(Square from, Square to) {
|
| 423 |
-
return Move((from << 6) + to);
|
| 424 |
-
}
|
| 425 |
-
|
| 426 |
-
template<MoveType T>
|
| 427 |
-
inline Move make(Square from, Square to, PieceType pt = KNIGHT) {
|
| 428 |
-
return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
|
| 429 |
-
}
|
| 430 |
-
|
| 431 |
-
inline bool is_ok(Move m) {
|
| 432 |
-
return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE
|
| 433 |
-
}
|
| 434 |
-
|
| 435 |
-
#endif // #ifndef TYPES_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/uci.cpp
DELETED
|
@@ -1,289 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <iostream>
|
| 22 |
-
#include <sstream>
|
| 23 |
-
#include <string>
|
| 24 |
-
|
| 25 |
-
#include "evaluate.h"
|
| 26 |
-
#include "movegen.h"
|
| 27 |
-
#include "position.h"
|
| 28 |
-
#include "search.h"
|
| 29 |
-
#include "thread.h"
|
| 30 |
-
#include "timeman.h"
|
| 31 |
-
#include "uci.h"
|
| 32 |
-
|
| 33 |
-
using namespace std;
|
| 34 |
-
|
| 35 |
-
extern void benchmark(const Position& pos, istream& is);
|
| 36 |
-
|
| 37 |
-
namespace {
|
| 38 |
-
|
| 39 |
-
// FEN string of the initial position, normal chess
|
| 40 |
-
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
| 41 |
-
|
| 42 |
-
// A list to keep track of the position states along the setup moves (from the
|
| 43 |
-
// start position to the position just before the search starts). Needed by
|
| 44 |
-
// 'draw by repetition' detection.
|
| 45 |
-
StateListPtr States(new std::deque<StateInfo>(1));
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
// position() is called when engine receives the "position" UCI command.
|
| 49 |
-
// The function sets up the position described in the given FEN string ("fen")
|
| 50 |
-
// or the starting position ("startpos") and then makes the moves given in the
|
| 51 |
-
// following move list ("moves").
|
| 52 |
-
|
| 53 |
-
void position(Position& pos, istringstream& is) {
|
| 54 |
-
|
| 55 |
-
Move m;
|
| 56 |
-
string token, fen;
|
| 57 |
-
|
| 58 |
-
is >> token;
|
| 59 |
-
|
| 60 |
-
if (token == "startpos")
|
| 61 |
-
{
|
| 62 |
-
fen = StartFEN;
|
| 63 |
-
is >> token; // Consume "moves" token if any
|
| 64 |
-
}
|
| 65 |
-
else if (token == "fen")
|
| 66 |
-
while (is >> token && token != "moves")
|
| 67 |
-
fen += token + " ";
|
| 68 |
-
else
|
| 69 |
-
return;
|
| 70 |
-
|
| 71 |
-
States = StateListPtr(new std::deque<StateInfo>(1));
|
| 72 |
-
pos.set(fen, Options["UCI_Chess960"], &States->back(), Threads.main());
|
| 73 |
-
|
| 74 |
-
// Parse move list (if any)
|
| 75 |
-
while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
|
| 76 |
-
{
|
| 77 |
-
States->push_back(StateInfo());
|
| 78 |
-
pos.do_move(m, States->back(), pos.gives_check(m));
|
| 79 |
-
}
|
| 80 |
-
}
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
// setoption() is called when engine receives the "setoption" UCI command. The
|
| 84 |
-
// function updates the UCI option ("name") to the given value ("value").
|
| 85 |
-
|
| 86 |
-
void setoption(istringstream& is) {
|
| 87 |
-
|
| 88 |
-
string token, name, value;
|
| 89 |
-
|
| 90 |
-
is >> token; // Consume "name" token
|
| 91 |
-
|
| 92 |
-
// Read option name (can contain spaces)
|
| 93 |
-
while (is >> token && token != "value")
|
| 94 |
-
name += string(" ", name.empty() ? 0 : 1) + token;
|
| 95 |
-
|
| 96 |
-
// Read option value (can contain spaces)
|
| 97 |
-
while (is >> token)
|
| 98 |
-
value += string(" ", value.empty() ? 0 : 1) + token;
|
| 99 |
-
|
| 100 |
-
if (Options.count(name))
|
| 101 |
-
Options[name] = value;
|
| 102 |
-
else
|
| 103 |
-
sync_cout << "No such option: " << name << sync_endl;
|
| 104 |
-
}
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
// go() is called when engine receives the "go" UCI command. The function sets
|
| 108 |
-
// the thinking time and other parameters from the input string, then starts
|
| 109 |
-
// the search.
|
| 110 |
-
|
| 111 |
-
void go(Position& pos, istringstream& is) {
|
| 112 |
-
|
| 113 |
-
Search::LimitsType limits;
|
| 114 |
-
string token;
|
| 115 |
-
|
| 116 |
-
limits.startTime = now(); // As early as possible!
|
| 117 |
-
|
| 118 |
-
while (is >> token)
|
| 119 |
-
if (token == "searchmoves")
|
| 120 |
-
while (is >> token)
|
| 121 |
-
limits.searchmoves.push_back(UCI::to_move(pos, token));
|
| 122 |
-
|
| 123 |
-
else if (token == "wtime") is >> limits.time[WHITE];
|
| 124 |
-
else if (token == "btime") is >> limits.time[BLACK];
|
| 125 |
-
else if (token == "winc") is >> limits.inc[WHITE];
|
| 126 |
-
else if (token == "binc") is >> limits.inc[BLACK];
|
| 127 |
-
else if (token == "movestogo") is >> limits.movestogo;
|
| 128 |
-
else if (token == "depth") is >> limits.depth;
|
| 129 |
-
else if (token == "nodes") is >> limits.nodes;
|
| 130 |
-
else if (token == "movetime") is >> limits.movetime;
|
| 131 |
-
else if (token == "mate") is >> limits.mate;
|
| 132 |
-
else if (token == "infinite") limits.infinite = 1;
|
| 133 |
-
else if (token == "ponder") limits.ponder = 1;
|
| 134 |
-
|
| 135 |
-
Threads.start_thinking(pos, States, limits);
|
| 136 |
-
}
|
| 137 |
-
|
| 138 |
-
} // namespace
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
/// UCI::loop() waits for a command from stdin, parses it and calls the appropriate
|
| 142 |
-
/// function. Also intercepts EOF from stdin to ensure gracefully exiting if the
|
| 143 |
-
/// GUI dies unexpectedly. When called with some command line arguments, e.g. to
|
| 144 |
-
/// run 'bench', once the command is executed the function returns immediately.
|
| 145 |
-
/// In addition to the UCI ones, also some additional debug commands are supported.
|
| 146 |
-
|
| 147 |
-
void UCI::loop(int argc, char* argv[]) {
|
| 148 |
-
|
| 149 |
-
Position pos;
|
| 150 |
-
string token, cmd;
|
| 151 |
-
|
| 152 |
-
pos.set(StartFEN, false, &States->back(), Threads.main());
|
| 153 |
-
|
| 154 |
-
for (int i = 1; i < argc; ++i)
|
| 155 |
-
cmd += std::string(argv[i]) + " ";
|
| 156 |
-
|
| 157 |
-
do {
|
| 158 |
-
if (argc == 1 && !getline(cin, cmd)) // Block here waiting for input or EOF
|
| 159 |
-
cmd = "quit";
|
| 160 |
-
|
| 161 |
-
istringstream is(cmd);
|
| 162 |
-
|
| 163 |
-
token.clear(); // getline() could return empty or blank line
|
| 164 |
-
is >> skipws >> token;
|
| 165 |
-
|
| 166 |
-
// The GUI sends 'ponderhit' to tell us to ponder on the same move the
|
| 167 |
-
// opponent has played. In case Signals.stopOnPonderhit is set we are
|
| 168 |
-
// waiting for 'ponderhit' to stop the search (for instance because we
|
| 169 |
-
// already ran out of time), otherwise we should continue searching but
|
| 170 |
-
// switching from pondering to normal search.
|
| 171 |
-
if ( token == "quit"
|
| 172 |
-
|| token == "stop"
|
| 173 |
-
|| (token == "ponderhit" && Search::Signals.stopOnPonderhit))
|
| 174 |
-
{
|
| 175 |
-
Search::Signals.stop = true;
|
| 176 |
-
Threads.main()->start_searching(true); // Could be sleeping
|
| 177 |
-
}
|
| 178 |
-
else if (token == "ponderhit")
|
| 179 |
-
Search::Limits.ponder = 0; // Switch to normal search
|
| 180 |
-
|
| 181 |
-
else if (token == "uci")
|
| 182 |
-
sync_cout << "id name " << engine_info(true)
|
| 183 |
-
<< "\n" << Options
|
| 184 |
-
<< "\nuciok" << sync_endl;
|
| 185 |
-
|
| 186 |
-
else if (token == "ucinewgame")
|
| 187 |
-
{
|
| 188 |
-
Search::clear();
|
| 189 |
-
Time.availableNodes = 0;
|
| 190 |
-
}
|
| 191 |
-
else if (token == "isready") sync_cout << "readyok" << sync_endl;
|
| 192 |
-
else if (token == "go") go(pos, is);
|
| 193 |
-
else if (token == "position") position(pos, is);
|
| 194 |
-
else if (token == "setoption") setoption(is);
|
| 195 |
-
|
| 196 |
-
// Additional custom non-UCI commands, useful for debugging
|
| 197 |
-
else if (token == "flip") pos.flip();
|
| 198 |
-
else if (token == "bench") benchmark(pos, is);
|
| 199 |
-
else if (token == "d") sync_cout << pos << sync_endl;
|
| 200 |
-
else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl;
|
| 201 |
-
else if (token == "perft")
|
| 202 |
-
{
|
| 203 |
-
int depth;
|
| 204 |
-
stringstream ss;
|
| 205 |
-
|
| 206 |
-
is >> depth;
|
| 207 |
-
ss << Options["Hash"] << " "
|
| 208 |
-
<< Options["Threads"] << " " << depth << " current perft";
|
| 209 |
-
|
| 210 |
-
benchmark(pos, ss);
|
| 211 |
-
}
|
| 212 |
-
else
|
| 213 |
-
sync_cout << "Unknown command: " << cmd << sync_endl;
|
| 214 |
-
|
| 215 |
-
} while (token != "quit" && argc == 1); // Passed args have one-shot behaviour
|
| 216 |
-
|
| 217 |
-
Threads.main()->wait_for_search_finished();
|
| 218 |
-
}
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
/// UCI::value() converts a Value to a string suitable for use with the UCI
|
| 222 |
-
/// protocol specification:
|
| 223 |
-
///
|
| 224 |
-
/// cp <x> The score from the engine's point of view in centipawns.
|
| 225 |
-
/// mate <y> Mate in y moves, not plies. If the engine is getting mated
|
| 226 |
-
/// use negative values for y.
|
| 227 |
-
|
| 228 |
-
string UCI::value(Value v) {
|
| 229 |
-
|
| 230 |
-
stringstream ss;
|
| 231 |
-
|
| 232 |
-
if (abs(v) < VALUE_MATE - MAX_PLY)
|
| 233 |
-
ss << "cp " << v * 100 / PawnValueEg;
|
| 234 |
-
else
|
| 235 |
-
ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
|
| 236 |
-
|
| 237 |
-
return ss.str();
|
| 238 |
-
}
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
/// UCI::square() converts a Square to a string in algebraic notation (g1, a7, etc.)
|
| 242 |
-
|
| 243 |
-
std::string UCI::square(Square s) {
|
| 244 |
-
return std::string{ char('a' + file_of(s)), char('1' + rank_of(s)) };
|
| 245 |
-
}
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
/// UCI::move() converts a Move to a string in coordinate notation (g1f3, a7a8q).
|
| 249 |
-
/// The only special case is castling, where we print in the e1g1 notation in
|
| 250 |
-
/// normal chess mode, and in e1h1 notation in chess960 mode. Internally all
|
| 251 |
-
/// castling moves are always encoded as 'king captures rook'.
|
| 252 |
-
|
| 253 |
-
string UCI::move(Move m, bool chess960) {
|
| 254 |
-
|
| 255 |
-
Square from = from_sq(m);
|
| 256 |
-
Square to = to_sq(m);
|
| 257 |
-
|
| 258 |
-
if (m == MOVE_NONE)
|
| 259 |
-
return "(none)";
|
| 260 |
-
|
| 261 |
-
if (m == MOVE_NULL)
|
| 262 |
-
return "0000";
|
| 263 |
-
|
| 264 |
-
if (type_of(m) == CASTLING && !chess960)
|
| 265 |
-
to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
|
| 266 |
-
|
| 267 |
-
string move = UCI::square(from) + UCI::square(to);
|
| 268 |
-
|
| 269 |
-
if (type_of(m) == PROMOTION)
|
| 270 |
-
move += " pnbrqk"[promotion_type(m)];
|
| 271 |
-
|
| 272 |
-
return move;
|
| 273 |
-
}
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
/// UCI::to_move() converts a string representing a move in coordinate notation
|
| 277 |
-
/// (g1f3, a7a8q) to the corresponding legal Move, if any.
|
| 278 |
-
|
| 279 |
-
Move UCI::to_move(const Position& pos, string& str) {
|
| 280 |
-
|
| 281 |
-
if (str.length() == 5) // Junior could send promotion piece in uppercase
|
| 282 |
-
str[4] = char(tolower(str[4]));
|
| 283 |
-
|
| 284 |
-
for (const auto& m : MoveList<LEGAL>(pos))
|
| 285 |
-
if (str == UCI::move(m, pos.is_chess960()))
|
| 286 |
-
return m;
|
| 287 |
-
|
| 288 |
-
return MOVE_NONE;
|
| 289 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/uci.h
DELETED
|
@@ -1,80 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#ifndef UCI_H_INCLUDED
|
| 22 |
-
#define UCI_H_INCLUDED
|
| 23 |
-
|
| 24 |
-
#include <map>
|
| 25 |
-
#include <string>
|
| 26 |
-
|
| 27 |
-
#include "types.h"
|
| 28 |
-
|
| 29 |
-
class Position;
|
| 30 |
-
|
| 31 |
-
namespace UCI {
|
| 32 |
-
|
| 33 |
-
class Option;
|
| 34 |
-
|
| 35 |
-
/// Custom comparator because UCI options should be case insensitive
|
| 36 |
-
struct CaseInsensitiveLess {
|
| 37 |
-
bool operator() (const std::string&, const std::string&) const;
|
| 38 |
-
};
|
| 39 |
-
|
| 40 |
-
/// Our options container is actually a std::map
|
| 41 |
-
typedef std::map<std::string, Option, CaseInsensitiveLess> OptionsMap;
|
| 42 |
-
|
| 43 |
-
/// Option class implements an option as defined by UCI protocol
|
| 44 |
-
class Option {
|
| 45 |
-
|
| 46 |
-
typedef void (*OnChange)(const Option&);
|
| 47 |
-
|
| 48 |
-
public:
|
| 49 |
-
Option(OnChange = nullptr);
|
| 50 |
-
Option(bool v, OnChange = nullptr);
|
| 51 |
-
Option(const char* v, OnChange = nullptr);
|
| 52 |
-
Option(int v, int min, int max, OnChange = nullptr);
|
| 53 |
-
|
| 54 |
-
Option& operator=(const std::string&);
|
| 55 |
-
void operator<<(const Option&);
|
| 56 |
-
operator int() const;
|
| 57 |
-
operator std::string() const;
|
| 58 |
-
|
| 59 |
-
private:
|
| 60 |
-
friend std::ostream& operator<<(std::ostream&, const OptionsMap&);
|
| 61 |
-
|
| 62 |
-
std::string defaultValue, currentValue, type;
|
| 63 |
-
int min, max;
|
| 64 |
-
size_t idx;
|
| 65 |
-
OnChange on_change;
|
| 66 |
-
};
|
| 67 |
-
|
| 68 |
-
void init(OptionsMap&);
|
| 69 |
-
void loop(int argc, char* argv[]);
|
| 70 |
-
std::string value(Value v);
|
| 71 |
-
std::string square(Square s);
|
| 72 |
-
std::string move(Move m, bool chess960);
|
| 73 |
-
std::string pv(const Position& pos, Depth depth, Value alpha, Value beta);
|
| 74 |
-
Move to_move(const Position& pos, std::string& str);
|
| 75 |
-
|
| 76 |
-
} // namespace UCI
|
| 77 |
-
|
| 78 |
-
extern UCI::OptionsMap Options;
|
| 79 |
-
|
| 80 |
-
#endif // #ifndef UCI_H_INCLUDED
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stockfish-8-linux/src/ucioption.cpp
DELETED
|
@@ -1,163 +0,0 @@
|
|
| 1 |
-
/*
|
| 2 |
-
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
-
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
-
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
-
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
| 6 |
-
|
| 7 |
-
Stockfish is free software: you can redistribute it and/or modify
|
| 8 |
-
it under the terms of the GNU General Public License as published by
|
| 9 |
-
the Free Software Foundation, either version 3 of the License, or
|
| 10 |
-
(at your option) any later version.
|
| 11 |
-
|
| 12 |
-
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
-
GNU General Public License for more details.
|
| 16 |
-
|
| 17 |
-
You should have received a copy of the GNU General Public License
|
| 18 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
-
*/
|
| 20 |
-
|
| 21 |
-
#include <algorithm>
|
| 22 |
-
#include <cassert>
|
| 23 |
-
#include <ostream>
|
| 24 |
-
|
| 25 |
-
#include "misc.h"
|
| 26 |
-
#include "search.h"
|
| 27 |
-
#include "thread.h"
|
| 28 |
-
#include "tt.h"
|
| 29 |
-
#include "uci.h"
|
| 30 |
-
#include "syzygy/tbprobe.h"
|
| 31 |
-
|
| 32 |
-
using std::string;
|
| 33 |
-
|
| 34 |
-
UCI::OptionsMap Options; // Global object
|
| 35 |
-
|
| 36 |
-
namespace UCI {
|
| 37 |
-
|
| 38 |
-
/// 'On change' actions, triggered by an option's value change
|
| 39 |
-
void on_clear_hash(const Option&) { Search::clear(); }
|
| 40 |
-
void on_hash_size(const Option& o) { TT.resize(o); }
|
| 41 |
-
void on_logger(const Option& o) { start_logger(o); }
|
| 42 |
-
void on_threads(const Option&) { Threads.read_uci_options(); }
|
| 43 |
-
void on_tb_path(const Option& o) { Tablebases::init(o); }
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
/// Our case insensitive less() function as required by UCI protocol
|
| 47 |
-
bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const {
|
| 48 |
-
|
| 49 |
-
return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(),
|
| 50 |
-
[](char c1, char c2) { return tolower(c1) < tolower(c2); });
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
/// init() initializes the UCI options to their hard-coded default values
|
| 55 |
-
|
| 56 |
-
void init(OptionsMap& o) {
|
| 57 |
-
|
| 58 |
-
const int MaxHashMB = Is64Bit ? 1024 * 1024 : 2048;
|
| 59 |
-
|
| 60 |
-
o["Debug Log File"] << Option("", on_logger);
|
| 61 |
-
o["Contempt"] << Option(0, -100, 100);
|
| 62 |
-
o["Threads"] << Option(1, 1, 128, on_threads);
|
| 63 |
-
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
| 64 |
-
o["Clear Hash"] << Option(on_clear_hash);
|
| 65 |
-
o["Ponder"] << Option(false);
|
| 66 |
-
o["MultiPV"] << Option(1, 1, 500);
|
| 67 |
-
o["Skill Level"] << Option(20, 0, 20);
|
| 68 |
-
o["Move Overhead"] << Option(30, 0, 5000);
|
| 69 |
-
o["Minimum Thinking Time"] << Option(20, 0, 5000);
|
| 70 |
-
o["Slow Mover"] << Option(89, 10, 1000);
|
| 71 |
-
o["nodestime"] << Option(0, 0, 10000);
|
| 72 |
-
o["UCI_Chess960"] << Option(false);
|
| 73 |
-
o["SyzygyPath"] << Option("<empty>", on_tb_path);
|
| 74 |
-
o["SyzygyProbeDepth"] << Option(1, 1, 100);
|
| 75 |
-
o["Syzygy50MoveRule"] << Option(true);
|
| 76 |
-
o["SyzygyProbeLimit"] << Option(6, 0, 6);
|
| 77 |
-
}
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
/// operator<<() is used to print all the options default values in chronological
|
| 81 |
-
/// insertion order (the idx field) and in the format defined by the UCI protocol.
|
| 82 |
-
|
| 83 |
-
std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
|
| 84 |
-
|
| 85 |
-
for (size_t idx = 0; idx < om.size(); ++idx)
|
| 86 |
-
for (const auto& it : om)
|
| 87 |
-
if (it.second.idx == idx)
|
| 88 |
-
{
|
| 89 |
-
const Option& o = it.second;
|
| 90 |
-
os << "\noption name " << it.first << " type " << o.type;
|
| 91 |
-
|
| 92 |
-
if (o.type != "button")
|
| 93 |
-
os << " default " << o.defaultValue;
|
| 94 |
-
|
| 95 |
-
if (o.type == "spin")
|
| 96 |
-
os << " min " << o.min << " max " << o.max;
|
| 97 |
-
|
| 98 |
-
break;
|
| 99 |
-
}
|
| 100 |
-
|
| 101 |
-
return os;
|
| 102 |
-
}
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
/// Option class constructors and conversion operators
|
| 106 |
-
|
| 107 |
-
Option::Option(const char* v, OnChange f) : type("string"), min(0), max(0), on_change(f)
|
| 108 |
-
{ defaultValue = currentValue = v; }
|
| 109 |
-
|
| 110 |
-
Option::Option(bool v, OnChange f) : type("check"), min(0), max(0), on_change(f)
|
| 111 |
-
{ defaultValue = currentValue = (v ? "true" : "false"); }
|
| 112 |
-
|
| 113 |
-
Option::Option(OnChange f) : type("button"), min(0), max(0), on_change(f)
|
| 114 |
-
{}
|
| 115 |
-
|
| 116 |
-
Option::Option(int v, int minv, int maxv, OnChange f) : type("spin"), min(minv), max(maxv), on_change(f)
|
| 117 |
-
{ defaultValue = currentValue = std::to_string(v); }
|
| 118 |
-
|
| 119 |
-
Option::operator int() const {
|
| 120 |
-
assert(type == "check" || type == "spin");
|
| 121 |
-
return (type == "spin" ? stoi(currentValue) : currentValue == "true");
|
| 122 |
-
}
|
| 123 |
-
|
| 124 |
-
Option::operator std::string() const {
|
| 125 |
-
assert(type == "string");
|
| 126 |
-
return currentValue;
|
| 127 |
-
}
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
/// operator<<() inits options and assigns idx in the correct printing order
|
| 131 |
-
|
| 132 |
-
void Option::operator<<(const Option& o) {
|
| 133 |
-
|
| 134 |
-
static size_t insert_order = 0;
|
| 135 |
-
|
| 136 |
-
*this = o;
|
| 137 |
-
idx = insert_order++;
|
| 138 |
-
}
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
/// operator=() updates currentValue and triggers on_change() action. It's up to
|
| 142 |
-
/// the GUI to check for option's limits, but we could receive the new value from
|
| 143 |
-
/// the user by console window, so let's check the bounds anyway.
|
| 144 |
-
|
| 145 |
-
Option& Option::operator=(const string& v) {
|
| 146 |
-
|
| 147 |
-
assert(!type.empty());
|
| 148 |
-
|
| 149 |
-
if ( (type != "button" && v.empty())
|
| 150 |
-
|| (type == "check" && v != "true" && v != "false")
|
| 151 |
-
|| (type == "spin" && (stoi(v) < min || stoi(v) > max)))
|
| 152 |
-
return *this;
|
| 153 |
-
|
| 154 |
-
if (type != "button")
|
| 155 |
-
currentValue = v;
|
| 156 |
-
|
| 157 |
-
if (on_change)
|
| 158 |
-
on_change(*this);
|
| 159 |
-
|
| 160 |
-
return *this;
|
| 161 |
-
}
|
| 162 |
-
|
| 163 |
-
} // namespace UCI
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|