Compare commits

..

14 Commits

Author SHA1 Message Date
Marco Costalba
096351d1f5 Stockfish 2.0.1
Always same siganture: 7224363

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-04 08:24:05 +01:00
Marco Costalba
6b96e6f33d Update Readme and polyglot files
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 23:55:12 +01:00
Marco Costalba
f200f3ccd2 Another attempt at fixing Chess960
Keep the isChess960 flag inside Position so that is
copied with the Position, but esplicitly highlight the
fact that a FEN string has not enough information to detect
Chess960 in general case. To do this add a boolean argument
isChess960 to from_fen() function so to self document this
shortcoming of FEN notation.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 22:50:38 +01:00
Marco Costalba
2bb555025f Revert Chess960 fix
Will be substituted by a better next patch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 22:48:08 +01:00
Tord Romstad
d5f2e32b5c Reintroduce the old "trapped bishop in the corner" evaluation term
for Chess960 games.

After 1918 games at 30"
Mod - Orig: 1052-866 (+532,-346,=1040), Elo +33.8
2011-01-03 22:32:57 +01:00
Joona Kiiski
83d8d54216 Use simple macro to enable operators
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 22:27:17 +01:00
Marco Costalba
078354060e Workaround broken function-style cast support in HP-UX
It seems HP's ANSI C++ doesn't understand very well
standard function-style cast.

Reported by Richard Lloyd.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 11:36:32 +01:00
Marco Costalba
5973e09854 Readd SRWLOCK and Condition Variables under Windows
And set them as default.

Introduce compile switch OLD_LOCKS to allow to fallback on
compatible locks supported by Windows XP and older versions.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 10:49:33 +01:00
Marco Costalba
22ede4442c Fix Chess960 regression
Introduced by me in before 1.9 and found by Tord that says:

The 'isChess960' slot in the 'Position' class is currently
set depending on the initial files of the rooks, and not on the value
of the UCI_Chess960 parameter. This is incorrect, as there are lots of
Chess960 positions where the rooks start on the usual files. As a
consequence (unless I am missing something), Stockfish will occasionally
output castling moves as e1g1/e1c1 rather than the correct e1h1/e1a1 format
in Chess960 games. It is possible that some or even most GUIs are robust
enough to accept both notations, but I wouldn't bet on it. And in any case,
Stockfish's behavior clearly violates the protocol.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 00:41:39 +01:00
Marco Costalba
deee18c758 Another (final?) attempt at squares_delta()
This time I have removed the function alltogether !

Sorry to work above a patch of UncombedCoconut (Justin Blanchard)
but I couldn't resist ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-02 11:52:51 +01:00
Marco Costalba
0693ff178e Fix old Glaurung bug related to search logging
When we log best and ponder move to a file before to
return from think we change the position. If position is
then not resended by GUI, as for manual user input we got
an error:

justinb@malibu:~$ stockfish
Stockfish 2.0 JA 64bit by Tord Romstad, Marco Costalba, Joona Kiiski
setoption name Use Search Log value true
go depth 1
info depth 1
info depth 1 seldepth 1 multipv 1 score cp 72 time 59 nodes 20 nps 338 pv g1f3
info depth 2
info depth 2 seldepth 2 multipv 1 score cp 12 time 59 nodes 44 nps 745 pv g1f3 g8f6
info nodes 84 nps 1423 time 59
bestmove g1f3 ponder g8f6
go depth 1
info depth 1 score mate 0
info nodes 87 nps 0 time 0
bestmove (none) ponder (none)

Bug spotted and fixed by UncombedCoconut.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-02 11:22:41 +01:00
Marco Costalba
57c51dd1ef Simplify squares_delta()
And rename in ray_direction()

Patch from UncombedCoconut.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-02 10:59:08 +01:00
Marco Costalba
f902ddaa89 Fix a crash on multi-pv
Bug reported by Tobias Haspel and fixed by Joona.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 23:10:37 +01:00
Marco Costalba
24485df3df Restore development version
And set "Use Sleeping Threads" to true because it keeps
much more responsive and cool my QUAD during tests :-)

It will be reverted back before to release that's the
reason to bundle it here.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 16:19:08 +01:00
20 changed files with 135 additions and 126 deletions

View File

@@ -8,8 +8,8 @@ Chess Partner, or Fritz) in order to be used comfortably. Read the
documentation for your GUI of choice for information about how to use
Stockfish with your GUI.
This version of Stockfish supports up to 8 CPUs, but has not been
tested thoroughly with more than 2. The program tries to detect the
This version of Stockfish supports up to 16 CPUs, but has not been
tested thoroughly with more than 4. The program tries to detect the
number of CPUs on your computer and set the number of search threads
accordingly, but please be aware that the detection is not always
correct. It is therefore recommended to inspect the value of the
@@ -41,10 +41,10 @@ This distribution of Stockfish consists of the following files:
3. Opening books
----------------
This version of Stockfish has experimental support for PolyGlot opening
books. For information about how to create such books, consult the
PolyGlot documentation. The book file can be selected by setting the
UCI parameter "Book File".
This version of Stockfish has support for PolyGlot opening books.
For information about how to create such books, consult the PolyGlot
documentation. The book file can be selected by setting the UCI
parameter "Book File".
4. Compiling it yourself
@@ -64,6 +64,9 @@ On 64 bit Unix-like systems the 'bsfq' assembly instruction will be used
for bit counting. Detection is automatic at compile time, but in case you
experience compile problems you can comment out #define USE_BSFQ line in types.h
In general is recommended to run 'make help' to see a list of make targets
with corresponding descriptions.
5. Terms of use
---------------

View File

@@ -43,6 +43,10 @@ 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
Use Sleeping Threads = false
Emergency Move Horizon = 40
Emergency Base Time = 200
Emergency Move Time = 70
Minimum Thinking Time = 20

View File

@@ -125,7 +125,7 @@ void benchmark(int argc, char* argv[]) {
{
Move moves[1] = { MOVE_NONE };
int dummy[2] = { 0, 0 };
Position pos(*it, 0);
Position pos(*it, false, 0);
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (valType == "perft")
{

View File

@@ -248,7 +248,6 @@ namespace {
void init_attacks();
void init_between_bitboards();
void init_pseudo_attacks();
SquareDelta squares_delta(Square orig, Square dest);
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);
@@ -288,10 +287,10 @@ void init_bitboards() {
init_masks();
init_attacks();
init_between_bitboards();
init_sliding_attacks(RAttacks, RAttackIndex, RMask, RShift, RMult, rookDeltas);
init_sliding_attacks(BAttacks, BAttackIndex, BMask, BShift, BMult, bishopDeltas);
init_pseudo_attacks();
init_between_bitboards();
}
@@ -454,40 +453,27 @@ namespace {
return result;
}
SquareDelta squares_delta(Square orig, Square dest) {
const SquareDelta deltas[] = { DELTA_N, DELTA_NE, DELTA_E, DELTA_SE,
DELTA_S, DELTA_SW, DELTA_W, DELTA_NW };
for (int idx = 0; idx < 8; idx++)
{
Square s = orig + deltas[idx];
while (square_is_ok(s) && square_distance(s, s - deltas[idx]) == 1)
{
if (s == dest)
return deltas[idx];
s += deltas[idx];
}
}
return DELTA_NONE;
}
void init_between_bitboards() {
Square s1, s2, s3;
SquareDelta d;
int f, r;
for (s1 = SQ_A1; s1 <= SQ_H8; s1++)
for (s2 = SQ_A1; s2 <= SQ_H8; s2++)
{
BetweenBB[s1][s2] = EmptyBoardBB;
d = squares_delta(s1, s2);
if (d != DELTA_NONE)
if (bit_is_set(QueenPseudoAttacks[s1], s2))
{
f = file_distance(s1, s2);
r = rank_distance(s1, s2);
d = SquareDelta(s2 - s1) / Max(f, r);
for (s3 = s1 + d; s3 != s2; s3 += d)
set_bit(&(BetweenBB[s1][s2]), s3);
}
}
}

View File

@@ -38,7 +38,7 @@ enum SquareColor {
LIGHT
};
ENABLE_OPERATORS_ON(Color);
ENABLE_OPERATORS_ON(Color)
////

View File

@@ -38,6 +38,6 @@ enum Depth {
DEPTH_NONE = -127 * ONE_PLY
};
ENABLE_OPERATORS_ON(Depth);
ENABLE_OPERATORS_ON(Depth)
#endif // !defined(DEPTH_H_INCLUDED)

View File

@@ -168,6 +168,11 @@ namespace {
// right to castle.
const Value TrappedRookPenalty = Value(180);
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
// a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
// happen in Chess960 games.
const Score TrappedBishopA1H1Penalty = make_score(100, 100);
// The SpaceMask[Color] contains the area of the board which is considered
// by the space evaluation. In the middle game, each side is given a bonus
// based on how many squares inside this area are safe and available for
@@ -556,6 +561,28 @@ namespace {
bonus += (Piece == ROOK ? RookOn7thBonus : QueenOn7thBonus);
}
// Special extra evaluation for bishops
if (Piece == BISHOP && pos.is_chess960())
{
// An important Chess960 pattern: A cornered bishop blocked by
// a friendly pawn diagonally in front of it is a very serious
// problem, especially when that pawn is also blocked.
if (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1))
{
SquareDelta d = pawn_push(Us)
+ (square_file(s) == FILE_A ? DELTA_E : DELTA_W);
if (pos.piece_on(s + d) == piece_of_color_and_type(Us, PAWN))
{
if (!pos.square_is_empty(s + d + pawn_push(Us)))
bonus -= 2*TrappedBishopA1H1Penalty;
else if (pos.piece_on(s + 2*d) == piece_of_color_and_type(Us, PAWN))
bonus -= TrappedBishopA1H1Penalty;
else
bonus -= TrappedBishopA1H1Penalty / 2;
}
}
}
// Special extra evaluation for rooks
if (Piece == ROOK)
{

View File

@@ -44,6 +44,25 @@ typedef pthread_cond_t WaitCondition;
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
// Default fast and race free locks and condition variables
#if !defined(OLD_LOCKS)
typedef SRWLOCK Lock;
typedef CONDITION_VARIABLE WaitCondition;
# define lock_init(x) InitializeSRWLock(x)
# define lock_grab(x) AcquireSRWLockExclusive(x)
# define lock_release(x) ReleaseSRWLockExclusive(x)
# define lock_destroy(x) (x)
# define cond_destroy(x) (x)
# define cond_init(x) InitializeConditionVariable(x)
# define cond_signal(x) WakeConditionVariable(x)
# define cond_wait(x,y) SleepConditionVariableSRW(x, y, INFINITE,0)
// Fallback solution to build for Windows XP and older versions, note that
// cond_wait() is racy between lock_release() and WaitForSingleObject().
#else
typedef CRITICAL_SECTION Lock;
typedef HANDLE WaitCondition;
@@ -57,4 +76,6 @@ typedef HANDLE WaitCondition;
# define cond_wait(x,y) { lock_release(y); WaitForSingleObject(*x, INFINITE); lock_grab(y); }
#endif
#endif
#endif // !defined(LOCK_H_INCLUDED)

View File

@@ -192,7 +192,7 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
// Clear the MaterialInfo object, and set its key
memset(mi, 0, sizeof(MaterialInfo));
mi->factor[WHITE] = mi->factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
mi->factor[WHITE] = mi->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
mi->key = key;
// Store game phase
@@ -353,7 +353,7 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
}
matValue += sign * v;
}
mi->value = int16_t(matValue / 16);
mi->value = (int16_t)(matValue / 16);
return mi;
}
@@ -407,7 +407,7 @@ Key EndgameFunctions::buildKey(const string& keyCode) {
}
fen += char(8 - keyCode.length() + '0');
fen += "/8/8/8/8/8/8/8 w - -";
return Position(fen, 0).get_material_key();
return Position(fen, false, 0).get_material_key();
}
const string EndgameFunctions::swapColors(const string& keyCode) {

View File

@@ -58,7 +58,7 @@ 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 = "2.0";
static const string EngineVersion = "2.0.1";
static const string AppName = "Stockfish";
static const string AppTag = "";

View File

@@ -562,7 +562,7 @@ namespace {
if (Type == CHECK)
{
// Condider only pawn moves which give direct checks
// Consider only pawn moves which give direct checks
b1 &= pos.attacks_from<PAWN>(ksq, Them);
b2 &= pos.attacks_from<PAWN>(ksq, Them);

View File

@@ -46,8 +46,8 @@ enum Piece {
BP = 9, BN = 10, BB = 11, BR = 12, BQ = 13, BK = 14, PIECE_NONE = 16
};
ENABLE_OPERATORS_ON(PieceType);
ENABLE_OPERATORS_ON(Piece);
ENABLE_OPERATORS_ON(PieceType)
ENABLE_OPERATORS_ON(Piece)
////

View File

@@ -152,9 +152,9 @@ Position::Position(const Position& pos, int th) {
nodes = 0;
}
Position::Position(const string& fen, int th) {
Position::Position(const string& fen, bool isChess960, int th) {
from_fen(fen);
from_fen(fen, isChess960);
threadID = th;
}
@@ -175,7 +175,7 @@ void Position::detach() {
/// string. This function is not very robust - make sure that input FENs are
/// correct (this is assumed to be the responsibility of the GUI).
void Position::from_fen(const string& fen) {
void Position::from_fen(const string& fen, bool c960) {
/*
A FEN string defines a particular position using only the ASCII character set.
@@ -274,10 +274,7 @@ void Position::from_fen(const string& fen) {
castleRightsMask[make_square(initialQRFile, RANK_1)] ^= WHITE_OOO;
castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO;
isChess960 = initialKFile != FILE_E
|| initialQRFile != FILE_A
|| initialKRFile != FILE_H;
isChess960 = c960;
find_checkers();
st->key = compute_key();

View File

@@ -134,10 +134,10 @@ public:
// Constructors
Position(const Position& pos, int threadID);
Position(const std::string& fen, int threadID);
Position(const std::string& fen, bool isChess960, int threadID);
// Text input/output
void from_fen(const std::string& fen);
void from_fen(const std::string& fen, bool isChess960);
const std::string to_fen() const;
void print(Move m = MOVE_NONE) const;

View File

@@ -513,6 +513,9 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
<< move_to_san(pos, ponderMove) // Works also with MOVE_NONE
<< endl;
// Return from think() with unchanged position
pos.undo_move(bestMove);
LogFile.close();
}
@@ -903,7 +906,7 @@ namespace {
// Write PV lines to transposition table, in case the relevant entries
// have been overwritten during the search.
for (int i = 0; i < MultiPV; i++)
for (int i = 0; i < Min(MultiPV, (int)rml.size()); i++)
rml[i].insert_pv_in_tt(pos);
return alpha;

View File

@@ -68,10 +68,10 @@ enum SquareDelta {
DELTA_NW = DELTA_N + DELTA_W
};
ENABLE_OPERATORS_ON(Square);
ENABLE_OPERATORS_ON(File);
ENABLE_OPERATORS_ON(Rank);
ENABLE_OPERATORS_ON(SquareDelta);
ENABLE_OPERATORS_ON(Square)
ENABLE_OPERATORS_ON(File)
ENABLE_OPERATORS_ON(Rank)
ENABLE_OPERATORS_ON(SquareDelta)
////

View File

@@ -59,10 +59,10 @@ public:
key32 = k;
data = (m & 0x1FFFF) | (t << 21) | (g << 23);
value16 = int16_t(v);
depth16 = int16_t(d);
staticValue = int16_t(statV);
staticValueMargin = int16_t(kd);
value16 = (int16_t)v;
depth16 = (int16_t)d;
staticValue = (int16_t)statV;
staticValueMargin = (int16_t)kd;
}
void set_generation(int g) { data = move() | (type() << 21) | (g << 23); }
@@ -132,7 +132,7 @@ extern TranspositionTable TT;
inline TTEntry* TranspositionTable::first_entry(const Key posKey) const {
return entries[uint32_t(posKey) & (size - 1)].data;
return entries[((uint32_t)posKey) & (size - 1)].data;
}

View File

@@ -70,6 +70,10 @@ typedef uint64_t Bitboard;
//// -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.
////
//// -DOLD_LOCKS | By default under Windows are used the fast Slim Reader/Writer (SRW)
//// | Locks and Condition Variables: these are not supported by Windows XP
//// | and older, to compile for those platforms you should enable OLD_LOCKS.
// Automatic detection for 64-bit under Windows
#if defined(_WIN64)
@@ -113,64 +117,20 @@ inline void __cpuid(int CPUInfo[4], int)
}
#endif
// Operators used by enum types like Depth, Piece, Square and so on.
// Templetized operators used by enum types like Depth, Piece, Square and so on.
// We don't want to write the same inline for each different enum. Note that we
// pass by value to silence scaring warnings when using volatiles.
// Because these templates override common operators and are included in all the
// files, there is a possibility that the compiler silently performs some unwanted
// overrides. To avoid possible very nasty bugs the templates are disabled by default
// and must be enabled for each type on a case by case base. The enabling trick
// uses template specialization, namely we just declare following struct.
template<typename T> struct TempletizedOperator;
// Then to enable the enum type we use following macro that defines a specialization
// of TempletizedOperator for the given enum T. Here is defined typedef Not_Enabled.
// Name of typedef is chosen to produce somewhat informative compile error messages.
#define ENABLE_OPERATORS_ON(T) \
template<> struct TempletizedOperator<T> { typedef T Not_Enabled; }
// Finally we use macro OK(T) to check if type T is enabled. The macro simply
// tries to use Not_Enabled, if was not previously defined a compile error occurs.
// The check is done fully at compile time and there is zero overhead at runtime.
#define OK(T) typedef typename TempletizedOperator<T>::Not_Enabled Type
template<typename T>
inline T operator+ (const T d1, const T d2) { OK(T); return T(int(d1) + int(d2)); }
template<typename T>
inline T operator- (const T d1, const T d2) { OK(T); return T(int(d1) - int(d2)); }
template<typename T>
inline T operator* (int i, const T d) { OK(T); return T(i * int(d)); }
template<typename T>
inline T operator* (const T d, int i) { OK(T); return T(int(d) * i); }
template<typename T>
inline T operator/ (const T d, int i) { OK(T); return T(int(d) / i); }
template<typename T>
inline T operator- (const T d) { OK(T); return T(-int(d)); }
template<typename T>
inline T operator++ (T& d, int) { OK(T); d = T(int(d) + 1); return d; }
template<typename T>
inline T operator-- (T& d, int) { OK(T); d = T(int(d) - 1); return d; }
template<typename T>
inline void operator+= (T& d1, const T d2) { OK(T); d1 = d1 + d2; }
template<typename T>
inline void operator-= (T& d1, const T d2) { OK(T); d1 = d1 - d2; }
template<typename T>
inline void operator*= (T& d, int i) { OK(T); d = T(int(d) * i); }
template<typename T>
inline void operator/= (T& d, int i) { OK(T); d = T(int(d) / i); }
#undef OK
#define ENABLE_OPERATORS_ON(T) \
inline T operator+ (const T d1, const T d2) { return T(int(d1) + int(d2)); } \
inline T operator- (const T d1, const T d2) { return T(int(d1) - int(d2)); } \
inline T operator* (int i, const T d) { return T(i * int(d)); } \
inline T operator* (const T d, int i) { return T(int(d) * i); } \
inline T operator/ (const T d, int i) { return T(int(d) / i); } \
inline T operator- (const T d) { return T(-int(d)); } \
inline T operator++ (T& d, int) {d = T(int(d) + 1); return d; } \
inline T operator-- (T& d, int) { d = T(int(d) - 1); return d; } \
inline void operator+= (T& d1, const T d2) { d1 = d1 + d2; } \
inline void operator-= (T& d1, const T d2) { d1 = d1 - d2; } \
inline void operator*= (T& d, int i) { d = T(int(d) * i); } \
inline void operator/= (T& d, int i) { d = T(int(d) / i); }
#endif // !defined(TYPES_H_INCLUDED)

View File

@@ -63,7 +63,7 @@ namespace {
bool execute_uci_command(const string& cmd) {
static Position pos(StartPositionFEN, 0); // The root position
static Position pos(StartPositionFEN, false, 0); // The root position
UCIParser up(cmd);
string token;
@@ -84,7 +84,7 @@ bool execute_uci_command(const string& cmd) {
cout << "uciok" << endl;
}
else if (token == "ucinewgame")
pos.from_fen(StartPositionFEN);
pos.from_fen(StartPositionFEN, false);
else if (token == "isready")
cout << "readyok" << endl;
@@ -147,7 +147,7 @@ namespace {
if (token == "startpos")
{
pos.from_fen(StartPositionFEN);
pos.from_fen(StartPositionFEN, false);
if (!(up >> token))
return;
}
@@ -159,7 +159,7 @@ namespace {
fen += token;
fen += ' ';
}
pos.from_fen(fen);
pos.from_fen(fen, Options["UCI_Chess960"].value<bool>());
}
if (token != "moves")

View File

@@ -43,7 +43,7 @@ enum Value {
VALUE_ENSURE_SIGNED = -1
};
ENABLE_OPERATORS_ON(Value);
ENABLE_OPERATORS_ON(Value)
enum ScaleFactor {
@@ -66,9 +66,6 @@ enum Score {
SCORE_ENSURE_32_BITS_SIZE_N = -(1 << 16)
};
ENABLE_OPERATORS_ON(Score);
// Extracting the _signed_ lower and upper 16 bits it not so trivial
// because according to the standard a simple cast to short is
// implementation defined and so is a right shift of a signed integer.
@@ -91,6 +88,17 @@ inline Score operator/(Score s, int i) { return make_score(mg_value(s) / i, eg_v
// a very high risk of overflow. So user should explicitly convert to integer.
inline Score operator*(Score s1, Score s2);
// Rest of operators are standard:
inline Score operator+ (const Score d1, const Score d2) { return Score(int(d1) + int(d2)); }
inline Score operator- (const Score d1, const Score d2) { return Score(int(d1) - int(d2)); }
inline Score operator* (int i, const Score d) { return Score(i * int(d)); }
inline Score operator* (const Score d, int i) { return Score(int(d) * i); }
inline Score operator- (const Score d) { return Score(-int(d)); }
inline void operator+= (Score& d1, const Score d2) { d1 = d1 + d2; }
inline void operator-= (Score& d1, const Score d2) { d1 = d1 - d2; }
inline void operator*= (Score& d, int i) { d = Score(int(d) * i); }
inline void operator/= (Score& d, int i) { d = Score(int(d) / i); }
////
//// Inline functions