Compare commits

..

23 Commits

Author SHA1 Message Date
Marco Costalba 48cfdfcc46 Fix threads count setting
Was broken after "Optimal tune for 8 cores" patch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 20:57:33 +01:00
Marco Costalba fa7b244dc9 Optimal tune for 8 cores
After deep tests Louis Zulli found on his OCTAL machine that
best setup for an 8 core CPU is as following

"Threads" = 8
"Minimum Split Depth" = 6 or 7 (mSD)
"Maximum Number of Threads per Split Point" = not important (MNTpSP)

Here are testing results:

mSD7 (8 threads) vs mSD4 (8 threads): 291 - 120 - 589
mSD6 vs mSD7: 168 - 188 - 644
mSD6-MNTpSP5 vs mSD6-MNTpSP6: 172 - 172 - 656
SF-7threads vs SF-8threads: 179 - 204 - 617

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 20:57:17 +01:00
Marco Costalba 29ad6a73fc Fix duplicated scaling function
We erroneusly added two times the same scaling function
to endgame's map.

Fix detected by valgrind becasue resulted in a memleak
of the first added scaling function.

Bug introduced by 30e8f0c9ad6a473 of 13/02/2009

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 19:40:43 +01:00
Marco Costalba ac48b16708 Update release number
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 14:59:55 +01:00
Marco Costalba 38b1c4b6b8 Another TT size limit fix attempt
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 14:17:00 +01:00
Marco Costalba 162dbeaee8 Remove a bogus assert
It is not true with old 1.6.xx code

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 14:09:23 +01:00
Marco Costalba 85146ca0a9 Check bounds in set_option_value()
Normally it's up to the GUI to check for option's limits,
but we could receive the new value directly from the user
by teminal window. So let's check the bounds anyway.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 14:06:59 +01:00
Joona Kiiski 02e12a69a7 Remove InfiniteSearch hack
With current search control system, I can see absolutely no
reason to classify fixed time search as infinite search.

So remove old dated hack

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 13:15:28 +01:00
Tord Romstad 6e8116e38f Make sure we make a move at the end of the search when reaching
maximum depth during a "go movetime ..." search. This prevents
Stockfish from hanging forever after finding a mate in two or
three while running a test suite at a level of a few seconds
per move.

No functional change when playing games at normal time controls.
2010-02-01 13:13:58 +01:00
Marco Costalba 29f7fab2a9 Do not wait when AbortSearch is set
It means we have already received "stop" or "quit" commands.

This fixes an hang in tactical test in Fritz GUI. Bug
introduced by previous bug fix :-(

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 13:13:20 +01:00
Marco Costalba 2af986bf31 Fix sending of best move during an infinite search
According to UCI standard once engine receives 'go infinite'
command it should search until the "stop" command and do not exit
the search without being told so, even if PLY_MAX has been reached.

Patch is quite invasive because it cleanups some hacks used
by fixed depth and fixed nodes modes, mainly during benchmarks.

Bug found by Pascal Georges.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 13:10:21 +01:00
Marco Costalba b67146b100 Add hardware POPCNT support for gcc
With new target 'make gcc-popcnt' it is now
possible to compile with enabled hardware POPCNT
support also with gcc. Until now was possible only
for Intel and MSVC compilers.

When this instruction is supported by CPU, for instance
on Intel i7 or i5 family, produced binary is a bit faster.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:48:49 +01:00
Joona Kiiski c1b1a94d81 Standardize set_option function
Previously input like "setoption name Use Search Log value true "
(note space at the end of the line) didn't work.

Now parse value same way as option name. This way we implicitly
left- and right-trim value.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:48:11 +01:00
Joona Kiiski 17212e5fcc Remove last use of uip.eof()
Value of uip.eof() should not be trusted.
input like "go infinite searchmoves " (note space in the end of line)
causes problems.

Check the return value of (uip >> token) instead

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:46:03 +01:00
Marco Costalba 46921dff27 Fix a couple of MSVC casting warnings
Also removed some trailing whitespaces and aligned
indentation to current standard.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:45:04 +01:00
Marco Costalba 941016e7a2 Check for thread creation successful completion
It is a good programming practice to verify a system
call has indeed succeed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:44:11 +01:00
Tord Romstad 290caf9960 Fixes a Chess960 bug when playing with more than one search thread.
The init_eval() function corrupted the static array castleRightsMask[]
in the Position class, resulting in instant crashes in most Chess960
games. Fixed by repairing the damage directly after the function is
called. Also modified the Position::to_fen() function to display
castle rights correctly for Chess960 positions, and added sanity checks
for uncastled rook files in Position::is_ok().
2010-02-01 12:40:09 +01:00
Marco Costalba 43fa3a4d64 Fix some races in SMP code
When a search fails high then sp->alpha is increased and
slave threads are requested to stop.

So we have to check for a stop request before to start a search
otherwise we could end up with sp->alpha >= sp->beta
leading to an assert in debug run in search_pv().

This patch fixes the assert and get rid of some of possible races.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:39:53 +01:00
Marco Costalba 64b4836d12 Fix enum Value issue with gcc 4.4
Louis Zulli reports a miscompile with g++-4.4 from MacPorts.

Namely enum Value is compiled as unsigned instead of signed integer
and this yields an issue in score_string() where float(v) is incorrectly
casted when Value v is negative.

This patch ensure that compiler choses a signed variable to store a Value.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:39:21 +01:00
Marco Costalba 5df7d62eb9 Fix 'position ..... moves ' parsing bug
If after 'moves' there is a space then we crash.

The problem is that operator>>() trims whitespaces so that
after 'moves' has been extract we are still not at eof()
but remaining string contains only spaces. So that the next
extarction operation uip >> token ends up with unchanged token
value that remains 'moves', this garbage value is then feeded
to RootPosition.do_move() through move_from_string() that does
not detect the invalid move value leading to a crash.

This bug is triggered by Shredder 12 interface under Mac that
puts a space after 'moves' without any actual move list.

Bug fixed by Justin Blanchard

After reviewing UCI parsing code I spotted other possible weak
points due to the fact that we don't test if the last extract
operation has been succesful. So I have extended Justing patch
to fix the remaining possible holes in uci.cpp

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:36:30 +01:00
Marco Costalba 82179c70dc Fix en-passant parsing from fen string
According to standard en-passant is recorded in fen string regardless
of whether there is a pawn in position to make an en passant capture.

Instead internally we set ep square only if the pawn can be captured.
So teach from_fen() to correctly handle this difference.

Bug reported and fixed by Justin Blanchard.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:36:06 +01:00
Marco Costalba de17652e47 Fix a possible crash in thread_is_available()
When we have more then 2 threads then we do an array
access with index 'Threads[slave].activeSplitPoints - 1'
This should be >= 0 because we tested the variable just
few statements before, but because is a shared variable
it could be that the 'slave' thread set the value to zero
just after we test it, so that when we use the decremented
variable for array access we crash.

Bug spotted by Bruno Causse.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:34:31 +01:00
Marco Costalba 647b79b556 Extend maximum hash size to 8 GB
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:14:37 +01:00
60 changed files with 3668 additions and 3539 deletions
+19 -4
View File
@@ -7,7 +7,7 @@ EngineCommand = ./stockfish
Book = false Book = false
BookFile = book.bin BookFile = book.bin
Log = false Log = true
LogFile = stockfish.log LogFile = stockfish.log
Resign = true Resign = true
@@ -19,18 +19,28 @@ Hash = 128
Threads = 1 Threads = 1
OwnBook = false OwnBook = false
Book File = book.bin Book File = book.bin
Best Book Move = false
Use Search Log = false Use Search Log = false
Search Log Filename = SearchLog.txt
Mobility (Middle Game) = 100 Mobility (Middle Game) = 100
Mobility (Endgame) = 100 Mobility (Endgame) = 100
Pawn Structure (Middle Game) = 100 Pawn Structure (Middle Game) = 100
Pawn Structure (Endgame) = 100 Pawn Structure (Endgame) = 100
Passed Pawns (Middle Game) = 100 Passed Pawns (Middle Game) = 100
Passed Pawns (Endgame) = 100 Passed Pawns (Endgame) = 100
Space = 100
Aggressiveness = 100 Aggressiveness = 100
Cowardice = 100 Cowardice = 100
King Safety Curve = Quadratic
Quadratic = Linear
King Safety Coefficient = 40
King Safety X Intercept = 0
King Safety Max Slope = 30
King Safety Max Value = 500
Queen Contact Check Bonus = 3
Queen Check Bonus = 2
Rook Check Bonus = 1
Bishop Check Bonus = 1
Knight Check Bonus = 1
Discovered Check Bonus = 3
Mate Threat Bonus = 3
Check Extension (PV nodes) = 2 Check Extension (PV nodes) = 2
Check Extension (non-PV nodes) = 1 Check Extension (non-PV nodes) = 1
Single Reply Extension (PV nodes) = 2 Single Reply Extension (PV nodes) = 2
@@ -43,6 +53,11 @@ Passed Pawn Extension (PV nodes) = 1
Passed Pawn Extension (non-PV nodes) = 0 Passed Pawn Extension (non-PV nodes) = 0
Pawn Endgame Extension (PV nodes) = 2 Pawn Endgame Extension (PV nodes) = 2
Pawn Endgame Extension (non-PV nodes) = 2 Pawn Endgame Extension (non-PV nodes) = 2
Full Depth Moves (PV nodes) = 14
Full Depth Moves (non-PV nodes) = 3
Threat Depth = 5
Futility Pruning (Main Search) = true
Futility Pruning (Quiescence Search) = true
Randomness = 0 Randomness = 0
Minimum Split Depth = 4 Minimum Split Depth = 4
Maximum Number of Threads per Split Point = 5 Maximum Number of Threads per Split Point = 5
+257 -450
View File
@@ -1,7 +1,7 @@
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1 # Stockfish, a UCI chess playing engine derived from Glaurung 2.1
# Copyright (C) 2004-2008 Tord Romstad (Glaurung author) # Copyright (C) 2004-2007 Tord Romstad
# Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad # Copyright (C) 2008 Marco Costalba
#
# This file is part of Stockfish. # This file is part of Stockfish.
# #
# Stockfish is free software: you can redistribute it and/or modify # Stockfish is free software: you can redistribute it and/or modify
@@ -18,490 +18,297 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
### ========================================================================== ### Executable name. Do not change
### Section 1. General Configuration
### ==========================================================================
### Executable name
EXE = stockfish EXE = stockfish
### Installation dir definitions
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
### Built-in benchmark for pgo-builds ### ==========================================================================
### Compiler speed switches for both GCC and ICC. These settings are generally
### fast on a broad range of systems, but may be changed experimentally
### ==========================================================================
GCCFLAGS = -O3 -msse
ICCFLAGS = -fast -msse
ICCFLAGS-OSX = -fast -mdynamic-no-pic
### ==========================================================================
### Enable/disable debugging, disabled by default
### ==========================================================================
GCCFLAGS += -DNDEBUG
ICCFLAGS += -DNDEBUG
ICCFLAGS-OSX += -DNDEBUG
### ==========================================================================
### Remove below comments to compile for a big-endian machine
### ==========================================================================
#GCCFLAGS += -DBIGENDIAN
#ICCFLAGS += -DBIGENDIAN
#ICCFLAGS-OSX += -DBIGENDIAN
### ==========================================================================
### Run built-in benchmark for pgo-builds with: 32MB hash 1 thread 10 depth
### These settings are generally fast, but may be changed experimentally
### ==========================================================================
PGOBENCH = ./$(EXE) bench 32 1 10 default depth PGOBENCH = ./$(EXE) bench 32 1 10 default depth
### Object files
### General compiler settings. Do not change
GCCFLAGS += -g -Wall -fno-exceptions -fno-rtti
ICCFLAGS += -g -Wall -fno-exceptions -fno-rtti -wd383,869,981,10187,10188,11505,11503
ICCFLAGS-OSX += -g -Wall -fno-exceptions -fno-rtti -wd383,869,981,10187,10188,11505,11503
### General linker settings. Do not change
LDFLAGS = -lpthread
### Object files. Do not change
OBJS = application.o bitboard.o pawns.o material.o endgame.o evaluate.o main.o \ OBJS = application.o bitboard.o pawns.o material.o endgame.o evaluate.o main.o \
misc.o move.o movegen.o history.o movepick.o search.o piece.o \ misc.o move.o movegen.o history.o movepick.o search.o piece.o \
position.o direction.o tt.o value.o uci.o ucioption.o \ position.o direction.o tt.o value.o uci.o ucioption.o \
mersenne.o book.o bitbase.o san.o benchmark.o mersenne.o book.o bitbase.o san.o benchmark.o
### ========================================================================== ### General rules. Do not change
### Section 2. High-level Configuration
### ==========================================================================
#
# flag --- Comp switch --- Description
# ----------------------------------------------------------------------------
#
# debug = no/yes --- -DNDEBUG --- Enable/Disable debug mode
# optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations
# arch = (name) --- (-arch) --- Target architecture
# os = (name) --- --- Target operating system
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
# bigendian = no/yes --- -DBIGENDIAN --- big/little-endian byte order
# prefetch = no/yes --- -DUSE_PREFETCH --- Use prefetch x86 asm-instruction
# bsfq = no/yes --- -DUSE_BSFQ --- Use bsfq x86_64 asm-instruction
# --- (Works only with GCC and ICC 64-bit)
# popcnt = no/yes --- -DUSE_POPCNT --- Use popcnt x86_64 asm-instruction
#
# Note that Makefile is space sensitive, so when adding new architectures
# or modifying existing flags, you have to make sure there are no extra spaces
# at the end of the line for flag values.
### 2.1. General
debug = no
optimize = yes
### 2.2 Architecture specific
# General-section
ifeq ($(ARCH),general-64)
arch = any
os = any
bits = 64
bigendian = no
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),general-32)
arch = any
os = any
bits = 32
bigendian = no
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),bigendian-64)
arch = any
os = any
bits = 64
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),bigendian-32)
arch = any
os = any
bits = 32
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
# x86-section
ifeq ($(ARCH),x86-64)
arch = x86_64
os = any
bits = 64
bigendian = no
prefetch = yes
bsfq = yes
popcnt = no
endif
ifeq ($(ARCH),x86-64-modern)
arch = x86_64
os = any
bits = 64
bigendian = no
prefetch = yes
bsfq = yes
popcnt = yes
endif
ifeq ($(ARCH),x86-32)
arch = i386
os = any
bits = 32
bigendian = no
prefetch = yes
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),x86-32-old)
arch = i386
os = any
bits = 32
bigendian = no
prefetch = no
bsfq = no
popcnt = no
endif
# osx-section
ifeq ($(ARCH),osx-ppc-64)
arch = ppc64
os = osx
bits = 64
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),osx-ppc-32)
arch = ppc
os = osx
bits = 32
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),osx-x86-64)
arch = x86_64
os = osx
bits = 64
bigendian = no
prefetch = yes
bsfq = yes
popcnt = no
endif
ifeq ($(ARCH),osx-x86-32)
arch = i386
os = osx
bits = 32
bigendian = no
prefetch = yes
bsfq = no
popcnt = no
endif
### ==========================================================================
### Section 3. Low-level configuration
### ==========================================================================
### 3.1 Selecting compiler (default = gcc)
ifeq ($(COMP),)
COMP=gcc
endif
ifeq ($(COMP),gcc)
comp=gcc
CXX=g++
profile_prepare = gcc-profile-prepare
profile_make = gcc-profile-make
profile_use = gcc-profile-use
profile_clean = gcc-profile-clean
endif
ifeq ($(COMP),icc)
comp=icc
CXX=icpc
profile_prepare = icc-profile-prepare
profile_make = icc-profile-make
profile_use = icc-profile-use
profile_clean = icc-profile-clean
endif
### 3.2 General compiler settings
CXXFLAGS += -g -Wall -fno-exceptions -fno-rtti $(EXTRACXXFLAGS)
ifeq ($(comp),icc)
CXXFLAGS += -wd383,869,981,10187,10188,11505,11503
endif
ifeq ($(os),osx)
CXXFLAGS += -arch $(arch)
endif
### 3.3 General linker settings
LDFLAGS += -lpthread $(EXTRALDFLAGS)
ifeq ($(os),osx)
LDFLAGS += -arch $(arch)
endif
### 3.4 Debugging
ifeq ($(debug),no)
CXXFLAGS += -DNDEBUG
endif
### 3.5 Optimization
ifeq ($(optimize),yes)
ifeq ($(comp),gcc)
CXXFLAGS += -O3
ifeq ($(os),osx)
ifeq ($(arch),i386)
CXXFLAGS += -mdynamic-no-pic
endif
ifeq ($(arch),x86_64)
CXXFLAGS += -mdynamic-no-pic
endif
endif
endif
ifeq ($(comp),icc)
CXXFLAGS += -fast
ifeq ($(os),osx)
CXXFLAGS += -mdynamic-no-pic
endif
endif
endif
### 3.6. Bits
ifeq ($(bits),64)
CXXFLAGS += -DIS_64BIT
endif
### 3.7 Endianess
ifeq ($(bigendian),yes)
CXXFLAGS += -DBIGENDIAN
endif
### 3.8 prefetch
ifeq ($(prefetch),yes)
CXXFLAGS += -msse
DEPENDFLAGS += -msse
else
CXXFLAGS += -DNO_PREFETCH
endif
### 3.9 bsfq
ifeq ($(bsfq),yes)
CXXFLAGS += -DUSE_BSFQ
endif
### 3.10 popcnt
ifeq ($(popcnt),yes)
CXXFLAGS += -DUSE_POPCNT
endif
### ==========================================================================
### Section 4. Public targets
### ==========================================================================
default: default:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) build $(MAKE) gcc
help: help:
@echo "" @echo ""
@echo "To compile stockfish, type: " @echo "Makefile options:"
@echo "" @echo ""
@echo "make target ARCH=arch [COMP=comp]" @echo "make > Default: Compiler = g++"
@echo "" @echo "make gcc-popcnt > Compiler = g++ + popcnt-support"
@echo "Supported targets:" @echo "make icc > Compiler = icpc"
@echo "" @echo "make icc-profile > Compiler = icpc + automatic pgo-build"
@echo "build > Build unoptimized version" @echo "make icc-profile-popcnt > Compiler = icpc + automatic pgo-build + popcnt-support"
@echo "profile-build > Build PGO-optimized version" @echo "make osx-ppc32 > PPC-Mac OS X 32 bit. Compiler = g++"
@echo "popcnt-profile-build > Build PGO-optimized version with optional popcnt-support" @echo "make osx-ppc64 > PPC-Mac OS X 64 bit. Compiler = g++"
@echo "strip > Strip executable" @echo "make osx-x86 > x86-Mac OS X 32 bit. Compiler = g++"
@echo "install > Install executable" @echo "make osx-x86_64 > x86-Mac OS X 64 bit. Compiler = g++"
@echo "clean > Clean up" @echo "make osx-icc32 > x86-Mac OS X 32 bit. Compiler = icpc"
@echo "testrun > Make sample run" @echo "make osx-icc64 > x86-Mac OS X 64 bit. Compiler = icpc"
@echo "" @echo "make osx-icc32-profile > OSX 32 bit. Compiler = icpc + automatic pgo-build"
@echo "Supported archs:" @echo "make osx-icc64-profile > OSX 64 bit. Compiler = icpc + automatic pgo-build"
@echo "" @echo "make strip > Strip executable"
@echo "x86-64 > x86 64-bit" @echo "make clean > Clean up"
@echo "x86-64-modern > x86 64-bit with runtime support for popcnt-instruction"
@echo "x86-32 > x86 32-bit excluding very old hardware without SSE-support"
@echo "x86-32-old > x86 32-bit including also very old hardware"
@echo "osx-ppc-64 > PPC-Mac OS X 64 bit"
@echo "osx-ppc-32 > PPC-Mac OS X 32 bit"
@echo "osx-x86-64 > x86-Mac OS X 64 bit"
@echo "osx-x86-32 > x86-Mac OS X 32 bit"
@echo "general-64 > unspecified 64-bit"
@echo "general-32 > unspecified 32-bit"
@echo "bigendian-64 > unspecified 64-bit with bigendian byte order"
@echo "bigendian-32 > unspecified 32-bit with bigendian byte order"
@echo ""
@echo "Supported comps:"
@echo ""
@echo "gcc > Gnu compiler (default)"
@echo "icc > Intel compiler"
@echo ""
@echo "Non-standard targets:"
@echo ""
@echo "make hpux > Compile for HP-UX. Compiler = aCC"
@echo ""
@echo "Examples. If you don't know what to do, you likely want to run: "
@echo ""
@echo "make profile-build ARCH=x86-64 (This is for 64-bit systems)"
@echo "make profile-build ARCH=x86-32 (This is for 32-bit systems)"
@echo "" @echo ""
build: all: $(EXE) .depend
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
profile-build: clean:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity $(RM) *.o .depend *~ $(EXE)
@echo ""
@echo "Step 0/4. Preparing for profile build."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
@echo ""
@echo "Step 1/4. Building executable for benchmark ..."
@touch *.cpp *.h
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
@echo ""
@echo "Step 2/4. Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo ""
@echo "Step 3/4. Building final executable ..."
@touch *.cpp
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
@echo ""
@echo "Step 4/4. Deleting profile data ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean)
popcnt-profile-build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity ### Possible targets. You may add your own ones here
@echo "" gcc:
@echo "Step 0/6. Preparing for profile build." $(MAKE) \
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare) CXX='g++' \
@echo "" CXXFLAGS="$(GCCFLAGS)" \
@echo "Step 1/6. Building executable for benchmark (popcnt disabled)..." all
gcc-popcnt:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS) -DUSE_POPCNT" \
all
icc:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS)" \
all
icc-profile-make:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS)" \
CXXFLAGS+='-prof-gen=srcpos -prof_dir ./profdir' \
all
icc-profile-use:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS)" \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
all
icc-profile:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h @touch *.cpp *.h
$(MAKE) ARCH=x86-64 COMP=$(COMP) $(profile_make) $(MAKE) icc-profile-make
@echo "" @echo ""
@echo "Step 2/6. Running benchmark for pgo-build (popcnt disabled)..." @echo "Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null @$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo "" @echo ""
@echo "Step 3/6. Building executable for benchmark (popcnt enabled)..."
@touch *.cpp *.h @touch *.cpp *.h
$(MAKE) ARCH=x86-64-modern COMP=$(COMP) $(profile_make) $(MAKE) icc-profile-use
@rm -rf profdir bench.txt
icc-profile-make-with-popcnt:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS) -DUSE_POPCNT" \
CXXFLAGS+='-prof-gen=srcpos -prof_dir ./profdir' \
all
icc-profile-use-with-popcnt:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS) -DUSE_POPCNT" \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
all
icc-profile-popcnt:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) icc-profile-make
@echo "" @echo ""
@echo "Step 4/6. Running benchmark for pgo-build (popcnt enabled)..." @echo "Running benchmark for pgo-build (popcnt disabled)..."
@$(PGOBENCH) > /dev/null @$(PGOBENCH) > /dev/null
@echo ""
@echo "Step 5/6. Building final executable ..."
@touch *.cpp *.h @touch *.cpp *.h
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use) $(MAKE) icc-profile-make-with-popcnt
@echo "" @echo ""
@echo "Step 6/6. Deleting profile data ..." @echo "Running benchmark for pgo-build (popcnt enabled)..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean) @$(PGOBENCH) > /dev/null
@echo "Benchmarks finished. Build final executable now ..."
@echo "" @echo ""
@touch *.cpp *.h
$(MAKE) icc-profile-use-with-popcnt
@rm -rf profdir bench.txt
osx-ppc32:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch ppc' \
LDFLAGS+='-arch ppc' \
all
osx-ppc64:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch ppc64' \
LDFLAGS+='-arch ppc64' \
all
osx-x86:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch i386' \
LDFLAGS+='-arch i386' \
all
osx-x86_64:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch x86_64' \
LDFLAGS+='-arch x86_64' \
all
osx-icc32:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
LDFLAGS+='-arch i386' \
all
osx-icc64:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch x86_64' \
LDFLAGS+='-arch x86_64' \
all
osx-icc32-profile-make:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
CXXFLAGS+='-prof_gen -prof_dir ./profdir' \
LDFLAGS+='-arch i386' \
all
osx-icc32-profile-use:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
LDFLAGS+='-arch i386' \
all
osx-icc32-profile:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) osx-icc32-profile-make
@echo ""
@echo "Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo ""
@touch *.cpp *.h
$(MAKE) osx-icc32-profile-use
@rm -rf profdir bench.txt
osx-icc64-profile-make:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch x86_64' \
CXXFLAGS+='-prof_gen -prof_dir ./profdir' \
LDFLAGS+='-arch x86_64' \
all
osx-icc64-profile-use:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch x86_64' \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
LDFLAGS+='-arch x86_64' \
all
osx-icc64-profile:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) osx-icc64-profile-make
@echo ""
@echo "Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo ""
@touch *.cpp *.h
$(MAKE) osx-icc64-profile-use
@rm -rf profdir bench.txt
strip: strip:
strip $(EXE) strip $(EXE)
install:
-mkdir -p -m 755 $(BINDIR)
-cp $(EXE) $(BINDIR)
-strip $(BINDIR)/$(EXE)
clean:
$(RM) $(EXE) *.o .depend *~ core bench.txt
testrun:
@$(PGOBENCH)
### ==========================================================================
### Section 5. Private targets
### ==========================================================================
all: $(EXE) .depend
config-sanity:
@echo ""
@echo "Config:"
@echo "debug: '$(debug)'"
@echo "optimize: '$(optimize)'"
@echo "arch: '$(arch)'"
@echo "os: '$(os)'"
@echo "bits: '$(bits)'"
@echo "bigendian: '$(bigendian)'"
@echo "prefetch: '$(prefetch)'"
@echo "bsfq: '$(bsfq)'"
@echo "popcnt: '$(popcnt)'"
@echo ""
@echo "Flags:"
@echo "CXX: $(CXX)"
@echo "CXXFLAGS: $(CXXFLAGS)"
@echo "LDFLAGS: $(LDFLAGS)"
@echo ""
@echo "Testing config sanity. If this fails, try 'make help' ..."
@echo ""
@test "$(debug)" = "yes" || test "$(debug)" = "no"
@test "$(optimize)" = "yes" || test "$(optimize)" = "no"
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc"
@test "$(os)" = "any" || test "$(os)" = "osx"
@test "$(bits)" = "32" || test "$(bits)" = "64"
@test "$(bigendian)" = "yes" || test "$(bigendian)" = "no"
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
@test "$(bsfq)" = "yes" || test "$(bsfq)" = "no"
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
@test "$(comp)" = "gcc" || test "$(comp)" = "icc"
### Compilation. Do not change
$(EXE): $(OBJS) $(EXE): $(OBJS)
$(CXX) -o $@ $(OBJS) $(LDFLAGS) $(CXX) $(LDFLAGS) -o $@ $(OBJS)
gcc-profile-prepare:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) gcc-profile-clean
gcc-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-generate' \
EXTRALDFLAGS='-lgcov' \
all
gcc-profile-use:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-use' \
all
gcc-profile-clean:
@rm -rf *.gcda *.gcno bench.txt
icc-profile-prepare:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) icc-profile-clean
@mkdir profdir
icc-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \
all
icc-profile-use:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \
all
icc-profile-clean:
@rm -rf profdir bench.txt
### Dependencies. Do not change
.depend: .depend:
-@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null $(CXX) -msse -MM $(OBJS:.o=.cpp) > $@
-include .depend
### ==========================================================================
### Section 6. Non-standard targets
### ==========================================================================
hpux:
$(MAKE) \
CXX='/opt/aCC/bin/aCC -AA +hpxstd98 -DBIGENDIAN -mt +O3 -DNDEBUG' \
CXXFLAGS="" \
LDFLAGS="" \
all
include .depend
+8 -11
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -49,7 +49,6 @@ Application::Application() {
Position::init_piece_square_tables(); Position::init_piece_square_tables();
init_eval(1); init_eval(1);
init_bitbases(); init_bitbases();
init_search();
init_threads(); init_threads();
// Make random number generation less deterministic, for book moves // Make random number generation less deterministic, for book moves
@@ -57,6 +56,12 @@ Application::Application() {
genrand_int32(); genrand_int32();
} }
Application::~Application() {
stop_threads();
quit_eval();
}
void Application::initialize() { void Application::initialize() {
// A static Application object is allocated // A static Application object is allocated
@@ -64,15 +69,7 @@ void Application::initialize() {
static Application singleton; static Application singleton;
} }
void Application::free_resources() {
// Warning, following functions reference global objects that
// must be still alive when free_resources() is called.
exit_threads();
quit_eval();
}
void Application::exit_with_failure() { void Application::exit_with_failure() {
exit(EXIT_FAILURE); exit(EXIT_FAILURE); // d'tor will be called automatically
} }
+2 -2
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -29,10 +29,10 @@ class Application {
Application(); Application();
Application(const Application&); Application(const Application&);
~Application();
public: public:
static void initialize(); static void initialize();
static void free_resources();
static void exit_with_failure(); static void exit_with_failure();
}; };
+10 -15
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -38,8 +38,8 @@ using namespace std;
const string BenchmarkPositions[] = { const string BenchmarkPositions[] = {
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -", "r4rk1/1b2qppp/p1n1p3/1p6/1b1PN3/3BRN2/PP3PPP/R2Q2K1 b - - 7 16",
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -", "4r1k1/ppq3pp/3b4/2pP4/2Q1p3/4B1P1/PP5P/R5K1 b - - 0 20",
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19", "4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14", "rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14",
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14", "r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14",
@@ -84,9 +84,9 @@ void benchmark(const string& commandLine) {
} }
csStr >> threads; csStr >> threads;
csVal >> val; csVal >> val;
if (val < 1 || val > MAX_THREADS) if (val < 1 || val > THREAD_MAX)
{ {
cerr << "The number of threads must be between 1 and " << MAX_THREADS << endl; cerr << "The number of threads must be between 1 and " << THREAD_MAX << endl;
Application::exit_with_failure(); Application::exit_with_failure();
} }
set_option_value("Hash", ttSize); set_option_value("Hash", ttSize);
@@ -151,18 +151,13 @@ void benchmark(const string& commandLine) {
{ {
Move moves[1] = {MOVE_NONE}; Move moves[1] = {MOVE_NONE};
int dummy[2] = {0, 0}; int dummy[2] = {0, 0};
Position pos(*it, 0); Position pos(*it);
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl; cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (limitType == "perft") if (limitType == "perft")
{ totalNodes += perft(pos, maxDepth * OnePly);
int64_t perftCnt = perft(pos, maxDepth * OnePly); else if (!think(pos, false, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
cerr << "\nPerft " << maxDepth << " result (nodes searched): " << perftCnt << endl << endl; break;
totalNodes += perftCnt; totalNodes += nodes_searched();
} else {
if (!think(pos, false, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched();
}
} }
cnt = get_system_time() - startTime; cnt = get_system_time() - startTime;
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+122 -122
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -226,9 +226,8 @@ Bitboard StepAttackBB[16][64];
Bitboard RayBB[64][8]; Bitboard RayBB[64][8];
Bitboard BetweenBB[64][64]; Bitboard BetweenBB[64][64];
Bitboard SquaresInFrontMask[2][64];
Bitboard PassedPawnMask[2][64]; Bitboard PassedPawnMask[2][64];
Bitboard AttackSpanMask[2][64]; Bitboard OutpostMask[2][64];
Bitboard BishopPseudoAttacks[64]; Bitboard BishopPseudoAttacks[64];
Bitboard RookPseudoAttacks[64]; Bitboard RookPseudoAttacks[64];
@@ -247,12 +246,14 @@ namespace {
void init_ray_bitboards(); void init_ray_bitboards();
void init_attacks(); void init_attacks();
void init_between_bitboards(); void init_between_bitboards();
void init_pseudo_attacks();
Bitboard index_to_bitboard(int index, Bitboard mask);
Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2], Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
int fmin, int fmax, int rmin, int rmax); int fmin, int fmax, int rmin, int rmax);
void init_sliding_attacks(Bitboard attacks[], int attackIndex[], Bitboard mask[], Bitboard index_to_bitboard(int index, Bitboard mask);
const int shift[], const Bitboard mult[], int deltas[][2]); void init_sliding_attacks(Bitboard attacks[],
int attackIndex[], Bitboard mask[],
const int shift[2], const Bitboard mult[],
int deltas[][2]);
void init_pseudo_attacks();
} }
@@ -264,14 +265,11 @@ namespace {
/// standard output. This is sometimes useful for debugging. /// standard output. This is sometimes useful for debugging.
void print_bitboard(Bitboard b) { void print_bitboard(Bitboard b) {
for(Rank r = RANK_8; r >= RANK_1; r--) {
for (Rank r = RANK_8; r >= RANK_1; r--) std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
{ for(File f = FILE_A; f <= FILE_H; f++)
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl; std::cout << "| " << (bit_is_set(b, make_square(f, r))? 'X' : ' ') << ' ';
for (File f = FILE_A; f <= FILE_H; f++) std::cout << "|" << std::endl;
std::cout << "| " << (bit_is_set(b, make_square(f, r))? 'X' : ' ') << ' ';
std::cout << "|" << std::endl;
} }
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl; std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
} }
@@ -281,10 +279,8 @@ void print_bitboard(Bitboard b) {
/// program initialization. /// program initialization.
void init_bitboards() { void init_bitboards() {
int rookDeltas[4][2] = {{0,1},{0,-1},{1,0},{-1,0}}; int rookDeltas[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int bishopDeltas[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}}; int bishopDeltas[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}};
init_masks(); init_masks();
init_ray_bitboards(); init_ray_bitboards();
init_attacks(); init_attacks();
@@ -301,8 +297,8 @@ void init_bitboards() {
#if defined(IS_64BIT) && !defined(USE_BSFQ) #if defined(IS_64BIT) && !defined(USE_BSFQ)
static CACHE_LINE_ALIGNMENT CACHE_LINE_ALIGNMENT
const int BitTable[64] = { static const int BitTable[64] = {
0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 40, 5, 17, 26, 38, 15, 0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 40, 5, 17, 26, 38, 15,
46, 29, 48, 10, 31, 35, 54, 21, 50, 41, 57, 63, 6, 12, 18, 24, 27, 33, 39, 46, 29, 48, 10, 31, 35, 54, 21, 50, 41, 57, 63, 6, 12, 18, 24, 27, 33, 39,
16, 37, 45, 47, 30, 53, 49, 56, 62, 11, 23, 32, 36, 44, 52, 55, 61, 22, 43, 16, 37, 45, 47, 30, 53, 49, 56, 62, 11, 23, 32, 36, 44, 52, 55, 61, 22, 43,
@@ -330,7 +326,6 @@ const int BitTable[64] = {
}; };
Square first_1(Bitboard b) { Square first_1(Bitboard b) {
b ^= (b - 1); b ^= (b - 1);
uint32_t fold = int(b) ^ int(b >> 32); uint32_t fold = int(b) ^ int(b >> 32);
return Square(BitTable[(fold * 0x783a9b23) >> 26]); return Square(BitTable[(fold * 0x783a9b23) >> 26]);
@@ -373,6 +368,28 @@ Square pop_1st_bit(Bitboard* bb) {
#endif #endif
int bitScanReverse32(uint32_t b)
{
int result = 0;
if (b > 0xFFFF) {
b >>= 16;
result += 16;
}
if (b > 0xFF) {
b >>= 8;
result += 8;
}
if (b > 0xF) {
b >>= 4;
result += 4;
}
if (b > 0x3) {
b >>= 2;
result += 2;
}
return result + (b > 0) + (b > 1);
}
namespace { namespace {
@@ -382,46 +399,39 @@ namespace {
// be necessary to touch any of them. // be necessary to touch any of them.
void init_masks() { void init_masks() {
SetMaskBB[SQ_NONE] = 0ULL; SetMaskBB[SQ_NONE] = 0ULL;
ClearMaskBB[SQ_NONE] = ~SetMaskBB[SQ_NONE]; ClearMaskBB[SQ_NONE] = ~SetMaskBB[SQ_NONE];
for(Square s = SQ_A1; s <= SQ_H8; s++) {
for (Square s = SQ_A1; s <= SQ_H8; s++) SetMaskBB[s] = (1ULL << s);
{ ClearMaskBB[s] = ~SetMaskBB[s];
SetMaskBB[s] = (1ULL << s);
ClearMaskBB[s] = ~SetMaskBB[s];
} }
for(Color c = WHITE; c <= BLACK; c++)
for (Color c = WHITE; c <= BLACK; c++) for(Square s = SQ_A1; s <= SQ_H8; s++) {
for (Square s = SQ_A1; s <= SQ_H8; s++) PassedPawnMask[c][s] =
{ in_front_bb(c, s) & this_and_neighboring_files_bb(s);
SquaresInFrontMask[c][s] = in_front_bb(c, s) & file_bb(s); OutpostMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
PassedPawnMask[c][s] = in_front_bb(c, s) & this_and_neighboring_files_bb(s); }
AttackSpanMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
}
for (Bitboard b = 0ULL; b < 256ULL; b++) for (Bitboard b = 0ULL; b < 256ULL; b++)
BitCount8Bit[b] = (uint8_t)count_1s(b); BitCount8Bit[b] = (uint8_t)count_1s(b);
} }
int remove_bit_8(int i) { return ((i & ~15) >> 1) | (i & 7); }
void init_ray_bitboards() { void init_ray_bitboards() {
int d[8] = {1, -1, 16, -16, 17, -17, 15, -15}; int d[8] = {1, -1, 16, -16, 17, -17, 15, -15};
for(int i = 0; i < 128; i = (i + 9) & ~8) {
for (int i = 0; i < 128; i = (i + 9) & ~8) for(int j = 0; j < 8; j++) {
for (int j = 0; j < 8; j++) RayBB[(i&7)|((i>>4)<<3)][j] = EmptyBoardBB;
{ for(int k = i + d[j]; (k & 0x88) == 0; k += d[j])
RayBB[remove_bit_8(i)][j] = EmptyBoardBB; set_bit(&(RayBB[(i&7)|((i>>4)<<3)][j]), Square((k&7)|((k>>4)<<3)));
for (int k = i + d[j]; (k & 0x88) == 0; k += d[j]) }
set_bit(&(RayBB[remove_bit_8(i)][j]), Square(remove_bit_8(k))); }
}
} }
void init_attacks() {
const int step[16][8] = { void init_attacks() {
int i, j, k, l;
int step[16][8] = {
{0}, {0},
{7,9,0}, {17,15,10,6,-6,-10,-15,-17}, {9,7,-7,-9,0}, {8,1,-1,-8,0}, {7,9,0}, {17,15,10,6,-6,-10,-15,-17}, {9,7,-7,-9,0}, {8,1,-1,-8,0},
{9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}, {0}, {0}, {9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}, {0}, {0},
@@ -429,115 +439,105 @@ namespace {
{9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8} {9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}
}; };
for (int i = 0; i < 64; i++) for(i = 0; i < 64; i++) {
for (int j = 0; j <= int(BK); j++) for(j = 0; j <= int(BK); j++) {
{ StepAttackBB[j][i] = EmptyBoardBB;
StepAttackBB[j][i] = EmptyBoardBB; for(k = 0; k < 8 && step[j][k] != 0; k++) {
for (int k = 0; k < 8 && step[j][k] != 0; k++) l = i + step[j][k];
{ if(l >= 0 && l < 64 && abs((i&7) - (l&7)) < 3)
int l = i + step[j][k]; StepAttackBB[j][i] |= (1ULL << l);
if (l >= 0 && l < 64 && abs((i & 7) - (l & 7)) < 3)
StepAttackBB[j][i] |= (1ULL << l);
}
} }
}
}
} }
Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2], Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
int fmin=0, int fmax=7, int rmin=0, int rmax=7) { int fmin=0, int fmax=7, int rmin=0, int rmax=7) {
Bitboard result = 0ULL; Bitboard result = 0ULL;
int rk = sq / 8; int rk = sq / 8, fl = sq % 8, r, f, i;
int fl = sq % 8; for(i = 0; i < dirs; i++) {
int dx = deltas[i][0], dy = deltas[i][1];
for (int i = 0; i < dirs; i++) for(f = fl+dx, r = rk+dy;
{ (dx==0 || (f>=fmin && f<=fmax)) && (dy==0 || (r>=rmin && r<=rmax));
int dx = deltas[i][0]; f += dx, r += dy) {
int dy = deltas[i][1]; result |= (1ULL << (f + r*8));
int f = fl + dx; if(block & (1ULL << (f + r*8))) break;
int r = rk + dy; }
while ( (dx == 0 || (f >= fmin && f <= fmax))
&& (dy == 0 || (r >= rmin && r <= rmax)))
{
result |= (1ULL << (f + r*8));
if (block & (1ULL << (f + r*8)))
break;
f += dx;
r += dy;
}
} }
return result; return result;
} }
void init_between_bitboards() { void init_between_bitboards() {
SquareDelta step[8] = {
const SquareDelta step[8] = { DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE
DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE }; };
SignedDirection d;
for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++) for(Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++) for(Square s2 = SQ_A1; s2 <= SQ_H8; s2++) {
{ BetweenBB[s1][s2] = EmptyBoardBB;
BetweenBB[s1][s2] = EmptyBoardBB; d = signed_direction_between_squares(s1, s2);
SignedDirection d = signed_direction_between_squares(s1, s2); if(d != SIGNED_DIR_NONE)
for(Square s3 = s1 + step[d]; s3 != s2; s3 += step[d])
if (d != SIGNED_DIR_NONE) set_bit(&(BetweenBB[s1][s2]), s3);
{
for (Square s3 = s1 + step[d]; s3 != s2; s3 += step[d])
set_bit(&(BetweenBB[s1][s2]), s3);
}
} }
} }
Bitboard index_to_bitboard(int index, Bitboard mask) { Bitboard index_to_bitboard(int index, Bitboard mask) {
int i, j, bits = count_1s(mask);
Bitboard result = 0ULL; Bitboard result = 0ULL;
int bits = count_1s(mask); for(i = 0; i < bits; i++) {
j = pop_1st_bit(&mask);
for (int i = 0; i < bits; i++) if(index & (1 << i)) result |= (1ULL << j);
{
int j = pop_1st_bit(&mask);
if (index & (1 << i))
result |= (1ULL << j);
} }
return result; return result;
} }
void init_sliding_attacks(Bitboard attacks[], int attackIndex[], Bitboard mask[],
const int shift[], const Bitboard mult[], int deltas[][2]) {
for (int i = 0, index = 0; i < 64; i++) void init_sliding_attacks(Bitboard attacks[],
{ int attackIndex[], Bitboard mask[],
attackIndex[i] = index; const int shift[2], const Bitboard mult[],
mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6); int deltas[][2]) {
int i, j, k, index = 0;
Bitboard b;
for(i = 0; i < 64; i++) {
attackIndex[i] = index;
mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6);
#if defined(IS_64BIT) #if defined(IS_64BIT)
int j = (1 << (64 - shift[i])); j = (1 << (64 - shift[i]));
#else #else
int j = (1 << (32 - shift[i])); j = (1 << (32 - shift[i]));
#endif #endif
for (int k = 0; k < j; k++) for(k = 0; k < j; k++) {
{
#if defined(IS_64BIT) #if defined(IS_64BIT)
Bitboard b = index_to_bitboard(k, mask[i]); b = index_to_bitboard(k, mask[i]);
attacks[index + ((b * mult[i]) >> shift[i])] = sliding_attacks(i, b, 4, deltas); attacks[index + ((b * mult[i]) >> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#else #else
Bitboard b = index_to_bitboard(k, mask[i]); b = index_to_bitboard(k, mask[i]);
unsigned v = int(b) * int(mult[i]) ^ int(b >> 32) * int(mult[i] >> 32); attacks[index +
attacks[index + (v >> shift[i])] = sliding_attacks(i, b, 4, deltas); (unsigned(int(b) * int(mult[i]) ^
int(b >> 32) * int(mult[i] >> 32))
>> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#endif #endif
} }
index += j; index += j;
} }
} }
void init_pseudo_attacks() {
for (Square s = SQ_A1; s <= SQ_H8; s++) void init_pseudo_attacks() {
{ Square s;
BishopPseudoAttacks[s] = bishop_attacks_bb(s, EmptyBoardBB); for(s = SQ_A1; s <= SQ_H8; s++) {
RookPseudoAttacks[s] = rook_attacks_bb(s, EmptyBoardBB); BishopPseudoAttacks[s] = bishop_attacks_bb(s, EmptyBoardBB);
QueenPseudoAttacks[s] = queen_attacks_bb(s, EmptyBoardBB); RookPseudoAttacks[s] = rook_attacks_bb(s, EmptyBoardBB);
QueenPseudoAttacks[s] = queen_attacks_bb(s, EmptyBoardBB);
} }
} }
+29 -21
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -74,9 +74,8 @@ extern Bitboard StepAttackBB[16][64];
extern Bitboard RayBB[64][8]; extern Bitboard RayBB[64][8];
extern Bitboard BetweenBB[64][64]; extern Bitboard BetweenBB[64][64];
extern Bitboard SquaresInFrontMask[2][64];
extern Bitboard PassedPawnMask[2][64]; extern Bitboard PassedPawnMask[2][64];
extern Bitboard AttackSpanMask[2][64]; extern Bitboard OutpostMask[2][64];
extern const uint64_t RMult[64]; extern const uint64_t RMult[64];
extern const int RShift[64]; extern const int RShift[64];
@@ -128,8 +127,9 @@ inline void do_move_bb(Bitboard *b, Bitboard move_bb) {
*b ^= move_bb; *b ^= move_bb;
} }
/// rank_bb() and file_bb() take a file or a square as input, and return /// rank_bb() and file_bb() gives a bitboard containing all squares on a given
/// a bitboard representing all squares on the given file or rank. /// file or rank. It is also possible to pass a square as input to these
/// functions.
inline Bitboard rank_bb(Rank r) { inline Bitboard rank_bb(Rank r) {
return RankBB[r]; return RankBB[r];
@@ -156,7 +156,7 @@ inline Bitboard neighboring_files_bb(File f) {
} }
inline Bitboard neighboring_files_bb(Square s) { inline Bitboard neighboring_files_bb(Square s) {
return NeighboringFilesBB[square_file(s)]; return neighboring_files_bb(square_file(s));
} }
@@ -169,7 +169,7 @@ inline Bitboard this_and_neighboring_files_bb(File f) {
} }
inline Bitboard this_and_neighboring_files_bb(Square s) { inline Bitboard this_and_neighboring_files_bb(Square s) {
return ThisAndNeighboringFilesBB[square_file(s)]; return this_and_neighboring_files_bb(square_file(s));
} }
@@ -195,7 +195,7 @@ inline Bitboard in_front_bb(Color c, Rank r) {
} }
inline Bitboard in_front_bb(Color c, Square s) { inline Bitboard in_front_bb(Color c, Square s) {
return InFrontBB[c][square_rank(s)]; return in_front_bb(c, square_rank(s));
} }
@@ -208,7 +208,7 @@ inline Bitboard behind_bb(Color c, Rank r) {
} }
inline Bitboard behind_bb(Color c, Square s) { inline Bitboard behind_bb(Color c, Square s) {
return InFrontBB[opposite_color(c)][square_rank(s)]; return in_front_bb(opposite_color(c), square_rank(s));
} }
@@ -274,11 +274,12 @@ inline Bitboard squares_between(Square s1, Square s2) {
/// squares_in_front_of takes a color and a square as input, and returns a /// squares_in_front_of takes a color and a square as input, and returns a
/// bitboard representing all squares along the line in front of the square, /// bitboard representing all squares along the line in front of the square,
/// from the point of view of the given color. Definition of the table is: /// from the point of view of the given color. For instance,
/// SquaresInFrontOf[c][s] = in_front_bb(c, s) & file_bb(s) /// squares_in_front_of(BLACK, SQ_E4) returns a bitboard with the squares
/// e3, e2 and e1 set.
inline Bitboard squares_in_front_of(Color c, Square s) { inline Bitboard squares_in_front_of(Color c, Square s) {
return SquaresInFrontMask[c][s]; return in_front_bb(c, s) & file_bb(s);
} }
@@ -286,27 +287,33 @@ inline Bitboard squares_in_front_of(Color c, Square s) {
/// behind the square instead of in front of the square. /// behind the square instead of in front of the square.
inline Bitboard squares_behind(Color c, Square s) { inline Bitboard squares_behind(Color c, Square s) {
return SquaresInFrontMask[opposite_color(c)][s]; return in_front_bb(opposite_color(c), s) & file_bb(s);
} }
/// passed_pawn_mask takes a color and a square as input, and returns a /// passed_pawn_mask takes a color and a square as input, and returns a
/// bitboard mask which can be used to test if a pawn of the given color on /// bitboard mask which can be used to test if a pawn of the given color on
/// the given square is a passed pawn. Definition of the table is: /// the given square is a passed pawn.
/// PassedPawnMask[c][s] = in_front_bb(c, s) & this_and_neighboring_files_bb(s)
inline Bitboard passed_pawn_mask(Color c, Square s) { inline Bitboard passed_pawn_mask(Color c, Square s) {
return PassedPawnMask[c][s]; return PassedPawnMask[c][s];
} }
/// attack_span_mask takes a color and a square as input, and returns a bitboard /// outpost_mask takes a color and a square as input, and returns a bitboard
/// representing all squares that can be attacked by a pawn of the given color /// mask which can be used to test whether a piece on the square can possibly
/// when it moves along its file starting from the given square. Definition is: /// be driven away by an enemy pawn.
/// AttackSpanMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
inline Bitboard attack_span_mask(Color c, Square s) { inline Bitboard outpost_mask(Color c, Square s) {
return AttackSpanMask[c][s]; return OutpostMask[c][s];
}
/// isolated_pawn_mask takes a square as input, and returns a bitboard mask
/// which can be used to test whether a pawn on the given square is isolated.
inline Bitboard isolated_pawn_mask(Square s) {
return neighboring_files_bb(s);
} }
@@ -342,6 +349,7 @@ extern Square pop_1st_bit(Bitboard* b);
extern void print_bitboard(Bitboard b); extern void print_bitboard(Bitboard b);
extern void init_bitboards(); extern void init_bitboards();
extern int bitScanReverse32(uint32_t b);
#endif // !defined(BITBOARD_H_INCLUDED) #endif // !defined(BITBOARD_H_INCLUDED)
+53 -20
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -26,18 +26,64 @@
// Select type of intrinsic bit count instruction to use, see // Select type of intrinsic bit count instruction to use, see
// README.txt on how to pgo compile with POPCNT support. // README.txt on how to pgo compile with POPCNT support.
#if !defined(USE_POPCNT)
#define POPCNT_INTRINSIC(x) 0 #if defined(__INTEL_COMPILER) && defined(USE_POPCNT) // Intel compiler
#elif defined(_MSC_VER)
#define POPCNT_INTRINSIC(x) (int)__popcnt64(x) #include <nmmintrin.h>
#elif defined(__GNUC__)
inline bool cpu_has_popcnt() {
int CPUInfo[4] = {-1};
__cpuid(CPUInfo, 0x00000001);
return (CPUInfo[2] >> 23) & 1;
}
#define POPCNT_INTRINSIC(x) _mm_popcnt_u64(x)
#elif defined(_MSC_VER) && defined(USE_POPCNT) // Microsoft compiler
#include <intrin.h>
inline bool cpu_has_popcnt() {
int CPUInfo[4] = {-1};
__cpuid(CPUInfo, 0x00000001);
return (CPUInfo[2] >> 23) & 1;
}
#define POPCNT_INTRINSIC(x) __popcnt64(x)
#elif defined(__GNUC__) && defined(USE_POPCNT) // Gcc compiler
inline void __cpuid(unsigned int op,
unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
*eax = op;
*ecx = 0;
__asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (*eax), "2" (*ecx));
}
inline bool cpu_has_popcnt() {
unsigned int eax, ebx, ecx, edx;
__cpuid(1, &eax, &ebx, &ecx, &edx);
return (ecx >> 23) & 1;
}
#define POPCNT_INTRINSIC(x) ({ \ #define POPCNT_INTRINSIC(x) ({ \
unsigned long __ret; \ unsigned long __ret; \
__asm__("popcnt %1, %0" : "=r" (__ret) : "r" (x)); \ __asm__("popcnt %1, %0" : "=r" (__ret) : "r" (x)); \
__ret; }) __ret; })
#endif #else // Safe fallback for unsupported compilers or when USE_POPCNT is disabled
inline bool cpu_has_popcnt() { return false; }
#define POPCNT_INTRINSIC(x) 0
#endif // cpu_has_popcnt() and POPCNT_INTRINSIC() definitions
/// Software implementation of bit count functions /// Software implementation of bit count functions
@@ -104,23 +150,10 @@ inline int count_1s_max_15(Bitboard b) {
} }
// Detect hardware POPCNT support
inline bool cpu_has_popcnt() {
int CPUInfo[4] = {-1};
__cpuid(CPUInfo, 0x00000001);
return (CPUInfo[2] >> 23) & 1;
}
// Global constant initialized at startup that is set to true if // Global constant initialized at startup that is set to true if
// CPU on which application runs supports POPCNT intrinsic. Unless // CPU on which application runs supports POPCNT intrinsic. Unless
// USE_POPCNT is not defined. // USE_POPCNT is not defined.
#if defined(USE_POPCNT)
const bool CpuHasPOPCNT = cpu_has_popcnt(); const bool CpuHasPOPCNT = cpu_has_popcnt();
#else
const bool CpuHasPOPCNT = false;
#endif
// Global constant used to print info about the use of 64 optimized // Global constant used to print info about the use of 64 optimized
+5 -17
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -390,7 +390,7 @@ void Book::close() {
/// Book::file_name() returns the file name of the currently active book, /// Book::file_name() returns the file name of the currently active book,
/// or the empty string if no book is open. /// or the empty string if no book is open.
const string Book::file_name() { // Not const to compile on HP-UX 11.X const string Book::file_name() const {
return is_open() ? fileName : ""; return is_open() ? fileName : "";
} }
@@ -399,15 +399,14 @@ const string Book::file_name() { // Not const to compile on HP-UX 11.X
/// Book::get_move() gets a book move for a given position. Returns /// Book::get_move() gets a book move for a given position. Returns
/// MOVE_NONE if no book move is found. /// MOVE_NONE if no book move is found.
Move Book::get_move(const Position& pos, bool findBestMove) { Move Book::get_move(const Position& pos) {
if (!is_open() || bookSize == 0) if (!is_open() || bookSize == 0)
return MOVE_NONE; return MOVE_NONE;
BookEntry entry; int bookMove = 0, scoresSum = 0;
int bookMove = MOVE_NONE;
int scoresSum = 0, bestScore = 0;
uint64_t key = book_key(pos); uint64_t key = book_key(pos);
BookEntry entry;
// Choose a book move among the possible moves for the given position // Choose a book move among the possible moves for the given position
for (int idx = find_key(key); idx < bookSize; idx++) for (int idx = find_key(key); idx < bookSize; idx++)
@@ -420,17 +419,6 @@ Move Book::get_move(const Position& pos, bool findBestMove) {
assert(score > 0); assert(score > 0);
// If findBestMove is true choose highest rated book move
if (findBestMove)
{
if (score > bestScore)
{
bestScore = score;
bookMove = entry.move;
}
continue;
}
// Choose book move according to its score. If a move has a very // Choose book move according to its score. If a move has a very
// high score it has more probability to be choosen then a one with // high score it has more probability to be choosen then a one with
// lower score. Note that first entry is always chosen. // lower score. Note that first entry is always chosen.
+3 -6
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -53,15 +53,12 @@ struct BookEntry {
}; };
class Book : private std::ifstream { class Book : private std::ifstream {
Book(const Book&); // just decleared..
Book& operator=(const Book&); // ..to avoid a warning
public: public:
Book() {}
~Book(); ~Book();
void open(const std::string& fName); void open(const std::string& fName);
void close(); void close();
const std::string file_name(); const std::string file_name() const;
Move get_move(const Position& pos, bool findBestMove); Move get_move(const Position& pos);
private: private:
Book& operator>>(uint64_t& n) { n = read_integer(8); return *this; } Book& operator>>(uint64_t& n) { n = read_integer(8); return *this; }
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+3 -5
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -27,8 +27,7 @@
enum Depth { enum Depth {
DEPTH_ZERO = 0, DEPTH_ZERO = 0,
DEPTH_MAX = 200, // 100 * OnePly; DEPTH_MAX = 200 // 100 * OnePly;
DEPTH_ENSURE_SIGNED = -1
}; };
@@ -49,8 +48,7 @@ inline void operator+= (Depth &d, int i) { d = Depth(int(d) + i); }
inline void operator+= (Depth &d1, Depth d2) { d1 += int(d2); } inline void operator+= (Depth &d1, Depth d2) { d1 += int(d2); }
inline Depth operator- (Depth d, int i) { return Depth(int(d) - i); } inline Depth operator- (Depth d, int i) { return Depth(int(d) - i); }
inline Depth operator- (Depth d1, Depth d2) { return Depth(int(d1) - int(d2)); } inline Depth operator- (Depth d1, Depth d2) { return Depth(int(d1) - int(d2)); }
inline void operator-= (Depth &d, int i) { d = Depth(int(d) - i); } inline void operator-= (Depth & d, int i) { d = Depth(int(d) - i); }
inline void operator-= (Depth &d1, Depth d2) { d1 -= int(d2); }
inline Depth operator* (Depth d, int i) { return Depth(int(d) * i); } inline Depth operator* (Depth d, int i) { return Depth(int(d) * i); }
inline Depth operator* (int i, Depth d) { return Depth(int(d) * i); } inline Depth operator* (int i, Depth d) { return Depth(int(d) * i); }
inline void operator*= (Depth &d, int i) { d = Depth(int(d) * i); } inline void operator*= (Depth &d, int i) { d = Depth(int(d) * i); }
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+21 -21
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -104,7 +104,7 @@ namespace {
/// attacking side a bonus for driving the defending king towards the edge /// attacking side a bonus for driving the defending king towards the edge
/// of the board, and for keeping the distance between the two kings small. /// of the board, and for keeping the distance between the two kings small.
template<> template<>
Value EvaluationFunction<KXK>::apply(const Position& pos) const { Value EvaluationFunction<KXK>::apply(const Position& pos) {
assert(pos.non_pawn_material(weakerSide) == Value(0)); assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.piece_count(weakerSide, PAWN) == Value(0)); assert(pos.piece_count(weakerSide, PAWN) == Value(0));
@@ -130,7 +130,7 @@ Value EvaluationFunction<KXK>::apply(const Position& pos) const {
/// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the /// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the
/// defending king towards a corner square of the right color. /// defending king towards a corner square of the right color.
template<> template<>
Value EvaluationFunction<KBNK>::apply(const Position& pos) const { Value EvaluationFunction<KBNK>::apply(const Position& pos) {
assert(pos.non_pawn_material(weakerSide) == Value(0)); assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.piece_count(weakerSide, PAWN) == Value(0)); assert(pos.piece_count(weakerSide, PAWN) == Value(0));
@@ -159,7 +159,7 @@ Value EvaluationFunction<KBNK>::apply(const Position& pos) const {
/// KP vs K. This endgame is evaluated with the help of a bitbase. /// KP vs K. This endgame is evaluated with the help of a bitbase.
template<> template<>
Value EvaluationFunction<KPK>::apply(const Position& pos) const { Value EvaluationFunction<KPK>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == Value(0)); assert(pos.non_pawn_material(strongerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == Value(0)); assert(pos.non_pawn_material(weakerSide) == Value(0));
@@ -207,7 +207,7 @@ Value EvaluationFunction<KPK>::apply(const Position& pos) const {
/// far advanced with support of the king, while the attacking king is far /// far advanced with support of the king, while the attacking king is far
/// away. /// away.
template<> template<>
Value EvaluationFunction<KRKP>::apply(const Position& pos) const { Value EvaluationFunction<KRKP>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame); assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -264,7 +264,7 @@ Value EvaluationFunction<KRKP>::apply(const Position& pos) const {
/// KR vs KB. This is very simple, and always returns drawish scores. The /// KR vs KB. This is very simple, and always returns drawish scores. The
/// score is slightly bigger when the defending king is close to the edge. /// score is slightly bigger when the defending king is close to the edge.
template<> template<>
Value EvaluationFunction<KRKB>::apply(const Position& pos) const { Value EvaluationFunction<KRKB>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame); assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -280,7 +280,7 @@ Value EvaluationFunction<KRKB>::apply(const Position& pos) const {
/// KR vs KN. The attacking side has slightly better winning chances than /// KR vs KN. The attacking side has slightly better winning chances than
/// in KR vs KB, particularly if the king and the knight are far apart. /// in KR vs KB, particularly if the king and the knight are far apart.
template<> template<>
Value EvaluationFunction<KRKN>::apply(const Position& pos) const { Value EvaluationFunction<KRKN>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame); assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -304,7 +304,7 @@ Value EvaluationFunction<KRKN>::apply(const Position& pos) const {
/// for the defending side in the search, this is usually sufficient to be /// for the defending side in the search, this is usually sufficient to be
/// able to win KQ vs KR. /// able to win KQ vs KR.
template<> template<>
Value EvaluationFunction<KQKR>::apply(const Position& pos) const { Value EvaluationFunction<KQKR>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame); assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -323,7 +323,7 @@ Value EvaluationFunction<KQKR>::apply(const Position& pos) const {
} }
template<> template<>
Value EvaluationFunction<KBBKN>::apply(const Position& pos) const { Value EvaluationFunction<KBBKN>::apply(const Position& pos) {
assert(pos.piece_count(strongerSide, BISHOP) == 2); assert(pos.piece_count(strongerSide, BISHOP) == 2);
assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMidgame); assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMidgame);
@@ -352,12 +352,12 @@ Value EvaluationFunction<KBBKN>::apply(const Position& pos) const {
/// K and two minors vs K and one or two minors or K and two knights against /// K and two minors vs K and one or two minors or K and two knights against
/// king alone are always draw. /// king alone are always draw.
template<> template<>
Value EvaluationFunction<KmmKm>::apply(const Position&) const { Value EvaluationFunction<KmmKm>::apply(const Position&) {
return Value(0); return Value(0);
} }
template<> template<>
Value EvaluationFunction<KNNK>::apply(const Position&) const { Value EvaluationFunction<KNNK>::apply(const Position&) {
return Value(0); return Value(0);
} }
@@ -367,7 +367,7 @@ Value EvaluationFunction<KNNK>::apply(const Position&) const {
/// returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling /// returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
/// will be used. /// will be used.
template<> template<>
ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) const { ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame); assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -421,7 +421,7 @@ ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) const {
/// It tests for fortress draws with a rook on the third rank defended by /// It tests for fortress draws with a rook on the third rank defended by
/// a pawn. /// a pawn.
template<> template<>
ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) const { ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame); assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
assert(pos.piece_count(strongerSide, QUEEN) == 1); assert(pos.piece_count(strongerSide, QUEEN) == 1);
@@ -452,7 +452,7 @@ ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) const {
/// It would also be nice to rewrite the actual code for this function, /// It would also be nice to rewrite the actual code for this function,
/// which is mostly copied from Glaurung 1.x, and not very pretty. /// which is mostly copied from Glaurung 1.x, and not very pretty.
template<> template<>
ScaleFactor ScalingFunction<KRPKR>::apply(const Position& pos) const { ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame); assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.piece_count(strongerSide, PAWN) == 1);
@@ -570,7 +570,7 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position& pos) const {
/// single pattern: If the stronger side has no pawns and the defending king /// single pattern: If the stronger side has no pawns and the defending king
/// is actively placed, the position is drawish. /// is actively placed, the position is drawish.
template<> template<>
ScaleFactor ScalingFunction<KRPPKRP>::apply(const Position& pos) const { ScaleFactor ScalingFunction<KRPPKRP>::apply(const Position &pos) {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame); assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 2); assert(pos.piece_count(strongerSide, PAWN) == 2);
@@ -609,7 +609,7 @@ ScaleFactor ScalingFunction<KRPPKRP>::apply(const Position& pos) const {
/// against king. There is just a single rule here: If all pawns are on /// against king. There is just a single rule here: If all pawns are on
/// the same rook file and are blocked by the defending king, it's a draw. /// the same rook file and are blocked by the defending king, it's a draw.
template<> template<>
ScaleFactor ScalingFunction<KPsK>::apply(const Position& pos) const { ScaleFactor ScalingFunction<KPsK>::apply(const Position &pos) {
assert(pos.non_pawn_material(strongerSide) == Value(0)); assert(pos.non_pawn_material(strongerSide) == Value(0));
assert(pos.piece_count(strongerSide, PAWN) >= 2); assert(pos.piece_count(strongerSide, PAWN) >= 2);
@@ -655,7 +655,7 @@ ScaleFactor ScalingFunction<KPsK>::apply(const Position& pos) const {
/// it's a draw. If the two bishops have opposite color, it's almost always /// it's a draw. If the two bishops have opposite color, it's almost always
/// a draw. /// a draw.
template<> template<>
ScaleFactor ScalingFunction<KBPKB>::apply(const Position& pos) const { ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame); assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -708,7 +708,7 @@ ScaleFactor ScalingFunction<KBPKB>::apply(const Position& pos) const {
/// KBPPKBScalingFunction scales KBPP vs KB endgames. It detects a few basic /// KBPPKBScalingFunction scales KBPP vs KB endgames. It detects a few basic
/// draws with opposite-colored bishops. /// draws with opposite-colored bishops.
template<> template<>
ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) const { ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame); assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -784,7 +784,7 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) const {
/// square of the king is not of the same color as the stronger side's bishop, /// square of the king is not of the same color as the stronger side's bishop,
/// it's a draw. /// it's a draw.
template<> template<>
ScaleFactor ScalingFunction<KBPKN>::apply(const Position& pos) const { ScaleFactor ScalingFunction<KBPKN>::apply(const Position &pos) {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame); assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -811,7 +811,7 @@ ScaleFactor ScalingFunction<KBPKN>::apply(const Position& pos) const {
/// If the pawn is a rook pawn on the 7th rank and the defending king prevents /// If the pawn is a rook pawn on the 7th rank and the defending king prevents
/// the pawn from advancing, the position is drawn. /// the pawn from advancing, the position is drawn.
template<> template<>
ScaleFactor ScalingFunction<KNPK>::apply(const Position& pos) const { ScaleFactor ScalingFunction<KNPK>::apply(const Position &pos) {
assert(pos.non_pawn_material(strongerSide) == KnightValueMidgame); assert(pos.non_pawn_material(strongerSide) == KnightValueMidgame);
assert(pos.piece_count(strongerSide, KNIGHT) == 1); assert(pos.piece_count(strongerSide, KNIGHT) == 1);
@@ -841,7 +841,7 @@ ScaleFactor ScalingFunction<KNPK>::apply(const Position& pos) const {
/// advanced and not on a rook file; in this case it is often possible to win /// advanced and not on a rook file; in this case it is often possible to win
/// (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1). /// (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
template<> template<>
ScaleFactor ScalingFunction<KPKP>::apply(const Position& pos) const { ScaleFactor ScalingFunction<KPKP>::apply(const Position &pos) {
assert(pos.non_pawn_material(strongerSide) == Value(0)); assert(pos.non_pawn_material(strongerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == Value(0)); assert(pos.non_pawn_material(weakerSide) == Value(0));
+4 -4
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -68,7 +68,7 @@ class EndgameFunctionBase {
public: public:
EndgameFunctionBase(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {} EndgameFunctionBase(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {}
virtual ~EndgameFunctionBase() {} virtual ~EndgameFunctionBase() {}
virtual T apply(const Position&) const = 0; virtual T apply(const Position&) = 0;
Color color() const { return strongerSide; } Color color() const { return strongerSide; }
protected: protected:
@@ -85,14 +85,14 @@ template<EndgameType>
struct EvaluationFunction : public EndgameEvaluationFunctionBase { struct EvaluationFunction : public EndgameEvaluationFunctionBase {
typedef EndgameEvaluationFunctionBase Base; typedef EndgameEvaluationFunctionBase Base;
explicit EvaluationFunction(Color c): EndgameEvaluationFunctionBase(c) {} explicit EvaluationFunction(Color c): EndgameEvaluationFunctionBase(c) {}
Value apply(const Position&) const; Value apply(const Position&);
}; };
template<EndgameType> template<EndgameType>
struct ScalingFunction : public EndgameScalingFunctionBase { struct ScalingFunction : public EndgameScalingFunctionBase {
typedef EndgameScalingFunctionBase Base; typedef EndgameScalingFunctionBase Base;
explicit ScalingFunction(Color c) : EndgameScalingFunctionBase(c) {} explicit ScalingFunction(Color c) : EndgameScalingFunctionBase(c) {}
ScaleFactor apply(const Position&) const; ScaleFactor apply(const Position&);
}; };
+400 -268
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -46,11 +46,9 @@ namespace {
const int GrainSize = 8; const int GrainSize = 8;
// Evaluation weights, initialized from UCI options // Evaluation weights, initialized from UCI options
enum { Mobility, PawnStructure, PassedPawns, Space, KingDangerUs, KingDangerThem }; Score WeightMobility, WeightPawnStructure;
Score Weights[6]; Score WeightPassedPawns, WeightSpace;
Score WeightKingSafety[2];
typedef Value V;
#define S(mg, eg) make_score(mg, eg)
// Internal evaluation weights. These are applied on top of the evaluation // Internal evaluation weights. These are applied on top of the evaluation
// weights read from UCI parameters. The purpose is to be able to change // weights read from UCI parameters. The purpose is to be able to change
@@ -58,9 +56,19 @@ namespace {
// parameters at 100, which looks prettier. // parameters at 100, which looks prettier.
// //
// Values modified by Joona Kiiski // Values modified by Joona Kiiski
const Score WeightsInternal[] = { const Score WeightMobilityInternal = make_score(248, 271);
S(248, 271), S(233, 201), S(252, 259), S(46, 0), S(247, 0), S(259, 0) const Score WeightPawnStructureInternal = make_score(233, 201);
}; const Score WeightPassedPawnsInternal = make_score(252, 259);
const Score WeightSpaceInternal = make_score( 46, 0);
const Score WeightKingSafetyInternal = make_score(247, 0);
const Score WeightKingOppSafetyInternal = make_score(259, 0);
// Mobility and outposts bonus modified by Joona Kiiski
typedef Value V;
#define S(mg, eg) make_score(mg, eg)
CACHE_LINE_ALIGNMENT
// Knight mobility bonus in middle game and endgame, indexed by the number // Knight mobility bonus in middle game and endgame, indexed by the number
// of attacked squares not occupied by friendly piecess. // of attacked squares not occupied by friendly piecess.
@@ -130,22 +138,28 @@ namespace {
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) // 8 V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) // 8
}; };
// ThreatBonus[attacking][attacked] contains bonus according to which // ThreatBonus[][] contains bonus according to which piece type
// piece type attacks which one. // attacks which one.
#define Z S(0, 0)
const Score ThreatBonus[8][8] = { const Score ThreatBonus[8][8] = {
{}, {}, { Z, Z, Z, Z, Z, Z, Z, Z }, // not used
{ S(0, 0), S( 7, 39), S( 0, 0), S(24, 49), S(41,100), S(41,100) }, // KNIGHT { Z, S(18,37), Z, S(37,47), S(55,97), S(55,97), Z, Z }, // KNIGHT attacks
{ S(0, 0), S( 7, 39), S(24, 49), S( 0, 0), S(41,100), S(41,100) }, // BISHOP { Z, S(18,37), S(37,47), Z, S(55,97), S(55,97), Z, Z }, // BISHOP attacks
{ S(0, 0), S(-1, 29), S(15, 49), S(15, 49), S( 0, 0), S(24, 49) }, // ROOK { Z, S( 9,27), S(27,47), S(27,47), Z, S(37,47), Z, Z }, // ROOK attacks
{ S(0, 0), S(15, 39), S(15, 39), S(15, 39), S(15, 39), S( 0, 0) } // QUEEN { Z, S(27,37), S(27,37), S(27,37), S(27,37), Z, Z, Z }, // QUEEN attacks
{ Z, Z, Z, Z, Z, Z, Z, Z }, // not used
{ Z, Z, Z, Z, Z, Z, Z, Z }, // not used
{ Z, Z, Z, Z, Z, Z, Z, Z } // not used
}; };
// ThreatedByPawnPenalty[] contains a penalty according to which piece // ThreatedByPawnPenalty[] contains a penalty according to which piece
// type is attacked by an enemy pawn. // type is attacked by an enemy pawn.
const Score ThreatedByPawnPenalty[8] = { const Score ThreatedByPawnPenalty[8] = {
S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118) Z, Z, S(56, 70), S(56, 70), S(76, 99), S(86, 118), Z, Z
}; };
#undef Z
#undef S #undef S
// Bonus for unstoppable passed pawns // Bonus for unstoppable passed pawns
@@ -197,21 +211,28 @@ namespace {
(1ULL<<SQ_C5) | (1ULL<<SQ_D5) | (1ULL<<SQ_E5) | (1ULL<<SQ_F5) (1ULL<<SQ_C5) | (1ULL<<SQ_D5) | (1ULL<<SQ_E5) | (1ULL<<SQ_F5)
}; };
/// King danger constants and variables. The king danger scores are taken /// King safety constants and variables. The king safety scores are taken
/// from the KingDangerTable[]. Various little "meta-bonuses" measuring /// from the array SafetyTable[]. Various little "meta-bonuses" measuring
/// the strength of the enemy attack are added up into an integer, which /// the strength of the attack are added up into an integer, which is used
/// is used as an index to KingDangerTable[]. /// as an index to SafetyTable[].
// KingAttackWeights[] contains king attack weights by piece type // Attack weights for each piece type and table indexed on piece type
const int KingAttackWeights[8] = { 0, 0, 2, 2, 3, 5 }; const int QueenAttackWeight = 5;
const int RookAttackWeight = 3;
const int BishopAttackWeight = 2;
const int KnightAttackWeight = 2;
// Bonuses for enemy's safe checks const int AttackWeight[] = { 0, 0, KnightAttackWeight, BishopAttackWeight, RookAttackWeight, QueenAttackWeight };
const int QueenContactCheckBonus = 3;
const int DiscoveredCheckBonus = 3; // Bonuses for safe checks, initialized from UCI options
const int QueenCheckBonus = 2; int QueenContactCheckBonus, DiscoveredCheckBonus;
const int RookCheckBonus = 1; int QueenCheckBonus, RookCheckBonus, BishopCheckBonus, KnightCheckBonus;
const int BishopCheckBonus = 1;
const int KnightCheckBonus = 1; // Scan for queen contact mates?
const bool QueenContactMates = true;
// Bonus for having a mate threat, initialized from UCI options
int MateThreatBonus;
// InitKingDanger[] contains bonuses based on the position of the defending // InitKingDanger[] contains bonuses based on the position of the defending
// king. // king.
@@ -226,13 +247,14 @@ namespace {
15, 15, 15, 15, 15, 15, 15, 15 15, 15, 15, 15, 15, 15, 15, 15
}; };
// KingDangerTable[color][] contains the actual king danger weighted scores // SafetyTable[] contains the actual king safety scores. It is initialized
Score KingDangerTable[2][128]; // in init_safety().
Value SafetyTable[100];
// Pawn and material hash tables, indexed by the current thread id. // Pawn and material hash tables, indexed by the current thread id.
// Note that they will be initialized at 0 being global variables. // Note that they will be initialized at 0 being global variables.
MaterialInfoTable* MaterialTable[MAX_THREADS]; MaterialInfoTable* MaterialTable[THREAD_MAX];
PawnInfoTable* PawnTable[MAX_THREADS]; PawnInfoTable* PawnTable[THREAD_MAX];
// Sizes of pawn and material hash tables // Sizes of pawn and material hash tables
const int PawnTableSize = 16384; const int PawnTableSize = 16384;
@@ -240,10 +262,7 @@ namespace {
// Function prototypes // Function prototypes
template<bool HasPopCnt> template<bool HasPopCnt>
Value do_evaluate(const Position& pos, EvalInfo& ei); Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID);
template<Color Us, bool HasPopCnt>
void init_attack_tables(const Position& pos, EvalInfo& ei);
template<Color Us, bool HasPopCnt> template<Color Us, bool HasPopCnt>
void evaluate_pieces_of_color(const Position& pos, EvalInfo& ei); void evaluate_pieces_of_color(const Position& pos, EvalInfo& ei);
@@ -255,12 +274,9 @@ namespace {
void evaluate_threats(const Position& pos, EvalInfo& ei); void evaluate_threats(const Position& pos, EvalInfo& ei);
template<Color Us, bool HasPopCnt> template<Color Us, bool HasPopCnt>
int evaluate_space(const Position& pos, EvalInfo& ei); void evaluate_space(const Position& pos, EvalInfo& ei);
template<Color Us>
void evaluate_passed_pawns(const Position& pos, EvalInfo& ei); void evaluate_passed_pawns(const Position& pos, EvalInfo& ei);
void evaluate_unstoppable_pawns(const Position& pos, EvalInfo& ei);
void evaluate_trapped_bishop_a7h7(const Position& pos, Square s, Color us, EvalInfo& ei); void evaluate_trapped_bishop_a7h7(const Position& pos, Square s, Color us, EvalInfo& ei);
void evaluate_trapped_bishop_a1h1(const Position& pos, Square s, Color us, EvalInfo& ei); void evaluate_trapped_bishop_a1h1(const Position& pos, Square s, Color us, EvalInfo& ei);
inline Score apply_weight(Score v, Score weight); inline Score apply_weight(Score v, Score weight);
@@ -277,21 +293,19 @@ namespace {
/// evaluate() is the main evaluation function. It always computes two /// evaluate() is the main evaluation function. It always computes two
/// values, an endgame score and a middle game score, and interpolates /// values, an endgame score and a middle game score, and interpolates
/// between them based on the remaining material. /// between them based on the remaining material.
Value evaluate(const Position& pos, EvalInfo& ei) { Value evaluate(const Position& pos, EvalInfo& ei, int threadID) {
return CpuHasPOPCNT ? do_evaluate<true>(pos, ei) return CpuHasPOPCNT ? do_evaluate<true>(pos, ei, threadID)
: do_evaluate<false>(pos, ei); : do_evaluate<false>(pos, ei, threadID);
} }
namespace { namespace {
template<bool HasPopCnt> template<bool HasPopCnt>
Value do_evaluate(const Position& pos, EvalInfo& ei) { Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID) {
ScaleFactor factor[2];
assert(pos.is_ok()); assert(pos.is_ok());
assert(pos.thread() >= 0 && pos.thread() < MAX_THREADS); assert(threadID >= 0 && threadID < THREAD_MAX);
assert(!pos.is_check()); assert(!pos.is_check());
memset(&ei, 0, sizeof(EvalInfo)); memset(&ei, 0, sizeof(EvalInfo));
@@ -301,7 +315,7 @@ Value do_evaluate(const Position& pos, EvalInfo& ei) {
ei.value = pos.value(); ei.value = pos.value();
// Probe the material hash table // Probe the material hash table
ei.mi = MaterialTable[pos.thread()]->get_material_info(pos); ei.mi = MaterialTable[threadID]->get_material_info(pos);
ei.value += ei.mi->material_value(); ei.value += ei.mi->material_value();
// If we have a specialized evaluation function for the current material // If we have a specialized evaluation function for the current material
@@ -310,16 +324,30 @@ Value do_evaluate(const Position& pos, EvalInfo& ei) {
return ei.mi->evaluate(pos); return ei.mi->evaluate(pos);
// After get_material_info() call that modifies them // After get_material_info() call that modifies them
ScaleFactor factor[2];
factor[WHITE] = ei.mi->scale_factor(pos, WHITE); factor[WHITE] = ei.mi->scale_factor(pos, WHITE);
factor[BLACK] = ei.mi->scale_factor(pos, BLACK); factor[BLACK] = ei.mi->scale_factor(pos, BLACK);
// Probe the pawn hash table // Probe the pawn hash table
ei.pi = PawnTable[pos.thread()]->get_pawn_info(pos); ei.pi = PawnTable[threadID]->get_pawn_info(pos);
ei.value += apply_weight(ei.pi->pawns_value(), Weights[PawnStructure]); ei.value += apply_weight(ei.pi->pawns_value(), WeightPawnStructure);
// Initialize attack bitboards with pawns evaluation // Initialize king attack bitboards and king attack zones for both sides
init_attack_tables<WHITE, HasPopCnt>(pos, ei); ei.attackedBy[WHITE][KING] = pos.attacks_from<KING>(pos.king_square(WHITE));
init_attack_tables<BLACK, HasPopCnt>(pos, ei); ei.attackedBy[BLACK][KING] = pos.attacks_from<KING>(pos.king_square(BLACK));
ei.kingZone[WHITE] = ei.attackedBy[BLACK][KING] | (ei.attackedBy[BLACK][KING] >> 8);
ei.kingZone[BLACK] = ei.attackedBy[WHITE][KING] | (ei.attackedBy[WHITE][KING] << 8);
// Initialize pawn attack bitboards for both sides
ei.attackedBy[WHITE][PAWN] = ei.pi->pawn_attacks(WHITE);
ei.attackedBy[BLACK][PAWN] = ei.pi->pawn_attacks(BLACK);
Bitboard b1 = ei.attackedBy[WHITE][PAWN] & ei.attackedBy[BLACK][KING];
Bitboard b2 = ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING];
if (b1)
ei.kingAttackersCount[WHITE] = count_1s_max_15<HasPopCnt>(b1)/2;
if (b2)
ei.kingAttackersCount[BLACK] = count_1s_max_15<HasPopCnt>(b2)/2;
// Evaluate pieces // Evaluate pieces
evaluate_pieces_of_color<WHITE, HasPopCnt>(pos, ei); evaluate_pieces_of_color<WHITE, HasPopCnt>(pos, ei);
@@ -331,44 +359,43 @@ Value do_evaluate(const Position& pos, EvalInfo& ei) {
evaluate_king<WHITE, HasPopCnt>(pos, ei); evaluate_king<WHITE, HasPopCnt>(pos, ei);
evaluate_king<BLACK, HasPopCnt>(pos, ei); evaluate_king<BLACK, HasPopCnt>(pos, ei);
// Evaluate tactical threats, we need full attack info including king // Evaluate tactical threats, we need full attack info
evaluate_threats<WHITE>(pos, ei); evaluate_threats<WHITE>(pos, ei);
evaluate_threats<BLACK>(pos, ei); evaluate_threats<BLACK>(pos, ei);
// Evaluate passed pawns, we need full attack info including king // Evaluate passed pawns. We evaluate passed pawns for both sides at once,
evaluate_passed_pawns<WHITE>(pos, ei); // because we need to know which side promotes first in positions where
evaluate_passed_pawns<BLACK>(pos, ei); // both sides have an unstoppable passed pawn. To be called after all attacks
// are computed, included king.
// If one side has only a king, check whether exsists any unstoppable passed pawn if (ei.pi->passed_pawns())
if (!pos.non_pawn_material(WHITE) || !pos.non_pawn_material(BLACK)) evaluate_passed_pawns(pos, ei);
evaluate_unstoppable_pawns(pos, ei);
Phase phase = ei.mi->game_phase(); Phase phase = ei.mi->game_phase();
// Middle-game specific evaluation terms // Middle-game specific evaluation terms
if (phase > PHASE_ENDGAME) if (phase > PHASE_ENDGAME)
{ {
// Pawn storms in positions with opposite castling // Pawn storms in positions with opposite castling.
if ( square_file(pos.king_square(WHITE)) >= FILE_E if ( square_file(pos.king_square(WHITE)) >= FILE_E
&& square_file(pos.king_square(BLACK)) <= FILE_D) && square_file(pos.king_square(BLACK)) <= FILE_D)
ei.value += make_score(ei.pi->queenside_storm_value(WHITE) - ei.pi->kingside_storm_value(BLACK), 0); ei.value += make_score(ei.pi->queenside_storm_value(WHITE) - ei.pi->kingside_storm_value(BLACK), 0);
else if ( square_file(pos.king_square(WHITE)) <= FILE_D else if ( square_file(pos.king_square(WHITE)) <= FILE_D
&& square_file(pos.king_square(BLACK)) >= FILE_E) && square_file(pos.king_square(BLACK)) >= FILE_E)
ei.value += make_score(ei.pi->kingside_storm_value(WHITE) - ei.pi->queenside_storm_value(BLACK), 0); ei.value += make_score(ei.pi->kingside_storm_value(WHITE) - ei.pi->queenside_storm_value(BLACK), 0);
// Evaluate space for both sides // Evaluate space for both sides
if (ei.mi->space_weight() > 0) if (ei.mi->space_weight() > 0)
{ {
int s = evaluate_space<WHITE, HasPopCnt>(pos, ei) - evaluate_space<BLACK, HasPopCnt>(pos, ei); evaluate_space<WHITE, HasPopCnt>(pos, ei);
ei.value += apply_weight(make_score(s * ei.mi->space_weight(), 0), Weights[Space]); evaluate_space<BLACK, HasPopCnt>(pos, ei);
} }
} }
// Mobility // Mobility
ei.value += apply_weight(ei.mobility, Weights[Mobility]); ei.value += apply_weight(ei.mobility, WeightMobility);
// If we don't already have an unusual scale factor, check for opposite // If we don't already have an unusual scale factor, check for opposite
// colored bishop endgames, and use a lower scale for those // colored bishop endgames, and use a lower scale for those
@@ -400,18 +427,37 @@ Value do_evaluate(const Position& pos, EvalInfo& ei) {
} }
// Interpolate between the middle game and the endgame score // Interpolate between the middle game and the endgame score
return Sign[pos.side_to_move()] * scale_by_game_phase(ei.value, phase, factor); Color stm = pos.side_to_move();
Value v = Sign[stm] * scale_by_game_phase(ei.value, phase, factor);
return (ei.mateThreat[stm] == MOVE_NONE ? v : 8 * QueenValueMidgame - v);
} }
} // namespace } // namespace
/// quick_evaluate() does a very approximate evaluation of the current position.
/// It currently considers only material and piece square table scores. Perhaps
/// we should add scores from the pawn and material hash tables?
Value quick_evaluate(const Position &pos) {
assert(pos.is_ok());
static const ScaleFactor sf[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};
Value v = scale_by_game_phase(pos.value(), MaterialInfoTable::game_phase(pos), sf);
return (pos.side_to_move() == WHITE ? v : -v);
}
/// init_eval() initializes various tables used by the evaluation function /// init_eval() initializes various tables used by the evaluation function
void init_eval(int threads) { void init_eval(int threads) {
assert(threads <= MAX_THREADS); assert(threads <= THREAD_MAX);
for (int i = 0; i < MAX_THREADS; i++) for (int i = 0; i < THREAD_MAX; i++)
{ {
if (i >= threads) if (i >= threads)
{ {
@@ -433,7 +479,7 @@ void init_eval(int threads) {
void quit_eval() { void quit_eval() {
for (int i = 0; i < MAX_THREADS; i++) for (int i = 0; i < THREAD_MAX; i++)
{ {
delete PawnTable[i]; delete PawnTable[i];
delete MaterialTable[i]; delete MaterialTable[i];
@@ -447,46 +493,28 @@ void quit_eval() {
void read_weights(Color us) { void read_weights(Color us) {
// King safety is asymmetrical. Our king danger level is weighted by Color them = opposite_color(us);
// "Cowardice" UCI parameter, instead the opponent one by "Aggressiveness".
const int kingDangerUs = (us == WHITE ? KingDangerUs : KingDangerThem);
const int kingDangerThem = (us == WHITE ? KingDangerThem : KingDangerUs);
Weights[Mobility] = weight_option("Mobility (Middle Game)", "Mobility (Endgame)", WeightsInternal[Mobility]); WeightMobility = weight_option("Mobility (Middle Game)", "Mobility (Endgame)", WeightMobilityInternal);
Weights[PawnStructure] = weight_option("Pawn Structure (Middle Game)", "Pawn Structure (Endgame)", WeightsInternal[PawnStructure]); WeightPawnStructure = weight_option("Pawn Structure (Middle Game)", "Pawn Structure (Endgame)", WeightPawnStructureInternal);
Weights[PassedPawns] = weight_option("Passed Pawns (Middle Game)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]); WeightPassedPawns = weight_option("Passed Pawns (Middle Game)", "Passed Pawns (Endgame)", WeightPassedPawnsInternal);
Weights[Space] = weight_option("Space", "Space", WeightsInternal[Space]); WeightSpace = weight_option("Space", "Space", WeightSpaceInternal);
Weights[kingDangerUs] = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]); WeightKingSafety[us] = weight_option("Cowardice", "Cowardice", WeightKingSafetyInternal);
Weights[kingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]); WeightKingSafety[them] = weight_option("Aggressiveness", "Aggressiveness", WeightKingOppSafetyInternal);
// If running in analysis mode, make sure we use symmetrical king safety. We do this // If running in analysis mode, make sure we use symmetrical king safety. We do this
// by replacing both Weights[kingDangerUs] and Weights[kingDangerThem] by their average. // by replacing both WeightKingSafety[us] and WeightKingSafety[them] by their average.
if (get_option_value_bool("UCI_AnalyseMode")) if (get_option_value_bool("UCI_AnalyseMode"))
Weights[kingDangerUs] = Weights[kingDangerThem] = (Weights[kingDangerUs] + Weights[kingDangerThem]) / 2; {
WeightKingSafety[us] = (WeightKingSafety[us] + WeightKingSafety[them]) / 2;
WeightKingSafety[them] = WeightKingSafety[us];
}
init_safety(); init_safety();
} }
namespace { namespace {
// init_attack_tables() initializes king bitboards for both sides adding
// pawn attacks. To be done before other evaluations.
template<Color Us, bool HasPopCnt>
void init_attack_tables(const Position& pos, EvalInfo& ei) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from<KING>(pos.king_square(Them));
ei.kingZone[Us] = (b | (Us == WHITE ? b >> 8 : b << 8));
ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
b &= ei.attackedBy[Us][PAWN];
if (b)
ei.kingAttackersCount[Us] = count_1s_max_15<HasPopCnt>(b) / 2;
}
// evaluate_outposts() evaluates bishop and knight outposts squares // evaluate_outposts() evaluates bishop and knight outposts squares
template<PieceType Piece, Color Us> template<PieceType Piece, Color Us>
@@ -544,7 +572,7 @@ namespace {
if (b & ei.kingZone[Us]) if (b & ei.kingZone[Us])
{ {
ei.kingAttackersCount[Us]++; ei.kingAttackersCount[Us]++;
ei.kingAttackersWeight[Us] += KingAttackWeights[Piece]; ei.kingAttackersWeight[Us] += AttackWeight[Piece];
Bitboard bb = (b & ei.attackedBy[Them][KING]); Bitboard bb = (b & ei.attackedBy[Them][KING]);
if (bb) if (bb)
ei.kingAdjacentZoneAttacksCount[Us] += count_1s_max_15<HasPopCnt>(bb); ei.kingAdjacentZoneAttacksCount[Us] += count_1s_max_15<HasPopCnt>(bb);
@@ -562,7 +590,7 @@ namespace {
ei.value -= Sign[Us] * ThreatedByPawnPenalty[Piece]; ei.value -= Sign[Us] * ThreatedByPawnPenalty[Piece];
// Bishop and knight outposts squares // Bishop and knight outposts squares
if ((Piece == BISHOP || Piece == KNIGHT) && pos.square_is_weak(s, Us)) if ((Piece == BISHOP || Piece == KNIGHT) && pos.square_is_weak(s, Them))
evaluate_outposts<Piece, Us>(pos, ei, s); evaluate_outposts<Piece, Us>(pos, ei, s);
// Special patterns: trapped bishops on a7/h7/a2/h2 // Special patterns: trapped bishops on a7/h7/a2/h2
@@ -690,170 +718,279 @@ namespace {
const Color Them = (Us == WHITE ? BLACK : WHITE); const Color Them = (Us == WHITE ? BLACK : WHITE);
Bitboard undefended, b, b1, b2, safe; Bitboard undefended, attackedByOthers, escapeSquares, occ, b, b2, safe;
Square from, to;
bool sente; bool sente;
int attackUnits, shelter = 0; int attackUnits, count, shelter = 0;
const Square ksq = pos.king_square(Us); const Square s = pos.king_square(Us);
// King shelter // King shelter
if (relative_rank(Us, ksq) <= RANK_4) if (relative_rank(Us, s) <= RANK_4)
{ {
shelter = ei.pi->get_king_shelter(pos, Us, ksq); shelter = ei.pi->get_king_shelter(pos, Us, s);
ei.value += Sign[Us] * make_score(shelter, 0); ei.value += Sign[Us] * make_score(shelter, 0);
} }
// King safety. This is quite complicated, and is almost certainly far // King safety. This is quite complicated, and is almost certainly far
// from optimally tuned. // from optimally tuned.
if ( pos.piece_count(Them, QUEEN) >= 1 if ( pos.piece_count(Them, QUEEN) >= 1
&& ei.kingAttackersCount[Them] >= 2 && ei.kingAttackersCount[Them] >= 2
&& pos.non_pawn_material(Them) >= QueenValueMidgame + RookValueMidgame && pos.non_pawn_material(Them) >= QueenValueMidgame + RookValueMidgame
&& ei.kingAdjacentZoneAttacksCount[Them]) && ei.kingAdjacentZoneAttacksCount[Them])
{ {
// Is it the attackers turn to move? // Is it the attackers turn to move?
sente = (Them == pos.side_to_move()); sente = (Them == pos.side_to_move());
// Find the attacked squares around the king which has no defenders // Find the attacked squares around the king which has no defenders
// apart from the king itself // apart from the king itself
undefended = ei.attacked_by(Them) & ei.attacked_by(Us, KING); undefended = ei.attacked_by(Them) & ei.attacked_by(Us, KING);
undefended &= ~( ei.attacked_by(Us, PAWN) | ei.attacked_by(Us, KNIGHT) undefended &= ~( ei.attacked_by(Us, PAWN) | ei.attacked_by(Us, KNIGHT)
| ei.attacked_by(Us, BISHOP) | ei.attacked_by(Us, ROOK) | ei.attacked_by(Us, BISHOP) | ei.attacked_by(Us, ROOK)
| ei.attacked_by(Us, QUEEN)); | ei.attacked_by(Us, QUEEN));
// Initialize the 'attackUnits' variable, which is used later on as an // Initialize the 'attackUnits' variable, which is used later on as an
// index to the KingDangerTable[] array. The initial value is based on // index to the SafetyTable[] array. The initial value is based on the
// the number and types of the enemy's attacking pieces, the number of // number and types of the attacking pieces, the number of attacked and
// attacked and undefended squares around our king, the square of the // undefended squares around the king, the square of the king, and the
// king, and the quality of the pawn shelter. // quality of the pawn shelter.
attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2) attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15<HasPopCnt>(undefended)) + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15<HasPopCnt>(undefended))
+ InitKingDanger[relative_square(Us, ksq)] + InitKingDanger[relative_square(Us, s)]
- shelter / 32; - (shelter >> 5);
// Analyse enemy's safe queen contact checks. First find undefended // Analyse safe queen contact checks
// squares around the king attacked by enemy queen... b = undefended & ei.attacked_by(Them, QUEEN) & ~pos.pieces_of_color(Them);
b = undefended & ei.attacked_by(Them, QUEEN) & ~pos.pieces_of_color(Them); if (b)
{
attackedByOthers = ei.attacked_by(Them, PAWN) | ei.attacked_by(Them, KNIGHT)
| ei.attacked_by(Them, BISHOP) | ei.attacked_by(Them, ROOK);
b &= attackedByOthers;
// Squares attacked by the queen and supported by another enemy piece and
// not defended by other pieces but our king.
if (b) if (b)
{ {
// ...then remove squares not supported by another enemy piece // The bitboard b now contains the squares available for safe queen
b &= ( ei.attacked_by(Them, PAWN) | ei.attacked_by(Them, KNIGHT) // contact checks.
| ei.attacked_by(Them, BISHOP) | ei.attacked_by(Them, ROOK)); count = count_1s_max_15<HasPopCnt>(b);
if (b) attackUnits += QueenContactCheckBonus * count * (sente ? 2 : 1);
attackUnits += QueenContactCheckBonus * count_1s_max_15<HasPopCnt>(b) * (sente ? 2 : 1);
// Is there a mate threat?
if (QueenContactMates && !pos.is_check())
{
escapeSquares = pos.attacks_from<KING>(s) & ~pos.pieces_of_color(Us) & ~attackedByOthers;
occ = pos.occupied_squares();
while (b)
{
to = pop_1st_bit(&b);
// Do we have escape squares from queen contact check attack ?
if (!(escapeSquares & ~queen_attacks_bb(to, occ & ClearMaskBB[s])))
{
// We have a mate, unless the queen is pinned or there
// is an X-ray attack through the queen.
for (int i = 0; i < pos.piece_count(Them, QUEEN); i++)
{
from = pos.piece_list(Them, QUEEN, i);
if ( bit_is_set(pos.attacks_from<QUEEN>(from), to)
&& !bit_is_set(pos.pinned_pieces(Them), from)
&& !(rook_attacks_bb(to, occ & ClearMaskBB[from]) & pos.pieces(ROOK, QUEEN, Us))
&& !(bishop_attacks_bb(to, occ & ClearMaskBB[from]) & pos.pieces(BISHOP, QUEEN, Us)))
// Set the mate threat move
ei.mateThreat[Them] = make_move(from, to);
}
}
}
}
} }
}
// Analyse enemy's safe distance checks for sliders and knights // Analyse safe distance checks
safe = ~(pos.pieces_of_color(Them) | ei.attacked_by(Us)); safe = ~(pos.pieces_of_color(Them) | ei.attacked_by(Us));
b1 = pos.attacks_from<ROOK>(ksq) & safe; if (QueenCheckBonus > 0 || RookCheckBonus > 0)
b2 = pos.attacks_from<BISHOP>(ksq) & safe; {
b = pos.attacks_from<ROOK>(s) & safe;
// Enemy queen safe checks // Queen checks
b = (b1 | b2) & ei.attacked_by(Them, QUEEN); b2 = b & ei.attacked_by(Them, QUEEN);
if (b) if (b2)
attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b); attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b2);
// Enemy rooks safe checks // Rook checks
b = b1 & ei.attacked_by(Them, ROOK); b2 = b & ei.attacked_by(Them, ROOK);
if (b) if (b2)
attackUnits += RookCheckBonus * count_1s_max_15<HasPopCnt>(b); attackUnits += RookCheckBonus * count_1s_max_15<HasPopCnt>(b2);
}
if (QueenCheckBonus > 0 || BishopCheckBonus > 0)
{
b = pos.attacks_from<BISHOP>(s) & safe;
// Enemy bishops safe checks // Queen checks
b = b2 & ei.attacked_by(Them, BISHOP); b2 = b & ei.attacked_by(Them, QUEEN);
if (b) if (b2)
attackUnits += BishopCheckBonus * count_1s_max_15<HasPopCnt>(b); attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b2);
// Enemy knights safe checks // Bishop checks
b = pos.attacks_from<KNIGHT>(ksq) & ei.attacked_by(Them, KNIGHT) & safe; b2 = b & ei.attacked_by(Them, BISHOP);
if (b) if (b2)
attackUnits += KnightCheckBonus * count_1s_max_15<HasPopCnt>(b); attackUnits += BishopCheckBonus * count_1s_max_15<HasPopCnt>(b2);
}
if (KnightCheckBonus > 0)
{
b = pos.attacks_from<KNIGHT>(s) & safe;
// To index KingDangerTable[] attackUnits must be in [0, 99] range // Knight checks
attackUnits = Min(99, Max(0, attackUnits)); b2 = b & ei.attacked_by(Them, KNIGHT);
if (b2)
attackUnits += KnightCheckBonus * count_1s_max_15<HasPopCnt>(b2);
}
// Finally, extract the king danger score from the KingDangerTable[] // Analyse discovered checks (only for non-pawns right now, consider
// array and subtract the score from evaluation. Set also ei.kingDanger[] // adding pawns later).
// value that will be used for pruning because this value can sometimes if (DiscoveredCheckBonus)
// be very big, and so capturing a single attacking piece can therefore {
// result in a score change far bigger than the value of the captured piece. b = pos.discovered_check_candidates(Them) & ~pos.pieces(PAWN);
ei.value -= Sign[Us] * KingDangerTable[Us][attackUnits]; if (b)
ei.kingDanger[Us] = mg_value(KingDangerTable[Us][attackUnits]); attackUnits += DiscoveredCheckBonus * count_1s_max_15<HasPopCnt>(b) * (sente ? 2 : 1);
}
// Has a mate threat been found? We don't do anything here if the
// side with the mating move is the side to move, because in that
// case the mating side will get a huge bonus at the end of the main
// evaluation function instead.
if (ei.mateThreat[Them] != MOVE_NONE)
attackUnits += MateThreatBonus;
// Ensure that attackUnits is between 0 and 99, in order to avoid array
// out of bounds errors.
attackUnits = Min(99, Max(0, attackUnits));
// Finally, extract the king safety score from the SafetyTable[] array.
// Add the score to the evaluation, and also to ei.futilityMargin. The
// reason for adding the king safety score to the futility margin is
// that the king safety scores can sometimes be very big, and that
// capturing a single attacking piece can therefore result in a score
// change far bigger than the value of the captured piece.
Score v = apply_weight(make_score(SafetyTable[attackUnits], 0), WeightKingSafety[Us]);
ei.value -= Sign[Us] * v;
if (Us == pos.side_to_move())
ei.futilityMargin += mg_value(v);
} }
} }
// evaluate_passed_pawns<>() evaluates the passed pawns of the given color // evaluate_passed_pawns() evaluates the passed pawns of the given color
template<Color Us> template<Color Us>
void evaluate_passed_pawns(const Position& pos, EvalInfo& ei) { void evaluate_passed_pawns_of_color(const Position& pos, int movesToGo[], Square pawnToGo[], EvalInfo& ei) {
const Color Them = (Us == WHITE ? BLACK : WHITE); const Color Them = (Us == WHITE ? BLACK : WHITE);
Bitboard squaresToQueen, defendedSquares, unsafeSquares, supportingPawns; Bitboard b2, b3, b4;
Bitboard b = ei.pi->passed_pawns() & pos.pieces_of_color(Us); Square ourKingSq = pos.king_square(Us);
Square theirKingSq = pos.king_square(Them);
Bitboard b = ei.pi->passed_pawns() & pos.pieces(PAWN, Us);
while (b) while (b)
{ {
Square s = pop_1st_bit(&b); Square s = pop_1st_bit(&b);
assert(pos.piece_on(s) == piece_of_color_and_type(Us, PAWN));
assert(pos.pawn_is_passed(Us, s)); assert(pos.pawn_is_passed(Us, s));
int r = int(relative_rank(Us, s) - RANK_2); int r = int(relative_rank(Us, s) - RANK_2);
int tr = r * (r - 1); int tr = Max(0, r * (r - 1));
// Base bonus based on rank // Base bonus based on rank
Value mbonus = Value(20 * tr); Value mbonus = Value(20 * tr);
Value ebonus = Value(10 + r * r * 10); Value ebonus = Value(10 + r * r * 10);
// Adjust bonus based on king proximity
if (tr) if (tr)
{ {
Square blockSq = s + pawn_push(Us); Square blockSq = s + pawn_push(Us);
// Adjust bonus based on kings proximity ebonus -= Value(square_distance(ourKingSq, blockSq) * 3 * tr);
ebonus -= Value(square_distance(pos.king_square(Us), blockSq) * 3 * tr); ebonus -= Value(square_distance(ourKingSq, blockSq + pawn_push(Us)) * 1 * tr);
ebonus -= Value(square_distance(pos.king_square(Us), blockSq + pawn_push(Us)) * 1 * tr); ebonus += Value(square_distance(theirKingSq, blockSq) * 6 * tr);
ebonus += Value(square_distance(pos.king_square(Them), blockSq) * 6 * tr);
// If the pawn is free to advance, increase bonus // If the pawn is free to advance, increase bonus
if (pos.square_is_empty(blockSq)) if (pos.square_is_empty(blockSq))
{ {
squaresToQueen = squares_in_front_of(Us, s); // There are no enemy pawns in the pawn's path
defendedSquares = squaresToQueen & ei.attacked_by(Us); b2 = squares_in_front_of(Us, s);
assert((b2 & pos.pieces(PAWN, Them)) == EmptyBoardBB);
// Squares attacked by us
b4 = b2 & ei.attacked_by(Us);
// Squares attacked or occupied by enemy pieces
b3 = b2 & (ei.attacked_by(Them) | pos.pieces_of_color(Them));
// If there is an enemy rook or queen attacking the pawn from behind, // If there is an enemy rook or queen attacking the pawn from behind,
// add all X-ray attacks by the rook or queen. Otherwise consider only // add all X-ray attacks by the rook or queen.
// the squares in the pawn's path attacked or occupied by the enemy.
if ( (squares_behind(Us, s) & pos.pieces(ROOK, QUEEN, Them)) if ( (squares_behind(Us, s) & pos.pieces(ROOK, QUEEN, Them))
&& (squares_behind(Us, s) & pos.pieces(ROOK, QUEEN, Them) & pos.attacks_from<QUEEN>(s))) && (squares_behind(Us, s) & pos.pieces(ROOK, QUEEN, Them) & pos.attacks_from<QUEEN>(s)))
unsafeSquares = squaresToQueen; b3 = b2;
else
unsafeSquares = squaresToQueen & (ei.attacked_by(Them) | pos.pieces_of_color(Them));
// If there aren't enemy attacks or pieces along the path to queen give // Are any of the squares in the pawn's path attacked or occupied by the enemy?
// huge bonus. Even bigger if we protect the pawn's path. if (b3 == EmptyBoardBB)
if (!unsafeSquares) // No enemy attacks or pieces, huge bonus!
ebonus += Value(tr * (squaresToQueen == defendedSquares ? 17 : 15)); // Even bigger if we protect the pawn's path
ebonus += Value(tr * (b2 == b4 ? 17 : 15));
else else
// OK, there are enemy attacks or pieces (but not pawns). Are those // OK, there are enemy attacks or pieces (but not pawns). Are those
// squares which are attacked by the enemy also attacked by us ? // squares which are attacked by the enemy also attacked by us ?
// If yes, big bonus (but smaller than when there are no enemy attacks), // If yes, big bonus (but smaller than when there are no enemy attacks),
// if no, somewhat smaller bonus. // if no, somewhat smaller bonus.
ebonus += Value(tr * ((unsafeSquares & defendedSquares) == unsafeSquares ? 13 : 8)); ebonus += Value(tr * ((b3 & b4) == b3 ? 13 : 8));
// At last, add a small bonus when there are no *friendly* pieces // At last, add a small bonus when there are no *friendly* pieces
// in the pawn's path. // in the pawn's path.
if (!(squaresToQueen & pos.pieces_of_color(Us))) if ((b2 & pos.pieces_of_color(Us)) == EmptyBoardBB)
ebonus += Value(tr); ebonus += Value(tr);
} }
} // tr != 0 } // tr != 0
// Increase the bonus if the passed pawn is supported by a friendly pawn // If the pawn is supported by a friendly pawn, increase bonus
// on the same rank and a bit smaller if it's on the previous rank. b2 = pos.pieces(PAWN, Us) & neighboring_files_bb(s);
supportingPawns = pos.pieces(PAWN, Us) & neighboring_files_bb(s); if (b2 & rank_bb(s))
if (supportingPawns & rank_bb(s))
ebonus += Value(r * 20); ebonus += Value(r * 20);
else if (supportingPawns & rank_bb(s - pawn_push(Us))) else if (pos.attacks_from<PAWN>(s, Them) & b2)
ebonus += Value(r * 12); ebonus += Value(r * 12);
// If the other side has only a king, check whether the pawn is
// unstoppable
if (pos.non_pawn_material(Them) == Value(0))
{
Square qsq;
int d;
qsq = relative_square(Us, make_square(square_file(s), RANK_8));
d = square_distance(s, qsq)
- square_distance(theirKingSq, qsq)
+ (Us != pos.side_to_move());
if (d < 0)
{
int mtg = RANK_8 - relative_rank(Us, s);
int blockerCount = count_1s_max_15(squares_in_front_of(Us,s) & pos.occupied_squares());
mtg += blockerCount;
d += blockerCount;
if (d < 0 && (!movesToGo[Us] || movesToGo[Us] > mtg))
{
movesToGo[Us] = mtg;
pawnToGo[Us] = s;
}
}
}
// Rook pawns are a special case: They are sometimes worse, and // Rook pawns are a special case: They are sometimes worse, and
// sometimes better than other passed pawns. It is difficult to find // sometimes better than other passed pawns. It is difficult to find
// good rules for determining whether they are good or bad. For now, // good rules for determining whether they are good or bad. For now,
@@ -869,54 +1006,23 @@ namespace {
ebonus -= ebonus / 4; ebonus -= ebonus / 4;
} }
// Add the scores for this pawn to the middle game and endgame eval // Add the scores for this pawn to the middle game and endgame eval.
ei.value += Sign[Us] * apply_weight(make_score(mbonus, ebonus), Weights[PassedPawns]); ei.value += Sign[Us] * apply_weight(make_score(mbonus, ebonus), WeightPassedPawns);
} // while } // while
} }
// evaluate_unstoppable_pawns() evaluates the unstoppable passed pawns for both sides // evaluate_passed_pawns() evaluates the passed pawns for both sides
void evaluate_unstoppable_pawns(const Position& pos, EvalInfo& ei) { void evaluate_passed_pawns(const Position& pos, EvalInfo& ei) {
int movesToGo[2] = {0, 0}; int movesToGo[2] = {0, 0};
Square pawnToGo[2] = {SQ_NONE, SQ_NONE}; Square pawnToGo[2] = {SQ_NONE, SQ_NONE};
for (Color c = WHITE; c <= BLACK; c++) // Evaluate pawns for each color
{ evaluate_passed_pawns_of_color<WHITE>(pos, movesToGo, pawnToGo, ei);
// Skip evaluation if other side has non-pawn pieces evaluate_passed_pawns_of_color<BLACK>(pos, movesToGo, pawnToGo, ei);
if (pos.non_pawn_material(opposite_color(c)))
continue;
Bitboard b = ei.pi->passed_pawns() & pos.pieces_of_color(c);
while (b)
{
Square s = pop_1st_bit(&b);
Square queeningSquare = relative_square(c, make_square(square_file(s), RANK_8));
int d = square_distance(s, queeningSquare)
- (relative_rank(c, s) == RANK_2) // Double pawn push
- square_distance(pos.king_square(opposite_color(c)), queeningSquare)
+ int(c != pos.side_to_move());
// Do we protect the path to queening ?
bool pathDefended = (ei.attacked_by(c) & squares_in_front_of(c, s)) == squares_in_front_of(c, s);
if (d < 0 || pathDefended)
{
int mtg = RANK_8 - relative_rank(c, s);
int blockerCount = count_1s_max_15(squares_in_front_of(c, s) & pos.occupied_squares());
mtg += blockerCount;
d += blockerCount;
if ((d < 0 || pathDefended) && (!movesToGo[c] || movesToGo[c] > mtg))
{
movesToGo[c] = mtg;
pawnToGo[c] = s;
}
}
}
}
// Neither side has an unstoppable passed pawn? // Neither side has an unstoppable passed pawn?
if (!(movesToGo[WHITE] | movesToGo[BLACK])) if (!(movesToGo[WHITE] | movesToGo[BLACK]))
@@ -1039,24 +1145,29 @@ namespace {
// twice. Finally, the space bonus is scaled by a weight taken from the // twice. Finally, the space bonus is scaled by a weight taken from the
// material hash table. // material hash table.
template<Color Us, bool HasPopCnt> template<Color Us, bool HasPopCnt>
int evaluate_space(const Position& pos, EvalInfo& ei) { void evaluate_space(const Position& pos, EvalInfo& ei) {
const Color Them = (Us == WHITE ? BLACK : WHITE); const Color Them = (Us == WHITE ? BLACK : WHITE);
// Find the safe squares for our pieces inside the area defined by // Find the safe squares for our pieces inside the area defined by
// SpaceMask[us]. A square is unsafe if it is attacked by an enemy // SpaceMask[us]. A square is unsafe if it is attacked by an enemy
// pawn, or if it is undefended and attacked by an enemy piece. // pawn, or if it is undefended and attacked by an enemy piece.
Bitboard safe = SpaceMask[Us]
& ~pos.pieces(PAWN, Us)
& ~ei.attacked_by(Them, PAWN)
& (ei.attacked_by(Us) | ~ei.attacked_by(Them));
// Find all squares which are at most three squares behind some friendly pawn Bitboard safeSquares = SpaceMask[Us]
Bitboard behind = pos.pieces(PAWN, Us); & ~pos.pieces(PAWN, Us)
behind |= (Us == WHITE ? behind >> 8 : behind << 8); & ~ei.attacked_by(Them, PAWN)
behind |= (Us == WHITE ? behind >> 16 : behind << 16); & ~(~ei.attacked_by(Us) & ei.attacked_by(Them));
return count_1s_max_15<HasPopCnt>(safe) + count_1s_max_15<HasPopCnt>(behind & safe); // Find all squares which are at most three squares behind some friendly
// pawn.
Bitboard behindFriendlyPawns = pos.pieces(PAWN, Us);
behindFriendlyPawns |= (Us == WHITE ? behindFriendlyPawns >> 8 : behindFriendlyPawns << 8);
behindFriendlyPawns |= (Us == WHITE ? behindFriendlyPawns >> 16 : behindFriendlyPawns << 16);
int space = count_1s_max_15<HasPopCnt>(safeSquares)
+ count_1s_max_15<HasPopCnt>(behindFriendlyPawns & safeSquares);
ei.value += Sign[Us] * apply_weight(make_score(space * ei.mi->space_weight(), 0), WeightSpace);
} }
@@ -1089,36 +1200,57 @@ namespace {
Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) { Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) {
// Scale option value from 100 to 256 Score uciWeight = make_score(get_option_value_int(mgOpt), get_option_value_int(egOpt));
int mg = get_option_value_int(mgOpt) * 256 / 100;
int eg = get_option_value_int(egOpt) * 256 / 100;
return apply_weight(make_score(mg, eg), internalWeight); // Convert to integer to prevent overflow
int mg = mg_value(uciWeight);
int eg = eg_value(uciWeight);
mg = (mg * 0x100) / 100;
eg = (eg * 0x100) / 100;
mg = (mg * mg_value(internalWeight)) / 0x100;
eg = (eg * eg_value(internalWeight)) / 0x100;
return make_score(mg, eg);
} }
// init_safety() initizes the king safety evaluation, based on UCI // init_safety() initizes the king safety evaluation, based on UCI
// parameters. It is called from read_weights(). // parameters. It is called from read_weights().
void init_safety() { void init_safety() {
const Value MaxSlope = Value(30); QueenContactCheckBonus = get_option_value_int("Queen Contact Check Bonus");
const Value Peak = Value(1280); QueenCheckBonus = get_option_value_int("Queen Check Bonus");
Value t[100]; RookCheckBonus = get_option_value_int("Rook Check Bonus");
BishopCheckBonus = get_option_value_int("Bishop Check Bonus");
KnightCheckBonus = get_option_value_int("Knight Check Bonus");
DiscoveredCheckBonus = get_option_value_int("Discovered Check Bonus");
MateThreatBonus = get_option_value_int("Mate Threat Bonus");
int maxSlope = get_option_value_int("King Safety Max Slope");
int peak = get_option_value_int("King Safety Max Value") * 256 / 100;
double a = get_option_value_int("King Safety Coefficient") / 100.0;
double b = get_option_value_int("King Safety X Intercept");
bool quad = (get_option_value_string("King Safety Curve") == "Quadratic");
bool linear = (get_option_value_string("King Safety Curve") == "Linear");
// First setup the base table
for (int i = 0; i < 100; i++) for (int i = 0; i < 100; i++)
{ {
t[i] = Value(int(0.4 * i * i)); if (i < b)
SafetyTable[i] = Value(0);
if (i > 0) else if (quad)
t[i] = Min(t[i], t[i - 1] + MaxSlope); SafetyTable[i] = Value((int)(a * (i - b) * (i - b)));
else if (linear)
t[i] = Min(t[i], Peak); SafetyTable[i] = Value((int)(100 * a * (i - b)));
} }
// Then apply the weights and get the final KingDangerTable[] array for (int i = 0; i < 100; i++)
for (Color c = WHITE; c <= BLACK; c++) {
for (int i = 0; i < 100; i++) if (SafetyTable[i+1] - SafetyTable[i] > maxSlope)
KingDangerTable[c][i] = apply_weight(make_score(t[i], 0), Weights[KingDangerUs + c]); for (int j = i + 1; j < 100; j++)
SafetyTable[j] = SafetyTable[j-1] + Value(maxSlope);
if (SafetyTable[i] > Value(peak))
SafetyTable[i] = Value(peak);
}
} }
} }
+10 -7
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -47,8 +47,6 @@ class Position;
struct EvalInfo { struct EvalInfo {
EvalInfo() { kingDanger[0] = kingDanger[1] = Value(0); }
// Middle game and endgame evaluations // Middle game and endgame evaluations
Score value; Score value;
@@ -89,11 +87,15 @@ struct EvalInfo {
// 2 to kingAdjacentZoneAttacksCount[BLACK]. // 2 to kingAdjacentZoneAttacksCount[BLACK].
int kingAdjacentZoneAttacksCount[2]; int kingAdjacentZoneAttacksCount[2];
// Middle game and endgame mobility scores // mateThreat[color] is a move for the given side which gives a direct mate.
Move mateThreat[2];
// Middle game and endgame mobility scores.
Score mobility; Score mobility;
// Value of the danger for the king of the given color // Extra futility margin. This is added to the standard futility margin
Value kingDanger[2]; // in the quiescence search.
Value futilityMargin;
}; };
@@ -101,7 +103,8 @@ struct EvalInfo {
//// Prototypes //// Prototypes
//// ////
extern Value evaluate(const Position& pos, EvalInfo& ei); extern Value evaluate(const Position& pos, EvalInfo& ei, int threadID);
extern Value quick_evaluate(const Position& pos);
extern void init_eval(int threads); extern void init_eval(int threads);
extern void quit_eval(); extern void quit_eval();
extern void read_weights(Color sideToMove); extern void read_weights(Color sideToMove);
+4 -27
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -42,7 +42,6 @@ History::History() { clear(); }
void History::clear() { void History::clear() {
memset(history, 0, 2 * 8 * 64 * sizeof(int)); memset(history, 0, 2 * 8 * 64 * sizeof(int));
memset(maxStaticValueDelta, 0, 2 * 8 * 64 * sizeof(int));
} }
@@ -62,7 +61,7 @@ void History::success(Piece p, Square to, Depth d) {
if (history[p][to] >= HistoryMax) if (history[p][to] >= HistoryMax)
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
for (int j = 0; j < 64; j++) for (int j = 0; j < 64; j++)
history[i][j] /= 2; history[i][j] /= 4;
} }
@@ -76,12 +75,8 @@ void History::failure(Piece p, Square to, Depth d) {
assert(square_is_ok(to)); assert(square_is_ok(to));
history[p][to] -= int(d) * int(d); history[p][to] -= int(d) * int(d);
if (history[p][to] < 0)
// Prevent history underflow history[p][to] = 0;
if (history[p][to] <= -HistoryMax)
for (int i = 0; i < 16; i++)
for (int j = 0; j < 64; j++)
history[i][j] /= 2;
} }
@@ -95,21 +90,3 @@ int History::move_ordering_score(Piece p, Square to) const {
return history[p][to]; return history[p][to];
} }
/// History::set_gain() and History::gain() store and retrieve the
/// gain of a move given the delta of the static position evaluations
/// before and after the move.
void History::set_gain(Piece p, Square to, Value delta)
{
if (delta >= maxStaticValueDelta[p][to])
maxStaticValueDelta[p][to] = delta;
else
maxStaticValueDelta[p][to]--;
}
Value History::gain(Piece p, Square to) const
{
return Value(maxStaticValueDelta[p][to]);
}
+3 -7
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -28,7 +28,6 @@
#include "depth.h" #include "depth.h"
#include "move.h" #include "move.h"
#include "piece.h" #include "piece.h"
#include "value.h"
//// ////
@@ -50,12 +49,9 @@ public:
void success(Piece p, Square to, Depth d); void success(Piece p, Square to, Depth d);
void failure(Piece p, Square to, Depth d); void failure(Piece p, Square to, Depth d);
int move_ordering_score(Piece p, Square to) const; int move_ordering_score(Piece p, Square to) const;
void set_gain(Piece p, Square to, Value delta);
Value gain(Piece p, Square to) const;
private: private:
int history[16][64]; // [piece][square] int history[16][64]; // [piece][square]
int maxStaticValueDelta[16][64]; // [piece][from_square][to_square]
}; };
@@ -65,13 +61,13 @@ private:
/// HistoryMax controls how often the history counters will be scaled down: /// HistoryMax controls how often the history counters will be scaled down:
/// When the history score for a move gets bigger than HistoryMax, all /// When the history score for a move gets bigger than HistoryMax, all
/// entries in the table are divided by 2. It is difficult to guess what /// entries in the table are divided by 4. It is difficult to guess what
/// the ideal value of this constant is. Scaling down the scores often has /// the ideal value of this constant is. Scaling down the scores often has
/// the effect that parts of the search tree which have been searched /// the effect that parts of the search tree which have been searched
/// recently have a bigger importance for move ordering than the moves which /// recently have a bigger importance for move ordering than the moves which
/// have been searched a long time ago. /// have been searched a long time ago.
const int HistoryMax = 50000 * OnePly; const int HistoryMax = 25000 * OnePly;
#endif // !defined(HISTORY_H_INCLUDED) #endif // !defined(HISTORY_H_INCLUDED)
+2 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -99,4 +99,5 @@ typedef CRITICAL_SECTION Lock;
#endif #endif
#endif // !defined(LOCK_H_INCLUDED) #endif // !defined(LOCK_H_INCLUDED)
+16 -18
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -57,19 +57,8 @@ int main(int argc, char *argv[]) {
CALLGRIND_START_INSTRUMENTATION; CALLGRIND_START_INSTRUMENTATION;
#endif #endif
if (argc <= 1) // Process command line arguments if any
{ if (argc > 1)
// Print copyright notice
cout << engine_name()
<< " by Tord Romstad, Marco Costalba, Joona Kiiski" << endl;
if (CpuHasPOPCNT)
cout << "Good! CPU has hardware POPCNT." << endl;
// Enter UCI mode
uci_main_loop();
}
else // Process command line arguments
{ {
if (string(argv[1]) != "bench" || argc < 4 || argc > 8) if (string(argv[1]) != "bench" || argc < 4 || argc > 8)
cout << "Usage: stockfish bench <hash size> <threads> " cout << "Usage: stockfish bench <hash size> <threads> "
@@ -79,13 +68,22 @@ int main(int argc, char *argv[]) {
else else
{ {
string time = argc > 4 ? argv[4] : "60"; string time = argc > 4 ? argv[4] : "60";
string fen = argc > 5 ? argv[5] : "default"; string fen = argc > 5 ? argv[5] : "default";
string lim = argc > 6 ? argv[6] : "time"; string lim = argc > 6 ? argv[6] : "time";
string tim = argc > 7 ? argv[7] : ""; string tim = argc > 7 ? argv[7] : "";
benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim + " " + tim); benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim + " " + tim);
} }
return 0;
} }
Application::free_resources(); // Print copyright notice
cout << engine_name()
<< ". By Tord Romstad, Marco Costalba, Joona Kiiski." << endl;
if (CpuHasPOPCNT)
cout << "Good! CPU has hardware POPCNT. We will use it." << endl;
// Enter UCI mode
uci_main_loop();
return 0; return 0;
} }
+53 -53
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -55,40 +55,17 @@ namespace {
{ 41, 41, 41, 41, 41, 41 }, { 37, 41, 41, 41, 41, 41 }, { 10, 62, 41, 41, 41, 41 }, { 41, 41, 41, 41, 41, 41 }, { 37, 41, 41, 41, 41, 41 }, { 10, 62, 41, 41, 41, 41 },
{ 57, 64, 39, 41, 41, 41 }, { 50, 40, 23, -22, 41, 41 }, { 106, 101, 3, 151, 171, 41 } }; { 57, 64, 39, 41, 41, 41 }, { 50, 40, 23, -22, 41, 41 }, { 106, 101, 3, 151, 171, 41 } };
// Named endgame evaluation and scaling functions, these
// are accessed direcly and not through the function maps.
EvaluationFunction<KmmKm> EvaluateKmmKm(WHITE);
EvaluationFunction<KXK> EvaluateKXK(WHITE), EvaluateKKX(BLACK);
ScalingFunction<KBPsK> ScaleKBPsK(WHITE), ScaleKKBPs(BLACK);
ScalingFunction<KQKRPs> ScaleKQKRPs(WHITE), ScaleKRPsKQ(BLACK);
ScalingFunction<KPsK> ScaleKPsK(WHITE), ScaleKKPs(BLACK);
ScalingFunction<KPKP> ScaleKPKPw(WHITE), ScaleKPKPb(BLACK);
typedef EndgameEvaluationFunctionBase EF; typedef EndgameEvaluationFunctionBase EF;
typedef EndgameScalingFunctionBase SF; typedef EndgameScalingFunctionBase SF;
// Endgame evaluation and scaling functions accessed direcly and not through
// the function maps because correspond to more then one material hash key.
EvaluationFunction<KmmKm> EvaluateKmmKm[] = { EvaluationFunction<KmmKm>(WHITE), EvaluationFunction<KmmKm>(BLACK) };
EvaluationFunction<KXK> EvaluateKXK[] = { EvaluationFunction<KXK>(WHITE), EvaluationFunction<KXK>(BLACK) };
ScalingFunction<KBPsK> ScaleKBPsK[] = { ScalingFunction<KBPsK>(WHITE), ScalingFunction<KBPsK>(BLACK) };
ScalingFunction<KQKRPs> ScaleKQKRPs[] = { ScalingFunction<KQKRPs>(WHITE), ScalingFunction<KQKRPs>(BLACK) };
ScalingFunction<KPsK> ScaleKPsK[] = { ScalingFunction<KPsK>(WHITE), ScalingFunction<KPsK>(BLACK) };
ScalingFunction<KPKP> ScaleKPKP[] = { ScalingFunction<KPKP>(WHITE), ScalingFunction<KPKP>(BLACK) };
// Helper templates used to detect a given material distribution
template<Color Us> bool is_KXK(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
return pos.non_pawn_material(Them) == Value(0)
&& pos.piece_count(Them, PAWN) == 0
&& pos.non_pawn_material(Us) >= RookValueMidgame;
}
template<Color Us> bool is_KBPsK(const Position& pos) {
return pos.non_pawn_material(Us) == BishopValueMidgame
&& pos.piece_count(Us, BISHOP) == 1
&& pos.piece_count(Us, PAWN) >= 1;
}
template<Color Us> bool is_KQKRPs(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
return pos.piece_count(Us, PAWN) == 0
&& pos.non_pawn_material(Us) == QueenValueMidgame
&& pos.piece_count(Us, QUEEN) == 1
&& pos.piece_count(Them, ROOK) == 1
&& pos.piece_count(Them, PAWN) >= 1;
}
} }
@@ -204,13 +181,22 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
if ((mi->evaluationFunction = funcs->get<EF>(key)) != NULL) if ((mi->evaluationFunction = funcs->get<EF>(key)) != NULL)
return mi; return mi;
else if (is_KXK<WHITE>(pos) || is_KXK<BLACK>(pos)) else if ( pos.non_pawn_material(BLACK) == Value(0)
&& pos.piece_count(BLACK, PAWN) == 0
&& pos.non_pawn_material(WHITE) >= RookValueMidgame)
{ {
mi->evaluationFunction = is_KXK<WHITE>(pos) ? &EvaluateKXK[WHITE] : &EvaluateKXK[BLACK]; mi->evaluationFunction = &EvaluateKXK;
return mi; return mi;
} }
else if ( pos.pieces(PAWN) == EmptyBoardBB else if ( pos.non_pawn_material(WHITE) == Value(0)
&& pos.pieces(ROOK) == EmptyBoardBB && pos.piece_count(WHITE, PAWN) == 0
&& pos.non_pawn_material(BLACK) >= RookValueMidgame)
{
mi->evaluationFunction = &EvaluateKKX;
return mi;
}
else if ( pos.pieces(PAWN) == EmptyBoardBB
&& pos.pieces(ROOK) == EmptyBoardBB
&& pos.pieces(QUEEN) == EmptyBoardBB) && pos.pieces(QUEEN) == EmptyBoardBB)
{ {
// Minor piece endgame with at least one minor piece per side and // Minor piece endgame with at least one minor piece per side and
@@ -221,7 +207,7 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
if ( pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2 if ( pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2
&& pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2) && pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2)
{ {
mi->evaluationFunction = &EvaluateKmmKm[WHITE]; mi->evaluationFunction = &EvaluateKmmKm;
return mi; return mi;
} }
} }
@@ -229,8 +215,10 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
// OK, we didn't find any special evaluation function for the current // OK, we didn't find any special evaluation function for the current
// material configuration. Is there a suitable scaling function? // material configuration. Is there a suitable scaling function?
// //
// We face problems when there are several conflicting applicable // The code below is rather messy, and it could easily get worse later,
// scaling functions and we need to decide which one to use. // if we decide to add more special cases. We face problems when there
// are several conflicting applicable scaling functions and we need to
// decide which one to use.
SF* sf; SF* sf;
if ((sf = funcs->get<SF>(key)) != NULL) if ((sf = funcs->get<SF>(key)) != NULL)
@@ -242,36 +230,48 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
// Generic scaling functions that refer to more then one material // Generic scaling functions that refer to more then one material
// distribution. Should be probed after the specialized ones. // distribution. Should be probed after the specialized ones.
// Note that these ones don't return after setting the function. // Note that these ones don't return after setting the function.
if (is_KBPsK<WHITE>(pos)) if ( pos.non_pawn_material(WHITE) == BishopValueMidgame
mi->scalingFunction[WHITE] = &ScaleKBPsK[WHITE]; && pos.piece_count(WHITE, BISHOP) == 1
&& pos.piece_count(WHITE, PAWN) >= 1)
mi->scalingFunction[WHITE] = &ScaleKBPsK;
if (is_KBPsK<BLACK>(pos)) if ( pos.non_pawn_material(BLACK) == BishopValueMidgame
mi->scalingFunction[BLACK] = &ScaleKBPsK[BLACK]; && pos.piece_count(BLACK, BISHOP) == 1
&& pos.piece_count(BLACK, PAWN) >= 1)
mi->scalingFunction[BLACK] = &ScaleKKBPs;
if (is_KQKRPs<WHITE>(pos)) if ( pos.piece_count(WHITE, PAWN) == 0
mi->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE]; && pos.non_pawn_material(WHITE) == QueenValueMidgame
&& pos.piece_count(WHITE, QUEEN) == 1
&& pos.piece_count(BLACK, ROOK) == 1
&& pos.piece_count(BLACK, PAWN) >= 1)
mi->scalingFunction[WHITE] = &ScaleKQKRPs;
else if (is_KQKRPs<BLACK>(pos)) else if ( pos.piece_count(BLACK, PAWN) == 0
mi->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK]; && pos.non_pawn_material(BLACK) == QueenValueMidgame
&& pos.piece_count(BLACK, QUEEN) == 1
&& pos.piece_count(WHITE, ROOK) == 1
&& pos.piece_count(WHITE, PAWN) >= 1)
mi->scalingFunction[BLACK] = &ScaleKRPsKQ;
if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) == Value(0)) if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) == Value(0))
{ {
if (pos.piece_count(BLACK, PAWN) == 0) if (pos.piece_count(BLACK, PAWN) == 0)
{ {
assert(pos.piece_count(WHITE, PAWN) >= 2); assert(pos.piece_count(WHITE, PAWN) >= 2);
mi->scalingFunction[WHITE] = &ScaleKPsK[WHITE]; mi->scalingFunction[WHITE] = &ScaleKPsK;
} }
else if (pos.piece_count(WHITE, PAWN) == 0) else if (pos.piece_count(WHITE, PAWN) == 0)
{ {
assert(pos.piece_count(BLACK, PAWN) >= 2); assert(pos.piece_count(BLACK, PAWN) >= 2);
mi->scalingFunction[BLACK] = &ScaleKPsK[BLACK]; mi->scalingFunction[BLACK] = &ScaleKKPs;
} }
else if (pos.piece_count(WHITE, PAWN) == 1 && pos.piece_count(BLACK, PAWN) == 1) else if (pos.piece_count(WHITE, PAWN) == 1 && pos.piece_count(BLACK, PAWN) == 1)
{ {
// This is a special case because we set scaling functions // This is a special case because we set scaling functions
// for both colors instead of only one. // for both colors instead of only one.
mi->scalingFunction[WHITE] = &ScaleKPKP[WHITE]; mi->scalingFunction[WHITE] = &ScaleKPKPw;
mi->scalingFunction[BLACK] = &ScaleKPKP[BLACK]; mi->scalingFunction[BLACK] = &ScaleKPKPb;
} }
} }
@@ -403,7 +403,7 @@ Key EndgameFunctions::buildKey(const string& keyCode) {
s << char(upcase? toupper(keyCode[i]) : tolower(keyCode[i])); s << char(upcase? toupper(keyCode[i]) : tolower(keyCode[i]));
} }
s << 8 - keyCode.length() << "/8/8/8/8/8/8/8 w -"; s << 8 - keyCode.length() << "/8/8/8/8/8/8/8 w -";
return Position(s.str(), 0).get_material_key(); return Position(s.str()).get_material_key();
} }
const string EndgameFunctions::swapColors(const string& keyCode) { const string EndgameFunctions::swapColors(const string& keyCode) {
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+77 -99
View File
@@ -41,131 +41,109 @@
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/ */
#include "types.h"
#include "mersenne.h" #include "mersenne.h"
namespace { /* Period parameters */
#define N 624
#define M 397
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
// Period parameters static unsigned long mt[N]; /* the array for the state vector */
const int N = 624; static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
const int M = 397;
const unsigned long MATRIX_A = 0x9908b0dfUL; // Constant vector a
const unsigned long UPPER_MASK = 0x80000000UL; // Most significant w-r bits
const unsigned long LOWER_MASK = 0x7fffffffUL; // Least significant r bits
unsigned long mt[N]; // The array for the state vector /* initializes mt[N] with a seed */
int mti = N + 1; // mti == N+1 means mt[N] is not initialized static void init_genrand(unsigned long s)
{
mt[0]= s & 0xffffffffUL;
for (mti=1; mti<N; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
mt[mti] &= 0xffffffffUL;
/* for >32 bit machines */
}
}
// Initializes mt[N] with a seed /* initialize by an array with array-length */
void init_genrand(unsigned long s) { /* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
static void init_by_array(unsigned long init_key[], int key_length)
{
int i, j, k;
init_genrand(19650218UL);
i=1; j=0;
k = (N>key_length ? N : key_length);
for (; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+ init_key[j] + j; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++; j++;
if (i>=N) { mt[0] = mt[N-1]; i=1; }
if (j>=key_length) j=0;
}
for (k=N-1; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
- i; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++;
if (i>=N) { mt[0] = mt[N-1]; i=1; }
}
mt[0]= s & 0xffffffffUL; mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
for (mti = 1; mti < N; mti++) }
{
// See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
// In the previous versions, MSBs of the seed affect
// only MSBs of the array mt[].
// 2002/01/09 modified by Makoto Matsumoto
mt[mti] = 1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti;
mt[mti] &= 0xffffffffUL; // For > 32 bit machines
}
}
// Initialize by an array with array-length
// init_key is the array for initializing keys
// key_length is its length
// slight change for C++, 2004/2/26
void init_by_array(unsigned long init_key[], int key_length) {
int i = 1;
int j = 0;
int k = (N > key_length ? N : key_length);
init_genrand(19650218UL);
for ( ; k; k--)
{
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; // Non linear
mt[i] &= 0xffffffffUL; // For WORDSIZE > 32 machines
i++; j++;
if (i >= N)
{
mt[0] = mt[N-1];
i = 1;
}
if (j >= key_length)
j = 0;
}
for (k = N-1; k; k--)
{
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i; // Non linear
mt[i] &= 0xffffffffUL; // For WORDSIZE > 32 machines
i++;
if (i >= N)
{
mt[0] = mt[N-1];
i = 1;
}
}
mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array
}
} // namespace
// Generates a random number on [0,0xffffffff]-interval
uint32_t genrand_int32() {
/* generates a random number on [0,0xffffffff]-interval */
uint32_t genrand_int32(void) {
unsigned long y; unsigned long y;
static unsigned long mag01[2] = {0x0UL, MATRIX_A}; static unsigned long mag01[2]={0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */ /* mag01[x] = x * MATRIX_A for x=0,1 */
// Generate N words at one time if (mti >= N) { /* generate N words at one time */
if (mti >= N) int kk;
{
int kk;
if (mti == N+1) // If init_genrand() has not been called, if (mti == N+1) /* if init_genrand() has not been called, */
init_genrand(5489UL); // a default initial seed is used. init_genrand(5489UL); /* a default initial seed is used */
for (kk = 0; kk < N-M; kk++) for (kk=0;kk<N-M;kk++) {
{ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL]; }
} for (;kk<N-1;kk++) {
for ( ; kk < N-1; kk++) y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
{ mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); }
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
} mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mti = 0;
mti = 0;
} }
y = mt[mti++]; y = mt[mti++];
// Tempering /* Tempering */
y ^= (y >> 11); y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL; y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18); y ^= (y >> 18);
return y; return y;
} }
uint64_t genrand_int64() { uint64_t genrand_int64(void) {
uint64_t x, y; uint64_t x, y;
x = genrand_int32(); x = genrand_int32(); y = genrand_int32();
y = genrand_int32(); return (x<<32)|y;
return (x << 32) | y;
} }
void init_mersenne() { void init_mersenne(void) {
unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
unsigned long init[4] = {0x123, 0x234, 0x345, 0x456};
unsigned long length = 4;
init_by_array(init, length); init_by_array(init, length);
} }
+4 -4
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -32,9 +32,9 @@
//// Prototypes //// Prototypes
//// ////
extern uint32_t genrand_int32(); extern uint32_t genrand_int32(void);
extern uint64_t genrand_int64(); extern uint64_t genrand_int64(void);
extern void init_mersenne(); extern void init_mersenne(void);
#endif // !defined(MERSENNE_H_INCLUDED) #endif // !defined(MERSENNE_H_INCLUDED)
+5 -44
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -27,9 +27,6 @@
# include <sys/time.h> # include <sys/time.h>
# include <sys/types.h> # include <sys/types.h>
# include <unistd.h> # include <unistd.h>
# if defined(__hpux)
# include <sys/pstat.h>
# endif
#else #else
@@ -39,10 +36,6 @@
#endif #endif
#if !defined(NO_PREFETCH)
# include <xmmintrin.h>
#endif
#include <cassert> #include <cassert>
#include <cstdio> #include <cstdio>
#include <iomanip> #include <iomanip>
@@ -51,14 +44,13 @@
#include "bitcount.h" #include "bitcount.h"
#include "misc.h" #include "misc.h"
#include "thread.h"
using namespace std; using namespace std;
/// Version number. If this is left empty, the current date (in the format /// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number. /// YYMMDD) is used as a version number.
static const string EngineVersion = "1.8 beta 2"; static const string EngineVersion = "1.6.3";
static const string AppName = "Stockfish"; static const string AppName = "Stockfish";
static const string AppTag = ""; static const string AppTag = "";
@@ -151,7 +143,7 @@ const string engine_name() {
const string cpu64(CpuHas64BitPath ? " 64bit" : ""); const string cpu64(CpuHas64BitPath ? " 64bit" : "");
if (!EngineVersion.empty()) if (!EngineVersion.empty())
return AppName + " " + EngineVersion + cpu64; return AppName+ " " + EngineVersion + cpu64;
string date(__DATE__); // From compiler, format is "Sep 21 2008" string date(__DATE__); // From compiler, format is "Sep 21 2008"
string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"); string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
@@ -193,15 +185,7 @@ int get_system_time() {
# if defined(_SC_NPROCESSORS_ONLN) # if defined(_SC_NPROCESSORS_ONLN)
int cpu_count() { int cpu_count() {
return Min(sysconf(_SC_NPROCESSORS_ONLN), MAX_THREADS); return Min(sysconf(_SC_NPROCESSORS_ONLN), 8);
}
# elif defined(__hpux)
int cpu_count() {
struct pst_dynamic psd;
if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) == -1)
return 1;
return Min(psd.psd_proc_cnt, MAX_THREADS);
} }
# else # else
int cpu_count() { int cpu_count() {
@@ -214,7 +198,7 @@ int cpu_count() {
int cpu_count() { int cpu_count() {
SYSTEM_INFO s; SYSTEM_INFO s;
GetSystemInfo(&s); GetSystemInfo(&s);
return Min(s.dwNumberOfProcessors, MAX_THREADS); return Min(s.dwNumberOfProcessors, 8);
} }
#endif #endif
@@ -291,27 +275,4 @@ int Bioskey()
return 0; return 0;
} }
} }
#endif #endif
/// prefetch() preloads the given address in L1/L2 cache. This is a non
/// blocking function and do not stalls the CPU waiting for data to be
/// loaded from RAM, that can be very slow.
#if defined(NO_PREFETCH)
void prefetch(char*) {}
#else
void prefetch(char* addr) {
#if defined(__INTEL_COMPILER) || defined(__ICL)
// This hack prevents prefetches to be optimized away by
// Intel compiler. Both MSVC and gcc seems not affected.
__asm__ ("");
#endif
_mm_prefetch(addr, _MM_HINT_T2);
_mm_prefetch(addr+64, _MM_HINT_T2); // 64 bytes ahead
}
#endif
+1 -2
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -55,7 +55,6 @@ extern const std::string engine_name();
extern int get_system_time(); extern int get_system_time();
extern int cpu_count(); extern int cpu_count();
extern int Bioskey(); extern int Bioskey();
extern void prefetch(char* addr);
//// ////
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+28 -8
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -86,10 +86,10 @@ inline void insertion_sort(T* firstMove, T* lastMove)
} }
} }
// Our dedicated sort in range [firstMove, lastMove), first splits // Our dedicated sort in range [firstMove, lastMove), it is well
// positive scores from ramining then order seaprately the two sets. // tuned for non-captures where we have a lot of zero scored moves.
template<typename T> template<typename T>
inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive) inline void sort_moves(T* firstMove, T* lastMove)
{ {
T tmp; T tmp;
T *p, *d; T *p, *d;
@@ -101,11 +101,11 @@ inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive)
// Split positives vs non-positives // Split positives vs non-positives
do { do {
while ((++p)->score > 0) {} while ((++p)->score > 0);
if (p != d) if (p != d)
{ {
while (--d != p && d->score <= 0) {} while (--d != p && d->score <= 0);
tmp = *p; tmp = *p;
*p = *d; *p = *d;
@@ -114,9 +114,29 @@ inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive)
} while (p != d); } while (p != d);
// Sort just positive scored moves, remaining only when we get there // Sort positives
insertion_sort<T>(firstMove, p); insertion_sort<T>(firstMove, p);
*lastPositive = p;
d = lastMove;
p--;
// Split zero vs negatives
do {
while ((++p)->score == 0);
if (p != d)
{
while (--d != p && d->score < 0);
tmp = *p;
*p = *d;
*d = tmp;
}
} while (p != d);
// Sort negatives
insertion_sort<T>(p, lastMove);
} }
// Picks up the best move in range [curMove, lastMove), one per cycle. // Picks up the best move in range [curMove, lastMove), one per cycle.
+1 -5
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -338,10 +338,6 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
||(square_rank(to) == RANK_1 && us != WHITE)) != bool(move_is_promotion(m))) ||(square_rank(to) == RANK_1 && us != WHITE)) != bool(move_is_promotion(m)))
return false; return false;
// The promotion piece, if any, must be valid
if (move_promotion_piece(m) > QUEEN || move_promotion_piece(m) == PAWN)
return false;
// Proceed according to the square delta between the origin and // Proceed according to the square delta between the origin and
// destination squares. // destination squares.
switch (direction) switch (direction)
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+36 -44
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -70,18 +70,18 @@ namespace {
/// search captures, promotions and some checks) and about how important good /// search captures, promotions and some checks) and about how important good
/// move ordering is at the current node. /// move ordering is at the current node.
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h, MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
SearchStack* ss, Value beta) : pos(p), H(h) { const History& h, SearchStack* ss) : pos(p), H(h) {
int searchTT = ttm; int searchTT = ttm;
ttMoves[0].move = ttm; ttMoves[0].move = ttm;
badCaptureThreshold = 0; finished = false;
lastBadCapture = badCaptures; lastBadCapture = badCaptures;
pinned = p.pinned_pieces(pos.side_to_move()); pinned = p.pinned_pieces(pos.side_to_move());
if (ss && !p.is_check()) if (ss && !p.is_check())
{ {
ttMoves[1].move = (ss->mateKiller == ttm) ? MOVE_NONE : ss->mateKiller; ttMoves[1].move = (ss->mateKiller == ttm)? MOVE_NONE : ss->mateKiller;
searchTT |= ttMoves[1].move; searchTT |= ttMoves[1].move;
killers[0].move = ss->killers[0]; killers[0].move = ss->killers[0];
killers[1].move = ss->killers[1]; killers[1].move = ss->killers[1];
@@ -91,28 +91,13 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h,
if (p.is_check()) if (p.is_check())
phasePtr = EvasionsPhaseTable; phasePtr = EvasionsPhaseTable;
else if (d > Depth(0)) else if (d > Depth(0))
{
// Consider sligtly negative captures as good if at low
// depth and far from beta.
if (ss && ss->eval < beta - PawnValueMidgame && d < 3 * OnePly)
badCaptureThreshold = -PawnValueMidgame;
phasePtr = MainSearchPhaseTable; phasePtr = MainSearchPhaseTable;
}
else if (d == Depth(0)) else if (d == Depth(0))
phasePtr = QsearchWithChecksPhaseTable; phasePtr = QsearchWithChecksPhaseTable;
else else
{
phasePtr = QsearchWithoutChecksPhaseTable; phasePtr = QsearchWithoutChecksPhaseTable;
// Skip TT move if is not a capture or a promotion, this avoids phasePtr += !searchTT - 1;
// qsearch tree explosion due to a possible perpetual check or
// similar rare cases when TT table is full.
if (ttm != MOVE_NONE && !pos.move_is_capture_or_promotion(ttm))
searchTT = ttMoves[0].move = MOVE_NONE;
}
phasePtr += int(!searchTT) - 1;
go_next_phase(); go_next_phase();
} }
@@ -144,7 +129,7 @@ void MovePicker::go_next_phase() {
case PH_NONCAPTURES: case PH_NONCAPTURES:
lastMove = generate_noncaptures(pos, moves); lastMove = generate_noncaptures(pos, moves);
score_noncaptures(); score_noncaptures();
sort_moves(moves, lastMove, &lastGoodNonCapture); sort_moves(moves, lastMove);
return; return;
case PH_BAD_CAPTURES: case PH_BAD_CAPTURES:
@@ -157,7 +142,7 @@ void MovePicker::go_next_phase() {
case PH_EVASIONS: case PH_EVASIONS:
assert(pos.is_check()); assert(pos.is_check());
lastMove = generate_evasions(pos, moves); lastMove = generate_evasions(pos, moves);
score_evasions_or_checks(); score_evasions();
return; return;
case PH_QCAPTURES: case PH_QCAPTURES:
@@ -166,12 +151,12 @@ void MovePicker::go_next_phase() {
return; return;
case PH_QCHECKS: case PH_QCHECKS:
// Perhaps we should order moves move here? FIXME
lastMove = generate_non_capture_checks(pos, moves); lastMove = generate_non_capture_checks(pos, moves);
score_evasions_or_checks();
return; return;
case PH_STOP: case PH_STOP:
lastMove = curMove + 1; // Avoids another go_next_phase() call lastMove = curMove + 1; // hack to be friendly for get_next_move()
return; return;
default: default:
@@ -231,16 +216,16 @@ void MovePicker::score_noncaptures() {
piece = pos.piece_on(from); piece = pos.piece_on(from);
hs = H.move_ordering_score(piece, to); hs = H.move_ordering_score(piece, to);
// Ensure history has always highest priority // Ensure history is always preferred to pst
if (hs > 0) if (hs > 0)
hs += 10000; hs += 1000;
// Gain table based scoring // pst based scoring
cur->score = hs + 16 * H.gain(piece, to); cur->score = hs + mg_value(pos.pst_delta(piece, from, to));
} }
} }
void MovePicker::score_evasions_or_checks() { void MovePicker::score_evasions() {
// Try good captures ordered by MVV/LVA, then non-captures if // Try good captures ordered by MVV/LVA, then non-captures if
// destination square is not under attack, ordered by history // destination square is not under attack, ordered by history
// value, and at the end bad-captures and non-captures with a // value, and at the end bad-captures and non-captures with a
@@ -248,15 +233,11 @@ void MovePicker::score_evasions_or_checks() {
Move m; Move m;
int seeScore; int seeScore;
// Skip if we don't have at least two moves to order
if (lastMove < moves + 2)
return;
for (MoveStack* cur = moves; cur != lastMove; cur++) for (MoveStack* cur = moves; cur != lastMove; cur++)
{ {
m = cur->move; m = cur->move;
if ((seeScore = pos.see_sign(m)) < 0) if ((seeScore = pos.see_sign(m)) < 0)
cur->score = seeScore - HistoryMax; // Be sure are at the bottom cur->score = seeScore;
else if (pos.move_is_capture(m)) else if (pos.move_is_capture(m))
cur->score = pos.midgame_value_of_piece_on(move_to(m)) cur->score = pos.midgame_value_of_piece_on(move_to(m))
- pos.type_of_piece_on(move_from(m)) + HistoryMax; - pos.type_of_piece_on(move_from(m)) + HistoryMax;
@@ -270,8 +251,6 @@ void MovePicker::score_evasions_or_checks() {
/// are no more moves left. /// are no more moves left.
/// It picks the move with the biggest score from a list of generated moves taking /// It picks the move with the biggest score from a list of generated moves taking
/// care not to return the tt move if has already been searched previously. /// care not to return the tt move if has already been searched previously.
/// Note that this function is not thread safe so should be lock protected by
/// caller when accessed through a shared MovePicker object.
Move MovePicker::get_next_move() { Move MovePicker::get_next_move() {
@@ -298,7 +277,7 @@ Move MovePicker::get_next_move() {
{ {
// Check for a non negative SEE now // Check for a non negative SEE now
int seeValue = pos.see_sign(move); int seeValue = pos.see_sign(move);
if (seeValue >= badCaptureThreshold) if (seeValue >= 0)
return move; return move;
// Losing capture, move it to the badCaptures[] array, note // Losing capture, move it to the badCaptures[] array, note
@@ -313,19 +292,14 @@ Move MovePicker::get_next_move() {
case PH_KILLERS: case PH_KILLERS:
move = (curMove++)->move; move = (curMove++)->move;
if ( move != MOVE_NONE if ( move != MOVE_NONE
&& move_is_legal(pos, move, pinned)
&& move != ttMoves[0].move && move != ttMoves[0].move
&& move != ttMoves[1].move && move != ttMoves[1].move
&& move_is_legal(pos, move, pinned)
&& !pos.move_is_capture(move)) && !pos.move_is_capture(move))
return move; return move;
break; break;
case PH_NONCAPTURES: case PH_NONCAPTURES:
// Sort negative scored moves only when we get there
if (curMove == lastGoodNonCapture)
insertion_sort(lastGoodNonCapture, lastMove);
move = (curMove++)->move; move = (curMove++)->move;
if ( move != ttMoves[0].move if ( move != ttMoves[0].move
&& move != ttMoves[1].move && move != ttMoves[1].move
@@ -366,3 +340,21 @@ Move MovePicker::get_next_move() {
} }
} }
/// A variant of get_next_move() which takes a lock as a parameter, used to
/// prevent multiple threads from picking the same move at a split point.
Move MovePicker::get_next_move(Lock &lock) {
lock_grab(&lock);
if (finished)
{
lock_release(&lock);
return MOVE_NONE;
}
Move m = get_next_move();
if (m == MOVE_NONE)
finished = true;
lock_release(&lock);
return m;
}
+9 -6
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#include "depth.h" #include "depth.h"
#include "history.h" #include "history.h"
#include "lock.h"
#include "position.h" #include "position.h"
@@ -49,23 +50,25 @@ class MovePicker {
MovePicker& operator=(const MovePicker&); // silence a warning under MSVC MovePicker& operator=(const MovePicker&); // silence a warning under MSVC
public: public:
MovePicker(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss = NULL, Value beta = -VALUE_INFINITE); MovePicker(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss = NULL);
Move get_next_move(); Move get_next_move();
Move get_next_move(Lock& lock);
int number_of_evasions() const; int number_of_evasions() const;
private: private:
void score_captures(); void score_captures();
void score_noncaptures(); void score_noncaptures();
void score_evasions_or_checks(); void score_evasions();
void go_next_phase(); void go_next_phase();
const Position& pos; const Position& pos;
const History& H; const History& H;
Bitboard pinned;
MoveStack ttMoves[2], killers[2]; MoveStack ttMoves[2], killers[2];
int badCaptureThreshold, phase; bool finished;
int phase;
const uint8_t* phasePtr; const uint8_t* phasePtr;
MoveStack *curMove, *lastMove, *lastGoodNonCapture, *lastBadCapture; MoveStack *curMove, *lastMove, *lastBadCapture;
Bitboard pinned;
MoveStack moves[256], badCaptures[64]; MoveStack moves[256], badCaptures[64];
}; };
+93 -74
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -94,13 +94,12 @@ namespace {
}; };
// Pawn storm open file bonuses by file // Pawn storm open file bonuses by file
const int16_t QStormOpenFileBonus[8] = { 31, 31, 18, 0, 0, 0, 0, 0 }; const int16_t KStormOpenFileBonus[8] = { 31, 31, 18, 0, 0, 0, 0, 0 };
const int16_t KStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 }; const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 };
// Pawn storm lever bonuses by file // Pawn storm lever bonuses by file
const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 }; const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 };
#undef S
} }
@@ -108,10 +107,11 @@ namespace {
//// Functions //// Functions
//// ////
/// PawnInfoTable c'tor and d'tor instantiated one each thread /// Constructor
PawnInfoTable::PawnInfoTable(unsigned numOfEntries) : size(numOfEntries) { PawnInfoTable::PawnInfoTable(unsigned numOfEntries) {
size = numOfEntries;
entries = new PawnInfo[size]; entries = new PawnInfo[size];
if (!entries) if (!entries)
{ {
@@ -122,8 +122,9 @@ PawnInfoTable::PawnInfoTable(unsigned numOfEntries) : size(numOfEntries) {
} }
PawnInfoTable::~PawnInfoTable() { /// Destructor
PawnInfoTable::~PawnInfoTable() {
delete [] entries; delete [] entries;
} }
@@ -139,11 +140,11 @@ void PawnInfo::clear() {
/// PawnInfoTable::get_pawn_info() takes a position object as input, computes /// PawnInfoTable::get_pawn_info() takes a position object as input, computes
/// a PawnInfo object, and returns a pointer to it. The result is also stored /// a PawnInfo object, and returns a pointer to it. The result is also
/// in a hash table, so we don't have to recompute everything when the same /// stored in a hash table, so we don't have to recompute everything when
/// pawn structure occurs again. /// the same pawn structure occurs again.
PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const { PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) {
assert(pos.is_ok()); assert(pos.is_ok());
@@ -178,13 +179,12 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const {
template<Color Us> template<Color Us>
Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns, Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
Bitboard theirPawns, PawnInfo* pi) const { Bitboard theirPawns, PawnInfo* pi) {
Bitboard b;
Square s; Square s;
File f; File f;
Rank r; Rank r;
bool passed, isolated, doubled, chain, backward, candidate;
int bonus; int bonus;
bool passed, isolated, doubled, opposed, chain, backward, candidate;
Score value = make_score(0, 0); Score value = make_score(0, 0);
const Square* ptr = pos.piece_list_begin(Us, PAWN); const Square* ptr = pos.piece_list_begin(Us, PAWN);
@@ -205,24 +205,79 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
assert(pos.piece_on(s) == piece_of_color_and_type(Us, PAWN)); assert(pos.piece_on(s) == piece_of_color_and_type(Us, PAWN));
// Calculate kingside and queenside pawn storm scores for both colors to be // Passed, isolated or doubled pawn?
// used when evaluating middle game positions with opposite side castling. passed = Position::pawn_is_passed(theirPawns, Us, s);
bonus = (f >= FILE_F ? evaluate_pawn_storm<Us, KingSide>(s, r, f, theirPawns) : 0); isolated = Position::pawn_is_isolated(ourPawns, s);
pi->ksStormValue[Us] += KStormTable[relative_square(Us, s)] + bonus; doubled = Position::pawn_is_doubled(ourPawns, Us, s);
bonus = (f <= FILE_C ? evaluate_pawn_storm<Us, QueenSide>(s, r, f, theirPawns) : 0); // We calculate kingside and queenside pawn storm
pi->qsStormValue[Us] += QStormTable[relative_square(Us, s)] + bonus; // scores for both colors. These are used when evaluating
// middle game positions with opposite side castling.
//
// Each pawn is given a base score given by a piece square table
// (KStormTable[] or QStormTable[]). Pawns which seem to have good
// chances of creating an open file by exchanging itself against an
// enemy pawn on an adjacent file gets an additional bonus.
// Our rank plus previous one. Used for chain detection. // Kingside pawn storms
b = rank_bb(r) | rank_bb(r + (Us == WHITE ? -1 : 1)); bonus = KStormTable[relative_square(Us, s)];
if (f >= FILE_F)
{
Bitboard b = outpost_mask(Us, s) & theirPawns & (FileFBB | FileGBB | FileHBB);
while (b)
{
Square s2 = pop_1st_bit(&b);
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
{
// The enemy pawn has no pawn beside itself, which makes it
// particularly vulnerable. Big bonus, especially against a
// weakness on the rook file.
if (square_file(s2) == FILE_H)
bonus += 4*StormLeverBonus[f] - 8*square_distance(s, s2);
else
bonus += 2*StormLeverBonus[f] - 4*square_distance(s, s2);
} else
// There is at least one enemy pawn beside the enemy pawn we look
// at, which means that the pawn has somewhat better chances of
// defending itself by advancing. Smaller bonus.
bonus += StormLeverBonus[f] - 2*square_distance(s, s2);
}
}
pi->ksStormValue[Us] += bonus;
// Passed, isolated, doubled or member of a pawn // Queenside pawn storms
// chain (but not the backward one) ? bonus = QStormTable[relative_square(Us, s)];
passed = !(theirPawns & passed_pawn_mask(Us, s)); if (f <= FILE_C)
doubled = ourPawns & squares_behind(Us, s); {
opposed = theirPawns & squares_in_front_of(Us, s); Bitboard b = outpost_mask(Us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
isolated = !(ourPawns & neighboring_files_bb(f)); while (b)
chain = ourPawns & neighboring_files_bb(f) & b; {
Square s2 = pop_1st_bit(&b);
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
{
// The enemy pawn has no pawn beside itself, which makes it
// particularly vulnerable. Big bonus, especially against a
// weakness on the rook file.
if (square_file(s2) == FILE_A)
bonus += 4*StormLeverBonus[f] - 16*square_distance(s, s2);
else
bonus += 2*StormLeverBonus[f] - 8*square_distance(s, s2);
} else
// There is at least one enemy pawn beside the enemy pawn we look
// at, which means that the pawn has somewhat better chances of
// defending itself by advancing. Smaller bonus.
bonus += StormLeverBonus[f] - 4*square_distance(s, s2);
}
}
pi->qsStormValue[Us] += bonus;
// Member of a pawn chain (but not the backward one)? We could speed up
// the test a little by introducing an array of masks indexed by color
// and square for doing the test, but because everything is hashed,
// it probably won't make any noticable difference.
chain = ourPawns
& neighboring_files_bb(f)
& (rank_bb(r) | rank_bb(r - (Us == WHITE ? 1 : -1)));
// Test for backward pawn // Test for backward pawn
// //
@@ -231,7 +286,7 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
// there are friendly pawns behind on neighboring files it cannot // there are friendly pawns behind on neighboring files it cannot
// be backward either. // be backward either.
if ( (passed | isolated | chain) if ( (passed | isolated | chain)
|| (ourPawns & attack_span_mask(opposite_color(Us), s)) || (ourPawns & behind_bb(Us, r) & neighboring_files_bb(f))
|| (pos.attacks_from<PAWN>(s, Us) & theirPawns)) || (pos.attacks_from<PAWN>(s, Us) & theirPawns))
backward = false; backward = false;
else else
@@ -240,7 +295,7 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
// pawn on neighboring files. We now check whether the pawn is // pawn on neighboring files. We now check whether the pawn is
// backward by looking in the forward direction on the neighboring // backward by looking in the forward direction on the neighboring
// files, and seeing whether we meet a friendly or an enemy pawn first. // files, and seeing whether we meet a friendly or an enemy pawn first.
b = pos.attacks_from<PAWN>(s, Us); Bitboard b = pos.attacks_from<PAWN>(s, Us);
// Note that we are sure to find something because pawn is not passed // Note that we are sure to find something because pawn is not passed
// nor isolated, so loop is potentially infinite, but it isn't. // nor isolated, so loop is potentially infinite, but it isn't.
@@ -252,12 +307,12 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns; backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns;
} }
assert(passed | opposed | (attack_span_mask(Us, s) & theirPawns));
// Test for candidate passed pawn // Test for candidate passed pawn
candidate = !(opposed | passed) candidate = !passed
&& (b = attack_span_mask(opposite_color(Us), s + pawn_push(Us)) & ourPawns) != EmptyBoardBB && !(theirPawns & file_bb(f))
&& count_1s_max_15(b) >= count_1s_max_15(attack_span_mask(Us, s) & theirPawns); && ( count_1s_max_15(neighboring_files_bb(f) & (behind_bb(Us, r) | rank_bb(r)) & ourPawns)
- count_1s_max_15(neighboring_files_bb(f) & in_front_bb(Us, r) & theirPawns)
>= 0);
// In order to prevent doubled passed pawns from receiving a too big // In order to prevent doubled passed pawns from receiving a too big
// bonus, only the frontmost passed pawn on each file is considered as // bonus, only the frontmost passed pawn on each file is considered as
@@ -265,12 +320,10 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
if (passed && (ourPawns & squares_in_front_of(Us, s))) if (passed && (ourPawns & squares_in_front_of(Us, s)))
passed = false; passed = false;
// Mark the pawn as passed. Pawn will be properly scored in evaluation // Score this pawn
// because we need full attack info to evaluate passed pawns.
if (passed) if (passed)
set_bit(&(pi->passedPawns), s); set_bit(&(pi->passedPawns), s);
// Score this pawn
if (isolated) if (isolated)
{ {
value -= IsolatedPawnPenalty[f]; value -= IsolatedPawnPenalty[f];
@@ -297,47 +350,13 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
} }
/// PawnInfoTable::evaluate_pawn_storm() evaluates each pawn which seems
/// to have good chances of creating an open file by exchanging itself
/// against an enemy pawn on an adjacent file.
template<Color Us, PawnInfoTable::SideType Side>
int PawnInfoTable::evaluate_pawn_storm(Square s, Rank r, File f, Bitboard theirPawns) const {
const Bitboard StormFilesBB = (Side == KingSide ? FileFBB | FileGBB | FileHBB
: FileABB | FileBBB | FileCBB);
const int K = (Side == KingSide ? 2 : 4);
const File RookFile = (Side == KingSide ? FILE_H : FILE_A);
Bitboard b = attack_span_mask(Us, s) & theirPawns & StormFilesBB;
int bonus = 0;
while (b)
{
// Give a bonus according to the distance of the nearest enemy pawn
Square s2 = pop_1st_bit(&b);
Rank r2 = square_rank(s2);
int v = StormLeverBonus[f] - K * rank_distance(r, r2);
// If enemy pawn has no pawn beside itself is particularly vulnerable.
// Big bonus, especially against a weakness on the rook file
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
v *= (square_file(s2) == RookFile ? 4 : 2);
bonus += v;
}
return bonus;
}
/// PawnInfo::updateShelter calculates and caches king shelter. It is called /// PawnInfo::updateShelter calculates and caches king shelter. It is called
/// only when king square changes, about 20% of total get_king_shelter() calls. /// only when king square changes, about 20% of total get_king_shelter() calls.
int PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) { int PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) {
Bitboard pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq);
unsigned shelter = 0; unsigned shelter = 0;
Bitboard pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq);
unsigned r = ksq & (7 << 3); unsigned r = ksq & (7 << 3);
for (int i = 1, k = (c ? -8 : 8); i < 4; i++) for (int i = 1, k = (c ? -8 : 8); i < 4; i++)
{ {
r += k; r += k;
+4 -9
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -64,10 +64,10 @@ private:
Key key; Key key;
Bitboard passedPawns; Bitboard passedPawns;
Bitboard pawnAttacks[2]; Bitboard pawnAttacks[2];
Square kingSquares[2];
Score value; Score value;
int16_t ksStormValue[2], qsStormValue[2]; int16_t ksStormValue[2], qsStormValue[2];
uint8_t halfOpenFiles[2]; uint8_t halfOpenFiles[2];
Square kingSquares[2];
uint8_t kingShelters[2]; uint8_t kingShelters[2];
}; };
@@ -78,19 +78,14 @@ private:
class PawnInfoTable { class PawnInfoTable {
enum SideType { KingSide, QueenSide };
public: public:
PawnInfoTable(unsigned numOfEntries); PawnInfoTable(unsigned numOfEntries);
~PawnInfoTable(); ~PawnInfoTable();
PawnInfo* get_pawn_info(const Position& pos) const; PawnInfo* get_pawn_info(const Position& pos);
private: private:
template<Color Us> template<Color Us>
Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi) const; Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi);
template<Color Us, SideType Side>
int evaluate_pawn_storm(Square s, Rank r, File f, Bitboard theirPawns) const;
unsigned size; unsigned size;
PawnInfo* entries; PawnInfo* entries;
+2 -2
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -38,7 +38,7 @@ static const string PieceChars(" pnbrqk PNBRQK");
char piece_type_to_char(PieceType pt, bool upcase) { char piece_type_to_char(PieceType pt, bool upcase) {
return PieceChars[pt + int(upcase) * 7]; return PieceChars[pt + upcase * 7];
} }
PieceType piece_type_from_char(char c) { PieceType piece_type_from_char(char c) {
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+122 -113
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -44,9 +44,12 @@ using std::string;
//// Variables //// Variables
//// ////
int Position::castleRightsMask[64];
Key Position::zobrist[2][8][64]; Key Position::zobrist[2][8][64];
Key Position::zobEp[64]; Key Position::zobEp[64];
Key Position::zobCastle[16]; Key Position::zobCastle[16];
Key Position::zobMaterial[2][8][16];
Key Position::zobSideToMove; Key Position::zobSideToMove;
Key Position::zobExclusion; Key Position::zobExclusion;
@@ -73,36 +76,12 @@ CheckInfo::CheckInfo(const Position& pos) {
checkSq[KING] = EmptyBoardBB; checkSq[KING] = EmptyBoardBB;
} }
Position::Position(const Position& pos) {
/// Position c'tors. Here we always create a copy of the original position copy(pos);
/// or the FEN string, we want the new born Position object do not depend
/// on any external data so we detach state pointer from the source one.
Position::Position(int th) : threadID(th) {}
Position::Position(const Position& pos, int th) {
memcpy(this, &pos, sizeof(Position));
detach(); // Always detach() in copy c'tor to avoid surprises
threadID = th;
} }
Position::Position(const string& fen, int th) { Position::Position(const string& fen) {
from_fen(fen); from_fen(fen);
threadID = th;
}
/// Position::detach() copies the content of the current state and castling
/// masks inside the position itself. This is needed when the st pointee could
/// become stale, as example because the caller is about to going out of scope.
void Position::detach() {
startState = *st;
st = &startState;
st->previous = NULL; // as a safe guard
} }
@@ -340,9 +319,8 @@ void Position::print(Move m) const {
std::cout << std::endl; std::cout << std::endl;
if (m != MOVE_NONE) if (m != MOVE_NONE)
{ {
Position p(*this, thread());
string col = (color_of_piece_on(move_from(m)) == BLACK ? ".." : ""); string col = (color_of_piece_on(move_from(m)) == BLACK ? ".." : "");
std::cout << "Move is: " << col << move_to_san(p, m) << std::endl; std::cout << "Move is: " << col << move_to_san(*this, m) << std::endl;
} }
for (Rank rank = RANK_8; rank >= RANK_1; rank--) for (Rank rank = RANK_8; rank >= RANK_1; rank--)
{ {
@@ -367,11 +345,20 @@ void Position::print(Move m) const {
} }
/// Position::copy() creates a copy of the input position.
void Position::copy(const Position& pos) {
memcpy(this, &pos, sizeof(Position));
saveState(); // detach and copy state info
}
/// Position:hidden_checkers<>() returns a bitboard of all pinned (against the /// Position:hidden_checkers<>() returns a bitboard of all pinned (against the
/// king) pieces for the given color and for the given pinner type. Or, when /// king) pieces for the given color and for the given pinner type. Or, when
/// template parameter FindPinned is false, the pieces of the given color /// template parameter FindPinned is false, the pieces of the given color
/// candidate for a discovery check against the enemy king. /// candidate for a discovery check against the enemy king.
/// Bitboard checkersBB must be already updated when looking for pinners. /// Note that checkersBB bitboard must be already updated.
template<bool FindPinned> template<bool FindPinned>
Bitboard Position::hidden_checkers(Color c) const { Bitboard Position::hidden_checkers(Color c) const {
@@ -405,8 +392,7 @@ Bitboard Position::hidden_checkers(Color c) const {
/// Position:pinned_pieces() returns a bitboard of all pinned (against the /// Position:pinned_pieces() returns a bitboard of all pinned (against the
/// king) pieces for the given color. Note that checkersBB bitboard must /// king) pieces for the given color.
/// be already updated.
Bitboard Position::pinned_pieces(Color c) const { Bitboard Position::pinned_pieces(Color c) const {
@@ -416,8 +402,7 @@ Bitboard Position::pinned_pieces(Color c) const {
/// Position:discovered_check_candidates() returns a bitboard containing all /// Position:discovered_check_candidates() returns a bitboard containing all
/// pieces for the given side which are candidates for giving a discovered /// pieces for the given side which are candidates for giving a discovered
/// check. Contrary to pinned_pieces() here there is no need of checkersBB /// check.
/// to be already updated.
Bitboard Position::discovered_check_candidates(Color c) const { Bitboard Position::discovered_check_candidates(Color c) const {
@@ -696,14 +681,14 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
assert(is_ok()); assert(is_ok());
assert(move_is_ok(m)); assert(move_is_ok(m));
Key key = st->key; Bitboard key = st->key;
// Copy some fields of old state to our new StateInfo object except the // Copy some fields of old state to our new StateInfo object except the
// ones which are recalculated from scratch anyway, then switch our state // ones which are recalculated from scratch anyway, then switch our state
// pointer to point to the new, ready to be updated, state. // pointer to point to the new, ready to be updated, state.
struct ReducedStateInfo { struct ReducedStateInfo {
Key pawnKey, materialKey; Key pawnKey, materialKey;
int castleRights, rule50, gamePly, pliesFromNull; int castleRights, rule50, pliesFromNull;
Square epSquare; Square epSquare;
Score value; Score value;
Value npMaterial[2]; Value npMaterial[2];
@@ -715,7 +700,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
// Save the current key to the history[] array, in order to be able to // Save the current key to the history[] array, in order to be able to
// detect repetition draws. // detect repetition draws.
history[st->gamePly++] = key; history[gamePly] = key;
gamePly++;
// Update side to move // Update side to move
key ^= zobSideToMove; key ^= zobSideToMove;
@@ -772,7 +758,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
} }
// Prefetch TT access as soon as we know key is updated // Prefetch TT access as soon as we know key is updated
prefetch((char*)TT.first_entry(key)); TT.prefetch(key);
// Move the piece // Move the piece
Bitboard move_bb = make_move_bb(from, to); Bitboard move_bb = make_move_bb(from, to);
@@ -807,46 +793,6 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
key ^= zobEp[st->epSquare]; key ^= zobEp[st->epSquare];
} }
} }
if (pm) // promotion ?
{
PieceType promotion = move_promotion_piece(m);
assert(promotion >= KNIGHT && promotion <= QUEEN);
// Insert promoted piece instead of pawn
clear_bit(&(byTypeBB[PAWN]), to);
set_bit(&(byTypeBB[promotion]), to);
board[to] = piece_of_color_and_type(us, promotion);
// Update piece counts
pieceCount[us][promotion]++;
pieceCount[us][PAWN]--;
// Update material key
st->materialKey ^= zobrist[us][PAWN][pieceCount[us][PAWN]];
st->materialKey ^= zobrist[us][promotion][pieceCount[us][promotion]-1];
// Update piece lists, move the last pawn at index[to] position
// and shrink the list. Add a new promotion piece to the list.
Square lastPawnSquare = pieceList[us][PAWN][pieceCount[us][PAWN]];
index[lastPawnSquare] = index[to];
pieceList[us][PAWN][index[lastPawnSquare]] = lastPawnSquare;
pieceList[us][PAWN][pieceCount[us][PAWN]] = SQ_NONE;
index[to] = pieceCount[us][promotion] - 1;
pieceList[us][promotion][index[to]] = to;
// Partially revert hash keys update
key ^= zobrist[us][PAWN][to] ^ zobrist[us][promotion][to];
st->pawnKey ^= zobrist[us][PAWN][to];
// Partially revert and update incremental scores
st->value -= pst(us, PAWN, to);
st->value += pst(us, promotion, to);
// Update material
st->npMaterial[us] += piece_value_midgame(promotion);
}
} }
// Update incremental scores // Update incremental scores
@@ -855,6 +801,46 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
// Set capture piece // Set capture piece
st->capture = capture; st->capture = capture;
if (pm) // promotion ?
{
PieceType promotion = move_promotion_piece(m);
assert(promotion >= KNIGHT && promotion <= QUEEN);
// Insert promoted piece instead of pawn
clear_bit(&(byTypeBB[PAWN]), to);
set_bit(&(byTypeBB[promotion]), to);
board[to] = piece_of_color_and_type(us, promotion);
// Update material key
st->materialKey ^= zobMaterial[us][PAWN][pieceCount[us][PAWN]];
st->materialKey ^= zobMaterial[us][promotion][pieceCount[us][promotion]+1];
// Update piece counts
pieceCount[us][PAWN]--;
pieceCount[us][promotion]++;
// Update piece lists, move the last pawn at index[to] position
// and shrink the list. Add a new promotion piece to the list.
Square lastPawnSquare = pieceList[us][PAWN][pieceCount[us][PAWN]];
index[lastPawnSquare] = index[to];
pieceList[us][PAWN][index[lastPawnSquare]] = lastPawnSquare;
pieceList[us][PAWN][pieceCount[us][PAWN]] = SQ_NONE;
index[to] = pieceCount[us][promotion] - 1;
pieceList[us][promotion][index[to]] = to;
// Partially revert hash keys update
key ^= zobrist[us][PAWN][to] ^ zobrist[us][promotion][to];
st->pawnKey ^= zobrist[us][PAWN][to];
// Partially revert and update incremental scores
st->value -= pst(us, PAWN, to);
st->value += pst(us, promotion, to);
// Update material
st->npMaterial[us] += piece_value_midgame(promotion);
}
// Update the key with the final value // Update the key with the final value
st->key = key; st->key = key;
@@ -894,31 +880,23 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
/// Position::do_capture_move() is a private method used to update captured /// Position::do_capture_move() is a private method used to update captured
/// piece info. It is called from the main Position::do_move function. /// piece info. It is called from the main Position::do_move function.
void Position::do_capture_move(Key& key, PieceType capture, Color them, Square to, bool ep) { void Position::do_capture_move(Bitboard& key, PieceType capture, Color them, Square to, bool ep) {
assert(capture != KING); assert(capture != KING);
Square capsq = to; Square capsq = to;
// If the captured piece was a pawn, update pawn hash key, if (ep) // en passant ?
// otherwise update non-pawn material.
if (capture == PAWN)
{ {
if (ep) // en passant ? capsq = (them == BLACK)? (to - DELTA_N) : (to - DELTA_S);
{
capsq = (them == BLACK)? (to - DELTA_N) : (to - DELTA_S);
assert(to == st->epSquare); assert(to == st->epSquare);
assert(relative_rank(opposite_color(them), to) == RANK_6); assert(relative_rank(opposite_color(them), to) == RANK_6);
assert(piece_on(to) == EMPTY); assert(piece_on(to) == EMPTY);
assert(piece_on(capsq) == piece_of_color_and_type(them, PAWN)); assert(piece_on(capsq) == piece_of_color_and_type(them, PAWN));
board[capsq] = EMPTY; board[capsq] = EMPTY;
}
st->pawnKey ^= zobrist[them][PAWN][capsq];
} }
else
st->npMaterial[them] -= piece_value_midgame(capture);
// Remove captured piece // Remove captured piece
clear_bit(&(byColorBB[them]), capsq); clear_bit(&(byColorBB[them]), capsq);
@@ -931,11 +909,18 @@ void Position::do_capture_move(Key& key, PieceType capture, Color them, Square t
// Update incremental scores // Update incremental scores
st->value -= pst(them, capture, capsq); st->value -= pst(them, capture, capsq);
// Update piece count // If the captured piece was a pawn, update pawn hash key,
pieceCount[them][capture]--; // otherwise update non-pawn material.
if (capture == PAWN)
st->pawnKey ^= zobrist[them][PAWN][capsq];
else
st->npMaterial[them] -= piece_value_midgame(capture);
// Update material hash key // Update material hash key
st->materialKey ^= zobrist[them][capture][pieceCount[them][capture]]; st->materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]];
// Update piece count
pieceCount[them][capture]--;
// Update piece list, move the last piece at index[capsq] position // Update piece list, move the last piece at index[capsq] position
// //
@@ -1060,6 +1045,7 @@ void Position::undo_move(Move m) {
assert(is_ok()); assert(is_ok());
assert(move_is_ok(m)); assert(move_is_ok(m));
gamePly--;
sideToMove = opposite_color(sideToMove); sideToMove = opposite_color(sideToMove);
if (move_is_castle(m)) if (move_is_castle(m))
@@ -1109,6 +1095,7 @@ void Position::undo_move(Move m) {
pieceList[us][PAWN][index[to]] = to; pieceList[us][PAWN][index[to]] = to;
} }
// Put the piece back at the source square // Put the piece back at the source square
Bitboard move_bb = make_move_bb(to, from); Bitboard move_bb = make_move_bb(to, from);
do_move_bb(&(byColorBB[us]), move_bb); do_move_bb(&(byColorBB[us]), move_bb);
@@ -1243,20 +1230,21 @@ void Position::do_null_move(StateInfo& backupSt) {
// Save the current key to the history[] array, in order to be able to // Save the current key to the history[] array, in order to be able to
// detect repetition draws. // detect repetition draws.
history[st->gamePly++] = st->key; history[gamePly] = st->key;
// Update the necessary information // Update the necessary information
if (st->epSquare != SQ_NONE) if (st->epSquare != SQ_NONE)
st->key ^= zobEp[st->epSquare]; st->key ^= zobEp[st->epSquare];
st->key ^= zobSideToMove; st->key ^= zobSideToMove;
prefetch((char*)TT.first_entry(st->key)); TT.prefetch(st->key);
sideToMove = opposite_color(sideToMove); sideToMove = opposite_color(sideToMove);
st->epSquare = SQ_NONE; st->epSquare = SQ_NONE;
st->rule50++; st->rule50++;
st->pliesFromNull = 0; st->pliesFromNull = 0;
st->value += (sideToMove == WHITE) ? TempoValue : -TempoValue; st->value += (sideToMove == WHITE) ? TempoValue : -TempoValue;
gamePly++;
} }
@@ -1278,7 +1266,7 @@ void Position::undo_null_move() {
// Update the necessary information // Update the necessary information
sideToMove = opposite_color(sideToMove); sideToMove = opposite_color(sideToMove);
st->rule50--; st->rule50--;
st->gamePly--; gamePly--;
} }
@@ -1307,11 +1295,11 @@ int Position::see_sign(Move m) const {
Square from = move_from(m); Square from = move_from(m);
Square to = move_to(m); Square to = move_to(m);
// Early return if SEE cannot be negative because captured piece value // Early return if SEE cannot be negative because capturing piece value
// is not less then capturing one. Note that king moves always return // is not bigger then captured one.
// here because king midgame value is set to 0. if ( midgame_value_of_piece_on(from) <= midgame_value_of_piece_on(to)
if (midgame_value_of_piece_on(to) >= midgame_value_of_piece_on(from)) && type_of_piece_on(from) != KING)
return 1; return 1;
return see(from, to); return see(from, to);
} }
@@ -1453,6 +1441,19 @@ int Position::see(Square from, Square to) const {
} }
/// Position::saveState() copies the content of the current state
/// inside startState and makes st point to it. This is needed
/// when the st pointee could become stale, as example because
/// the caller is about to going out of scope.
void Position::saveState() {
startState = *st;
st = &startState;
st->previous = NULL; // as a safe guard
}
/// Position::clear() erases the position object to a pristine state, with an /// Position::clear() erases the position object to a pristine state, with an
/// empty board, white to move, and no castling rights. /// empty board, white to move, and no castling rights.
@@ -1475,6 +1476,7 @@ void Position::clear() {
pieceList[0][i][j] = pieceList[1][i][j] = SQ_NONE; pieceList[0][i][j] = pieceList[1][i][j] = SQ_NONE;
sideToMove = WHITE; sideToMove = WHITE;
gamePly = 0;
initialKFile = FILE_E; initialKFile = FILE_E;
initialKRFile = FILE_H; initialKRFile = FILE_H;
initialQRFile = FILE_A; initialQRFile = FILE_A;
@@ -1489,7 +1491,7 @@ void Position::clear() {
void Position::reset_game_ply() { void Position::reset_game_ply() {
st->gamePly = 0; gamePly = 0;
} }
@@ -1593,8 +1595,8 @@ Key Position::compute_material_key() const {
for (PieceType pt = PAWN; pt <= QUEEN; pt++) for (PieceType pt = PAWN; pt <= QUEEN; pt++)
{ {
int count = piece_count(c, pt); int count = piece_count(c, pt);
for (int i = 0; i < count; i++) for (int i = 0; i <= count; i++)
result ^= zobrist[c][pt][i]; result ^= zobMaterial[c][pt][i];
} }
return result; return result;
} }
@@ -1653,7 +1655,6 @@ Value Position::compute_non_pawn_material(Color c) const {
/// Position::is_draw() tests whether the position is drawn by material, /// Position::is_draw() tests whether the position is drawn by material,
/// repetition, or the 50 moves rule. It does not detect stalemates, this /// repetition, or the 50 moves rule. It does not detect stalemates, this
/// must be done by the search. /// must be done by the search.
// FIXME: Currently we are not handling 50 move rule correctly when in check
bool Position::is_draw() const { bool Position::is_draw() const {
@@ -1667,8 +1668,8 @@ bool Position::is_draw() const {
return true; return true;
// Draw by repetition? // Draw by repetition?
for (int i = 4, e = Min(Min(st->gamePly, st->rule50), st->pliesFromNull); i <= e; i += 2) for (int i = 2; i < Min(Min(gamePly, st->rule50), st->pliesFromNull); i += 2)
if (history[st->gamePly - i] == st->key) if (history[gamePly - i] == st->key)
return true; return true;
return false; return false;
@@ -1747,6 +1748,15 @@ void Position::init_zobrist() {
zobCastle[i] = genrand_int64(); zobCastle[i] = genrand_int64();
zobSideToMove = genrand_int64(); zobSideToMove = genrand_int64();
for (int i = 0; i < 2; i++)
for (int j = 0; j < 8; j++)
for (int k = 0; k < 16; k++)
zobMaterial[i][j][k] = (k > 0)? Key(genrand_int64()) : Key(0LL);
for (int i = 0; i < 16; i++)
zobMaterial[0][KING][i] = zobMaterial[1][KING][i] = Key(0ULL);
zobExclusion = genrand_int64(); zobExclusion = genrand_int64();
} }
@@ -1783,7 +1793,6 @@ void Position::flipped_copy(const Position& pos) {
assert(pos.is_ok()); assert(pos.is_ok());
clear(); clear();
threadID = pos.thread();
// Board // Board
for (Square s = SQ_A1; s <= SQ_H8; s++) for (Square s = SQ_A1; s <= SQ_H8; s++)
+32 -32
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -70,9 +70,9 @@ struct CheckInfo {
CheckInfo(const Position&); CheckInfo(const Position&);
Square ksq;
Bitboard dcCandidates; Bitboard dcCandidates;
Bitboard checkSq[8]; Bitboard checkSq[8];
Square ksq;
}; };
/// Castle rights, encoded as bit fields /// Castle rights, encoded as bit fields
@@ -100,13 +100,13 @@ enum Phase {
struct StateInfo { struct StateInfo {
Key pawnKey, materialKey; Key pawnKey, materialKey;
int castleRights, rule50, gamePly, pliesFromNull; int castleRights, rule50, pliesFromNull;
Square epSquare; Square epSquare;
Score value; Score value;
Value npMaterial[2]; Value npMaterial[2];
PieceType capture;
Key key; Key key;
PieceType capture;
Bitboard checkersBB; Bitboard checkersBB;
StateInfo* previous; StateInfo* previous;
}; };
@@ -139,9 +139,6 @@ class Position {
friend class MaterialInfo; friend class MaterialInfo;
friend class EndgameFunctions; friend class EndgameFunctions;
Position(); // No default or copy c'tor allowed
Position(const Position& pos);
public: public:
enum GamePhase { enum GamePhase {
MidGame, MidGame,
@@ -149,9 +146,9 @@ public:
}; };
// Constructors // Constructors
explicit Position(int threadID); Position() {}
Position(const Position& pos, int threadID); Position(const Position& pos);
Position(const std::string& fen, int threadID); Position(const std::string& fen);
// Text input/output // Text input/output
void from_fen(const std::string& fen); void from_fen(const std::string& fen);
@@ -159,6 +156,7 @@ public:
void print(Move m = MOVE_NONE) const; void print(Move m = MOVE_NONE) const;
// Copying // Copying
void copy(const Position& pos);
void flipped_copy(const Position& pos); void flipped_copy(const Position& pos);
// The piece on a given square // The piece on a given square
@@ -226,17 +224,17 @@ public:
bool move_is_passed_pawn_push(Move m) const; bool move_is_passed_pawn_push(Move m) const;
bool move_attacks_square(Move m, Square s) const; bool move_attacks_square(Move m, Square s) const;
// Piece captured with previous moves
PieceType captured_piece() const;
// Information about pawns // Information about pawns
bool pawn_is_passed(Color c, Square s) const; bool pawn_is_passed(Color c, Square s) const;
static bool pawn_is_passed(Bitboard theirPawns, Color c, Square s);
static bool pawn_is_isolated(Bitboard ourPawns, Square s);
static bool pawn_is_doubled(Bitboard ourPawns, Color c, Square s);
// Weak squares // Weak squares
bool square_is_weak(Square s, Color c) const; bool square_is_weak(Square s, Color c) const;
// Doing and undoing moves // Doing and undoing moves
void detach(); void saveState();
void do_move(Move m, StateInfo& st); void do_move(Move m, StateInfo& st);
void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck); void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck);
void undo_move(Move m); void undo_move(Move m);
@@ -274,9 +272,6 @@ public:
bool opposite_colored_bishops() const; bool opposite_colored_bishops() const;
bool has_pawn_on_7th(Color c) const; bool has_pawn_on_7th(Color c) const;
// Current thread ID searching on the position
int thread() const;
// Reset the gamePly variable to 0 // Reset the gamePly variable to 0
void reset_game_ply(); void reset_game_ply();
@@ -296,7 +291,7 @@ private:
void allow_ooo(Color c); void allow_ooo(Color c);
// Helper functions for doing and undoing moves // Helper functions for doing and undoing moves
void do_capture_move(Key& key, PieceType capture, Color them, Square to, bool ep); void do_capture_move(Bitboard& key, PieceType capture, Color them, Square to, bool ep);
void do_castle_move(Move m); void do_castle_move(Move m);
void undo_castle_move(Move m); void undo_castle_move(Move m);
void find_checkers(); void find_checkers();
@@ -329,17 +324,18 @@ private:
// Other info // Other info
Color sideToMove; Color sideToMove;
int gamePly;
Key history[MaxGameLength]; Key history[MaxGameLength];
int castleRightsMask[64];
StateInfo startState;
File initialKFile, initialKRFile, initialQRFile; File initialKFile, initialKRFile, initialQRFile;
int threadID; StateInfo startState;
StateInfo* st; StateInfo* st;
// Static variables // Static variables
static int castleRightsMask[64];
static Key zobrist[2][8][64]; static Key zobrist[2][8][64];
static Key zobEp[64]; static Key zobEp[64];
static Key zobCastle[16]; static Key zobCastle[16];
static Key zobMaterial[2][8][16];
static Key zobSideToMove; static Key zobSideToMove;
static Score PieceSquareTable[16][64]; static Score PieceSquareTable[16][64];
static Key zobExclusion; static Key zobExclusion;
@@ -414,8 +410,8 @@ inline int Position::piece_count(Color c, PieceType pt) const {
return pieceCount[c][pt]; return pieceCount[c][pt];
} }
inline Square Position::piece_list(Color c, PieceType pt, int idx) const { inline Square Position::piece_list(Color c, PieceType pt, int index) const {
return pieceList[c][pt][idx]; return pieceList[c][pt][index];
} }
inline const Square* Position::piece_list_begin(Color c, PieceType pt) const { inline const Square* Position::piece_list_begin(Color c, PieceType pt) const {
@@ -487,8 +483,20 @@ inline bool Position::pawn_is_passed(Color c, Square s) const {
return !(pieces(PAWN, opposite_color(c)) & passed_pawn_mask(c, s)); return !(pieces(PAWN, opposite_color(c)) & passed_pawn_mask(c, s));
} }
inline bool Position::pawn_is_passed(Bitboard theirPawns, Color c, Square s) {
return !(theirPawns & passed_pawn_mask(c, s));
}
inline bool Position::pawn_is_isolated(Bitboard ourPawns, Square s) {
return !(ourPawns & neighboring_files_bb(s));
}
inline bool Position::pawn_is_doubled(Bitboard ourPawns, Color c, Square s) {
return ourPawns & squares_behind(c, s);
}
inline bool Position::square_is_weak(Square s, Color c) const { inline bool Position::square_is_weak(Square s, Color c) const {
return !(pieces(PAWN, opposite_color(c)) & attack_span_mask(c, s)); return !(pieces(PAWN, c) & outpost_mask(opposite_color(c), s));
} }
inline Key Position::get_key() const { inline Key Position::get_key() const {
@@ -559,12 +567,4 @@ inline bool Position::move_is_capture_or_promotion(Move m) const {
return (m & (0x1F << 12)) ? !move_is_castle(m) : !square_is_empty(move_to(m)); return (m & (0x1F << 12)) ? !move_is_castle(m) : !square_is_empty(move_to(m));
} }
inline PieceType Position::captured_piece() const {
return st->capture;
}
inline int Position::thread() const {
return threadID;
}
#endif // !defined(POSITION_H_INCLUDED) #endif // !defined(POSITION_H_INCLUDED)
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+7 -7
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -63,7 +63,7 @@ namespace {
/// that the move is a legal move from the position. The return value is /// that the move is a legal move from the position. The return value is
/// a string containing the move in short algebraic notation. /// a string containing the move in short algebraic notation.
const string move_to_san(Position& pos, Move m) { const string move_to_san(const Position& pos, Move m) {
assert(pos.is_ok()); assert(pos.is_ok());
assert(move_is_ok(m)); assert(move_is_ok(m));
@@ -123,10 +123,10 @@ const string move_to_san(Position& pos, Move m) {
// Position::move_is_check doesn't detect all checks (not castling moves, // Position::move_is_check doesn't detect all checks (not castling moves,
// promotions and en passant captures). // promotions and en passant captures).
StateInfo st; StateInfo st;
pos.do_move(m, st); Position p(pos);
if (pos.is_check()) p.do_move(m, st);
san += pos.is_mate() ? "#" : "+"; if (p.is_check())
pos.undo_move(m); san += p.is_mate()? "#" : "+";
return san; return san;
} }
@@ -299,7 +299,7 @@ const string line_to_san(const Position& pos, Move line[], int startColumn, bool
string moveStr; string moveStr;
size_t length = 0; size_t length = 0;
size_t maxLength = 80 - startColumn; size_t maxLength = 80 - startColumn;
Position p(pos, pos.thread()); Position p(pos);
for (int i = 0; line[i] != MOVE_NONE; i++) for (int i = 0; line[i] != MOVE_NONE; i++)
{ {
+2 -2
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -36,7 +36,7 @@
//// Prototypes //// Prototypes
//// ////
extern const std::string move_to_san(Position& pos, Move m); extern const std::string move_to_san(const Position& pos, Move m);
extern Move move_from_san(const Position& pos, const std::string& str); extern Move move_from_san(const Position& pos, const std::string& str);
extern const std::string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines); extern const std::string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines);
extern const std::string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes, Value score, ValueType type, Move pv[]); extern const std::string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes, Value score, ValueType type, Move pv[]);
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+2023 -1796
View File
File diff suppressed because it is too large Load Diff
+3 -9
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -27,7 +27,6 @@
#include "depth.h" #include "depth.h"
#include "move.h" #include "move.h"
#include "value.h"
//// ////
@@ -47,20 +46,16 @@ const int KILLER_MAX = 2;
/// from nodes shallower and deeper in the tree during the search. Each /// from nodes shallower and deeper in the tree during the search. Each
/// search thread has its own array of SearchStack objects, indexed by the /// search thread has its own array of SearchStack objects, indexed by the
/// current ply. /// current ply.
struct EvalInfo;
struct SearchStack { struct SearchStack {
Move pv[PLY_MAX_PLUS_2]; Move pv[PLY_MAX_PLUS_2];
Move currentMove; Move currentMove;
Move mateKiller; Move mateKiller;
Move threatMove; Move threatMove;
Move excludedMove;
Move killers[KILLER_MAX]; Move killers[KILLER_MAX];
Depth reduction; Depth reduction;
Value eval;
bool skipNullMove;
void init(); void init(int ply);
void initKillers(); void initKillers();
}; };
@@ -69,9 +64,8 @@ struct SearchStack {
//// Prototypes //// Prototypes
//// ////
extern void init_search();
extern void init_threads(); extern void init_threads();
extern void exit_threads(); extern void stop_threads();
extern bool think(const Position &pos, bool infinite, bool ponder, int side_to_move, extern bool think(const Position &pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth, int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]); int maxNodes, int maxTime, Move searchMoves[]);
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+22 -37
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -26,8 +26,6 @@
//// Includes //// Includes
//// ////
#include <cstring>
#include "lock.h" #include "lock.h"
#include "movepick.h" #include "movepick.h"
#include "position.h" #include "position.h"
@@ -38,8 +36,7 @@
//// Constants and variables //// Constants and variables
//// ////
const int MAX_THREADS = 8; const int THREAD_MAX = 8;
const int ACTIVE_SPLIT_POINTS_MAX = 8;
//// ////
@@ -47,47 +44,35 @@ const int ACTIVE_SPLIT_POINTS_MAX = 8;
//// ////
struct SplitPoint { struct SplitPoint {
SplitPoint *parent;
// Const data after splitPoint has been setup Position pos;
SplitPoint* parent; SearchStack sstack[THREAD_MAX][PLY_MAX_PLUS_2];
const Position* pos; SearchStack *parentSstack;
Depth depth;
bool pvNode, mateThreat;
Value beta;
int ply; int ply;
SearchStack sstack[MAX_THREADS][PLY_MAX_PLUS_2]; Depth depth;
volatile Value alpha, beta, bestValue, futilityValue;
// Const pointers to shared data Value approximateEval;
MovePicker* mp; bool pvNode;
SearchStack* parentSstack; int master, slaves[THREAD_MAX];
// Shared data
Lock lock; Lock lock;
volatile Value alpha; MovePicker *mp;
volatile Value bestValue; volatile int moves;
volatile int moveCount; volatile int cpus;
volatile bool stopRequest; bool finished;
volatile int slaves[MAX_THREADS];
}; };
// ThreadState type is used to represent thread's current state
enum ThreadState
{
THREAD_SEARCHING, // thread is performing work
THREAD_AVAILABLE, // thread is polling for work
THREAD_SLEEPING, // we are not thinking, so thread is sleeping
THREAD_BOOKED, // other thread (master) has booked us as a slave
THREAD_WORKISWAITING, // master has ordered us to start
THREAD_TERMINATED // we are quitting and thread is terminated
};
struct Thread { struct Thread {
SplitPoint* volatile splitPoint; SplitPoint *splitPoint;
volatile int activeSplitPoints; volatile int activeSplitPoints;
uint64_t nodes; uint64_t nodes;
uint64_t betaCutOffs[2]; uint64_t betaCutOffs[2];
volatile ThreadState state; bool failHighPly1;
volatile bool stop;
volatile bool running;
volatile bool idle;
volatile bool workIsWaiting;
volatile bool printCurrentLine;
unsigned char pad[64]; // set some distance among local data for each thread unsigned char pad[64]; // set some distance among local data for each thread
}; };
+45 -8
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <xmmintrin.h>
#include "movegen.h" #include "movegen.h"
#include "tt.h" #include "tt.h"
@@ -54,6 +55,8 @@ TranspositionTable::~TranspositionTable() {
void TranspositionTable::set_size(size_t mbSize) { void TranspositionTable::set_size(size_t mbSize) {
assert(mbSize >= 4 && mbSize <= 8192);
size_t newSize = 1024; size_t newSize = 1024;
// We store a cluster of ClusterSize number of TTEntry for each position // We store a cluster of ClusterSize number of TTEntry for each position
@@ -88,6 +91,16 @@ void TranspositionTable::clear() {
} }
/// TranspositionTable::first_entry returns a pointer to the first
/// entry of a cluster given a position. The low 32 bits of the key
/// are used to get the index in the table.
inline TTEntry* TranspositionTable::first_entry(const Key posKey) const {
return entries[uint32_t(posKey) & (size - 1)].data;
}
/// TranspositionTable::store writes a new entry containing a position, /// TranspositionTable::store writes a new entry containing a position,
/// a value, a value type, a search depth, and a best move to the /// a value, a value type, a search depth, and a best move to the
/// transposition table. Transposition table is organized in clusters of /// transposition table. Transposition table is organized in clusters of
@@ -98,7 +111,7 @@ void TranspositionTable::clear() {
/// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL /// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL
/// never replaces another entry for the same position. /// never replaces another entry for the same position.
void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m, Value statV, Value kingD) { void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m) {
TTEntry *tte, *replace; TTEntry *tte, *replace;
uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key
@@ -108,11 +121,14 @@ void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d,
{ {
if (!tte->key() || tte->key() == posKey32) // empty or overwrite old if (!tte->key() || tte->key() == posKey32) // empty or overwrite old
{ {
// Preserve any exsisting ttMove // Do not overwrite when new type is VALUE_TYPE_EV_LO
if (tte->key() && t == VALUE_TYPE_EV_LO)
return;
if (m == MOVE_NONE) if (m == MOVE_NONE)
m = tte->move(); m = tte->move();
tte->save(posKey32, v, t, d, m, generation, statV, kingD); *tte = TTEntry(posKey32, v, t, d, m, generation);
return; return;
} }
else if (i == 0) // replace would be a no-op in this common case else if (i == 0) // replace would be a no-op in this common case
@@ -125,7 +141,7 @@ void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d,
if (c1 + c2 + c3 > 0) if (c1 + c2 + c3 > 0)
replace = tte; replace = tte;
} }
replace->save(posKey32, v, t, d, m, generation, statV, kingD); *replace = TTEntry(posKey32, v, t, d, m, generation);
writes++; writes++;
} }
@@ -147,6 +163,27 @@ TTEntry* TranspositionTable::retrieve(const Key posKey) const {
} }
/// TranspositionTable::prefetch looks up the current position in the
/// transposition table and load it in L1/L2 cache. This is a non
/// blocking function and do not stalls the CPU waiting for data
/// to be loaded from RAM, that can be very slow. When we will
/// subsequently call retrieve() the TT data will be already
/// quickly accessible in L1/L2 CPU cache.
void TranspositionTable::prefetch(const Key posKey) const {
#if defined(__INTEL_COMPILER) || defined(__ICL)
// This hack prevents prefetches to be optimized away by the
// Intel compiler. Both MSVC and gcc seems not affected.
__asm__ ("");
#endif
char const* addr = (char*)first_entry(posKey);
_mm_prefetch(addr, _MM_HINT_T2);
_mm_prefetch(addr+64, _MM_HINT_T2); // 64 bytes ahead
}
/// TranspositionTable::new_search() is called at the beginning of every new /// TranspositionTable::new_search() is called at the beginning of every new
/// search. It increments the "generation" variable, which is used to /// search. It increments the "generation" variable, which is used to
/// distinguish transposition table entries from previous searches from /// distinguish transposition table entries from previous searches from
@@ -167,13 +204,13 @@ void TranspositionTable::new_search() {
void TranspositionTable::insert_pv(const Position& pos, Move pv[]) { void TranspositionTable::insert_pv(const Position& pos, Move pv[]) {
StateInfo st; StateInfo st;
Position p(pos, pos.thread()); Position p(pos);
for (int i = 0; pv[i] != MOVE_NONE; i++) for (int i = 0; pv[i] != MOVE_NONE; i++)
{ {
TTEntry *tte = retrieve(p.get_key()); TTEntry *tte = retrieve(p.get_key());
if (!tte || tte->move() != pv[i]) if (!tte || tte->move() != pv[i])
store(p.get_key(), VALUE_NONE, VALUE_TYPE_NONE, Depth(-127*OnePly), pv[i], VALUE_NONE, VALUE_NONE); store(p.get_key(), VALUE_NONE, VALUE_TYPE_NONE, Depth(-127*OnePly), pv[i]);
p.do_move(pv[i], st); p.do_move(pv[i], st);
} }
} }
@@ -189,7 +226,7 @@ void TranspositionTable::extract_pv(const Position& pos, Move pv[], const int PL
const TTEntry* tte; const TTEntry* tte;
StateInfo st; StateInfo st;
Position p(pos, pos.thread()); Position p(pos);
int ply = 0; int ply = 0;
// Update position to the end of current PV // Update position to the end of current PV
+20 -37
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -53,45 +53,36 @@
class TTEntry { class TTEntry {
public: public:
void save(uint32_t k, Value v, ValueType t, Depth d, Move m, int g, Value statV, Value kd) { TTEntry() {}
TTEntry(uint32_t k, Value v, ValueType t, Depth d, Move m, int generation)
: key_ (k), data((m & 0x1FFFF) | (t << 20) | (generation << 23)),
value_(int16_t(v)), depth_(int16_t(d)) {}
key32 = k; uint32_t key() const { return key_; }
data = (m & 0x1FFFF) | (t << 20) | (g << 23); Depth depth() const { return Depth(depth_); }
value16 = int16_t(v);
depth16 = int16_t(d);
staticValue = int16_t(statV);
kingDanger = int16_t(kd);
}
uint32_t key() const { return key32; }
Depth depth() const { return Depth(depth16); }
Move move() const { return Move(data & 0x1FFFF); } Move move() const { return Move(data & 0x1FFFF); }
Value value() const { return Value(value16); } Value value() const { return Value(value_); }
ValueType type() const { return ValueType((data >> 20) & 7); } ValueType type() const { return ValueType((data >> 20) & 7); }
int generation() const { return data >> 23; } int generation() const { return (data >> 23); }
Value static_value() const { return Value(staticValue); }
Value king_danger() const { return Value(kingDanger); }
private: private:
uint32_t key32; uint32_t key_;
uint32_t data; uint32_t data;
int16_t value16; int16_t value_;
int16_t depth16; int16_t depth_;
int16_t staticValue;
int16_t kingDanger;
}; };
/// This is the number of TTEntry slots for each position /// This is the number of TTEntry slots for each position
const int ClusterSize = 4; const int ClusterSize = 5;
/// Each group of ClusterSize number of TTEntry form a TTCluster /// Each group of ClusterSize number of TTEntry form a TTCluster
/// that is indexed by a single position key. TTCluster size must /// that is indexed by a single position key. Cluster is padded
/// be not bigger then a cache line size, in case it is less then /// to a cache line size so to guarantee always aligned accesses.
/// it should be padded to guarantee always aligned accesses.
struct TTCluster { struct TTCluster {
TTEntry data[ClusterSize]; TTEntry data[ClusterSize];
char cache_line_padding[64 - sizeof(TTEntry[ClusterSize])];
}; };
@@ -106,15 +97,17 @@ public:
~TranspositionTable(); ~TranspositionTable();
void set_size(size_t mbSize); void set_size(size_t mbSize);
void clear(); void clear();
void store(const Key posKey, Value v, ValueType type, Depth d, Move m, Value statV, Value kingD); void store(const Key posKey, Value v, ValueType type, Depth d, Move m);
TTEntry* retrieve(const Key posKey) const; TTEntry* retrieve(const Key posKey) const;
void prefetch(const Key posKey) const;
void new_search(); void new_search();
void insert_pv(const Position& pos, Move pv[]); void insert_pv(const Position& pos, Move pv[]);
void extract_pv(const Position& pos, Move pv[], const int PLY_MAX); void extract_pv(const Position& pos, Move pv[], const int PLY_MAX);
int full() const; int full() const;
TTEntry* first_entry(const Key posKey) const;
private: private:
inline TTEntry* first_entry(const Key posKey) const;
// Be sure 'writes' is at least one cache line away // Be sure 'writes' is at least one cache line away
// from read only variables. // from read only variables.
unsigned char pad_before[64 - sizeof(unsigned)]; unsigned char pad_before[64 - sizeof(unsigned)];
@@ -128,14 +121,4 @@ private:
extern TranspositionTable TT; extern TranspositionTable TT;
/// TranspositionTable::first_entry returns a pointer to the first
/// entry of a cluster given a position. The low 32 bits of the key
/// are used to get the index in the table.
inline TTEntry* TranspositionTable::first_entry(const Key posKey) const {
return entries[uint32_t(posKey) & (size - 1)].data;
}
#endif // !defined(TT_H_INCLUDED) #endif // !defined(TT_H_INCLUDED)
+9 -45
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -49,32 +49,20 @@ typedef uint64_t Bitboard;
//// ////
//// Configuration //// Compiler specific defines
//// ////
//// For Linux and OSX configuration is done automatically using Makefile. // Quiet a warning on Intel compiler
//// To get started type "make help". #if !defined(__SIZEOF_INT__ )
//// #define __SIZEOF_INT__ 0
//// For windows part of the configuration is detected automatically, but #endif
//// some switches need to be set manually:
////
//// -DNDEBUG | Disable debugging mode. Use always.
////
//// -DNO_PREFETCH | Disable use of prefetch asm-instruction. A must if you want the
//// | executable to run on some very old machines.
////
//// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction.
//// | Works only in 64-bit mode. For compiling requires hardware
//// | with popcnt support. Around 4% speed-up.
// Automatic detection for 64-bit under Windows // Check for 64 bits for different compilers: Intel, MSVC and gcc
#if defined(_WIN64) #if defined(__x86_64) || defined(_M_X64) || defined(_WIN64) || (__SIZEOF_INT__ > 4)
#define IS_64BIT #define IS_64BIT
#endif #endif
// Automatic detection for use of bsfq asm-instruction under Windows. #if defined(IS_64BIT) && (defined(__GNUC__) || defined(__INTEL_COMPILER))
// Works only in 64-bit mode. Does not work with MSVC.
#if defined(_WIN64) && defined(__INTEL_COMPILER)
#define USE_BSFQ #define USE_BSFQ
#endif #endif
@@ -85,28 +73,4 @@ typedef uint64_t Bitboard;
#define CACHE_LINE_ALIGNMENT __attribute__ ((aligned(64))) #define CACHE_LINE_ALIGNMENT __attribute__ ((aligned(64)))
#endif #endif
// Define a __cpuid() function for gcc compilers, for Intel and MSVC
// is already available as an intrinsic.
#if defined(_MSC_VER)
#include <intrin.h>
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
inline void __cpuid(int CPUInfo[4], int InfoType)
{
int* eax = CPUInfo + 0;
int* ebx = CPUInfo + 1;
int* ecx = CPUInfo + 2;
int* edx = CPUInfo + 3;
*eax = InfoType;
*ecx = 0;
__asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (*eax), "2" (*ecx));
}
#else
inline void __cpuid(int CPUInfo[4], int)
{
CPUInfo[0] = CPUInfo[1] = CPUInfo[2] = CPUInfo[3] = 0;
}
#endif
#endif // !defined(TYPES_H_INCLUDED) #endif // !defined(TYPES_H_INCLUDED)
+6 -6
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -54,7 +54,7 @@ namespace {
// The root position. This is set up when the user (or in practice, the GUI) // The root position. This is set up when the user (or in practice, the GUI)
// sends the "position" UCI command. The root position is sent to the think() // sends the "position" UCI command. The root position is sent to the think()
// function when the program receives the "go" command. // function when the program receives the "go" command.
Position RootPosition(0); Position RootPosition;
// Local functions // Local functions
bool handle_command(const string& command); bool handle_command(const string& command);
@@ -143,7 +143,7 @@ namespace {
RootPosition.print(); RootPosition.print();
else if (token == "flip") else if (token == "flip")
{ {
Position p(RootPosition, RootPosition.thread()); Position p(RootPosition);
RootPosition.flipped_copy(p); RootPosition.flipped_copy(p);
} }
else if (token == "eval") else if (token == "eval")
@@ -151,7 +151,7 @@ namespace {
EvalInfo ei; EvalInfo ei;
cout << "Incremental mg: " << mg_value(RootPosition.value()) cout << "Incremental mg: " << mg_value(RootPosition.value())
<< "\nIncremental eg: " << eg_value(RootPosition.value()) << "\nIncremental eg: " << eg_value(RootPosition.value())
<< "\nFull eval: " << evaluate(RootPosition, ei) << endl; << "\nFull eval: " << evaluate(RootPosition, ei, 0) << endl;
} }
else if (token == "key") else if (token == "key")
cout << "key: " << hex << RootPosition.get_key() cout << "key: " << hex << RootPosition.get_key()
@@ -210,7 +210,7 @@ namespace {
} }
// Our StateInfo st is about going out of scope so copy // Our StateInfo st is about going out of scope so copy
// its content inside RootPosition before they disappear. // its content inside RootPosition before they disappear.
RootPosition.detach(); RootPosition.saveState();
} }
} }
} }
@@ -308,7 +308,7 @@ namespace {
string token; string token;
int depth, tm, n; int depth, tm, n;
Position pos(RootPosition, RootPosition.thread()); Position pos = RootPosition;
if (!(uip >> depth)) if (!(uip >> depth))
return; return;
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+27 -8
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -79,7 +79,6 @@ namespace {
o["Use Search Log"] = Option(false); o["Use Search Log"] = Option(false);
o["Search Log Filename"] = Option("SearchLog.txt"); o["Search Log Filename"] = Option("SearchLog.txt");
o["Book File"] = Option("book.bin"); o["Book File"] = Option("book.bin");
o["Best Book Move"] = Option(false);
o["Mobility (Middle Game)"] = Option(100, 0, 200); o["Mobility (Middle Game)"] = Option(100, 0, 200);
o["Mobility (Endgame)"] = Option(100, 0, 200); o["Mobility (Endgame)"] = Option(100, 0, 200);
o["Pawn Structure (Middle Game)"] = Option(100, 0, 200); o["Pawn Structure (Middle Game)"] = Option(100, 0, 200);
@@ -89,28 +88,48 @@ namespace {
o["Space"] = Option(100, 0, 200); o["Space"] = Option(100, 0, 200);
o["Aggressiveness"] = Option(100, 0, 200); o["Aggressiveness"] = Option(100, 0, 200);
o["Cowardice"] = Option(100, 0, 200); o["Cowardice"] = Option(100, 0, 200);
o["King Safety Curve"] = Option("Quadratic", COMBO);
o["King Safety Curve"].comboValues.push_back("Quadratic");
o["King Safety Curve"].comboValues.push_back("Linear"); /*, "From File"*/
o["King Safety Coefficient"] = Option(40, 1, 100);
o["King Safety X Intercept"] = Option(0, 0, 20);
o["King Safety Max Slope"] = Option(30, 10, 100);
o["King Safety Max Value"] = Option(500, 100, 1000);
o["Queen Contact Check Bonus"] = Option(3, 0, 8);
o["Queen Check Bonus"] = Option(2, 0, 4);
o["Rook Check Bonus"] = Option(1, 0, 4);
o["Bishop Check Bonus"] = Option(1, 0, 4);
o["Knight Check Bonus"] = Option(1, 0, 4);
o["Discovered Check Bonus"] = Option(3, 0, 8);
o["Mate Threat Bonus"] = Option(3, 0, 8);
o["Check Extension (PV nodes)"] = Option(2, 0, 2); o["Check Extension (PV nodes)"] = Option(2, 0, 2);
o["Check Extension (non-PV nodes)"] = Option(1, 0, 2); o["Check Extension (non-PV nodes)"] = Option(1, 0, 2);
o["Single Evasion Extension (PV nodes)"] = Option(2, 0, 2); o["Single Reply Extension (PV nodes)"] = Option(2, 0, 2);
o["Single Evasion Extension (non-PV nodes)"] = Option(2, 0, 2); o["Single Reply Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Mate Threat Extension (PV nodes)"] = Option(2, 0, 2); o["Mate Threat Extension (PV nodes)"] = Option(0, 0, 2);
o["Mate Threat Extension (non-PV nodes)"] = Option(2, 0, 2); o["Mate Threat Extension (non-PV nodes)"] = Option(0, 0, 2);
o["Pawn Push to 7th Extension (PV nodes)"] = Option(1, 0, 2); o["Pawn Push to 7th Extension (PV nodes)"] = Option(1, 0, 2);
o["Pawn Push to 7th Extension (non-PV nodes)"] = Option(1, 0, 2); o["Pawn Push to 7th Extension (non-PV nodes)"] = Option(1, 0, 2);
o["Passed Pawn Extension (PV nodes)"] = Option(1, 0, 2); o["Passed Pawn Extension (PV nodes)"] = Option(1, 0, 2);
o["Passed Pawn Extension (non-PV nodes)"] = Option(0, 0, 2); o["Passed Pawn Extension (non-PV nodes)"] = Option(0, 0, 2);
o["Pawn Endgame Extension (PV nodes)"] = Option(2, 0, 2); o["Pawn Endgame Extension (PV nodes)"] = Option(2, 0, 2);
o["Pawn Endgame Extension (non-PV nodes)"] = Option(2, 0, 2); o["Pawn Endgame Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Full Depth Moves (PV nodes)"] = Option(10, 1, 100);
o["Full Depth Moves (non-PV nodes)"] = Option(3, 1, 100);
o["Threat Depth"] = Option(5, 0, 100);
o["Randomness"] = Option(0, 0, 10); o["Randomness"] = Option(0, 0, 10);
o["Minimum Split Depth"] = Option(4, 4, 7); o["Minimum Split Depth"] = Option(4, 4, 7);
o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8); o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8);
o["Threads"] = Option(1, 1, MAX_THREADS); o["Threads"] = Option(1, 1, THREAD_MAX);
o["Hash"] = Option(32, 4, 8192); o["Hash"] = Option(32, 4, 8192);
o["Clear Hash"] = Option(false, BUTTON); o["Clear Hash"] = Option(false, BUTTON);
o["New Game"] = Option(false, BUTTON); o["New Game"] = Option(false, BUTTON);
o["Ponder"] = Option(true); o["Ponder"] = Option(true);
o["OwnBook"] = Option(true); o["OwnBook"] = Option(true);
o["MultiPV"] = Option(1, 1, 500); o["MultiPV"] = Option(1, 1, 500);
o["UCI_ShowCurrLine"] = Option(false);
o["UCI_Chess960"] = Option(false); o["UCI_Chess960"] = Option(false);
o["UCI_AnalyseMode"] = Option(false); o["UCI_AnalyseMode"] = Option(false);
@@ -317,7 +336,7 @@ void push_button(const string& buttonName) {
bool button_was_pressed(const string& buttonName) { bool button_was_pressed(const string& buttonName) {
if (!get_option_value<bool>(buttonName)) if (!get_option_value<bool>(buttonName))
return false; return false;
set_option_value(buttonName, "false"); set_option_value(buttonName, "false");
return true; return true;
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+6 -3
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -33,10 +33,13 @@
//// ////
enum ValueType { enum ValueType {
VALUE_TYPE_NONE = 0, VALUE_TYPE_NONE = 0,
VALUE_TYPE_UPPER = 1, // Upper bound VALUE_TYPE_UPPER = 1, // Upper bound
VALUE_TYPE_LOWER = 2, // Lower bound VALUE_TYPE_LOWER = 2, // Lower bound
VALUE_TYPE_EXACT = VALUE_TYPE_UPPER | VALUE_TYPE_LOWER VALUE_TYPE_EXACT = 3, // Exact score
VALUE_TYPE_EVAL = 4, // Evaluation cache
VALUE_TYPE_EV_UP = 5, // Evaluation cache for upper bound
VALUE_TYPE_EV_LO = 6 // Evaluation cache for lower bound
}; };