/*
Protector -- a UCI chess engine
Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _evaluation_h_
#define _evaluation_h_
#include "position.h"
#include "bitboard.h"
#include "keytable.h"
#define WHITE_BISHOP_LIGHT 0x01
#define WHITE_BISHOP_DARK 0x02
#define BLACK_BISHOP_LIGHT 0x04
#define BLACK_BISHOP_DARK 0x08
#define WHITE_BISHOP_PAIR 0x03
#define BLACK_BISHOP_PAIR 0x0C
typedef struct
{
Bitboard upwardRealm[2];
Bitboard downwardRealm[2];
Bitboard pawnAttackableSquares[2];
Bitboard pawnProtectedSquares[2];
Bitboard doubledPawns[2];
Bitboard passedPawns[2];
Bitboard candidatePawns[2];
#ifdef BONUS_TARGETS
Bitboard openingTargets[2];
Bitboard endgameTargets[2];
#endif
#ifdef BONUS_HIDDEN_PASSER
Bitboard hiddenCandidatePawns[2];
bool hasPassersOrCandidates[2];
#endif
#ifdef MALUS_SLIGHTLY_BACKWARD
Bitboard slightlyBackward[2];
#endif
Bitboard weakPawns[2];
Bitboard fixedPawns[2];
Bitboard countedSquares[2];
Bitboard unprotectedPieces[2];
Bitboard weakOutpostSquares[2];
KingAttacks *kingAttacks[2];
Bitboard kingAttackSquares[2];
#ifdef CALCULATE_TARGETS
Bitboard pieceAttacks[2];
#endif
int numAttackers[2];
int attackPoints[2];
int spaceAttackPoints[2];
int openingPoints[2], endgamePoints[2];
bool evaluateKingSafety[2];
KingSafetyHashInfo *kingsafetyHashtable;
}
EvaluationBase;
extern const int PHASE_MAX;
/**
* Calculate the weight of the non-pawn-pieces of the specified color.
*/
INLINE int getMaterialValue(const Position * position, const Color color)
{
const int VALUE_SMALL_PIECE = 300;
const int ROOK_DIFF = 500 - VALUE_SMALL_PIECE;
const int QUEEN_DIFF = 950 - VALUE_SMALL_PIECE;
const int numNonPawnPieces = numberOfNonPawnPieces(position, color) - 1;
const int numRooks = getPieceCount(position, (Piece) (ROOK | color));
const int numQueens = getPieceCount(position, (Piece) (QUEEN | color));
return numQueens * QUEEN_DIFF + numRooks * ROOK_DIFF +
numNonPawnPieces * VALUE_SMALL_PIECE +
position->numberOfPawns[color] * 100;
}
/**
* Calculate the weight of the non-pawn-pieces of the specified color.
*/
INLINE int getPieceValue(const Position * position, const Color color)
{
const int VALUE_SMALL_PIECE = 300;
const int ROOK_DIFF = 500 - VALUE_SMALL_PIECE;
const int QUEEN_DIFF = 950 - VALUE_SMALL_PIECE;
const int numNonPawnPieces = numberOfNonPawnPieces(position, color) - 1;
const int numRooks = getPieceCount(position, (Piece) (ROOK | color));
const int numQueens = getPieceCount(position, (Piece) (QUEEN | color));
return numQueens * QUEEN_DIFF + numRooks * ROOK_DIFF +
numNonPawnPieces * VALUE_SMALL_PIECE;
}
/**
* Calculate the weight of the non-pawn-pieces of the specified color.
*
* @return a value in the range [0-44]
*/
INLINE int getPieceWeight(const Position * position, const Color color)
{
const int numNonPawnPieces = numberOfNonPawnPieces(position, color) - 1;
const int numRooks = getPieceCount(position, (Piece) (ROOK | color));
const int numQueens = getPieceCount(position, (Piece) (QUEEN | color));
return 3 * numQueens + numRooks + numNonPawnPieces;
}
/**
* Calculate the value of the non-pawn-pieces of the specified color.
*
* @return a centipawn value
*/
INLINE int getOpeningPieceWeight(const Position * position, const Color color)
{
return position->openingValue[color] -
PAWN_VALUE_OPENING * position->numberOfPawns[color];
}
/**
* Calculate the phase index of the specified position.
*
* @return a value in the range [0(initial position)-256(endgame)]
*/
INLINE int phaseIndex(const Position * position)
{
const int basicPhase = max(0, PHASE_MAX -
getPieceWeight(position, WHITE) -
getPieceWeight(position, BLACK));
assert(getPieceWeight(position, WHITE) >= 0);
assert(getPieceWeight(position, WHITE) <= 44);
assert(getPieceWeight(position, BLACK) >= 0);
assert(getPieceWeight(position, BLACK) <= 44);
assert(basicPhase >= 0);
assert(basicPhase <= PHASE_MAX);
return (basicPhase * 256 + (PHASE_MAX / 2)) / PHASE_MAX;
}
INLINE bool hasBishopPair(const Position * position, const Color color)
{
const Bitboard *bishops =
&position->piecesOfType[(Piece) (BISHOP | color)];
return (bool) ((lightSquares & *bishops) != EMPTY_BITBOARD &&
(darkSquares & *bishops) != EMPTY_BITBOARD);
}
#define VALUE_TEMPO_OPENING 20
#define VALUE_TEMPO_ENDGAME 10
/**
* Calculate a rough value of the specified position,
* based on the current pst-values and the specified evaluation base.
*
* @return the value of the specified position
*/
INLINE int positionalBalance(const Position * position, EvaluationBase * base)
{
int openingValue =
(base->openingPoints[WHITE] - base->openingPoints[BLACK] +
position->openingValue[WHITE] - position->openingValue[BLACK]);
int endgameValue =
(base->endgamePoints[WHITE] - base->endgamePoints[BLACK] +
position->endgameValue[WHITE] - position->endgameValue[BLACK]);
const int pi = phaseIndex(position);
int value;
assert(pi >= 0 && pi <= 256);
if (hasBishopPair(position, WHITE))
{
openingValue += VALUE_BISHOP_PAIR_OPENING;
endgameValue += VALUE_BISHOP_PAIR_ENDGAME;
}
if (hasBishopPair(position, BLACK))
{
openingValue -= VALUE_BISHOP_PAIR_OPENING;
endgameValue -= VALUE_BISHOP_PAIR_ENDGAME;
}
if (position->activeColor == WHITE)
{
openingValue += VALUE_TEMPO_OPENING;
endgameValue += VALUE_TEMPO_ENDGAME;
}
else
{
openingValue -= VALUE_TEMPO_OPENING;
endgameValue -= VALUE_TEMPO_ENDGAME;
}
value = (openingValue * (256 - pi) + endgameValue * pi) / 256;
return (position->activeColor == WHITE ? value : -value);
}
/**
* Calculate a rough value of the specified position,
* based on the current pst-values.
*
* @return the value of the specified position
*/
INLINE int basicPositionalBalance(Position * position)
{
int openingValue =
(position->openingValue[WHITE] - position->openingValue[BLACK]);
int endgameValue =
(position->endgameValue[WHITE] - position->endgameValue[BLACK]);
const int pi = phaseIndex(position);
int value;
assert(pi >= 0 && pi <= 256);
if (hasBishopPair(position, WHITE))
{
openingValue += VALUE_BISHOP_PAIR_OPENING;
endgameValue += VALUE_BISHOP_PAIR_ENDGAME;
}
if (hasBishopPair(position, BLACK))
{
openingValue -= VALUE_BISHOP_PAIR_OPENING;
endgameValue -= VALUE_BISHOP_PAIR_ENDGAME;
}
if (position->activeColor == WHITE)
{
openingValue += VALUE_TEMPO_OPENING;
endgameValue += VALUE_TEMPO_ENDGAME;
}
else
{
openingValue -= VALUE_TEMPO_OPENING;
endgameValue -= VALUE_TEMPO_ENDGAME;
}
value = (openingValue * (256 - pi) + endgameValue * pi) / 256;
return (position->activeColor == WHITE ? value : -value);
}
/**
* Calculate the value of the specified position.
*
* @return the value of the specified position
*/
int getValue(Position * position, const int alpha, const int beta,
PawnHashInfo * pawnHashtable,
KingSafetyHashInfo * kingsafetyHashtable);
/**
* Check if the specified color can win the specified position.
*
* @return FALSE if the specified color doesn't have sufficient material
* left to win the position
*/
INLINE bool hasWinningPotential(Position * position, Color color)
{
return (bool) (position->numberOfPieces[color] > 1);
}
/**
* Check if the pawn at the specified square is a passed pawn.
*/
bool pawnIsPassed(const Position * position, const Square pawnSquare,
const Color pawnColor);
/**
* Reset the pawn hashtable.
*/
void resetPawnHashtable(void);
/**
* Flip the given position and check if it yields the same result.
*
* @return FALSE if the flipped position yields a diffent result
*/
bool flipTest(Position * position,
PawnHashInfo * pawnHashtable,
KingSafetyHashInfo * kingsafetyHashtable);
/**
* Initialize this module.
*
* @return 0 if no errors occurred.
*/
int initializeModuleEvaluation(void);
/**
* Test this module.
*
* @return 0 if all tests succeed.
*/
int testModuleEvaluation(void);
/**
* Get the king safety hash value for the given king square.
*/
INLINE Bitboard getKingPawnSafetyHashValue(const Position * position,
const Color color)
{
const int mask[2] =
{ WHITE_00 | WHITE_000 | 16, BLACK_00 | BLACK_000 | 32 };
const int index = (position->castlingRights | 48) & mask[color];
return position->pawnHashValue ^
GENERATED_KEYTABLE[color][position->king[color]] ^
GENERATED_KEYTABLE[2][index];
}
INLINE bool piecesAreBalanced(const Position * position)
{
return (bool) (getPieceCount(position, WHITE_QUEEN) ==
getPieceCount(position, BLACK_QUEEN) &&
getPieceCount(position, WHITE_ROOK) ==
getPieceCount(position, BLACK_ROOK) &&
getPieceCount(position, WHITE_BISHOP) ==
getPieceCount(position, BLACK_BISHOP) &&
getPieceCount(position, WHITE_KNIGHT) ==
getPieceCount(position, BLACK_KNIGHT));
}
INLINE int getPawnWidth(const Position * position, const Color color)
{
const Bitboard tmp = position->piecesOfType[(Piece) (PAWN | color)] |
minValue[position->king[opponent(color)]];
return getWidth(tmp);
}
INLINE int getPassedPawnWidth(const Position * position,
const EvaluationBase * base, const Color color)
{
const Bitboard tmp = base->passedPawns[color] |
minValue[position->king[opponent(color)]];
return getWidth(tmp);
}
#endif