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
+63 -48
View File
@@ -1,48 +1,63 @@
[PolyGlot]
EngineDir = .
EngineCommand = ./stockfish
Book = false
BookFile = book.bin
Log = false
LogFile = stockfish.log
Resign = true
ResignScore = 600
[Engine]
Hash = 128
Threads = 1
OwnBook = false
Book File = book.bin
Best Book Move = false
Use Search Log = false
Search Log Filename = SearchLog.txt
Mobility (Middle Game) = 100
Mobility (Endgame) = 100
Pawn Structure (Middle Game) = 100
Pawn Structure (Endgame) = 100
Passed Pawns (Middle Game) = 100
Passed Pawns (Endgame) = 100
Space = 100
Aggressiveness = 100
Cowardice = 100
Check Extension (PV nodes) = 2
Check Extension (non-PV nodes) = 1
Single Reply Extension (PV nodes) = 2
Single Reply Extension (non-PV nodes) = 2
Mate Threat Extension (PV nodes) = 0
Mate Threat Extension (non-PV nodes) = 0
Pawn Push to 7th Extension (PV nodes) = 1
Pawn Push to 7th Extension (non-PV nodes) = 1
Passed Pawn Extension (PV nodes) = 1
Passed Pawn Extension (non-PV nodes) = 0
Pawn Endgame Extension (PV nodes) = 2
Pawn Endgame Extension (non-PV nodes) = 2
Randomness = 0
Minimum Split Depth = 4
Maximum Number of Threads per Split Point = 5
[PolyGlot]
EngineDir = .
EngineCommand = ./stockfish
Book = false
BookFile = book.bin
Log = true
LogFile = stockfish.log
Resign = true
ResignScore = 600
[Engine]
Hash = 128
Threads = 1
OwnBook = false
Book File = book.bin
Use Search Log = false
Mobility (Middle Game) = 100
Mobility (Endgame) = 100
Pawn Structure (Middle Game) = 100
Pawn Structure (Endgame) = 100
Passed Pawns (Middle Game) = 100
Passed Pawns (Endgame) = 100
Aggressiveness = 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 (non-PV nodes) = 1
Single Reply Extension (PV nodes) = 2
Single Reply Extension (non-PV nodes) = 2
Mate Threat Extension (PV nodes) = 0
Mate Threat Extension (non-PV nodes) = 0
Pawn Push to 7th Extension (PV nodes) = 1
Pawn Push to 7th Extension (non-PV nodes) = 1
Passed Pawn Extension (PV nodes) = 1
Passed Pawn Extension (non-PV nodes) = 0
Pawn Endgame Extension (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
Minimum Split Depth = 4
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
# Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
# Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
#
# Copyright (C) 2004-2007 Tord Romstad
# Copyright (C) 2008 Marco Costalba
# This file is part of Stockfish.
#
# 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/>.
### ==========================================================================
### Section 1. General Configuration
### ==========================================================================
### Executable name
### Executable name. Do not change
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
### 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 \
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 \
mersenne.o book.o bitbase.o san.o benchmark.o
### ==========================================================================
### 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
### ==========================================================================
### General rules. Do not change
default:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) build
$(MAKE) gcc
help:
@echo ""
@echo "To compile stockfish, type: "
@echo "Makefile options:"
@echo ""
@echo "make target ARCH=arch [COMP=comp]"
@echo ""
@echo "Supported targets:"
@echo ""
@echo "build > Build unoptimized version"
@echo "profile-build > Build PGO-optimized version"
@echo "popcnt-profile-build > Build PGO-optimized version with optional popcnt-support"
@echo "strip > Strip executable"
@echo "install > Install executable"
@echo "clean > Clean up"
@echo "testrun > Make sample run"
@echo ""
@echo "Supported archs:"
@echo ""
@echo "x86-64 > x86 64-bit"
@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 "make > Default: Compiler = g++"
@echo "make gcc-popcnt > Compiler = g++ + popcnt-support"
@echo "make icc > Compiler = icpc"
@echo "make icc-profile > Compiler = icpc + automatic pgo-build"
@echo "make icc-profile-popcnt > Compiler = icpc + automatic pgo-build + popcnt-support"
@echo "make osx-ppc32 > PPC-Mac OS X 32 bit. Compiler = g++"
@echo "make osx-ppc64 > PPC-Mac OS X 64 bit. Compiler = g++"
@echo "make osx-x86 > x86-Mac OS X 32 bit. Compiler = g++"
@echo "make osx-x86_64 > x86-Mac OS X 64 bit. Compiler = g++"
@echo "make osx-icc32 > x86-Mac OS X 32 bit. Compiler = icpc"
@echo "make osx-icc64 > x86-Mac OS X 64 bit. Compiler = icpc"
@echo "make osx-icc32-profile > OSX 32 bit. Compiler = icpc + automatic pgo-build"
@echo "make osx-icc64-profile > OSX 64 bit. Compiler = icpc + automatic pgo-build"
@echo "make strip > Strip executable"
@echo "make clean > Clean up"
@echo ""
build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
all: $(EXE) .depend
profile-build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
@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)
clean:
$(RM) *.o .depend *~ $(EXE)
popcnt-profile-build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
@echo ""
@echo "Step 0/6. Preparing for profile build."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
@echo ""
@echo "Step 1/6. Building executable for benchmark (popcnt disabled)..."
### Possible targets. You may add your own ones here
gcc:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
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
$(MAKE) ARCH=x86-64 COMP=$(COMP) $(profile_make)
$(MAKE) icc-profile-make
@echo ""
@echo "Step 2/6. Running benchmark for pgo-build (popcnt disabled)..."
@echo "Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo ""
@echo "Step 3/6. Building executable for benchmark (popcnt enabled)..."
@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 "Step 4/6. Running benchmark for pgo-build (popcnt enabled)..."
@echo "Running benchmark for pgo-build (popcnt disabled)..."
@$(PGOBENCH) > /dev/null
@echo ""
@echo "Step 5/6. Building final executable ..."
@touch *.cpp *.h
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
$(MAKE) icc-profile-make-with-popcnt
@echo ""
@echo "Step 6/6. Deleting profile data ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean)
@echo "Running benchmark for pgo-build (popcnt enabled)..."
@$(PGOBENCH) > /dev/null
@echo "Benchmarks finished. Build final executable now ..."
@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 $(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)
$(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:
-@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null
-include .depend
### ==========================================================================
### Section 6. Non-standard targets
### ==========================================================================
hpux:
$(MAKE) \
CXX='/opt/aCC/bin/aCC -AA +hpxstd98 -DBIGENDIAN -mt +O3 -DNDEBUG' \
CXXFLAGS="" \
LDFLAGS="" \
all
$(CXX) -msse -MM $(OBJS:.o=.cpp) > $@
include .depend
+8 -11
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
it under the terms of the GNU General Public License as published by
@@ -49,7 +49,6 @@ Application::Application() {
Position::init_piece_square_tables();
init_eval(1);
init_bitbases();
init_search();
init_threads();
// Make random number generation less deterministic, for book moves
@@ -57,6 +56,12 @@ Application::Application() {
genrand_int32();
}
Application::~Application() {
stop_threads();
quit_eval();
}
void Application::initialize() {
// A static Application object is allocated
@@ -64,15 +69,7 @@ void Application::initialize() {
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() {
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
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
it under the terms of the GNU General Public License as published by
@@ -29,10 +29,10 @@ class Application {
Application();
Application(const Application&);
~Application();
public:
static void initialize();
static void free_resources();
static void exit_with_failure();
};
+10 -15
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
it under the terms of the GNU General Public License as published by
@@ -38,8 +38,8 @@ using namespace std;
const string BenchmarkPositions[] = {
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -",
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -",
"r4rk1/1b2qppp/p1n1p3/1p6/1b1PN3/3BRN2/PP3PPP/R2Q2K1 b - - 7 16",
"4r1k1/ppq3pp/3b4/2pP4/2Q1p3/4B1P1/PP5P/R5K1 b - - 0 20",
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14",
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14",
@@ -84,9 +84,9 @@ void benchmark(const string& commandLine) {
}
csStr >> threads;
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();
}
set_option_value("Hash", ttSize);
@@ -151,18 +151,13 @@ void benchmark(const string& commandLine) {
{
Move moves[1] = {MOVE_NONE};
int dummy[2] = {0, 0};
Position pos(*it, 0);
Position pos(*it);
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (limitType == "perft")
{
int64_t perftCnt = perft(pos, maxDepth * OnePly);
cerr << "\nPerft " << maxDepth << " result (nodes searched): " << perftCnt << endl << endl;
totalNodes += perftCnt;
} else {
if (!think(pos, false, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched();
}
totalNodes += perft(pos, maxDepth * OnePly);
else if (!think(pos, false, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched();
}
cnt = get_system_time() - startTime;
+1 -1
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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
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
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
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
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
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
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 BetweenBB[64][64];
Bitboard SquaresInFrontMask[2][64];
Bitboard PassedPawnMask[2][64];
Bitboard AttackSpanMask[2][64];
Bitboard OutpostMask[2][64];
Bitboard BishopPseudoAttacks[64];
Bitboard RookPseudoAttacks[64];
@@ -247,12 +246,14 @@ namespace {
void init_ray_bitboards();
void init_attacks();
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],
int fmin, int fmax, int rmin, int rmax);
void init_sliding_attacks(Bitboard attacks[], int attackIndex[], Bitboard mask[],
const int shift[], const Bitboard mult[], int deltas[][2]);
Bitboard index_to_bitboard(int index, Bitboard mask);
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.
void print_bitboard(Bitboard b) {
for (Rank r = RANK_8; r >= RANK_1; r--)
{
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
for (File f = FILE_A; f <= FILE_H; f++)
std::cout << "| " << (bit_is_set(b, make_square(f, r))? 'X' : ' ') << ' ';
std::cout << "|" << std::endl;
for(Rank r = RANK_8; r >= RANK_1; r--) {
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
for(File f = FILE_A; f <= FILE_H; f++)
std::cout << "| " << (bit_is_set(b, make_square(f, r))? 'X' : ' ') << ' ';
std::cout << "|" << std::endl;
}
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
}
@@ -281,10 +279,8 @@ void print_bitboard(Bitboard b) {
/// program initialization.
void init_bitboards() {
int rookDeltas[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int bishopDeltas[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}};
init_masks();
init_ray_bitboards();
init_attacks();
@@ -301,8 +297,8 @@ void init_bitboards() {
#if defined(IS_64BIT) && !defined(USE_BSFQ)
static CACHE_LINE_ALIGNMENT
const int BitTable[64] = {
CACHE_LINE_ALIGNMENT
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,
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,
@@ -330,7 +326,6 @@ const int BitTable[64] = {
};
Square first_1(Bitboard b) {
b ^= (b - 1);
uint32_t fold = int(b) ^ int(b >> 32);
return Square(BitTable[(fold * 0x783a9b23) >> 26]);
@@ -373,6 +368,28 @@ Square pop_1st_bit(Bitboard* bb) {
#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 {
@@ -382,46 +399,39 @@ namespace {
// be necessary to touch any of them.
void init_masks() {
SetMaskBB[SQ_NONE] = 0ULL;
ClearMaskBB[SQ_NONE] = ~SetMaskBB[SQ_NONE];
for (Square s = SQ_A1; s <= SQ_H8; s++)
{
SetMaskBB[s] = (1ULL << s);
ClearMaskBB[s] = ~SetMaskBB[s];
for(Square s = SQ_A1; s <= SQ_H8; s++) {
SetMaskBB[s] = (1ULL << s);
ClearMaskBB[s] = ~SetMaskBB[s];
}
for (Color c = WHITE; c <= BLACK; c++)
for (Square s = SQ_A1; s <= SQ_H8; s++)
{
SquaresInFrontMask[c][s] = in_front_bb(c, s) & file_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(Color c = WHITE; c <= BLACK; c++)
for(Square s = SQ_A1; s <= SQ_H8; s++) {
PassedPawnMask[c][s] =
in_front_bb(c, s) & this_and_neighboring_files_bb(s);
OutpostMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
}
for (Bitboard b = 0ULL; b < 256ULL; b++)
BitCount8Bit[b] = (uint8_t)count_1s(b);
}
int remove_bit_8(int i) { return ((i & ~15) >> 1) | (i & 7); }
void init_ray_bitboards() {
int d[8] = {1, -1, 16, -16, 17, -17, 15, -15};
for (int i = 0; i < 128; i = (i + 9) & ~8)
for (int j = 0; j < 8; j++)
{
RayBB[remove_bit_8(i)][j] = EmptyBoardBB;
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)));
}
for(int i = 0; i < 128; i = (i + 9) & ~8) {
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])
set_bit(&(RayBB[(i&7)|((i>>4)<<3)][j]), Square((k&7)|((k>>4)<<3)));
}
}
}
void init_attacks() {
const int step[16][8] = {
void init_attacks() {
int i, j, k, l;
int step[16][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},
@@ -429,115 +439,105 @@ namespace {
{9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}
};
for (int i = 0; i < 64; i++)
for (int j = 0; j <= int(BK); j++)
{
StepAttackBB[j][i] = EmptyBoardBB;
for (int k = 0; k < 8 && step[j][k] != 0; k++)
{
int l = i + step[j][k];
if (l >= 0 && l < 64 && abs((i & 7) - (l & 7)) < 3)
StepAttackBB[j][i] |= (1ULL << l);
}
for(i = 0; i < 64; i++) {
for(j = 0; j <= int(BK); j++) {
StepAttackBB[j][i] = EmptyBoardBB;
for(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)
StepAttackBB[j][i] |= (1ULL << l);
}
}
}
}
Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
int fmin=0, int fmax=7, int rmin=0, int rmax=7) {
Bitboard result = 0ULL;
int rk = sq / 8;
int fl = sq % 8;
for (int i = 0; i < dirs; i++)
{
int dx = deltas[i][0];
int dy = deltas[i][1];
int f = fl + dx;
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;
}
int rk = sq / 8, fl = sq % 8, r, f, i;
for(i = 0; i < dirs; i++) {
int dx = deltas[i][0], dy = deltas[i][1];
for(f = fl+dx, r = rk+dy;
(dx==0 || (f>=fmin && f<=fmax)) && (dy==0 || (r>=rmin && r<=rmax));
f += dx, r += dy) {
result |= (1ULL << (f + r*8));
if(block & (1ULL << (f + r*8))) break;
}
}
return result;
}
void init_between_bitboards() {
const SquareDelta step[8] = { DELTA_E, DELTA_W, DELTA_N, DELTA_S,
DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE };
for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++)
{
BetweenBB[s1][s2] = EmptyBoardBB;
SignedDirection d = signed_direction_between_squares(s1, s2);
if (d != SIGNED_DIR_NONE)
{
for (Square s3 = s1 + step[d]; s3 != s2; s3 += step[d])
set_bit(&(BetweenBB[s1][s2]), s3);
}
SquareDelta step[8] = {
DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE
};
SignedDirection d;
for(Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for(Square s2 = SQ_A1; s2 <= SQ_H8; s2++) {
BetweenBB[s1][s2] = EmptyBoardBB;
d = signed_direction_between_squares(s1, s2);
if(d != SIGNED_DIR_NONE)
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) {
int i, j, bits = count_1s(mask);
Bitboard result = 0ULL;
int bits = count_1s(mask);
for (int i = 0; i < bits; i++)
{
int j = pop_1st_bit(&mask);
if (index & (1 << i))
result |= (1ULL << j);
for(i = 0; i < bits; i++) {
j = pop_1st_bit(&mask);
if(index & (1 << i)) result |= (1ULL << j);
}
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++)
{
attackIndex[i] = index;
mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6);
void init_sliding_attacks(Bitboard attacks[],
int attackIndex[], Bitboard mask[],
const int shift[2], const Bitboard mult[],
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)
int j = (1 << (64 - shift[i]));
j = (1 << (64 - shift[i]));
#else
int j = (1 << (32 - shift[i]));
j = (1 << (32 - shift[i]));
#endif
for (int k = 0; k < j; k++)
{
for(k = 0; k < j; k++) {
#if defined(IS_64BIT)
Bitboard b = index_to_bitboard(k, mask[i]);
attacks[index + ((b * mult[i]) >> shift[i])] = sliding_attacks(i, b, 4, deltas);
b = index_to_bitboard(k, mask[i]);
attacks[index + ((b * mult[i]) >> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#else
Bitboard b = index_to_bitboard(k, mask[i]);
unsigned v = int(b) * int(mult[i]) ^ int(b >> 32) * int(mult[i] >> 32);
attacks[index + (v >> shift[i])] = sliding_attacks(i, b, 4, deltas);
b = index_to_bitboard(k, mask[i]);
attacks[index +
(unsigned(int(b) * int(mult[i]) ^
int(b >> 32) * int(mult[i] >> 32))
>> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#endif
}
index += j;
}
index += j;
}
}
void init_pseudo_attacks() {
for (Square s = SQ_A1; s <= SQ_H8; s++)
{
BishopPseudoAttacks[s] = bishop_attacks_bb(s, EmptyBoardBB);
RookPseudoAttacks[s] = rook_attacks_bb(s, EmptyBoardBB);
QueenPseudoAttacks[s] = queen_attacks_bb(s, EmptyBoardBB);
void init_pseudo_attacks() {
Square s;
for(s = SQ_A1; s <= SQ_H8; s++) {
BishopPseudoAttacks[s] = bishop_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
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
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 BetweenBB[64][64];
extern Bitboard SquaresInFrontMask[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 int RShift[64];
@@ -128,8 +127,9 @@ inline void do_move_bb(Bitboard *b, Bitboard move_bb) {
*b ^= move_bb;
}
/// rank_bb() and file_bb() take a file or a square as input, and return
/// a bitboard representing all squares on the given file or rank.
/// rank_bb() and file_bb() gives a bitboard containing all squares on a given
/// file or rank. It is also possible to pass a square as input to these
/// functions.
inline Bitboard rank_bb(Rank r) {
return RankBB[r];
@@ -156,7 +156,7 @@ inline Bitboard neighboring_files_bb(File f) {
}
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) {
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) {
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) {
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
/// 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:
/// SquaresInFrontOf[c][s] = in_front_bb(c, s) & file_bb(s)
/// from the point of view of the given color. For instance,
/// 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) {
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.
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
/// 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:
/// PassedPawnMask[c][s] = in_front_bb(c, s) & this_and_neighboring_files_bb(s)
/// the given square is a passed pawn.
inline Bitboard passed_pawn_mask(Color c, Square s) {
return PassedPawnMask[c][s];
}
/// attack_span_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
/// when it moves along its file starting from the given square. Definition is:
/// AttackSpanMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
/// outpost_mask takes a color and a square as input, and returns a bitboard
/// mask which can be used to test whether a piece on the square can possibly
/// be driven away by an enemy pawn.
inline Bitboard attack_span_mask(Color c, Square s) {
return AttackSpanMask[c][s];
inline Bitboard outpost_mask(Color c, Square 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 init_bitboards();
extern int bitScanReverse32(uint32_t b);
#endif // !defined(BITBOARD_H_INCLUDED)
+53 -20
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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
// README.txt on how to pgo compile with POPCNT support.
#if !defined(USE_POPCNT)
#define POPCNT_INTRINSIC(x) 0
#elif defined(_MSC_VER)
#define POPCNT_INTRINSIC(x) (int)__popcnt64(x)
#elif defined(__GNUC__)
#if defined(__INTEL_COMPILER) && defined(USE_POPCNT) // Intel compiler
#include <nmmintrin.h>
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) ({ \
unsigned long __ret; \
__asm__("popcnt %1, %0" : "=r" (__ret) : "r" (x)); \
__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
@@ -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
// CPU on which application runs supports POPCNT intrinsic. Unless
// USE_POPCNT is not defined.
#if defined(USE_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
+5 -17
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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,
/// 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 : "";
}
@@ -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
/// 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)
return MOVE_NONE;
BookEntry entry;
int bookMove = MOVE_NONE;
int scoresSum = 0, bestScore = 0;
int bookMove = 0, scoresSum = 0;
uint64_t key = book_key(pos);
BookEntry entry;
// Choose a book move among the possible moves for the given position
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);
// 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
// high score it has more probability to be choosen then a one with
// 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
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
it under the terms of the GNU General Public License as published by
@@ -53,15 +53,12 @@ struct BookEntry {
};
class Book : private std::ifstream {
Book(const Book&); // just decleared..
Book& operator=(const Book&); // ..to avoid a warning
public:
Book() {}
~Book();
void open(const std::string& fName);
void close();
const std::string file_name();
Move get_move(const Position& pos, bool findBestMove);
const std::string file_name() const;
Move get_move(const Position& pos);
private:
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
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
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
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
it under the terms of the GNU General Public License as published by
@@ -27,8 +27,7 @@
enum Depth {
DEPTH_ZERO = 0,
DEPTH_MAX = 200, // 100 * OnePly;
DEPTH_ENSURE_SIGNED = -1
DEPTH_MAX = 200 // 100 * OnePly;
};
@@ -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 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 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 & d, int i) { d = 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 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
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
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
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
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
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
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
/// of the board, and for keeping the distance between the two kings small.
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.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
/// defending king towards a corner square of the right color.
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.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.
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(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
/// away.
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.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
/// score is slightly bigger when the defending king is close to the edge.
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.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
/// in KR vs KB, particularly if the king and the knight are far apart.
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.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
/// able to win KQ vs KR.
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.piece_count(strongerSide, PAWN) == 0);
@@ -323,7 +323,7 @@ Value EvaluationFunction<KQKR>::apply(const Position& pos) const {
}
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.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
/// king alone are always draw.
template<>
Value EvaluationFunction<KmmKm>::apply(const Position&) const {
Value EvaluationFunction<KmmKm>::apply(const Position&) {
return Value(0);
}
template<>
Value EvaluationFunction<KNNK>::apply(const Position&) const {
Value EvaluationFunction<KNNK>::apply(const Position&) {
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
/// will be used.
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.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
/// a pawn.
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.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,
/// which is mostly copied from Glaurung 1.x, and not very pretty.
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.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
/// is actively placed, the position is drawish.
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.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
/// the same rook file and are blocked by the defending king, it's a draw.
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.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
/// a draw.
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.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
/// draws with opposite-colored bishops.
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.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,
/// it's a draw.
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.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
/// the pawn from advancing, the position is drawn.
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.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
/// (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
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(weakerSide) == Value(0));
+4 -4
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
it under the terms of the GNU General Public License as published by
@@ -68,7 +68,7 @@ class EndgameFunctionBase {
public:
EndgameFunctionBase(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {}
virtual ~EndgameFunctionBase() {}
virtual T apply(const Position&) const = 0;
virtual T apply(const Position&) = 0;
Color color() const { return strongerSide; }
protected:
@@ -85,14 +85,14 @@ template<EndgameType>
struct EvaluationFunction : public EndgameEvaluationFunctionBase {
typedef EndgameEvaluationFunctionBase Base;
explicit EvaluationFunction(Color c): EndgameEvaluationFunctionBase(c) {}
Value apply(const Position&) const;
Value apply(const Position&);
};
template<EndgameType>
struct ScalingFunction : public EndgameScalingFunctionBase {
typedef EndgameScalingFunctionBase Base;
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
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
it under the terms of the GNU General Public License as published by
@@ -46,11 +46,9 @@ namespace {
const int GrainSize = 8;
// Evaluation weights, initialized from UCI options
enum { Mobility, PawnStructure, PassedPawns, Space, KingDangerUs, KingDangerThem };
Score Weights[6];
typedef Value V;
#define S(mg, eg) make_score(mg, eg)
Score WeightMobility, WeightPawnStructure;
Score WeightPassedPawns, WeightSpace;
Score WeightKingSafety[2];
// Internal evaluation weights. These are applied on top of the evaluation
// weights read from UCI parameters. The purpose is to be able to change
@@ -58,9 +56,19 @@ namespace {
// parameters at 100, which looks prettier.
//
// Values modified by Joona Kiiski
const Score WeightsInternal[] = {
S(248, 271), S(233, 201), S(252, 259), S(46, 0), S(247, 0), S(259, 0)
};
const Score WeightMobilityInternal = make_score(248, 271);
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
// 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
};
// ThreatBonus[attacking][attacked] contains bonus according to which
// piece type attacks which one.
// ThreatBonus[][] contains bonus according to which piece type
// attacks which one.
#define Z S(0, 0)
const Score ThreatBonus[8][8] = {
{}, {},
{ S(0, 0), S( 7, 39), S( 0, 0), S(24, 49), S(41,100), S(41,100) }, // KNIGHT
{ S(0, 0), S( 7, 39), S(24, 49), S( 0, 0), S(41,100), S(41,100) }, // BISHOP
{ S(0, 0), S(-1, 29), S(15, 49), S(15, 49), S( 0, 0), S(24, 49) }, // ROOK
{ S(0, 0), S(15, 39), S(15, 39), S(15, 39), S(15, 39), S( 0, 0) } // QUEEN
{ Z, Z, Z, Z, Z, Z, Z, Z }, // not used
{ Z, S(18,37), Z, S(37,47), S(55,97), S(55,97), Z, Z }, // KNIGHT attacks
{ Z, S(18,37), S(37,47), Z, S(55,97), S(55,97), Z, Z }, // BISHOP attacks
{ Z, S( 9,27), S(27,47), S(27,47), Z, S(37,47), Z, Z }, // ROOK attacks
{ 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
// type is attacked by an enemy pawn.
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
// Bonus for unstoppable passed pawns
@@ -197,21 +211,28 @@ namespace {
(1ULL<<SQ_C5) | (1ULL<<SQ_D5) | (1ULL<<SQ_E5) | (1ULL<<SQ_F5)
};
/// King danger constants and variables. The king danger scores are taken
/// from the KingDangerTable[]. Various little "meta-bonuses" measuring
/// the strength of the enemy attack are added up into an integer, which
/// is used as an index to KingDangerTable[].
/// King safety constants and variables. The king safety scores are taken
/// from the array SafetyTable[]. Various little "meta-bonuses" measuring
/// the strength of the attack are added up into an integer, which is used
/// as an index to SafetyTable[].
// KingAttackWeights[] contains king attack weights by piece type
const int KingAttackWeights[8] = { 0, 0, 2, 2, 3, 5 };
// Attack weights for each piece type and table indexed on piece type
const int QueenAttackWeight = 5;
const int RookAttackWeight = 3;
const int BishopAttackWeight = 2;
const int KnightAttackWeight = 2;
// Bonuses for enemy's safe checks
const int QueenContactCheckBonus = 3;
const int DiscoveredCheckBonus = 3;
const int QueenCheckBonus = 2;
const int RookCheckBonus = 1;
const int BishopCheckBonus = 1;
const int KnightCheckBonus = 1;
const int AttackWeight[] = { 0, 0, KnightAttackWeight, BishopAttackWeight, RookAttackWeight, QueenAttackWeight };
// Bonuses for safe checks, initialized from UCI options
int QueenContactCheckBonus, DiscoveredCheckBonus;
int QueenCheckBonus, RookCheckBonus, BishopCheckBonus, KnightCheckBonus;
// 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
// king.
@@ -226,13 +247,14 @@ namespace {
15, 15, 15, 15, 15, 15, 15, 15
};
// KingDangerTable[color][] contains the actual king danger weighted scores
Score KingDangerTable[2][128];
// SafetyTable[] contains the actual king safety scores. It is initialized
// in init_safety().
Value SafetyTable[100];
// Pawn and material hash tables, indexed by the current thread id.
// Note that they will be initialized at 0 being global variables.
MaterialInfoTable* MaterialTable[MAX_THREADS];
PawnInfoTable* PawnTable[MAX_THREADS];
MaterialInfoTable* MaterialTable[THREAD_MAX];
PawnInfoTable* PawnTable[THREAD_MAX];
// Sizes of pawn and material hash tables
const int PawnTableSize = 16384;
@@ -240,10 +262,7 @@ namespace {
// Function prototypes
template<bool HasPopCnt>
Value do_evaluate(const Position& pos, EvalInfo& ei);
template<Color Us, bool HasPopCnt>
void init_attack_tables(const Position& pos, EvalInfo& ei);
Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID);
template<Color Us, bool HasPopCnt>
void evaluate_pieces_of_color(const Position& pos, EvalInfo& ei);
@@ -255,12 +274,9 @@ namespace {
void evaluate_threats(const Position& pos, EvalInfo& ei);
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_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_a1h1(const Position& pos, Square s, Color us, EvalInfo& ei);
inline Score apply_weight(Score v, Score weight);
@@ -277,21 +293,19 @@ namespace {
/// evaluate() is the main evaluation function. It always computes two
/// values, an endgame score and a middle game score, and interpolates
/// 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)
: do_evaluate<false>(pos, ei);
return CpuHasPOPCNT ? do_evaluate<true>(pos, ei, threadID)
: do_evaluate<false>(pos, ei, threadID);
}
namespace {
template<bool HasPopCnt>
Value do_evaluate(const Position& pos, EvalInfo& ei) {
ScaleFactor factor[2];
Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID) {
assert(pos.is_ok());
assert(pos.thread() >= 0 && pos.thread() < MAX_THREADS);
assert(threadID >= 0 && threadID < THREAD_MAX);
assert(!pos.is_check());
memset(&ei, 0, sizeof(EvalInfo));
@@ -301,7 +315,7 @@ Value do_evaluate(const Position& pos, EvalInfo& ei) {
ei.value = pos.value();
// 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();
// 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);
// After get_material_info() call that modifies them
ScaleFactor factor[2];
factor[WHITE] = ei.mi->scale_factor(pos, WHITE);
factor[BLACK] = ei.mi->scale_factor(pos, BLACK);
// Probe the pawn hash table
ei.pi = PawnTable[pos.thread()]->get_pawn_info(pos);
ei.value += apply_weight(ei.pi->pawns_value(), Weights[PawnStructure]);
ei.pi = PawnTable[threadID]->get_pawn_info(pos);
ei.value += apply_weight(ei.pi->pawns_value(), WeightPawnStructure);
// Initialize attack bitboards with pawns evaluation
init_attack_tables<WHITE, HasPopCnt>(pos, ei);
init_attack_tables<BLACK, HasPopCnt>(pos, ei);
// Initialize king attack bitboards and king attack zones for both sides
ei.attackedBy[WHITE][KING] = pos.attacks_from<KING>(pos.king_square(WHITE));
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_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<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<BLACK>(pos, ei);
// Evaluate passed pawns, we need full attack info including king
evaluate_passed_pawns<WHITE>(pos, ei);
evaluate_passed_pawns<BLACK>(pos, ei);
// If one side has only a king, check whether exsists any unstoppable passed pawn
if (!pos.non_pawn_material(WHITE) || !pos.non_pawn_material(BLACK))
evaluate_unstoppable_pawns(pos, ei);
// Evaluate passed pawns. We evaluate passed pawns for both sides at once,
// because we need to know which side promotes first in positions where
// both sides have an unstoppable passed pawn. To be called after all attacks
// are computed, included king.
if (ei.pi->passed_pawns())
evaluate_passed_pawns(pos, ei);
Phase phase = ei.mi->game_phase();
// Middle-game specific evaluation terms
if (phase > PHASE_ENDGAME)
{
// Pawn storms in positions with opposite castling
if ( square_file(pos.king_square(WHITE)) >= FILE_E
&& square_file(pos.king_square(BLACK)) <= FILE_D)
// Pawn storms in positions with opposite castling.
if ( square_file(pos.king_square(WHITE)) >= FILE_E
&& 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
&& square_file(pos.king_square(BLACK)) >= FILE_E)
else if ( square_file(pos.king_square(WHITE)) <= FILE_D
&& 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
if (ei.mi->space_weight() > 0)
{
int s = evaluate_space<WHITE, HasPopCnt>(pos, ei) - evaluate_space<BLACK, HasPopCnt>(pos, ei);
ei.value += apply_weight(make_score(s * ei.mi->space_weight(), 0), Weights[Space]);
}
// Evaluate space for both sides
if (ei.mi->space_weight() > 0)
{
evaluate_space<WHITE, HasPopCnt>(pos, ei);
evaluate_space<BLACK, HasPopCnt>(pos, ei);
}
}
// 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
// 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
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
/// 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
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)
{
@@ -433,7 +479,7 @@ void init_eval(int threads) {
void quit_eval() {
for (int i = 0; i < MAX_THREADS; i++)
for (int i = 0; i < THREAD_MAX; i++)
{
delete PawnTable[i];
delete MaterialTable[i];
@@ -447,46 +493,28 @@ void quit_eval() {
void read_weights(Color us) {
// King safety is asymmetrical. Our king danger level is weighted by
// "Cowardice" UCI parameter, instead the opponent one by "Aggressiveness".
const int kingDangerUs = (us == WHITE ? KingDangerUs : KingDangerThem);
const int kingDangerThem = (us == WHITE ? KingDangerThem : KingDangerUs);
Color them = opposite_color(us);
Weights[Mobility] = weight_option("Mobility (Middle Game)", "Mobility (Endgame)", WeightsInternal[Mobility]);
Weights[PawnStructure] = weight_option("Pawn Structure (Middle Game)", "Pawn Structure (Endgame)", WeightsInternal[PawnStructure]);
Weights[PassedPawns] = weight_option("Passed Pawns (Middle Game)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]);
Weights[Space] = weight_option("Space", "Space", WeightsInternal[Space]);
Weights[kingDangerUs] = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]);
Weights[kingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]);
WeightMobility = weight_option("Mobility (Middle Game)", "Mobility (Endgame)", WeightMobilityInternal);
WeightPawnStructure = weight_option("Pawn Structure (Middle Game)", "Pawn Structure (Endgame)", WeightPawnStructureInternal);
WeightPassedPawns = weight_option("Passed Pawns (Middle Game)", "Passed Pawns (Endgame)", WeightPassedPawnsInternal);
WeightSpace = weight_option("Space", "Space", WeightSpaceInternal);
WeightKingSafety[us] = weight_option("Cowardice", "Cowardice", WeightKingSafetyInternal);
WeightKingSafety[them] = weight_option("Aggressiveness", "Aggressiveness", WeightKingOppSafetyInternal);
// 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"))
Weights[kingDangerUs] = Weights[kingDangerThem] = (Weights[kingDangerUs] + Weights[kingDangerThem]) / 2;
{
WeightKingSafety[us] = (WeightKingSafety[us] + WeightKingSafety[them]) / 2;
WeightKingSafety[them] = WeightKingSafety[us];
}
init_safety();
}
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
template<PieceType Piece, Color Us>
@@ -544,7 +572,7 @@ namespace {
if (b & ei.kingZone[Us])
{
ei.kingAttackersCount[Us]++;
ei.kingAttackersWeight[Us] += KingAttackWeights[Piece];
ei.kingAttackersWeight[Us] += AttackWeight[Piece];
Bitboard bb = (b & ei.attackedBy[Them][KING]);
if (bb)
ei.kingAdjacentZoneAttacksCount[Us] += count_1s_max_15<HasPopCnt>(bb);
@@ -562,7 +590,7 @@ namespace {
ei.value -= Sign[Us] * ThreatedByPawnPenalty[Piece];
// 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);
// Special patterns: trapped bishops on a7/h7/a2/h2
@@ -690,170 +718,279 @@ namespace {
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;
int attackUnits, shelter = 0;
const Square ksq = pos.king_square(Us);
int attackUnits, count, shelter = 0;
const Square s = pos.king_square(Us);
// 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);
}
// King safety. This is quite complicated, and is almost certainly far
// from optimally tuned.
if ( pos.piece_count(Them, QUEEN) >= 1
&& ei.kingAttackersCount[Them] >= 2
&& pos.non_pawn_material(Them) >= QueenValueMidgame + RookValueMidgame
&& ei.kingAttackersCount[Them] >= 2
&& pos.non_pawn_material(Them) >= QueenValueMidgame + RookValueMidgame
&& ei.kingAdjacentZoneAttacksCount[Them])
{
// Is it the attackers turn to move?
sente = (Them == pos.side_to_move());
// Is it the attackers turn to move?
sente = (Them == pos.side_to_move());
// Find the attacked squares around the king which has no defenders
// apart from the king itself
undefended = ei.attacked_by(Them) & ei.attacked_by(Us, KING);
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, QUEEN));
// Find the attacked squares around the king which has no defenders
// apart from the king itself
undefended = ei.attacked_by(Them) & ei.attacked_by(Us, KING);
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, QUEEN));
// Initialize the 'attackUnits' variable, which is used later on as an
// index to the KingDangerTable[] array. The initial value is based on
// the number and types of the enemy's attacking pieces, the number of
// attacked and undefended squares around our king, the square of the
// king, and the quality of the pawn shelter.
attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15<HasPopCnt>(undefended))
+ InitKingDanger[relative_square(Us, ksq)]
- shelter / 32;
// Initialize the 'attackUnits' variable, which is used later on as an
// index to the SafetyTable[] array. The initial value is based on the
// number and types of the attacking pieces, the number of attacked and
// undefended squares around the king, the square of the king, and the
// quality of the pawn shelter.
attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15<HasPopCnt>(undefended))
+ InitKingDanger[relative_square(Us, s)]
- (shelter >> 5);
// Analyse enemy's safe queen contact checks. First find undefended
// squares around the king attacked by enemy queen...
b = undefended & ei.attacked_by(Them, QUEEN) & ~pos.pieces_of_color(Them);
// Analyse safe queen contact checks
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)
{
// ...then remove squares not supported by another enemy piece
b &= ( ei.attacked_by(Them, PAWN) | ei.attacked_by(Them, KNIGHT)
| ei.attacked_by(Them, BISHOP) | ei.attacked_by(Them, ROOK));
if (b)
attackUnits += QueenContactCheckBonus * count_1s_max_15<HasPopCnt>(b) * (sente ? 2 : 1);
// The bitboard b now contains the squares available for safe queen
// contact checks.
count = count_1s_max_15<HasPopCnt>(b);
attackUnits += QueenContactCheckBonus * count * (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
safe = ~(pos.pieces_of_color(Them) | ei.attacked_by(Us));
// Analyse safe distance checks
safe = ~(pos.pieces_of_color(Them) | ei.attacked_by(Us));
b1 = pos.attacks_from<ROOK>(ksq) & safe;
b2 = pos.attacks_from<BISHOP>(ksq) & safe;
if (QueenCheckBonus > 0 || RookCheckBonus > 0)
{
b = pos.attacks_from<ROOK>(s) & safe;
// Enemy queen safe checks
b = (b1 | b2) & ei.attacked_by(Them, QUEEN);
if (b)
attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b);
// Queen checks
b2 = b & ei.attacked_by(Them, QUEEN);
if (b2)
attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b2);
// Enemy rooks safe checks
b = b1 & ei.attacked_by(Them, ROOK);
if (b)
attackUnits += RookCheckBonus * count_1s_max_15<HasPopCnt>(b);
// Rook checks
b2 = b & ei.attacked_by(Them, ROOK);
if (b2)
attackUnits += RookCheckBonus * count_1s_max_15<HasPopCnt>(b2);
}
if (QueenCheckBonus > 0 || BishopCheckBonus > 0)
{
b = pos.attacks_from<BISHOP>(s) & safe;
// Enemy bishops safe checks
b = b2 & ei.attacked_by(Them, BISHOP);
if (b)
attackUnits += BishopCheckBonus * count_1s_max_15<HasPopCnt>(b);
// Queen checks
b2 = b & ei.attacked_by(Them, QUEEN);
if (b2)
attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b2);
// Enemy knights safe checks
b = pos.attacks_from<KNIGHT>(ksq) & ei.attacked_by(Them, KNIGHT) & safe;
if (b)
attackUnits += KnightCheckBonus * count_1s_max_15<HasPopCnt>(b);
// Bishop checks
b2 = b & ei.attacked_by(Them, BISHOP);
if (b2)
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
attackUnits = Min(99, Max(0, attackUnits));
// Knight checks
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[]
// array and subtract the score from evaluation. Set also ei.kingDanger[]
// value that will be used for pruning because this value can sometimes
// 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.
ei.value -= Sign[Us] * KingDangerTable[Us][attackUnits];
ei.kingDanger[Us] = mg_value(KingDangerTable[Us][attackUnits]);
// Analyse discovered checks (only for non-pawns right now, consider
// adding pawns later).
if (DiscoveredCheckBonus)
{
b = pos.discovered_check_candidates(Them) & ~pos.pieces(PAWN);
if (b)
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>
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);
Bitboard squaresToQueen, defendedSquares, unsafeSquares, supportingPawns;
Bitboard b = ei.pi->passed_pawns() & pos.pieces_of_color(Us);
Bitboard b2, b3, b4;
Square ourKingSq = pos.king_square(Us);
Square theirKingSq = pos.king_square(Them);
Bitboard b = ei.pi->passed_pawns() & pos.pieces(PAWN, Us);
while (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));
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
Value mbonus = Value(20 * tr);
Value ebonus = Value(10 + r * r * 10);
// Adjust bonus based on king proximity
if (tr)
{
Square blockSq = s + pawn_push(Us);
// Adjust bonus based on kings proximity
ebonus -= Value(square_distance(pos.king_square(Us), blockSq) * 3 * tr);
ebonus -= Value(square_distance(pos.king_square(Us), blockSq + pawn_push(Us)) * 1 * tr);
ebonus += Value(square_distance(pos.king_square(Them), blockSq) * 6 * tr);
ebonus -= Value(square_distance(ourKingSq, blockSq) * 3 * tr);
ebonus -= Value(square_distance(ourKingSq, blockSq + pawn_push(Us)) * 1 * tr);
ebonus += Value(square_distance(theirKingSq, blockSq) * 6 * tr);
// If the pawn is free to advance, increase bonus
if (pos.square_is_empty(blockSq))
{
squaresToQueen = squares_in_front_of(Us, s);
defendedSquares = squaresToQueen & ei.attacked_by(Us);
// There are no enemy pawns in the pawn's path
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,
// add all X-ray attacks by the rook or queen. Otherwise consider only
// the squares in the pawn's path attacked or occupied by the enemy.
// add all X-ray attacks by the rook or queen.
if ( (squares_behind(Us, s) & pos.pieces(ROOK, QUEEN, Them))
&& (squares_behind(Us, s) & pos.pieces(ROOK, QUEEN, Them) & pos.attacks_from<QUEEN>(s)))
unsafeSquares = squaresToQueen;
else
unsafeSquares = squaresToQueen & (ei.attacked_by(Them) | pos.pieces_of_color(Them));
b3 = b2;
// If there aren't enemy attacks or pieces along the path to queen give
// huge bonus. Even bigger if we protect the pawn's path.
if (!unsafeSquares)
ebonus += Value(tr * (squaresToQueen == defendedSquares ? 17 : 15));
// Are any of the squares in the pawn's path attacked or occupied by the enemy?
if (b3 == EmptyBoardBB)
// No enemy attacks or pieces, huge bonus!
// Even bigger if we protect the pawn's path
ebonus += Value(tr * (b2 == b4 ? 17 : 15));
else
// OK, there are enemy attacks or pieces (but not pawns). Are those
// 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 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
// in the pawn's path.
if (!(squaresToQueen & pos.pieces_of_color(Us)))
if ((b2 & pos.pieces_of_color(Us)) == EmptyBoardBB)
ebonus += Value(tr);
}
} // tr != 0
// Increase the bonus if the passed pawn is supported by a friendly pawn
// on the same rank and a bit smaller if it's on the previous rank.
supportingPawns = pos.pieces(PAWN, Us) & neighboring_files_bb(s);
if (supportingPawns & rank_bb(s))
// If the pawn is supported by a friendly pawn, increase bonus
b2 = pos.pieces(PAWN, Us) & neighboring_files_bb(s);
if (b2 & rank_bb(s))
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);
// 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
// sometimes better than other passed pawns. It is difficult to find
// good rules for determining whether they are good or bad. For now,
@@ -869,54 +1006,23 @@ namespace {
ebonus -= ebonus / 4;
}
// 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]);
// Add the scores for this pawn to the middle game and endgame eval.
ei.value += Sign[Us] * apply_weight(make_score(mbonus, ebonus), WeightPassedPawns);
} // 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};
Square pawnToGo[2] = {SQ_NONE, SQ_NONE};
for (Color c = WHITE; c <= BLACK; c++)
{
// Skip evaluation if other side has non-pawn pieces
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;
}
}
}
}
// Evaluate pawns for each color
evaluate_passed_pawns_of_color<WHITE>(pos, movesToGo, pawnToGo, ei);
evaluate_passed_pawns_of_color<BLACK>(pos, movesToGo, pawnToGo, ei);
// Neither side has an unstoppable passed pawn?
if (!(movesToGo[WHITE] | movesToGo[BLACK]))
@@ -1039,24 +1145,29 @@ namespace {
// twice. Finally, the space bonus is scaled by a weight taken from the
// material hash table.
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);
// 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
// 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 behind = pos.pieces(PAWN, Us);
behind |= (Us == WHITE ? behind >> 8 : behind << 8);
behind |= (Us == WHITE ? behind >> 16 : behind << 16);
Bitboard safeSquares = SpaceMask[Us]
& ~pos.pieces(PAWN, Us)
& ~ei.attacked_by(Them, PAWN)
& ~(~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) {
// Scale option value from 100 to 256
int mg = get_option_value_int(mgOpt) * 256 / 100;
int eg = get_option_value_int(egOpt) * 256 / 100;
Score uciWeight = make_score(get_option_value_int(mgOpt), get_option_value_int(egOpt));
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
// parameters. It is called from read_weights().
// parameters. It is called from read_weights().
void init_safety() {
const Value MaxSlope = Value(30);
const Value Peak = Value(1280);
Value t[100];
QueenContactCheckBonus = get_option_value_int("Queen Contact Check Bonus");
QueenCheckBonus = get_option_value_int("Queen Check Bonus");
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++)
{
t[i] = Value(int(0.4 * i * i));
if (i > 0)
t[i] = Min(t[i], t[i - 1] + MaxSlope);
t[i] = Min(t[i], Peak);
if (i < b)
SafetyTable[i] = Value(0);
else if (quad)
SafetyTable[i] = Value((int)(a * (i - b) * (i - b)));
else if (linear)
SafetyTable[i] = Value((int)(100 * a * (i - b)));
}
// Then apply the weights and get the final KingDangerTable[] array
for (Color c = WHITE; c <= BLACK; c++)
for (int i = 0; i < 100; i++)
KingDangerTable[c][i] = apply_weight(make_score(t[i], 0), Weights[KingDangerUs + c]);
for (int i = 0; i < 100; i++)
{
if (SafetyTable[i+1] - SafetyTable[i] > maxSlope)
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
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
it under the terms of the GNU General Public License as published by
@@ -47,8 +47,6 @@ class Position;
struct EvalInfo {
EvalInfo() { kingDanger[0] = kingDanger[1] = Value(0); }
// Middle game and endgame evaluations
Score value;
@@ -89,11 +87,15 @@ struct EvalInfo {
// 2 to kingAdjacentZoneAttacksCount[BLACK].
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;
// Value of the danger for the king of the given color
Value kingDanger[2];
// Extra futility margin. This is added to the standard futility margin
// in the quiescence search.
Value futilityMargin;
};
@@ -101,7 +103,8 @@ struct EvalInfo {
//// 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 quit_eval();
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
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
it under the terms of the GNU General Public License as published by
@@ -42,7 +42,6 @@ History::History() { clear(); }
void History::clear() {
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)
for (int i = 0; i < 16; i++)
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));
history[p][to] -= int(d) * int(d);
// Prevent history underflow
if (history[p][to] <= -HistoryMax)
for (int i = 0; i < 16; i++)
for (int j = 0; j < 64; j++)
history[i][j] /= 2;
if (history[p][to] < 0)
history[p][to] = 0;
}
@@ -95,21 +90,3 @@ int History::move_ordering_score(Piece p, Square to) const {
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
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
it under the terms of the GNU General Public License as published by
@@ -28,7 +28,6 @@
#include "depth.h"
#include "move.h"
#include "piece.h"
#include "value.h"
////
@@ -50,12 +49,9 @@ public:
void success(Piece p, Square to, Depth d);
void failure(Piece p, Square to, Depth d);
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:
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:
/// 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 effect that parts of the search tree which have been searched
/// recently have a bigger importance for move ordering than the moves which
/// have been searched a long time ago.
const int HistoryMax = 50000 * OnePly;
const int HistoryMax = 25000 * OnePly;
#endif // !defined(HISTORY_H_INCLUDED)
+2 -1
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
it under the terms of the GNU General Public License as published by
@@ -99,4 +99,5 @@ typedef CRITICAL_SECTION Lock;
#endif
#endif // !defined(LOCK_H_INCLUDED)
+16 -18
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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;
#endif
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
// Process command line arguments if any
if (argc > 1)
{
if (string(argv[1]) != "bench" || argc < 4 || argc > 8)
cout << "Usage: stockfish bench <hash size> <threads> "
@@ -79,13 +68,22 @@ int main(int argc, char *argv[]) {
else
{
string time = argc > 4 ? argv[4] : "60";
string fen = argc > 5 ? argv[5] : "default";
string lim = argc > 6 ? argv[6] : "time";
string tim = argc > 7 ? argv[7] : "";
string fen = argc > 5 ? argv[5] : "default";
string lim = argc > 6 ? argv[6] : "time";
string tim = argc > 7 ? argv[7] : "";
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;
}
+53 -53
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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 },
{ 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 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)
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;
}
else if ( pos.pieces(PAWN) == EmptyBoardBB
&& pos.pieces(ROOK) == EmptyBoardBB
else if ( pos.non_pawn_material(WHITE) == Value(0)
&& 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)
{
// 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
&& pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2)
{
mi->evaluationFunction = &EvaluateKmmKm[WHITE];
mi->evaluationFunction = &EvaluateKmmKm;
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
// material configuration. Is there a suitable scaling function?
//
// We face problems when there are several conflicting applicable
// scaling functions and we need to decide which one to use.
// The code below is rather messy, and it could easily get worse later,
// 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;
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
// distribution. Should be probed after the specialized ones.
// Note that these ones don't return after setting the function.
if (is_KBPsK<WHITE>(pos))
mi->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];
if ( pos.non_pawn_material(WHITE) == BishopValueMidgame
&& pos.piece_count(WHITE, BISHOP) == 1
&& pos.piece_count(WHITE, PAWN) >= 1)
mi->scalingFunction[WHITE] = &ScaleKBPsK;
if (is_KBPsK<BLACK>(pos))
mi->scalingFunction[BLACK] = &ScaleKBPsK[BLACK];
if ( pos.non_pawn_material(BLACK) == BishopValueMidgame
&& pos.piece_count(BLACK, BISHOP) == 1
&& pos.piece_count(BLACK, PAWN) >= 1)
mi->scalingFunction[BLACK] = &ScaleKKBPs;
if (is_KQKRPs<WHITE>(pos))
mi->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE];
if ( pos.piece_count(WHITE, PAWN) == 0
&& 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))
mi->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK];
else if ( pos.piece_count(BLACK, PAWN) == 0
&& 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.piece_count(BLACK, PAWN) == 0)
{
assert(pos.piece_count(WHITE, PAWN) >= 2);
mi->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
mi->scalingFunction[WHITE] = &ScaleKPsK;
}
else if (pos.piece_count(WHITE, PAWN) == 0)
{
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)
{
// This is a special case because we set scaling functions
// for both colors instead of only one.
mi->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
mi->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
mi->scalingFunction[WHITE] = &ScaleKPKPw;
mi->scalingFunction[BLACK] = &ScaleKPKPb;
}
}
@@ -403,7 +403,7 @@ Key EndgameFunctions::buildKey(const string& keyCode) {
s << char(upcase? toupper(keyCode[i]) : tolower(keyCode[i]));
}
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) {
+1 -1
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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)
*/
#include "types.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
const int N = 624;
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
static unsigned long mt[N]; /* the array for the state vector */
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
unsigned long mt[N]; // The array for the state vector
int mti = N + 1; // mti == N+1 means mt[N] is not initialized
/* initializes mt[N] with a seed */
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
void init_genrand(unsigned long s) {
/* 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 */
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;
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() {
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
}
/* generates a random number on [0,0xffffffff]-interval */
uint32_t genrand_int32(void) {
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 */
// Generate N words at one time
if (mti >= N)
{
int kk;
if (mti >= N) { /* generate N words at one time */
int kk;
if (mti == N+1) // If init_genrand() has not been called,
init_genrand(5489UL); // a default initial seed is used.
if (mti == N+1) /* if init_genrand() has not been called, */
init_genrand(5489UL); /* a default initial seed is used */
for (kk = 0; kk < N-M; kk++)
{
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
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[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
for (kk=0;kk<N-M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
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[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
// Tempering
/* Tempering */
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
return y;
}
uint64_t genrand_int64() {
uint64_t genrand_int64(void) {
uint64_t x, y;
x = genrand_int32();
y = genrand_int32();
return (x << 32) | y;
x = genrand_int32(); y = genrand_int32();
return (x<<32)|y;
}
void init_mersenne() {
unsigned long init[4] = {0x123, 0x234, 0x345, 0x456};
unsigned long length = 4;
void init_mersenne(void) {
unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
init_by_array(init, length);
}
+4 -4
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
it under the terms of the GNU General Public License as published by
@@ -32,9 +32,9 @@
//// Prototypes
////
extern uint32_t genrand_int32();
extern uint64_t genrand_int64();
extern void init_mersenne();
extern uint32_t genrand_int32(void);
extern uint64_t genrand_int64(void);
extern void init_mersenne(void);
#endif // !defined(MERSENNE_H_INCLUDED)
+5 -44
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
it under the terms of the GNU General Public License as published by
@@ -27,9 +27,6 @@
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
# if defined(__hpux)
# include <sys/pstat.h>
# endif
#else
@@ -39,10 +36,6 @@
#endif
#if !defined(NO_PREFETCH)
# include <xmmintrin.h>
#endif
#include <cassert>
#include <cstdio>
#include <iomanip>
@@ -51,14 +44,13 @@
#include "bitcount.h"
#include "misc.h"
#include "thread.h"
using namespace std;
/// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number.
static const string EngineVersion = "1.8 beta 1";
static const string EngineVersion = "1.6.3";
static const string AppName = "Stockfish";
static const string AppTag = "";
@@ -151,7 +143,7 @@ const string engine_name() {
const string cpu64(CpuHas64BitPath ? " 64bit" : "");
if (!EngineVersion.empty())
return AppName + " " + EngineVersion + cpu64;
return AppName+ " " + EngineVersion + cpu64;
string date(__DATE__); // From compiler, format is "Sep 21 2008"
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)
int cpu_count() {
return Min(sysconf(_SC_NPROCESSORS_ONLN), MAX_THREADS);
}
# 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);
return Min(sysconf(_SC_NPROCESSORS_ONLN), 8);
}
# else
int cpu_count() {
@@ -214,7 +198,7 @@ int cpu_count() {
int cpu_count() {
SYSTEM_INFO s;
GetSystemInfo(&s);
return Min(s.dwNumberOfProcessors, MAX_THREADS);
return Min(s.dwNumberOfProcessors, 8);
}
#endif
@@ -291,27 +275,4 @@ int Bioskey()
return 0;
}
}
#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
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
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 cpu_count();
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
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
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
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
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
// positive scores from ramining then order seaprately the two sets.
// Our dedicated sort in range [firstMove, lastMove), it is well
// tuned for non-captures where we have a lot of zero scored moves.
template<typename T>
inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive)
inline void sort_moves(T* firstMove, T* lastMove)
{
T tmp;
T *p, *d;
@@ -101,11 +101,11 @@ inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive)
// Split positives vs non-positives
do {
while ((++p)->score > 0) {}
while ((++p)->score > 0);
if (p != d)
{
while (--d != p && d->score <= 0) {}
while (--d != p && d->score <= 0);
tmp = *p;
*p = *d;
@@ -114,9 +114,29 @@ inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive)
} while (p != d);
// Sort just positive scored moves, remaining only when we get there
// Sort positives
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.
+1 -5
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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)))
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
// destination squares.
switch (direction)
+1 -1
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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
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
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
/// move ordering is at the current node.
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h,
SearchStack* ss, Value beta) : pos(p), H(h) {
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
const History& h, SearchStack* ss) : pos(p), H(h) {
int searchTT = ttm;
ttMoves[0].move = ttm;
badCaptureThreshold = 0;
finished = false;
lastBadCapture = badCaptures;
pinned = p.pinned_pieces(pos.side_to_move());
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;
killers[0].move = ss->killers[0];
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())
phasePtr = EvasionsPhaseTable;
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;
}
else if (d == Depth(0))
phasePtr = QsearchWithChecksPhaseTable;
else
{
phasePtr = QsearchWithoutChecksPhaseTable;
// Skip TT move if is not a capture or a promotion, this avoids
// 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;
phasePtr += !searchTT - 1;
go_next_phase();
}
@@ -144,7 +129,7 @@ void MovePicker::go_next_phase() {
case PH_NONCAPTURES:
lastMove = generate_noncaptures(pos, moves);
score_noncaptures();
sort_moves(moves, lastMove, &lastGoodNonCapture);
sort_moves(moves, lastMove);
return;
case PH_BAD_CAPTURES:
@@ -157,7 +142,7 @@ void MovePicker::go_next_phase() {
case PH_EVASIONS:
assert(pos.is_check());
lastMove = generate_evasions(pos, moves);
score_evasions_or_checks();
score_evasions();
return;
case PH_QCAPTURES:
@@ -166,12 +151,12 @@ void MovePicker::go_next_phase() {
return;
case PH_QCHECKS:
// Perhaps we should order moves move here? FIXME
lastMove = generate_non_capture_checks(pos, moves);
score_evasions_or_checks();
return;
case PH_STOP:
lastMove = curMove + 1; // Avoids another go_next_phase() call
lastMove = curMove + 1; // hack to be friendly for get_next_move()
return;
default:
@@ -231,16 +216,16 @@ void MovePicker::score_noncaptures() {
piece = pos.piece_on(from);
hs = H.move_ordering_score(piece, to);
// Ensure history has always highest priority
// Ensure history is always preferred to pst
if (hs > 0)
hs += 10000;
hs += 1000;
// Gain table based scoring
cur->score = hs + 16 * H.gain(piece, to);
// pst based scoring
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
// destination square is not under attack, ordered by history
// value, and at the end bad-captures and non-captures with a
@@ -248,15 +233,11 @@ void MovePicker::score_evasions_or_checks() {
Move m;
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++)
{
m = cur->move;
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))
cur->score = pos.midgame_value_of_piece_on(move_to(m))
- pos.type_of_piece_on(move_from(m)) + HistoryMax;
@@ -270,8 +251,6 @@ void MovePicker::score_evasions_or_checks() {
/// are no more moves left.
/// 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.
/// 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() {
@@ -298,7 +277,7 @@ Move MovePicker::get_next_move() {
{
// Check for a non negative SEE now
int seeValue = pos.see_sign(move);
if (seeValue >= badCaptureThreshold)
if (seeValue >= 0)
return move;
// Losing capture, move it to the badCaptures[] array, note
@@ -313,19 +292,14 @@ Move MovePicker::get_next_move() {
case PH_KILLERS:
move = (curMove++)->move;
if ( move != MOVE_NONE
&& move_is_legal(pos, move, pinned)
&& move != ttMoves[0].move
&& move != ttMoves[1].move
&& move_is_legal(pos, move, pinned)
&& !pos.move_is_capture(move))
return move;
break;
case PH_NONCAPTURES:
// Sort negative scored moves only when we get there
if (curMove == lastGoodNonCapture)
insertion_sort(lastGoodNonCapture, lastMove);
move = (curMove++)->move;
if ( move != ttMoves[0].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
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
it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#include "depth.h"
#include "history.h"
#include "lock.h"
#include "position.h"
@@ -49,23 +50,25 @@ class MovePicker {
MovePicker& operator=(const MovePicker&); // silence a warning under MSVC
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(Lock& lock);
int number_of_evasions() const;
private:
void score_captures();
void score_noncaptures();
void score_evasions_or_checks();
void score_evasions();
void go_next_phase();
const Position& pos;
const History& H;
Bitboard pinned;
MoveStack ttMoves[2], killers[2];
int badCaptureThreshold, phase;
bool finished;
int phase;
const uint8_t* phasePtr;
MoveStack *curMove, *lastMove, *lastGoodNonCapture, *lastBadCapture;
MoveStack *curMove, *lastMove, *lastBadCapture;
Bitboard pinned;
MoveStack moves[256], badCaptures[64];
};
+93 -74
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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
const int16_t QStormOpenFileBonus[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 KStormOpenFileBonus[8] = { 31, 31, 18, 0, 0, 0, 0, 0 };
const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 };
// Pawn storm lever bonuses by file
const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 };
#undef S
}
@@ -108,10 +107,11 @@ namespace {
//// 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];
if (!entries)
{
@@ -122,8 +122,9 @@ PawnInfoTable::PawnInfoTable(unsigned numOfEntries) : size(numOfEntries) {
}
PawnInfoTable::~PawnInfoTable() {
/// Destructor
PawnInfoTable::~PawnInfoTable() {
delete [] entries;
}
@@ -139,11 +140,11 @@ void PawnInfo::clear() {
/// 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
/// in a hash table, so we don't have to recompute everything when the same
/// pawn structure occurs again.
/// a PawnInfo object, and returns a pointer to it. The result is also
/// stored in a hash table, so we don't have to recompute everything when
/// 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());
@@ -178,13 +179,12 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const {
template<Color Us>
Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
Bitboard theirPawns, PawnInfo* pi) const {
Bitboard b;
Bitboard theirPawns, PawnInfo* pi) {
Square s;
File f;
Rank r;
bool passed, isolated, doubled, chain, backward, candidate;
int bonus;
bool passed, isolated, doubled, opposed, chain, backward, candidate;
Score value = make_score(0, 0);
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));
// Calculate kingside and queenside pawn storm scores for both colors to be
// used when evaluating middle game positions with opposite side castling.
bonus = (f >= FILE_F ? evaluate_pawn_storm<Us, KingSide>(s, r, f, theirPawns) : 0);
pi->ksStormValue[Us] += KStormTable[relative_square(Us, s)] + bonus;
// Passed, isolated or doubled pawn?
passed = Position::pawn_is_passed(theirPawns, Us, s);
isolated = Position::pawn_is_isolated(ourPawns, s);
doubled = Position::pawn_is_doubled(ourPawns, Us, s);
bonus = (f <= FILE_C ? evaluate_pawn_storm<Us, QueenSide>(s, r, f, theirPawns) : 0);
pi->qsStormValue[Us] += QStormTable[relative_square(Us, s)] + bonus;
// We calculate kingside and queenside pawn storm
// 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.
b = rank_bb(r) | rank_bb(r + (Us == WHITE ? -1 : 1));
// Kingside pawn storms
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
// chain (but not the backward one) ?
passed = !(theirPawns & passed_pawn_mask(Us, s));
doubled = ourPawns & squares_behind(Us, s);
opposed = theirPawns & squares_in_front_of(Us, s);
isolated = !(ourPawns & neighboring_files_bb(f));
chain = ourPawns & neighboring_files_bb(f) & b;
// Queenside pawn storms
bonus = QStormTable[relative_square(Us, s)];
if (f <= FILE_C)
{
Bitboard b = outpost_mask(Us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
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_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
//
@@ -231,7 +286,7 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
// there are friendly pawns behind on neighboring files it cannot
// be backward either.
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))
backward = false;
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
// backward by looking in the forward direction on the neighboring
// 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
// 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;
}
assert(passed | opposed | (attack_span_mask(Us, s) & theirPawns));
// Test for candidate passed pawn
candidate = !(opposed | passed)
&& (b = attack_span_mask(opposite_color(Us), s + pawn_push(Us)) & ourPawns) != EmptyBoardBB
&& count_1s_max_15(b) >= count_1s_max_15(attack_span_mask(Us, s) & theirPawns);
candidate = !passed
&& !(theirPawns & file_bb(f))
&& ( 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
// 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)))
passed = false;
// Mark the pawn as passed. Pawn will be properly scored in evaluation
// because we need full attack info to evaluate passed pawns.
// Score this pawn
if (passed)
set_bit(&(pi->passedPawns), s);
// Score this pawn
if (isolated)
{
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
/// only when king square changes, about 20% of total get_king_shelter() calls.
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;
Bitboard pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq);
unsigned r = ksq & (7 << 3);
for (int i = 1, k = (c ? -8 : 8); i < 4; i++)
{
r += k;
+4 -9
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
it under the terms of the GNU General Public License as published by
@@ -64,10 +64,10 @@ private:
Key key;
Bitboard passedPawns;
Bitboard pawnAttacks[2];
Square kingSquares[2];
Score value;
int16_t ksStormValue[2], qsStormValue[2];
uint8_t halfOpenFiles[2];
Square kingSquares[2];
uint8_t kingShelters[2];
};
@@ -78,19 +78,14 @@ private:
class PawnInfoTable {
enum SideType { KingSide, QueenSide };
public:
PawnInfoTable(unsigned numOfEntries);
~PawnInfoTable();
PawnInfo* get_pawn_info(const Position& pos) const;
PawnInfo* get_pawn_info(const Position& pos);
private:
template<Color Us>
Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi) const;
template<Color Us, SideType Side>
int evaluate_pawn_storm(Square s, Rank r, File f, Bitboard theirPawns) const;
Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi);
unsigned size;
PawnInfo* entries;
+2 -2
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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) {
return PieceChars[pt + int(upcase) * 7];
return PieceChars[pt + upcase * 7];
}
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
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
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
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
it under the terms of the GNU General Public License as published by
@@ -44,9 +44,12 @@ using std::string;
//// Variables
////
int Position::castleRightsMask[64];
Key Position::zobrist[2][8][64];
Key Position::zobEp[64];
Key Position::zobCastle[16];
Key Position::zobMaterial[2][8][16];
Key Position::zobSideToMove;
Key Position::zobExclusion;
@@ -73,36 +76,12 @@ CheckInfo::CheckInfo(const Position& pos) {
checkSq[KING] = EmptyBoardBB;
}
/// Position c'tors. Here we always create a copy of the original position
/// 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 Position& pos) {
copy(pos);
}
Position::Position(const string& fen, int th) {
Position::Position(const string& 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;
if (m != MOVE_NONE)
{
Position p(*this, thread());
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--)
{
@@ -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
/// 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
/// 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>
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
/// king) pieces for the given color. Note that checkersBB bitboard must
/// be already updated.
/// king) pieces for the given color.
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
/// pieces for the given side which are candidates for giving a discovered
/// check. Contrary to pinned_pieces() here there is no need of checkersBB
/// to be already updated.
/// check.
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(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
// ones which are recalculated from scratch anyway, then switch our state
// pointer to point to the new, ready to be updated, state.
struct ReducedStateInfo {
Key pawnKey, materialKey;
int castleRights, rule50, gamePly, pliesFromNull;
int castleRights, rule50, pliesFromNull;
Square epSquare;
Score value;
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
// detect repetition draws.
history[st->gamePly++] = key;
history[gamePly] = key;
gamePly++;
// Update side to move
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((char*)TT.first_entry(key));
TT.prefetch(key);
// Move the piece
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];
}
}
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
@@ -855,6 +801,46 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
// Set capture piece
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
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
/// 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);
Square capsq = to;
// If the captured piece was a pawn, update pawn hash key,
// otherwise update non-pawn material.
if (capture == PAWN)
if (ep) // en passant ?
{
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(relative_rank(opposite_color(them), to) == RANK_6);
assert(piece_on(to) == EMPTY);
assert(piece_on(capsq) == piece_of_color_and_type(them, PAWN));
assert(to == st->epSquare);
assert(relative_rank(opposite_color(them), to) == RANK_6);
assert(piece_on(to) == EMPTY);
assert(piece_on(capsq) == piece_of_color_and_type(them, PAWN));
board[capsq] = EMPTY;
}
st->pawnKey ^= zobrist[them][PAWN][capsq];
board[capsq] = EMPTY;
}
else
st->npMaterial[them] -= piece_value_midgame(capture);
// Remove captured piece
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
st->value -= pst(them, capture, capsq);
// Update piece count
pieceCount[them][capture]--;
// If the captured piece was a pawn, update pawn hash key,
// 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
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
//
@@ -1060,6 +1045,7 @@ void Position::undo_move(Move m) {
assert(is_ok());
assert(move_is_ok(m));
gamePly--;
sideToMove = opposite_color(sideToMove);
if (move_is_castle(m))
@@ -1109,6 +1095,7 @@ void Position::undo_move(Move m) {
pieceList[us][PAWN][index[to]] = to;
}
// Put the piece back at the source square
Bitboard move_bb = make_move_bb(to, from);
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
// detect repetition draws.
history[st->gamePly++] = st->key;
history[gamePly] = st->key;
// Update the necessary information
if (st->epSquare != SQ_NONE)
st->key ^= zobEp[st->epSquare];
st->key ^= zobSideToMove;
prefetch((char*)TT.first_entry(st->key));
TT.prefetch(st->key);
sideToMove = opposite_color(sideToMove);
st->epSquare = SQ_NONE;
st->rule50++;
st->pliesFromNull = 0;
st->value += (sideToMove == WHITE) ? TempoValue : -TempoValue;
gamePly++;
}
@@ -1278,7 +1266,7 @@ void Position::undo_null_move() {
// Update the necessary information
sideToMove = opposite_color(sideToMove);
st->rule50--;
st->gamePly--;
gamePly--;
}
@@ -1307,11 +1295,11 @@ int Position::see_sign(Move m) const {
Square from = move_from(m);
Square to = move_to(m);
// Early return if SEE cannot be negative because captured piece value
// is not less then capturing one. Note that king moves always return
// here because king midgame value is set to 0.
if (midgame_value_of_piece_on(to) >= midgame_value_of_piece_on(from))
return 1;
// Early return if SEE cannot be negative because capturing piece value
// is not bigger then captured one.
if ( midgame_value_of_piece_on(from) <= midgame_value_of_piece_on(to)
&& type_of_piece_on(from) != KING)
return 1;
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
/// 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;
sideToMove = WHITE;
gamePly = 0;
initialKFile = FILE_E;
initialKRFile = FILE_H;
initialQRFile = FILE_A;
@@ -1489,7 +1491,7 @@ void Position::clear() {
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++)
{
int count = piece_count(c, pt);
for (int i = 0; i < count; i++)
result ^= zobrist[c][pt][i];
for (int i = 0; i <= count; i++)
result ^= zobMaterial[c][pt][i];
}
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,
/// repetition, or the 50 moves rule. It does not detect stalemates, this
/// must be done by the search.
// FIXME: Currently we are not handling 50 move rule correctly when in check
bool Position::is_draw() const {
@@ -1667,8 +1668,8 @@ bool Position::is_draw() const {
return true;
// Draw by repetition?
for (int i = 4, e = Min(Min(st->gamePly, st->rule50), st->pliesFromNull); i <= e; i += 2)
if (history[st->gamePly - i] == st->key)
for (int i = 2; i < Min(Min(gamePly, st->rule50), st->pliesFromNull); i += 2)
if (history[gamePly - i] == st->key)
return true;
return false;
@@ -1747,6 +1748,15 @@ void Position::init_zobrist() {
zobCastle[i] = 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();
}
@@ -1783,7 +1793,6 @@ void Position::flipped_copy(const Position& pos) {
assert(pos.is_ok());
clear();
threadID = pos.thread();
// Board
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
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
it under the terms of the GNU General Public License as published by
@@ -70,9 +70,9 @@ struct CheckInfo {
CheckInfo(const Position&);
Square ksq;
Bitboard dcCandidates;
Bitboard checkSq[8];
Square ksq;
};
/// Castle rights, encoded as bit fields
@@ -100,13 +100,13 @@ enum Phase {
struct StateInfo {
Key pawnKey, materialKey;
int castleRights, rule50, gamePly, pliesFromNull;
int castleRights, rule50, pliesFromNull;
Square epSquare;
Score value;
Value npMaterial[2];
PieceType capture;
Key key;
PieceType capture;
Bitboard checkersBB;
StateInfo* previous;
};
@@ -139,9 +139,6 @@ class Position {
friend class MaterialInfo;
friend class EndgameFunctions;
Position(); // No default or copy c'tor allowed
Position(const Position& pos);
public:
enum GamePhase {
MidGame,
@@ -149,9 +146,9 @@ public:
};
// Constructors
explicit Position(int threadID);
Position(const Position& pos, int threadID);
Position(const std::string& fen, int threadID);
Position() {}
Position(const Position& pos);
Position(const std::string& fen);
// Text input/output
void from_fen(const std::string& fen);
@@ -159,6 +156,7 @@ public:
void print(Move m = MOVE_NONE) const;
// Copying
void copy(const Position& pos);
void flipped_copy(const Position& pos);
// The piece on a given square
@@ -226,17 +224,17 @@ public:
bool move_is_passed_pawn_push(Move m) const;
bool move_attacks_square(Move m, Square s) const;
// Piece captured with previous moves
PieceType captured_piece() const;
// Information about pawns
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
bool square_is_weak(Square s, Color c) const;
// Doing and undoing moves
void detach();
void saveState();
void do_move(Move m, StateInfo& st);
void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck);
void undo_move(Move m);
@@ -274,9 +272,6 @@ public:
bool opposite_colored_bishops() 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
void reset_game_ply();
@@ -296,7 +291,7 @@ private:
void allow_ooo(Color c);
// 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 undo_castle_move(Move m);
void find_checkers();
@@ -329,17 +324,18 @@ private:
// Other info
Color sideToMove;
int gamePly;
Key history[MaxGameLength];
int castleRightsMask[64];
StateInfo startState;
File initialKFile, initialKRFile, initialQRFile;
int threadID;
StateInfo startState;
StateInfo* st;
// Static variables
static int castleRightsMask[64];
static Key zobrist[2][8][64];
static Key zobEp[64];
static Key zobCastle[16];
static Key zobMaterial[2][8][16];
static Key zobSideToMove;
static Score PieceSquareTable[16][64];
static Key zobExclusion;
@@ -414,8 +410,8 @@ inline int Position::piece_count(Color c, PieceType pt) const {
return pieceCount[c][pt];
}
inline Square Position::piece_list(Color c, PieceType pt, int idx) const {
return pieceList[c][pt][idx];
inline Square Position::piece_list(Color c, PieceType pt, int index) const {
return pieceList[c][pt][index];
}
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));
}
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 {
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 {
@@ -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));
}
inline PieceType Position::captured_piece() const {
return st->capture;
}
inline int Position::thread() const {
return threadID;
}
#endif // !defined(POSITION_H_INCLUDED)
+1 -1
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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
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
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
/// 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(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,
// promotions and en passant captures).
StateInfo st;
pos.do_move(m, st);
if (pos.is_check())
san += pos.is_mate() ? "#" : "+";
pos.undo_move(m);
Position p(pos);
p.do_move(m, st);
if (p.is_check())
san += p.is_mate()? "#" : "+";
return san;
}
@@ -299,7 +299,7 @@ const string line_to_san(const Position& pos, Move line[], int startColumn, bool
string moveStr;
size_t length = 0;
size_t maxLength = 80 - startColumn;
Position p(pos, pos.thread());
Position p(pos);
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
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
it under the terms of the GNU General Public License as published by
@@ -36,7 +36,7 @@
//// 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 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[]);
+1 -1
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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
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
it under the terms of the GNU General Public License as published by
@@ -27,7 +27,6 @@
#include "depth.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
/// search thread has its own array of SearchStack objects, indexed by the
/// current ply.
struct EvalInfo;
struct SearchStack {
Move pv[PLY_MAX_PLUS_2];
Move currentMove;
Move mateKiller;
Move threatMove;
Move excludedMove;
Move killers[KILLER_MAX];
Depth reduction;
Value eval;
bool skipNullMove;
void init();
void init(int ply);
void initKillers();
};
@@ -69,9 +64,8 @@ struct SearchStack {
//// Prototypes
////
extern void init_search();
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,
int time[], int increment[], int movesToGo, int maxDepth,
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
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
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
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
it under the terms of the GNU General Public License as published by
@@ -26,8 +26,6 @@
//// Includes
////
#include <cstring>
#include "lock.h"
#include "movepick.h"
#include "position.h"
@@ -38,8 +36,7 @@
//// Constants and variables
////
const int MAX_THREADS = 8;
const int ACTIVE_SPLIT_POINTS_MAX = 8;
const int THREAD_MAX = 8;
////
@@ -47,47 +44,35 @@ const int ACTIVE_SPLIT_POINTS_MAX = 8;
////
struct SplitPoint {
// Const data after splitPoint has been setup
SplitPoint* parent;
const Position* pos;
Depth depth;
bool pvNode, mateThreat;
Value beta;
SplitPoint *parent;
Position pos;
SearchStack sstack[THREAD_MAX][PLY_MAX_PLUS_2];
SearchStack *parentSstack;
int ply;
SearchStack sstack[MAX_THREADS][PLY_MAX_PLUS_2];
// Const pointers to shared data
MovePicker* mp;
SearchStack* parentSstack;
// Shared data
Depth depth;
volatile Value alpha, beta, bestValue, futilityValue;
Value approximateEval;
bool pvNode;
int master, slaves[THREAD_MAX];
Lock lock;
volatile Value alpha;
volatile Value bestValue;
volatile int moveCount;
volatile bool stopRequest;
volatile int slaves[MAX_THREADS];
MovePicker *mp;
volatile int moves;
volatile int cpus;
bool finished;
};
// 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 {
SplitPoint* volatile splitPoint;
SplitPoint *splitPoint;
volatile int activeSplitPoints;
uint64_t nodes;
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
};
+45 -8
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
#include <cassert>
#include <cmath>
#include <cstring>
#include <xmmintrin.h>
#include "movegen.h"
#include "tt.h"
@@ -54,6 +55,8 @@ TranspositionTable::~TranspositionTable() {
void TranspositionTable::set_size(size_t mbSize) {
assert(mbSize >= 4 && mbSize <= 8192);
size_t newSize = 1024;
// 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,
/// a value, a value type, a search depth, and a best move to the
/// 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
/// 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;
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
{
// 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)
m = tte->move();
tte->save(posKey32, v, t, d, m, generation, statV, kingD);
*tte = TTEntry(posKey32, v, t, d, m, generation);
return;
}
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)
replace = tte;
}
replace->save(posKey32, v, t, d, m, generation, statV, kingD);
*replace = TTEntry(posKey32, v, t, d, m, generation);
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
/// search. It increments the "generation" variable, which is used to
/// 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[]) {
StateInfo st;
Position p(pos, pos.thread());
Position p(pos);
for (int i = 0; pv[i] != MOVE_NONE; i++)
{
TTEntry *tte = retrieve(p.get_key());
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);
}
}
@@ -189,7 +226,7 @@ void TranspositionTable::extract_pv(const Position& pos, Move pv[], const int PL
const TTEntry* tte;
StateInfo st;
Position p(pos, pos.thread());
Position p(pos);
int ply = 0;
// 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
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
it under the terms of the GNU General Public License as published by
@@ -53,45 +53,36 @@
class TTEntry {
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;
data = (m & 0x1FFFF) | (t << 20) | (g << 23);
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); }
uint32_t key() const { return key_; }
Depth depth() const { return Depth(depth_); }
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); }
int generation() const { return data >> 23; }
Value static_value() const { return Value(staticValue); }
Value king_danger() const { return Value(kingDanger); }
int generation() const { return (data >> 23); }
private:
uint32_t key32;
uint32_t key_;
uint32_t data;
int16_t value16;
int16_t depth16;
int16_t staticValue;
int16_t kingDanger;
int16_t value_;
int16_t depth_;
};
/// 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
/// that is indexed by a single position key. TTCluster size must
/// be not bigger then a cache line size, in case it is less then
/// it should be padded to guarantee always aligned accesses.
/// that is indexed by a single position key. Cluster is padded
/// to a cache line size so to guarantee always aligned accesses.
struct TTCluster {
TTEntry data[ClusterSize];
char cache_line_padding[64 - sizeof(TTEntry[ClusterSize])];
};
@@ -106,15 +97,17 @@ public:
~TranspositionTable();
void set_size(size_t mbSize);
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;
void prefetch(const Key posKey) const;
void new_search();
void insert_pv(const Position& pos, Move pv[]);
void extract_pv(const Position& pos, Move pv[], const int PLY_MAX);
int full() const;
TTEntry* first_entry(const Key posKey) const;
private:
inline TTEntry* first_entry(const Key posKey) const;
// Be sure 'writes' is at least one cache line away
// from read only variables.
unsigned char pad_before[64 - sizeof(unsigned)];
@@ -128,14 +121,4 @@ private:
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)
+9 -45
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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.
//// To get started type "make help".
////
//// For windows part of the configuration is detected automatically, but
//// 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.
// Quiet a warning on Intel compiler
#if !defined(__SIZEOF_INT__ )
#define __SIZEOF_INT__ 0
#endif
// Automatic detection for 64-bit under Windows
#if defined(_WIN64)
// Check for 64 bits for different compilers: Intel, MSVC and gcc
#if defined(__x86_64) || defined(_M_X64) || defined(_WIN64) || (__SIZEOF_INT__ > 4)
#define IS_64BIT
#endif
// Automatic detection for use of bsfq asm-instruction under Windows.
// Works only in 64-bit mode. Does not work with MSVC.
#if defined(_WIN64) && defined(__INTEL_COMPILER)
#if defined(IS_64BIT) && (defined(__GNUC__) || defined(__INTEL_COMPILER))
#define USE_BSFQ
#endif
@@ -85,28 +73,4 @@ typedef uint64_t Bitboard;
#define CACHE_LINE_ALIGNMENT __attribute__ ((aligned(64)))
#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)
+6 -6
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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)
// sends the "position" UCI command. The root position is sent to the think()
// function when the program receives the "go" command.
Position RootPosition(0);
Position RootPosition;
// Local functions
bool handle_command(const string& command);
@@ -143,7 +143,7 @@ namespace {
RootPosition.print();
else if (token == "flip")
{
Position p(RootPosition, RootPosition.thread());
Position p(RootPosition);
RootPosition.flipped_copy(p);
}
else if (token == "eval")
@@ -151,7 +151,7 @@ namespace {
EvalInfo ei;
cout << "Incremental mg: " << mg_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")
cout << "key: " << hex << RootPosition.get_key()
@@ -210,7 +210,7 @@ namespace {
}
// Our StateInfo st is about going out of scope so copy
// its content inside RootPosition before they disappear.
RootPosition.detach();
RootPosition.saveState();
}
}
}
@@ -308,7 +308,7 @@ namespace {
string token;
int depth, tm, n;
Position pos(RootPosition, RootPosition.thread());
Position pos = RootPosition;
if (!(uip >> depth))
return;
+1 -1
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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
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
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["Search Log Filename"] = Option("SearchLog.txt");
o["Book File"] = Option("book.bin");
o["Best Book Move"] = Option(false);
o["Mobility (Middle Game)"] = Option(100, 0, 200);
o["Mobility (Endgame)"] = 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["Aggressiveness"] = 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 (non-PV nodes)"] = Option(1, 0, 2);
o["Single Evasion Extension (PV nodes)"] = Option(2, 0, 2);
o["Single Evasion Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Mate Threat Extension (PV nodes)"] = Option(2, 0, 2);
o["Mate Threat Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Single Reply Extension (PV nodes)"] = Option(2, 0, 2);
o["Single Reply Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Mate Threat Extension (PV nodes)"] = Option(0, 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 (non-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["Pawn Endgame Extension (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["Minimum Split Depth"] = Option(4, 4, 7);
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["Clear Hash"] = Option(false, BUTTON);
o["New Game"] = Option(false, BUTTON);
o["Ponder"] = Option(true);
o["OwnBook"] = Option(true);
o["MultiPV"] = Option(1, 1, 500);
o["UCI_ShowCurrLine"] = Option(false);
o["UCI_Chess960"] = Option(false);
o["UCI_AnalyseMode"] = Option(false);
@@ -317,7 +336,7 @@ void push_button(const string& buttonName) {
bool button_was_pressed(const string& buttonName) {
if (!get_option_value<bool>(buttonName))
return false;
return false;
set_option_value(buttonName, "false");
return true;
+1 -1
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
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
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
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
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
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
it under the terms of the GNU General Public License as published by
@@ -33,10 +33,13 @@
////
enum ValueType {
VALUE_TYPE_NONE = 0,
VALUE_TYPE_NONE = 0,
VALUE_TYPE_UPPER = 1, // Upper 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
};