/*
Texel - A UCI chess engine.
Copyright (C) 2012-2014 Peter Ă–sterlund, peterosterlund2@gmail.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/>.
*/
/*
* evaluate.hpp
*
* Created on: Feb 25, 2012
* Author: petero
*/
#ifndef EVALUATE_HPP_
#define EVALUATE_HPP_
#include "parameters.hpp"
#include "piece.hpp"
#include "position.hpp"
#include "util/alignedAlloc.hpp"
class EvaluateTest;
/** Position evaluation routines. */
class Evaluate {
friend class EvaluateTest;
private:
struct PawnHashData {
PawnHashData();
U64 key;
S16 current; // For hash replacement policy
S16 score; // Positive score means good for white
S16 passedBonusW;
S16 passedBonusB;
U64 passedPawns; // The most advanced passed pawns for each file
// Contains both white and black pawns
U64 outPostsW; // Possible outpost squares for white
U64 outPostsB;
U64 stalePawns; // Pawns that can not be used for "pawn breaks"
};
struct MaterialHashData {
MaterialHashData();
int id;
int score;
S16 wPawnIPF, bPawnIPF;
S16 wKnightIPF, bKnightIPF;
S16 castleIPF, queenIPF;
S16 wPassedPawnIPF, bPassedPawnIPF;
S16 kingSafetyIPF;
S16 diffColorBishopIPF;
S16 wKnightOutPostIPF, bKnightOutPostIPF;
U8 endGame;
};
struct KingSafetyHashData {
KingSafetyHashData();
U64 key;
int score;
S16 current; // For hash replacement policy
};
public:
struct EvalHashTables {
EvalHashTables();
std::vector<PawnHashData> pawnHash;
std::vector<MaterialHashData> materialHash;
vector_aligned<KingSafetyHashData> kingSafetyHash;
};
/** Constructor. */
Evaluate(EvalHashTables& et);
static int pieceValueOrder[Piece::nPieceTypes];
static const int* psTab1[Piece::nPieceTypes];
static const int* psTab2[Piece::nPieceTypes];
/** Get evaluation hash tables. */
static std::shared_ptr<EvalHashTables> getEvalHashTables();
/**
* Static evaluation of a position.
* @param pos The position to evaluate.
* @return The evaluation score, measured in centipawns.
* Positive values are good for the side to make the next move.
*/
int evalPos(const Position& pos);
int evalPosPrint(const Position& pos);
/** Compute "swindle" score corresponding to an evaluation score when
* the position is a known TB draw. */
static int swindleScore(int evalScore);
/**
* Interpolate between (x1,y1) and (x2,y2).
* If x < x1, return y1, if x > x2 return y2. Otherwise, use linear interpolation.
*/
static int interpolate(int x, int x1, int y1, int x2, int y2);
static const int IPOLMAX = 1024;
/** Compute v1 + (v2-v1)*k/IPOLMAX */
static int interpolate(int v1, int v2, int k);
static void staticInitialize();
static void updateEvalParams();
private:
template <bool print> int evalPos(const Position& pos);
/** Compute score based on piece square tables. Positive values are good for white. */
int pieceSquareEval(const Position& pos);
/** Get material score */
int materialScore(const Position& pos, bool print);
/** Compute material score. */
void computeMaterialScore(const Position& pos, MaterialHashData& mhd, bool print) const;
/** Implement the "when ahead trade pieces, when behind trade pawns" rule. */
int tradeBonus(const Position& pos, int wCorr, int bCorr) const;
/** Score castling ability. */
int castleBonus(const Position& pos);
PawnHashData& getPawnHashEntry(std::vector<PawnHashData>& pawnHash, U64 key);
int pawnBonus(const Position& pos);
/** Compute set of pawns that can not participate in "pawn breaks". */
static U64 computeStalePawns(const Position& pos);
/** Compute pawn hash data for pos. */
void computePawnHashData(const Position& pos, PawnHashData& ph);
/** Compute rook bonus. Rook on open/half-open file. */
int rookBonus(const Position& pos);
/** Compute bishop evaluation. */
int bishopEval(const Position& pos, int oldScore);
/** Compute knight evaluation. */
int knightEval(const Position& pos);
/** Bonus for threatening opponent pieces. */
int threatBonus(const Position& pos);
/** Bonus for own pieces protected by pawns. */
int protectBonus(const Position& pos);
/** Compute king safety for both kings. */
int kingSafety(const Position& pos);
KingSafetyHashData& getKingSafetyHashEntry(vector_aligned<KingSafetyHashData>& ksHash, U64 key);
int kingSafetyKPPart(const Position& pos);
static int castleMaskFactor[256];
static int knightMobScoreA[64][9];
static U64 knightKingProtectPattern[64];
static U64 bishopKingProtectPattern[64];
std::vector<PawnHashData>& pawnHash;
const PawnHashData* phd;
std::vector<MaterialHashData>& materialHash;
const MaterialHashData* mhd;
vector_aligned<KingSafetyHashData>& kingSafetyHash;
// King safety variables
U64 wKingZone, bKingZone; // Squares close to king that are worth attacking
int wKingAttacks, bKingAttacks; // Number of attacks close to white/black king
U64 wAttacksBB, bAttacksBB;
U64 wPawnAttacks, bPawnAttacks; // Squares attacked by white/black pawns
};
inline
Evaluate::PawnHashData::PawnHashData()
: key((U64)-1), // Non-zero to avoid collision for positions with no pawns
current(0), score(0),
passedBonusW(0),
passedBonusB(0),
passedPawns(0) {
}
inline
Evaluate::MaterialHashData::MaterialHashData()
: id(-1), score(0) {
}
inline
Evaluate::KingSafetyHashData::KingSafetyHashData()
: key((U64)-1), score(0), current(0) {
}
inline
Evaluate::EvalHashTables::EvalHashTables() {
pawnHash.resize(1<<16);
kingSafetyHash.resize(1 << 15);
materialHash.resize(1 << 14);
}
inline int
Evaluate::interpolate(int x, int x1, int y1, int x2, int y2) {
if (x > x2) {
return y2;
} else if (x < x1) {
return y1;
} else {
return (x - x1) * (y2 - y1) / (x2 - x1) + y1;
}
}
inline int
Evaluate::interpolate(int v1, int v2, int k) {
return v1 + (v2 - v1) * k / IPOLMAX;
}
inline int
Evaluate::materialScore(const Position& pos, bool print) {
int mId = pos.materialId();
int key = (mId >> 16) * 40507 + mId;
MaterialHashData& newMhd = materialHash[key & (materialHash.size() - 1)];
if ((newMhd.id != mId) || print)
computeMaterialScore(pos, newMhd, print);
mhd = &newMhd;
return newMhd.score;
}
inline Evaluate::PawnHashData&
Evaluate::getPawnHashEntry(std::vector<Evaluate::PawnHashData>& pawnHash, U64 key) {
int e0 = (int)key & (pawnHash.size() - 2);
int e1 = e0 + 1;
if (pawnHash[e0].key == key) {
pawnHash[e0].current = 1;
pawnHash[e1].current = 0;
return pawnHash[e0];
}
if (pawnHash[e1].key == key) {
pawnHash[e1].current = 1;
pawnHash[e0].current = 0;
return pawnHash[e1];
}
if (pawnHash[e0].current) {
pawnHash[e1].current = 1;
pawnHash[e0].current = 0;
return pawnHash[e1];
} else {
pawnHash[e0].current = 1;
pawnHash[e1].current = 0;
return pawnHash[e0];
}
}
inline Evaluate::KingSafetyHashData&
Evaluate::getKingSafetyHashEntry(vector_aligned<Evaluate::KingSafetyHashData>& ksHash, U64 key) {
int e0 = (int)key & (ksHash.size() - 2);
int e1 = e0 + 1;
if (ksHash[e0].key == key) {
ksHash[e0].current = 1;
ksHash[e1].current = 0;
return ksHash[e0];
}
if (ksHash[e1].key == key) {
ksHash[e1].current = 1;
ksHash[e0].current = 0;
return ksHash[e1];
}
if (ksHash[e0].current) {
ksHash[e1].current = 1;
ksHash[e0].current = 0;
return ksHash[e1];
} else {
ksHash[e0].current = 1;
ksHash[e1].current = 0;
return ksHash[e0];
}
}
#endif /* EVALUATE_HPP_ */