//   GreKo chess engine
//   (c) 2002-2021 Vladimir Medvedev <vrm@bk.ru>
//   http://greko.su

#include "eval_params.h"
#include "notation.h"
#include "utils.h"

struct FeatureInfo
{
	FeatureInfo(const string& name_, size_t index_, size_t len_) :
		name(name_),
		index(index_),
		len(len_)
	{}

	string name;
	size_t index;
	size_t len;
};
vector<FeatureInfo> g_features;

vector<double> g_w;

size_t Mid_Pawn;
size_t Mid_PawnPassed;
size_t Mid_PawnDoubled;
size_t Mid_PawnIsolated;
size_t Mid_PawnBackwards;
size_t Mid_Knight;
size_t Mid_KnightMobility;
size_t Mid_KnightKingDistance;
size_t Mid_KnightStrong;
size_t Mid_Bishop;
size_t Mid_BishopMobility;
size_t Mid_BishopKingDistance;
size_t Mid_BishopStrong;
size_t Mid_Rook;
size_t Mid_RookMobility;
size_t Mid_RookKingDistance;
size_t Mid_RookOpen;
size_t Mid_RookSemiOpen;
size_t Mid_Rook7th;
size_t Mid_Queen;
size_t Mid_QueenMobility;
size_t Mid_QueenKingDistance;
size_t Mid_King;
size_t Mid_KingPawnShield;
size_t Mid_KingPawnStorm;
size_t Mid_KingExposed;
size_t Mid_PiecePairs;
size_t Mid_AttackKing;
size_t Mid_AttackStronger;
size_t Mid_Tempo;

size_t End_Pawn;
size_t End_PawnPassed;
size_t End_PawnDoubled;
size_t End_PawnIsolated;
size_t End_PawnBackwards;
size_t End_Knight;
size_t End_KnightMobility;
size_t End_KnightKingDistance;
size_t End_KnightStrong;
size_t End_Bishop;
size_t End_BishopMobility;
size_t End_BishopKingDistance;
size_t End_BishopStrong;
size_t End_Rook;
size_t End_RookMobility;
size_t End_RookKingDistance;
size_t End_RookOpen;
size_t End_RookSemiOpen;
size_t End_Rook7th;
size_t End_Queen;
size_t End_QueenMobility;
size_t End_QueenKingDistance;
size_t End_King;
size_t End_KingPawnShield;
size_t End_KingPawnStorm;
size_t End_KingExposed;
size_t End_PiecePairs;
size_t End_AttackKing;
size_t End_AttackStronger;
size_t End_Tempo;

size_t NUMBER_OF_FEATURES;
size_t maxTagLength = 0;

void InitFeatures()
{
	size_t index = 0;
	g_features.clear();

#define REGISTER_FEATURE(var, len)                            \
	var = index;                                              \
	g_features.push_back(FeatureInfo(#var, index, len));      \
	index += len;                                             \
	if (strlen(#var) > maxTagLength)                          \
	    maxTagLength = strlen(#var);

	REGISTER_FEATURE(Mid_Pawn, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_PawnPassed, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_PawnDoubled, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_PawnIsolated, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_PawnBackwards, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_Knight, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_KnightMobility, MOB_KNIGHT_SIZE)
	REGISTER_FEATURE(Mid_KnightKingDistance, DISTANCE_SIZE)
	REGISTER_FEATURE(Mid_KnightStrong, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_Bishop, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_BishopMobility, MOB_BISHOP_SIZE)
	REGISTER_FEATURE(Mid_BishopKingDistance, DISTANCE_SIZE)
	REGISTER_FEATURE(Mid_BishopStrong, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_Rook, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_RookMobility, MOB_ROOK_SIZE)
	REGISTER_FEATURE(Mid_RookKingDistance, DISTANCE_SIZE)
	REGISTER_FEATURE(Mid_RookOpen, 1)
	REGISTER_FEATURE(Mid_RookSemiOpen, 1)
	REGISTER_FEATURE(Mid_Rook7th, 1)
	REGISTER_FEATURE(Mid_Queen, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_QueenMobility, MOB_QUEEN_SIZE)
	REGISTER_FEATURE(Mid_QueenKingDistance, DISTANCE_SIZE)
	REGISTER_FEATURE(Mid_King, PSQ_SIZE + 1)
	REGISTER_FEATURE(Mid_KingPawnShield, KING_PAWN_SHIELD_SIZE)
	REGISTER_FEATURE(Mid_KingPawnStorm, KING_PAWN_STORM_SIZE)
	REGISTER_FEATURE(Mid_KingExposed, KING_EXPOSED_SIZE)
	REGISTER_FEATURE(Mid_PiecePairs, 16)
	REGISTER_FEATURE(Mid_AttackKing, 1)
	REGISTER_FEATURE(Mid_AttackStronger, 1)
	REGISTER_FEATURE(Mid_Tempo, 1)

	REGISTER_FEATURE(End_Pawn, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_PawnPassed, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_PawnDoubled, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_PawnIsolated, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_PawnBackwards, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_Knight, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_KnightMobility, MOB_KNIGHT_SIZE)
	REGISTER_FEATURE(End_KnightKingDistance, DISTANCE_SIZE)
	REGISTER_FEATURE(End_KnightStrong, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_Bishop, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_BishopMobility, MOB_BISHOP_SIZE)
	REGISTER_FEATURE(End_BishopKingDistance, DISTANCE_SIZE)
	REGISTER_FEATURE(End_BishopStrong, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_Rook, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_RookMobility, MOB_ROOK_SIZE)
	REGISTER_FEATURE(End_RookKingDistance, DISTANCE_SIZE)
	REGISTER_FEATURE(End_RookOpen, 1)
	REGISTER_FEATURE(End_RookSemiOpen, 1)
	REGISTER_FEATURE(End_Rook7th, 1)
	REGISTER_FEATURE(End_Queen, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_QueenMobility, MOB_QUEEN_SIZE)
	REGISTER_FEATURE(End_QueenKingDistance, DISTANCE_SIZE)
	REGISTER_FEATURE(End_King, PSQ_SIZE + 1)
	REGISTER_FEATURE(End_KingPawnShield, KING_PAWN_SHIELD_SIZE)
	REGISTER_FEATURE(End_KingPawnStorm, KING_PAWN_STORM_SIZE)
	REGISTER_FEATURE(End_KingExposed, KING_EXPOSED_SIZE)
	REGISTER_FEATURE(End_PiecePairs, 16)
	REGISTER_FEATURE(End_AttackKing, 1)
	REGISTER_FEATURE(End_AttackStronger, 1)
	REGISTER_FEATURE(End_Tempo, 1)

	NUMBER_OF_FEATURES = index;

#undef REGISTER_FEATURE
}
////////////////////////////////////////////////////////////////////////////////

string FeatureName(size_t index)
{
	for (size_t i = 0; i < g_features.size(); ++i)
	{
		if (g_features[i].index <= index &&
			index < g_features[i].index + g_features[i].len)
		{
			stringstream ss;
			ss << g_features[i].name <<
				"[" << index - g_features[i].index << "]";
			return ss.str();
		}
	}
	return "<unknown>";
}
////////////////////////////////////////////////////////////////////////////////

void SetDefaultWeights(vector<double>& x)
{
	x.clear();
	x.resize(NUMBER_OF_FEATURES);

#ifdef PSQ_16
#ifdef FEATURES_TABULAR
	static const double src[] =
	{
		81, -10, 0, -4, 23, 13, 17, 23, 2, 0, 55, 37, 9, 0, -6, -16, 0, 4,
		1, -3, 7, -2, -7, 5, 0, 11, 0, 55, 6, 1, -9, -22, -7, 0, -8, -9, 1,
		7, -15, 1, 0, -1, -8, 0, 0, 0, -7, 10, -2, 0, 0, -8, 14, 0, 0, -14,
		-2, -3, 0, 2, 0, 49, 0, -5, -8, -6, -5, 0, 0, -8, 11, 1, -4, -3, 8,
		12, -6, 0, 0, 1, 25, 2, -16, -9, 0, 198, 2, 9, 7, 17, 19, 20, 14, 17,
		-20, 4, 37, 24, 25, 25, 16, 15, 0, 0, -11, 31, 30, 0, 53, 0, 61, 0,
		88, 73, 23, 18, 2, 2, -3, -12, -20, 19, 0, -17, 5, 0, 0, 0, 14, 14,
		0, 0, 0, 28, 5, -11, 0, 0, 246, 3, 14, 28, 21, 28, 15, 26, 14, -11,
		-10, 42, 40, 40, 44, 36, 17, 0, 0, -27, -14, 9, 16, 17, 21, 21, 19,
		17, 27, 32, 30, 0, 24, 81, 13, 11, 0, 0, 11, 18, 0, 23, 15, -6, 0,
		6, 28, 0, -4, 0, 0, 0, 3, 12, 18, 0, 0, 0, 289, 19, 11, 18, 33, 34,
		41, 24, 24, 78, 38, 31, 0, -1, 6, 25, 41, 0, 0, -6, -4, -2, 0, 3, 4,
		14, 19, 21, 27, 21, 41, 80, 0, 73, 95, 49, 29, 13, 8, -2, -12, -6,
		79, 27, 38, 709, 92, 74, 67, 70, 72, 68, 73, 85, 88, 34, 50, 48, 65,
		78, 110, 135, 0, 0, 0, 0, 0, -7, -12, -2, -1, 10, 17, 22, 28, 36, 35,
		35, 37, 37, 36, 36, 32, 36, 39, 42, 51, 21, 1, 0, 0, 0, 177, 105, 89,
		80, 65, 46, 30, 19, 0, -33, 12, 22, -9, 0, -18, 20, 0, 0, 0, 1, -16,
		-14, 9, 22, -10, -61, -31, -26, -8, 7, 9, 17, 18, 21, 27, 42, 35, -11,
		30, 1, -27, 3, -22, -60, 0, 0, 0, 0, 14, 65, 25, 12, 6, 4, 0, 4, 0,
		3, 0, 0, -7, -28, -8, -30, -13, -43, -30, -1, 1, -1, 0, 0, 0, 84, 7,
		-9, 5, 7, 76, -12, 1, -9, -12, 89, 0, 5, 1, 0, 0, 7, 58, 18, 96, 27,
		22, 12, 0, 0, 6, 15, 0, 0, 79, 38, 7, -5, -6, -4, 0, 46, 5, 10, 0,
		0, 0, -2, 19, 3, 0, 79, 50, 15, -9, -27, -43, 0, -39, -29, 0, 0, 0,
		0, 2, 0, -5, 0, 0, -31, -47, 0, 16, 10, 0, -9, 0, -1, 0, 0, 0, 3, -11,
		9, 0, -37, -6, 0, 0, 0, 12, 0, 0, 1, -6, 1, 0, 0, 3, 0, 0, 0, 0, 0,
		-2, 1, -9, 0, 0, 173, 4, 10, 13, 16, 19, 9, 16, 11, 10, 12, 19, 24,
		24, 0, 1, 9, 0, 0, 4, 5, 22, 0, 42, 0, 52, 0, -7, 8, 34, 45, 33, 22,
		19, -17, 0, 9, -13, -6, -6, 24, 10, 4, -14, 13, 0, 1, 23, 0, -5, -1,
		0, 0, 221, 14, 21, 15, 16, 16, 21, 20, 24, 38, 37, 23, 29, 20, 17,
		7, -1, 0, 0, -39, -19, -10, 0, 9, 22, 33, 37, 50, 34, 38, 25, 0, 0,
		0, 23, 29, 31, 29, 22, 0, 0, 0, 0, 0, 3, 13, 0, 0, 0, -20, -24, 6,
		-7, 1, 0, 3, 0, 0, 361, 37, 36, 40, 33, 34, 28, 33, 31, 52, 28, 60,
		62, 54, 26, 3, -2, 0, 0, -25, -15, -2, 11, 26, 43, 34, 45, 45, 45,
		49, 39, 0, 0, 5, 0, 12, 23, 31, 42, 45, 61, 46, -13, 25, 28, 675, 58,
		67, 88, 65, 65, 88, 75, 61, 98, 126, 118, 97, 88, 64, 17, -10, 0, 0,
		0, 0, 0, 0, 0, -18, 0, -20, -29, 0, 8, 2, 18, 28, 44, 51, 63, 64, 74,
		67, 74, 51, 47, 11, 2, 2, 0, 0, 156, 173, 118, 79, 50, 8, 0, 0, 0,
		-15, -3, 4, 16, 15, 12, -1, -36, -81, 9, 23, 26, 22, 7, -3, -32, 11,
		14, 11, 1, -12, -4, -6, -7, 9, -11, -24, -3, 15, -24, -3, 38, -15,
		7, 66, -30, 0, 0, 0, 0, -34, 42, 31, 11, 14, 7, 13, 10, 0, 1, 2, 9,
		12, 0, 5, -1, 2, -1, -13, -18, -23, -46, -30, -44, 21, 0, 20, 28, 0,
		41, 19, 20, 20, 19, 76, 63, 28, 20, 63, 0, 1, 53, 12
	};
	memcpy(&(x[0]), src, NUMBER_OF_FEATURES * sizeof(double));
#endif
#endif
}
////////////////////////////////////////////////////////////////////////////////

bool ReadWeights(vector<double>& x, const string& file)
{
	x.clear();
	x.resize(NUMBER_OF_FEATURES);

	ifstream ifs(file.c_str());
	if (ifs.good())
	{
		string s;
		while (getline(ifs, s))
		{
			istringstream iss(s);
			string name;
			double value;

			if (!(iss >> name))
				continue;

			for (size_t i = 0; i < g_features.size(); ++i)
			{
				if (g_features[i].name == name)
				{
					size_t index = g_features[i].index;
					size_t offset = 0;
					while (iss >> value)
					{
						x[index + offset] = value;
						++offset;
						if (offset >= g_features[i].len)
							break;
					}
					break;
				}
			}
		}
		return true;
	}
	return false;
}
////////////////////////////////////////////////////////////////////////////////

void WriteWeights(const vector<double>& x, const string& file)
{
	ofstream ofs(file.c_str());
	if (ofs.good())
	{
		for (size_t i = 0; i < g_features.size(); ++i)
		{
			string name = g_features[i].name;
			size_t index = g_features[i].index;
			size_t len = g_features[i].len;

			ofs << setw(maxTagLength + 2) << left << name;
			for (size_t j = 0; j < len; ++j)
				ofs << " " << (int)x[index + j];
			ofs << endl;

			if (i == g_features.size() / 2 - 1)
				ofs << endl;
		}
	}
}
////////////////////////////////////////////////////////////////////////////////
