/*
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/>.
*/
/*
* parameters.hpp
*
* Created on: Feb 25, 2012
* Author: petero
*/
#ifndef PARAMETERS_HPP_
#define PARAMETERS_HPP_
#include "util/util.hpp"
#include "piece.hpp"
#include "position.hpp"
#include <memory>
#include <functional>
#include <map>
#include <string>
#include <cassert>
/** Handles all UCI parameters. */
class Parameters {
public:
enum Type {
CHECK,
SPIN,
COMBO,
BUTTON,
STRING
};
/** Observer pattern. */
class Listener {
using Func = std::function<void()>;
public:
int addListener(Func f, bool callNow = true);
void removeListener(int id);
protected:
void notify();
private:
int nextId = 0;
std::map<int, Func> listeners;
};
/** Base class for UCI parameters. */
struct ParamBase : public Listener {
std::string name;
Type type;
ParamBase(const std::string& n, Type t) : name(n), type(t) { }
ParamBase(const ParamBase& other) = delete;
ParamBase& operator=(const ParamBase& other) = delete;
virtual bool getBoolPar() const { assert(false); return false; }
virtual int getIntPar() const { assert(false); return 0; }
virtual std::string getStringPar() const { assert(false); return ""; }
virtual void set(const std::string& value) { assert(false); }
};
/** A boolean parameter. */
struct CheckParam : public ParamBase {
bool value;
bool defaultValue;
CheckParam(const std::string& name, bool def)
: ParamBase(name, CHECK) {
this->value = def;
this->defaultValue = def;
}
bool getBoolPar() const override { return value; }
void set(const std::string& value) override {
if (toLowerCase(value) == "true")
this->value = true;
else if (toLowerCase(value) == "false")
this->value = false;
notify();
}
};
/** An integer parameter. */
struct SpinParam : public ParamBase {
int minValue;
int maxValue;
int value;
int defaultValue;
SpinParam(const std::string& name, int minV, int maxV, int def)
: ParamBase(name, SPIN) {
minValue = minV;
maxValue = maxV;
value = def;
defaultValue = def;
}
int getIntPar() const override { return value; }
void set(const std::string& value) override {
int val;
if (str2Num(value, val) && (val >= minValue) && (val <= maxValue)) {
this->value = val;
notify();
}
}
int getDefaultValue() const { return defaultValue; }
int getMinValue() const { return minValue; }
int getMaxValue() const { return maxValue; }
};
/** A multi-choice parameter. */
struct ComboParam : public ParamBase {
std::vector<std::string> allowedValues;
std::string value;
std::string defaultValue;
ComboParam(const std::string& name, const std::vector<std::string>& allowed,
const std::string& def)
: ParamBase(name, COMBO) {
this->allowedValues = allowed;
this->value = def;
this->defaultValue = def;
}
std::string getStringPar() const override { return value; }
void set(const std::string& value) override {
for (size_t i = 0; i < allowedValues.size(); i++) {
const std::string& allowed = allowedValues[i];
if (toLowerCase(allowed) == toLowerCase(value)) {
this->value = allowed;
notify();
break;
}
}
}
};
/** An action parameter. */
struct ButtonParam : public ParamBase {
ButtonParam(const std::string& name)
: ParamBase(name, BUTTON) { }
void set(const std::string& value) override {
notify();
}
};
/** A string parameter. */
struct StringParam : public ParamBase {
std::string value;
std::string defaultValue;
StringParam(const std::string& name, const std::string& def)
: ParamBase(name, STRING) {
this->value = def;
this->defaultValue = def;
}
std::string getStringPar() const override { return value; }
void set(const std::string& value) override {
this->value = value;
notify();
}
};
/** Get singleton instance. */
static Parameters& instance();
/** Retrieve list of all parameters. */
void getParamNames(std::vector<std::string>& parNames);
std::shared_ptr<ParamBase> getParam(const std::string& name) const;
bool getBoolPar(const std::string& name) const;
int getIntPar(const std::string& name) const;
std::string getStringPar(const std::string& name) const;
void set(const std::string& name, const std::string& value);
/** Register a parameter. */
void addPar(const std::shared_ptr<ParamBase>& p);
private:
Parameters();
std::map<std::string, std::shared_ptr<ParamBase>> params;
std::vector<std::string> paramNames;
};
// ----------------------------------------------------------------------------
/** Param can be either a UCI parameter or a compile time constant. */
template <int defaultValue, int minValue, int maxValue, bool uci> class Param;
template <int defaultValue, int minValue, int maxValue>
class Param<defaultValue, minValue, maxValue, false> {
public:
Param() {}
operator int() const { return defaultValue; }
void registerParam(const std::string& name, Parameters& pars) {}
template <typename Func> void addListener(Func f) { f(); }
};
template <int defaultValue, int minValue, int maxValue>
class Param<defaultValue, minValue, maxValue, true> {
public:
Param() : value(0) {}
operator int() const { return value; }
void registerParam(const std::string& name, Parameters& pars) {
par = std::make_shared<Parameters::SpinParam>(name, minValue, maxValue, defaultValue);
pars.addPar(par);
par->addListener([this](){ value = par->getIntPar(); });
}
template <typename Func> void addListener(Func f) {
if (par)
par->addListener(f, false);
f();
}
private:
int value;
std::shared_ptr<Parameters::SpinParam> par;
};
#define DECLARE_PARAM(name, defV, minV, maxV, uci) \
using name##ParamType = Param<defV,minV,maxV,uci>; \
extern name##ParamType name;
#define DEFINE_PARAM(name) \
name##ParamType name;
#define REGISTER_PARAM(varName, uciName) \
varName.registerParam(uciName, *this);
// ----------------------------------------------------------------------------
/** Non-template base class to reduce executable code size. */
class ParamTableBase : public Parameters::Listener {
public:
int getMinValue() const { return minValue; }
int getMaxValue() const { return maxValue; }
protected:
ParamTableBase(bool uci0, int minVal0, int maxVal0) :
uci(uci0), minValue(minVal0), maxValue(maxVal0) {}
void registerParamsN(const std::string& name, Parameters& pars,
int* table, int* parNo, int N);
void modifiedN(int* table, int* parNo, int N);
const bool uci;
const int minValue;
const int maxValue;
std::vector<std::shared_ptr<Parameters::SpinParam>> params;
};
template <int N>
class ParamTable : public ParamTableBase {
public:
ParamTable(int minVal, int maxVal, bool uci,
std::initializer_list<int> data,
std::initializer_list<int> parNo);
int operator[](int i) const { return table[i]; }
const int* getTable() const { return table; }
void registerParams(const std::string& name, Parameters& pars) {
registerParamsN(name, pars, table, parNo, N);
}
private:
int table[N];
int parNo[N];
};
template <int N>
class ParamTableMirrored {
public:
ParamTableMirrored(ParamTable<N>& orig0) : orig(orig0) {
orig.addListener([this]() {
if (N == 64) {
for (int sq = 0; sq < N; sq++)
table[sq] = orig[Position::mirrorY(sq)];
} else {
for (int i = 0; i < N; i++)
table[i] = orig[N-1-i];
}
});
}
int operator[](int i) const { return table[i]; }
const int* getTable() const { return table; }
private:
int table[N];
ParamTable<N>& orig;
};
template <int N>
ParamTable<N>::ParamTable(int minVal0, int maxVal0, bool uci0,
std::initializer_list<int> table0,
std::initializer_list<int> parNo0)
: ParamTableBase(uci0, minVal0, maxVal0) {
assert(table0.size() == N);
assert(parNo0.size() == N);
for (int i = 0; i < N; i++) {
table[i] = table0.begin()[i];
parNo[i] = parNo0.begin()[i];
}
}
inline bool
Parameters::getBoolPar(const std::string& name) const {
return getParam(name)->getBoolPar();
}
inline int
Parameters::getIntPar(const std::string& name) const {
return getParam(name)->getIntPar();
}
inline std::string
Parameters::getStringPar(const std::string& name) const {
return getParam(name)->getStringPar();
}
inline void
Parameters::set(const std::string& name, const std::string& value) {
auto it = params.find(toLowerCase(name));
if (it == params.end())
return;
it->second->set(value);
}
// ----------------------------------------------------------------------------
// UCI parameters
namespace UciParams {
extern std::shared_ptr<Parameters::SpinParam> hash;
extern std::shared_ptr<Parameters::CheckParam> ownBook;
extern std::shared_ptr<Parameters::CheckParam> ponder;
extern std::shared_ptr<Parameters::CheckParam> analyseMode;
extern std::shared_ptr<Parameters::SpinParam> strength;
extern std::shared_ptr<Parameters::SpinParam> threads;
extern std::shared_ptr<Parameters::SpinParam> multiPV;
extern std::shared_ptr<Parameters::StringParam> gtbPath;
extern std::shared_ptr<Parameters::SpinParam> gtbCache;
extern std::shared_ptr<Parameters::StringParam> rtbPath;
extern std::shared_ptr<Parameters::SpinParam> minProbeDepth;
extern std::shared_ptr<Parameters::ButtonParam> clearHash;
}
// ----------------------------------------------------------------------------
// Tuning parameters
const bool useUciParam = false;
extern int pieceValue[Piece::nPieceTypes];
// Evaluation parameters
DECLARE_PARAM(pV, 100, 1, 200, useUciParam);
DECLARE_PARAM(nV, 385, 1, 800, useUciParam);
DECLARE_PARAM(bV, 385, 1, 800, useUciParam);
DECLARE_PARAM(rV, 597, 1, 1200, useUciParam);
DECLARE_PARAM(qV, 1215, 1, 2400, useUciParam);
DECLARE_PARAM(kV, 9900, 9900, 9900, false); // Used by SEE algorithm but not included in board material sums
DECLARE_PARAM(pawnIslandPenalty, 8, 0, 50, useUciParam);
DECLARE_PARAM(pawnBackwardPenalty, 15, 0, 50, useUciParam);
DECLARE_PARAM(pawnSemiBackwardPenalty1, 6, -50, 50, useUciParam);
DECLARE_PARAM(pawnSemiBackwardPenalty2, 2, -50, 50, useUciParam);
DECLARE_PARAM(pawnRaceBonus, 181, 0, 1000, useUciParam);
DECLARE_PARAM(passedPawnEGFactor, 63, 1, 128, useUciParam);
DECLARE_PARAM(RBehindPP1, 10, -100, 100, useUciParam);
DECLARE_PARAM(RBehindPP2, 24, -100, 100, useUciParam);
DECLARE_PARAM(QvsRMBonus1, 30, -100, 100, useUciParam);
DECLARE_PARAM(QvsRMBonus2, -8, -100, 100, useUciParam);
DECLARE_PARAM(knightVsQueenBonus1, 125, 0, 200, useUciParam);
DECLARE_PARAM(knightVsQueenBonus2, 251, 0, 600, useUciParam);
DECLARE_PARAM(knightVsQueenBonus3, 357, 0, 800, useUciParam);
DECLARE_PARAM(krkpBonus, 135, 0, 400, useUciParam);
DECLARE_PARAM(krpkbBonus, 140, -200, 200, useUciParam);
DECLARE_PARAM(krpkbPenalty, 70, 0, 128, useUciParam);
DECLARE_PARAM(krpknBonus, 259, 0, 400, useUciParam);
DECLARE_PARAM(RvsBPBonus, -38, -200, 200, useUciParam);
DECLARE_PARAM(pawnTradePenalty, 54, 0, 100, useUciParam);
DECLARE_PARAM(pieceTradeBonus, 10, 0, 100, useUciParam);
DECLARE_PARAM(pawnTradeThreshold, 361, 100, 1000, useUciParam);
DECLARE_PARAM(pieceTradeThreshold, 717, 10, 1000, useUciParam);
DECLARE_PARAM(threatBonus1, 63, 5, 500, useUciParam);
DECLARE_PARAM(threatBonus2, 1191, 100, 10000, useUciParam);
DECLARE_PARAM(rookHalfOpenBonus, 14, 0, 100, useUciParam);
DECLARE_PARAM(rookOpenBonus, 21, 0, 100, useUciParam);
DECLARE_PARAM(rookDouble7thRowBonus, 78, 0, 100, useUciParam);
DECLARE_PARAM(trappedRookPenalty1, 59, 0, 200, useUciParam);
DECLARE_PARAM(trappedRookPenalty2, 31, 0, 200, useUciParam);
DECLARE_PARAM(bishopPairPawnPenalty, 5, 0, 10, useUciParam);
DECLARE_PARAM(trappedBishopPenalty, 128, 0, 300, useUciParam);
DECLARE_PARAM(oppoBishopPenalty, 80, 0, 128, useUciParam);
DECLARE_PARAM(kingSafetyHalfOpenBCDEFG1, 18, 0, 100, useUciParam);
DECLARE_PARAM(kingSafetyHalfOpenBCDEFG2, -2, -50, 100, useUciParam);
DECLARE_PARAM(kingSafetyHalfOpenAH1, 21, 0, 100, useUciParam);
DECLARE_PARAM(kingSafetyHalfOpenAH2, 14, 0, 100, useUciParam);
DECLARE_PARAM(kingSafetyWeight1, 26, -50, 200, useUciParam);
DECLARE_PARAM(kingSafetyWeight2, -50, -50, 200, useUciParam);
DECLARE_PARAM(kingSafetyWeight3, 7, -50, 200, useUciParam);
DECLARE_PARAM(kingSafetyWeight4, 1, -50, 200, useUciParam);
DECLARE_PARAM(kingSafetyThreshold, 46, 0, 200, useUciParam);
DECLARE_PARAM(knightKingProtectBonus, 12, -50, 50, useUciParam);
DECLARE_PARAM(bishopKingProtectBonus, 15, -50, 50, useUciParam);
DECLARE_PARAM(pawnStormBonus, 12, 0, 20, useUciParam);
DECLARE_PARAM(pawnLoMtrl, 503, 0, 10000, useUciParam);
DECLARE_PARAM(pawnHiMtrl, 3205, 0, 10000, useUciParam);
DECLARE_PARAM(minorLoMtrl, 1114, 0, 10000, useUciParam);
DECLARE_PARAM(minorHiMtrl, 3743, 0, 10000, useUciParam);
DECLARE_PARAM(castleLoMtrl, 712, 0, 10000, useUciParam);
DECLARE_PARAM(castleHiMtrl, 7884, 0, 10000, useUciParam);
DECLARE_PARAM(queenLoMtrl, 4504, 0, 10000, useUciParam);
DECLARE_PARAM(queenHiMtrl, 6544, 0, 10000, useUciParam);
DECLARE_PARAM(passedPawnLoMtrl, 768, 0, 10000, useUciParam);
DECLARE_PARAM(passedPawnHiMtrl, 2511, 0, 10000, useUciParam);
DECLARE_PARAM(kingSafetyLoMtrl, 919, 0, 10000, useUciParam);
DECLARE_PARAM(kingSafetyHiMtrl, 3567, 0, 10000, useUciParam);
DECLARE_PARAM(oppoBishopLoMtrl, 752, 0, 10000, useUciParam);
DECLARE_PARAM(oppoBishopHiMtrl, 3386, 0, 10000, useUciParam);
DECLARE_PARAM(knightOutpostLoMtrl, 157, 0, 10000, useUciParam);
DECLARE_PARAM(knightOutpostHiMtrl, 539, 0, 10000, useUciParam);
extern ParamTable<64> kt1b, kt2b, pt1b, pt2b, nt1b, nt2b, bt1b, bt2b, qt1b, qt2b, rt1b;
extern ParamTableMirrored<64> kt1w, kt2w, pt1w, pt2w, nt1w, nt2w, bt1w, bt2w, qt1w, qt2w, rt1w;
extern ParamTable<64> knightOutpostBonus;
extern ParamTable<64> protectedPawnBonus, attackedPawnBonus;
extern ParamTable<4> protectBonus;
extern ParamTable<15> rookMobScore;
extern ParamTable<14> bishMobScore;
extern ParamTable<28> knightMobScore;
extern ParamTable<28> queenMobScore;
extern ParamTable<36> connectedPPBonus;
extern ParamTable<8> passedPawnBonusX, passedPawnBonusY;
extern ParamTable<10> ppBlockerBonus;
extern ParamTable<8> candidatePassedBonus;
extern ParamTable<16> majorPieceRedundancy;
extern ParamTable<5> QvsRRBonus;
extern ParamTable<7> RvsMBonus, RvsMMBonus;
extern ParamTable<4> bishopPairValue;
extern ParamTable<7> rookEGDrawFactor, RvsBPDrawFactor;
extern ParamTable<4> castleFactor;
extern ParamTable<9> pawnShelterTable, pawnStormTable;
extern ParamTable<14> kingAttackWeight;
extern ParamTable<5> kingPPSupportK;
extern ParamTable<8> kingPPSupportP;
extern ParamTable<8> pawnDoubledPenalty;
extern ParamTable<8> pawnIsolatedPenalty;
extern ParamTable<10> halfMoveFactor;
extern ParamTable<9> stalePawnFactor;
// Search parameters
DECLARE_PARAM(aspirationWindow, 15, 1, 100, useUciParam);
DECLARE_PARAM(rootLMRMoveCount, 2, 0, 100, useUciParam);
DECLARE_PARAM(razorMargin1, 86, 1, 500, useUciParam);
DECLARE_PARAM(razorMargin2, 353, 1, 1000, useUciParam);
DECLARE_PARAM(reverseFutilityMargin1, 204, 1, 1000, useUciParam);
DECLARE_PARAM(reverseFutilityMargin2, 420, 1, 1000, useUciParam);
DECLARE_PARAM(reverseFutilityMargin3, 533, 1, 2000, useUciParam);
DECLARE_PARAM(reverseFutilityMargin4, 788, 1, 3000, useUciParam);
DECLARE_PARAM(futilityMargin1, 61, 1, 500, useUciParam);
DECLARE_PARAM(futilityMargin2, 144, 1, 500, useUciParam);
DECLARE_PARAM(futilityMargin3, 268, 1, 1000, useUciParam);
DECLARE_PARAM(futilityMargin4, 334, 1, 1000, useUciParam);
DECLARE_PARAM(lmpMoveCountLimit1, 3, 1, 256, useUciParam);
DECLARE_PARAM(lmpMoveCountLimit2, 6, 1, 256, useUciParam);
DECLARE_PARAM(lmpMoveCountLimit3, 12, 1, 256, useUciParam);
DECLARE_PARAM(lmpMoveCountLimit4, 24, 1, 256, useUciParam);
DECLARE_PARAM(lmrMoveCountLimit1, 3, 1, 256, useUciParam);
DECLARE_PARAM(lmrMoveCountLimit2, 12, 1, 256, useUciParam);
DECLARE_PARAM(quiesceMaxSortMoves, 8, 0, 256, useUciParam);
DECLARE_PARAM(deltaPruningMargin, 152, 0, 1000, useUciParam);
// Time management parameters
DECLARE_PARAM(timeMaxRemainingMoves, 35, 2, 200, useUciParam);
DECLARE_PARAM(bufferTime, 1000, 1, 10000, useUciParam);
DECLARE_PARAM(minTimeUsage, 85, 1, 100, useUciParam);
DECLARE_PARAM(maxTimeUsage, 400, 100, 1000, useUciParam);
DECLARE_PARAM(timePonderHitRate, 35, 1, 100, useUciParam);
#endif /* PARAMETERS_HPP_ */