/**
 * @file eval.c
 *
 * Evaluation function.
 *
 * @date 1998 - 2024
 * @author Richard Delorme
 * @version 4.6
 */

#include "eval.h"

#include "bit.h"
#include "board.h"
#include "options.h"
#include "move.h"
#include "util.h"

#include <stdlib.h>
#include <assert.h>
#include <string.h>

/** coordinate to feature conversion */
typedef struct CoordinateToFeature {
	int n_feature;
	struct {
		uint16_t i;
		uint16_t x;
	} feature[7];
} CoordinateToFeature;

/** feature to coordinates conversion */
typedef struct FeatureToCoordinate {
	uint32_t n_square;
	uint8_t x[12];
} FeatureToCoordinate;

/** array to convert features into coordinates */
static const FeatureToCoordinate EVAL_F2X[] = {
	{ 9, {A1, B1, A2, B2, C1, A3, C2, B3, C3}},
	{ 9, {H1, G1, H2, G2, F1, H3, F2, G3, F3}},
	{ 9, {A8, A7, B8, B7, A6, C8, B6, C7, C6}},
	{ 9, {H8, H7, G8, G7, H6, F8, G6, F7, F6}},

	{10, {A5, A4, A3, A2, A1, B2, B1, C1, D1, E1}},
	{10, {H5, H4, H3, H2, H1, G2, G1, F1, E1, D1}},
	{10, {A4, A5, A6, A7, A8, B7, B8, C8, D8, E8}},
	{10, {H4, H5, H6, H7, H8, G7, G8, F8, E8, D8}},

	{10, {B2, A1, B1, C1, D1, E1, F1, G1, H1, G2}},
	{10, {B7, A8, B8, C8, D8, E8, F8, G8, H8, G7}},
	{10, {B2, A1, A2, A3, A4, A5, A6, A7, A8, B7}},
	{10, {G2, H1, H2, H3, H4, H5, H6, H7, H8, G7}},

	{10, {A1, C1, D1, C2, D2, E2, F2, E1, F1, H1}},
	{10, {A8, C8, D8, C7, D7, E7, F7, E8, F8, H8}},
	{10, {A1, A3, A4, B3, B4, B5, B6, A5, A6, A8}},
	{10, {H1, H3, H4, G3, G4, G5, G6, H5, H6, H8}},

	{ 8, {A2, B2, C2, D2, E2, F2, G2, H2}},
	{ 8, {A7, B7, C7, D7, E7, F7, G7, H7}},
	{ 8, {B1, B2, B3, B4, B5, B6, B7, B8}},
	{ 8, {G1, G2, G3, G4, G5, G6, G7, G8}},

	{ 8, {A3, B3, C3, D3, E3, F3, G3, H3}},
	{ 8, {A6, B6, C6, D6, E6, F6, G6, H6}},
	{ 8, {C1, C2, C3, C4, C5, C6, C7, C8}},
	{ 8, {F1, F2, F3, F4, F5, F6, F7, F8}},

	{ 8, {A4, B4, C4, D4, E4, F4, G4, H4}},
	{ 8, {A5, B5, C5, D5, E5, F5, G5, H5}},
	{ 8, {D1, D2, D3, D4, D5, D6, D7, D8}},
	{ 8, {E1, E2, E3, E4, E5, E6, E7, E8}},

	{ 8, {A1, B2, C3, D4, E5, F6, G7, H8}},
	{ 8, {A8, B7, C6, D5, E4, F3, G2, H1}},

	{ 7, {B1, C2, D3, E4, F5, G6, H7}},
	{ 7, {H2, G3, F4, E5, D6, C7, B8}},
	{ 7, {A2, B3, C4, D5, E6, F7, G8}},
	{ 7, {G1, F2, E3, D4, C5, B6, A7}},

	{ 6, {C1, D2, E3, F4, G5, H6}},
	{ 6, {A3, B4, C5, D6, E7, F8}},
	{ 6, {F1, E2, D3, C4, B5, A6}},
	{ 6, {H3, G4, F5, E6, D7, C8}},

	{ 5, {D1, E2, F3, G4, H5}},
	{ 5, {A4, B5, C6, D7, E8}},
	{ 5, {E1, D2, C3, B4, A5}},
	{ 5, {H4, G5, F6, E7, D8}},

	{ 4, {D1, C2, B3, A4}},
	{ 4, {A5, B6, C7, D8}},
	{ 4, {E1, F2, G3, H4}},
	{ 4, {H5, G6, F7, E8}},

	{ 0, {NOMOVE}},
	{ 0, {NOMOVE}}
};

/** array to convert coordinates into feature */
#if !USE_SIMD || (!defined(__ARM_NEON) && !defined(__AVX2__))
static const CoordinateToFeature EVAL_X2F[] = {
	{7, {{ 0,  6561}, { 4,   243}, { 8,  6561}, {10,  6561}, {12, 19683}, {14, 19683}, {28,  2187}}},  /* a1 */
	{5, {{ 0,  2187}, { 4,    27}, { 8,  2187}, {18,  2187}, {30,   729}}},                            /* b1 */
	{6, {{ 0,    81}, { 4,     9}, { 8,   729}, {12,  6561}, {22,  2187}, {34,   243}}},               /* c1 */
	{7, {{ 4,     3}, { 5,     1}, { 8,   243}, {12,  2187}, {26,  2187}, {38,    81}, {42,    27}}},  /* d1 */
	{7, {{ 4,     1}, { 5,     3}, { 8,    81}, {12,     9}, {27,  2187}, {40,    81}, {44,    27}}},  /* e1 */
	{6, {{ 1,    81}, { 5,     9}, { 8,    27}, {12,     3}, {23,  2187}, {36,   243}}},               /* f1 */
	{5, {{ 1,  2187}, { 5,    27}, { 8,     9}, {19,  2187}, {33,   729}}},                            /* g1 */
	{7, {{ 1,  6561}, { 5,   243}, { 8,     3}, {11,  6561}, {12,     1}, {15, 19683}, {29,     1}}},  /* h1 */
	{5, {{ 0,   729}, { 4,   729}, {10,  2187}, {16,  2187}, {32,   729}}},                            /* a2 */
	{7, {{ 0,   243}, { 4,    81}, { 8, 19683}, {10, 19683}, {16,   729}, {18,   729}, {28,   729}}},  /* b2 */
	{6, {{ 0,     9}, {12,   729}, {16,   243}, {22,   729}, {30,   243}, {42,     9}}},               /* c2 */
	{5, {{12,   243}, {16,    81}, {26,   729}, {34,    81}, {40,    27}}},                            /* d2 */
	{5, {{12,    81}, {16,    27}, {27,   729}, {36,    81}, {38,    27}}},                            /* e2 */
	{6, {{ 1,     9}, {12,    27}, {16,     9}, {23,   729}, {33,   243}, {44,     9}}},               /* f2 */
	{7, {{ 1,   243}, { 5,    81}, { 8,     1}, {11, 19683}, {16,     3}, {19,   729}, {29,     3}}},  /* g2 */
	{5, {{ 1,   729}, { 5,   729}, {11,  2187}, {16,     1}, {31,   729}}},                            /* h2 */
	{6, {{ 0,    27}, { 4,  2187}, {10,   729}, {14,  6561}, {20,  2187}, {35,   243}}},               /* a3 */
	{6, {{ 0,     3}, {14,   729}, {18,   243}, {20,   729}, {32,   243}, {42,     3}}},               /* b3 */
	{5, {{ 0,     1}, {20,   243}, {22,   243}, {28,   243}, {40,     9}}},                            /* c3 */
	{4, {{20,    81}, {26,   243}, {30,    81}, {36,    27}}},                                         /* d3 */
	{4, {{20,    27}, {27,   243}, {33,    81}, {34,    27}}},                                         /* e3 */
	{5, {{ 1,     1}, {20,     9}, {23,   243}, {29,     9}, {38,     9}}},                            /* f3 */
	{6, {{ 1,     3}, {15,   729}, {19,   243}, {20,     3}, {31,   243}, {44,     3}}},               /* g3 */
	{6, {{ 1,    27}, { 5,  2187}, {11,   729}, {15,  6561}, {20,     1}, {37,   243}}},               /* h3 */
	{7, {{ 4,  6561}, { 6, 19683}, {10,   243}, {14,  2187}, {24,  2187}, {39,    81}, {42,     1}}},  /* a4 */
	{5, {{14,   243}, {18,    81}, {24,   729}, {35,    81}, {40,     3}}},                            /* b4 */
	{4, {{22,    81}, {24,   243}, {32,    81}, {36,     9}}},                                         /* c4 */
	{4, {{24,    81}, {26,    81}, {28,    81}, {33,    27}}},                                         /* d4 */
	{4, {{24,    27}, {27,    81}, {29,    27}, {30,    27}}},                                         /* e4 */
	{4, {{23,    81}, {24,     9}, {31,    81}, {34,     9}}},                                         /* f4 */
	{5, {{15,   243}, {19,    81}, {24,     3}, {37,    81}, {38,     3}}},                            /* g4 */
	{7, {{ 5,  6561}, { 7, 19683}, {11,   243}, {15,  2187}, {24,     1}, {41,    81}, {44,     1}}},  /* h4 */
	{7, {{ 4, 19683}, { 6,  6561}, {10,    81}, {14,     9}, {25,  2187}, {40,     1}, {43,    27}}},  /* a5 */
	{5, {{14,    81}, {18,    27}, {25,   729}, {36,     3}, {39,    27}}},                            /* b5 */
	{4, {{22,    27}, {25,   243}, {33,     9}, {35,    27}}},                                         /* c5 */
	{4, {{25,    81}, {26,    27}, {29,    81}, {32,    27}}},                                         /* d5 */
	{4, {{25,    27}, {27,    27}, {28,    27}, {31,    27}}},                                         /* e5 */
	{4, {{23,    27}, {25,     9}, {30,     9}, {37,    27}}},                                         /* f5 */
	{5, {{15,    81}, {19,    27}, {25,     3}, {34,     3}, {41,    27}}},                            /* g5 */
	{7, {{ 5, 19683}, { 7,  6561}, {11,    81}, {15,     9}, {25,     1}, {38,     1}, {45,    27}}},  /* h5 */
	{6, {{ 2,    81}, { 6,  2187}, {10,    27}, {14,     3}, {21,  2187}, {36,     1}}},               /* a6 */
	{6, {{ 2,     9}, {14,    27}, {18,     9}, {21,   729}, {33,     3}, {43,     9}}},               /* b6 */
	{5, {{ 2,     1}, {21,   243}, {22,     9}, {29,   243}, {39,     9}}},                            /* c6 */
	{4, {{21,    81}, {26,     9}, {31,     9}, {35,     9}}},                                         /* d6 */
	{4, {{21,    27}, {27,     9}, {32,     9}, {37,     9}}},                                         /* e6 */
	{5, {{ 3,     1}, {21,     9}, {23,     9}, {28,     9}, {41,     9}}},                            /* f6 */
	{6, {{ 3,     9}, {15,    27}, {19,     9}, {21,     3}, {30,     3}, {45,     9}}},               /* g6 */
	{6, {{ 3,    81}, { 7,  2187}, {11,    27}, {15,     3}, {21,     1}, {34,     1}}},               /* h6 */
	{5, {{ 2,  2187}, { 6,   729}, {10,     9}, {17,  2187}, {33,     1}}},                            /* a7 */
	{7, {{ 2,   243}, { 6,    81}, { 9, 19683}, {10,     1}, {17,   729}, {18,     3}, {29,   729}}},  /* b7 */
	{6, {{ 2,     3}, {13,   729}, {17,   243}, {22,     3}, {31,     3}, {43,     3}}},               /* c7 */
	{5, {{13,   243}, {17,    81}, {26,     3}, {37,     3}, {39,     3}}},                            /* d7 */
	{5, {{13,    81}, {17,    27}, {27,     3}, {35,     3}, {41,     3}}},                            /* e7 */
	{6, {{ 3,     3}, {13,    27}, {17,     9}, {23,     3}, {32,     3}, {45,     3}}},               /* f7 */
	{7, {{ 3,   243}, { 7,    81}, { 9,     1}, {11,     1}, {17,     3}, {19,     3}, {28,     3}}},  /* g7 */
	{5, {{ 3,  2187}, { 7,   729}, {11,     9}, {17,     1}, {30,     1}}},                            /* h7 */
	{7, {{ 2,  6561}, { 6,   243}, { 9,  6561}, {10,     3}, {13, 19683}, {14,     1}, {29,  2187}}},  /* a8 */
	{5, {{ 2,   729}, { 6,    27}, { 9,  2187}, {18,     1}, {31,     1}}},                            /* b8 */
	{6, {{ 2,    27}, { 6,     9}, { 9,   729}, {13,  6561}, {22,     1}, {37,     1}}},               /* c8 */
	{7, {{ 6,     3}, { 7,     1}, { 9,   243}, {13,  2187}, {26,     1}, {41,     1}, {43,     1}}},  /* d8 */
	{7, {{ 6,     1}, { 7,     3}, { 9,    81}, {13,     9}, {27,     1}, {39,     1}, {45,     1}}},  /* e8 */
	{6, {{ 3,    27}, { 7,     9}, { 9,    27}, {13,     3}, {23,     1}, {35,     1}}},               /* f8 */
	{5, {{ 3,   729}, { 7,    27}, { 9,     9}, {19,     1}, {32,     1}}},                            /* g8 */
	{7, {{ 3,  6561}, { 7,   243}, { 9,     3}, {11,     3}, {13,     1}, {15,     1}, {28,     1}}},  /* h8 */
	{0, {{ 0,     0},}}, // offset
	{0, {{ 0,     0},}} // hack to get 3 * 16 features
};
#endif

const Feature EVAL_FEATURE[] = {
	{{ // a1
		 6561,     0,     0,     0,   243,     0,     0,     0,  6561,     0,  6561,     0, 19683,     0, 19683,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,  2187,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // b1
		 2187,     0,     0,     0,    27,     0,     0,     0,  2187,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,  2187,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   729,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // c1
		   81,     0,     0,     0,     9,     0,     0,     0,   729,     0,     0,     0,  6561,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,  2187,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,   243,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // d1
		    0,     0,     0,     0,     3,     1,     0,     0,   243,     0,     0,     0,  2187,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,  2187,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,    81,     0,     0,     0,    27,     0,     0,     0,     0,     0
	}}, {{ // e1
		    0,     0,     0,     0,     1,     3,     0,     0,    81,     0,     0,     0,     9,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,  2187,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,    81,     0,     0,     0,    27,     0,     0,     0
	}}, {{ // f1
		    0,    81,     0,     0,     0,     9,     0,     0,    27,     0,     0,     0,     3,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,  2187,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,   243,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // g1
		    0,  2187,     0,     0,     0,    27,     0,     0,     9,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,  2187,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,   729,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // h1
		    0,  6561,     0,     0,     0,   243,     0,     0,     3,     0,     0,  6561,     1,     0,     0, 19683,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     1,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // a2
		  729,     0,     0,     0,   729,     0,     0,     0,     0,     0,  2187,     0,     0,     0,     0,     0,
		 2187,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		  729,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // b2
		  243,     0,     0,     0,    81,     0,     0,     0, 19683,     0, 19683,     0,     0,     0,     0,     0,
		  729,     0,   729,     0,     0,     0,     0,     0,     0,     0,     0,     0,   729,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // c2
		    9,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   729,     0,     0,     0,
		  243,     0,     0,     0,     0,     0,   729,     0,     0,     0,     0,     0,     0,     0,   243,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     9,     0,     0,     0,     0,     0
	}}, {{ // d2
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   243,     0,     0,     0,
		   81,     0,     0,     0,     0,     0,     0,     0,     0,     0,   729,     0,     0,     0,     0,     0,
		    0,     0,    81,     0,     0,     0,     0,     0,    27,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // e2
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,    81,     0,     0,     0,
		   27,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   729,     0,     0,     0,     0,
		    0,     0,     0,     0,    81,     0,    27,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // f2
		    0,     9,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,    27,     0,     0,     0,
		    9,     0,     0,     0,     0,     0,     0,   729,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,   243,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     9,     0,     0,     0
	}}, {{ // g2
		    0,   243,     0,     0,     0,    81,     0,     0,     1,     0,     0, 19683,     0,     0,     0,     0,
		    3,     0,     0,   729,     0,     0,     0,     0,     0,     0,     0,     0,     0,     3,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // h2
		    0,   729,     0,     0,     0,   729,     0,     0,     0,     0,     0,  2187,     0,     0,     0,     0,
		    1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   729,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // a3
		   27,     0,     0,     0,  2187,     0,     0,     0,     0,     0,   729,     0,     0,     0,  6561,     0,
		    0,     0,     0,     0,  2187,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,   243,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // b3
		    3,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   729,     0,
		    0,     0,   243,     0,   729,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		  243,     0,     0,     0,     0,     0,     0,     0,     0,     0,     3,     0,     0,     0,     0,     0
	}}, {{ // c3
		    1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,   243,     0,   243,     0,     0,     0,     0,     0,   243,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     9,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // d3
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,    81,     0,     0,     0,     0,     0,   243,     0,     0,     0,    81,     0,
		    0,     0,     0,     0,    27,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // e3
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,    27,     0,     0,     0,     0,     0,     0,   243,     0,     0,     0,     0,
		    0,    81,    27,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // f3
		    0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     9,     0,     0,   243,     0,     0,     0,     0,     0,     9,     0,     0,
		    0,     0,     0,     0,     0,     0,     9,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // g3
		    0,     3,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   729,
		    0,     0,     0,   243,     3,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   243,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     3,     0,     0,     0
	}}, {{ // h3
		    0,    27,     0,     0,     0,  2187,     0,     0,     0,     0,     0,   729,     0,     0,     0,  6561,
		    0,     0,     0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,   243,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // a4
		    0,     0,     0,     0,  6561,     0, 19683,     0,     0,     0,   243,     0,     0,     0,  2187,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,  2187,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,    81,     0,     0,     1,     0,     0,     0,     0,     0
	}}, {{ // b4
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   243,     0,
		    0,     0,    81,     0,     0,     0,     0,     0,   729,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,    81,     0,     0,     0,     0,     3,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // c4
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,    81,     0,   243,     0,     0,     0,     0,     0,     0,     0,
		   81,     0,     0,     0,     9,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // d4
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,    81,     0,    81,     0,    81,     0,     0,     0,
		    0,    27,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // e4
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,    27,     0,     0,    81,     0,    27,    27,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // f4
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,    81,     9,     0,     0,     0,     0,     0,     0,    81,
		    0,     0,     9,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // g4
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   243,
		    0,     0,     0,    81,     0,     0,     0,     0,     3,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,    81,     3,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // h4
		    0,     0,     0,     0,     0,  6561,     0, 19683,     0,     0,     0,   243,     0,     0,     0,  2187,
		    0,     0,     0,     0,     0,     0,     0,     0,     1,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,    81,     0,     0,     1,     0,     0,     0
	}}, {{ // a5
		    0,     0,     0,     0, 19683,     0,  6561,     0,     0,     0,    81,     0,     0,     0,     9,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,  2187,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     1,     0,     0,    27,     0,     0,     0,     0
	}}, {{ // b5
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,    81,     0,
		    0,     0,    27,     0,     0,     0,     0,     0,     0,   729,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     3,     0,     0,    27,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // c5
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,    27,     0,     0,   243,     0,     0,     0,     0,     0,     0,
		    0,     9,     0,    27,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // d5
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,    81,    27,     0,     0,    81,     0,     0,
		   27,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // e5
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,    27,     0,    27,    27,     0,     0,    27,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // f5
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,    27,     0,     9,     0,     0,     0,     0,     9,     0,
		    0,     0,     0,     0,     0,    27,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // g5
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,    81,
		    0,     0,     0,    27,     0,     0,     0,     0,     0,     3,     0,     0,     0,     0,     0,     0,
		    0,     0,     3,     0,     0,     0,     0,     0,     0,    27,     0,     0,     0,     0,     0,     0
	}}, {{ // h5
		    0,     0,     0,     0,     0, 19683,     0,  6561,     0,     0,     0,    81,     0,     0,     0,     9,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     1,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     1,     0,     0,     0,     0,     0,     0,    27,     0,     0
	}}, {{ // a6
		    0,     0,    81,     0,     0,     0,  2187,     0,     0,     0,    27,     0,     0,     0,     3,     0,
		    0,     0,     0,     0,     0,  2187,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // b6
		    0,     0,     9,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,    27,     0,
		    0,     0,     9,     0,     0,   729,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     3,     0,     0,     0,     0,     0,     0,     0,     0,     0,     9,     0,     0,     0,     0
	}}, {{ // c6
		    0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,   243,     9,     0,     0,     0,     0,     0,     0,   243,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     9,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // d6
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,    81,     0,     0,     0,     0,     9,     0,     0,     0,     0,     9,
		    0,     0,     0,     9,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // e6
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,    27,     0,     0,     0,     0,     0,     9,     0,     0,     0,     0,
		    9,     0,     0,     0,     0,     9,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // f6
		    0,     0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     9,     0,     9,     0,     0,     0,     0,     9,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     9,     0,     0,     0,     0,     0,     0
	}}, {{ // g6
		    0,     0,     0,     9,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,    27,
		    0,     0,     0,     9,     0,     3,     0,     0,     0,     0,     0,     0,     0,     0,     3,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     9,     0,     0
	}}, {{ // h6
		    0,     0,     0,    81,     0,     0,     0,  2187,     0,     0,     0,    27,     0,     0,     0,     3,
		    0,     0,     0,     0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // a7
		    0,     0,  2187,     0,     0,     0,   729,     0,     0,     0,     9,     0,     0,     0,     0,     0,
		    0,  2187,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // b7
		    0,     0,   243,     0,     0,     0,    81,     0,     0, 19683,     1,     0,     0,     0,     0,     0,
		    0,   729,     3,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   729,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // c7
		    0,     0,     3,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   729,     0,     0,
		    0,   243,     0,     0,     0,     0,     3,     0,     0,     0,     0,     0,     0,     0,     0,     3,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     3,     0,     0,     0,     0
	}}, {{ // d7
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,   243,     0,     0,
		    0,    81,     0,     0,     0,     0,     0,     0,     0,     0,     3,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     3,     0,     3,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // e7
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,    81,     0,     0,
		    0,    27,     0,     0,     0,     0,     0,     0,     0,     0,     0,     3,     0,     0,     0,     0,
		    0,     0,     0,     3,     0,     0,     0,     0,     0,     3,     0,     0,     0,     0,     0,     0
	}}, {{ // f7
		    0,     0,     0,     3,     0,     0,     0,     0,     0,     0,     0,     0,     0,    27,     0,     0,
		    0,     9,     0,     0,     0,     0,     0,     3,     0,     0,     0,     0,     0,     0,     0,     0,
		    3,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     3,     0,     0
	}}, {{ // g7
		    0,     0,     0,   243,     0,     0,     0,    81,     0,     1,     0,     1,     0,     0,     0,     0,
		    0,     3,     0,     3,     0,     0,     0,     0,     0,     0,     0,     0,     3,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // h7
		    0,     0,     0,  2187,     0,     0,     0,   729,     0,     0,     0,     9,     0,     0,     0,     0,
		    0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     1,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // a8
		    0,     0,  6561,     0,     0,     0,   243,     0,     0,  6561,     3,     0,     0, 19683,     1,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,  2187,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // b8
		    0,     0,   729,     0,     0,     0,    27,     0,     0,  2187,     0,     0,     0,     0,     0,     0,
		    0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     1,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // c8
		    0,     0,    27,     0,     0,     0,     9,     0,     0,   729,     0,     0,     0,  6561,     0,     0,
		    0,     0,     0,     0,     0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // d8
		    0,     0,     0,     0,     0,     0,     3,     1,     0,   243,     0,     0,     0,  2187,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     1,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     1,     0,     1,     0,     0,     0,     0
	}}, {{ // e8
		    0,     0,     0,     0,     0,     0,     1,     3,     0,    81,     0,     0,     0,     9,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     1,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     1,     0,     0,     0,     0,     0,     1,     0,     0
	}}, {{ // f8
		    0,     0,     0,    27,     0,     0,     0,     9,     0,    27,     0,     0,     0,     3,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // g8
		    0,     0,     0,   729,     0,     0,     0,    27,     0,     9,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    1,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // h8
		    0,     0,     0,  6561,     0,     0,     0,   243,     0,     3,     0,     3,     0,     1,     0,     1,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     1,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}, {{ // PASS
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
		    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0
	}}
};


/** feature size */
static const uint32_t EVAL_SIZE[] = {19683, 59049, 59049, 59049, 6561, 6561, 6561, 6561, 2187, 729, 243, 81, 1};

/** packed feature size */
static const uint32_t EVAL_PACKED_SIZE[] = {10206, 29889, 29646, 29646, 3321, 3321, 3321, 3321, 1134, 378, 135, 45, 1};

/** feature offset */
static const uint32_t WEIGHT_OFFSET[] = {
	     0,
	 19683,
	 78732,
	137781,
	196830,
};

/** feature offset */
static const uint32_t FEATURE_OFFSET[] = {
	    0,     0,     0,     0,
	    0,     0,     0,     0,
	    0,     0,     0,     0,
	    0,     0,     0,     0,
	    0,     0,     0,     0,
	 6561,  6561,  6561,  6561,
	13122, 13122, 13122, 13122,
	19683, 19683,
	26244, 26244, 26244, 26244,
	28431, 28431, 28431, 28431,
	29160, 29160, 29160, 29160,
	29403, 29403, 29403, 29403,
	29484, 29485
};

/** Evaluation weights by color & ply */
static int16_t *EVAL_WEIGHT[65][2];

/** number of (unpacked) weights */
static const uint32_t EVAL_N_WEIGHT = 226315;

/** number of plies */
static const uint32_t EVAL_N_PLY = 61;

/** number of features */
static const uint32_t EVAL_N_FEATURE = 47;

/** eval weight load status */
static int EVAL_LOADED = 0;

/** evaluation function error coefficient parameters */
static double EVAL_A, EVAL_B, EVAL_C, EVAL_a, EVAL_b, EVAL_c;


/**
 * @brief Opponent feature.
 *
 * Compute a feature from the opponent point of view.
 * @param l feature.
 * @param d feature size.
 * @return opponent feature.
 */
static uint32_t opponent_feature(uint32_t l, uint32_t d)
{
	static const uint8_t o[] = {1, 0, 2};
	uint32_t f = o[l % 3];

	if (d > 1) f += opponent_feature(l / 3, d - 1) * 3;

	return f;
}

/**
 * @brief player's symetric feature.
 *
 * Compute a symetric feature.
 * @param sym symetries.
 * @param n feature length.
 * @param j feature.
 * @return player's feature.
 */
static uint32_t player_feature(const int sym[], uint32_t n, uint32_t l)
{
	uint32_t power3[] = {1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683 };
	uint32_t f, i;

	for (f = i = 0; i < n; ++i) {
		f += ((l / power3[sym[i]]) % 3) * power3[i];
	}

	return f;
}

static int** alloc_pack(size_t size)
{
	int **pack = (int**) malloc (2 * sizeof (int*));
	pack[0] = (int*) malloc(size * sizeof (int));
	pack[1] = (int*) malloc(size * sizeof (int));
	return pack;
}

static void free_pack(int **pack)
 {
	free(pack[1]);
	free(pack[0]);
	free(pack);
}

/**
 * @brief Unpack a feature
 *
 */
static int **unpack(const uint32_t length, const uint32_t size, const int sym[])
{
	uint32_t i, j, n;
	int ** pack = alloc_pack(size);

	for (i = n = 0; i < size; ++i) {
		j = player_feature(sym, length, i);
		if (j < i) pack[0][i] = pack[0][j];
		else pack[0][i] = n++;
		pack[1][opponent_feature(i, length)] = pack[0][i];
	}
	return pack;
}

/**
 * @brief Load the evaluation function features' weights.
 *
 * The weights are stored in a global variable, because, once loaded from the
 * file, they stay constant during the lifetime of the program. As loading
 * the weights is time & resource consuming, a counter variable check that
 * the weights are effectively loaded only once.
 *
 * @param file File name of the evaluation function data.
 */
void eval_open(const char* file)
{
	const uint32_t n_w = 114364;
	uint32_t edax_header, eval_header;
	uint32_t version, release, build;
	double date;
	uint32_t ply, i, j, k, r, offset;
	FILE* f;
	int16_t *w = NULL;
	static const int sym_S10[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
	static const int sym_C10[] = { 9, 8, 7, 6, 4, 5, 3, 2, 1, 0 };
	static const int sym_C9[]  = { 0, 2, 1, 4, 3, 5, 7, 6, 8};
	/** feature symetry packing */
	int **EVAL_C10, **EVAL_S10, **EVAL_C9, **EVAL_S8, **EVAL_S7, **EVAL_S6, **EVAL_S5, **EVAL_S4;

	if (EVAL_LOADED++) return;

	// create unpacking tables
	// linear symetries
	EVAL_S10 = unpack(10, 59049, sym_S10);     // 10 squares (edge +X ) : 59049 -> 29646
	EVAL_S8  = unpack( 8,  6561, sym_S10 + 2); // 8 squares : 6561 -> 3321
	EVAL_S7  = unpack( 7,  2187, sym_S10 + 3); // 7 squares : 2187 -> 1134
	EVAL_S6  = unpack( 6,   729, sym_S10 + 4); // 6 squares :  729 ->  378
	EVAL_S5  = unpack( 5,   243, sym_S10 + 5); // 5 squares :  243 ->  135
	EVAL_S4  = unpack( 4,    81, sym_S10 + 6); // 4 squares :   81  -> 45
	// corner symetries
	EVAL_C9  = unpack( 9, 19683, sym_C9);      // 9 corner squares 19683 -> 1006
	EVAL_C10 = unpack(10, 59049, sym_C10);     // 10 squares (angle + X) : 59049 -> 29889

	// allocation
	int16_t *eval_weight = (int16_t*) malloc(2 * EVAL_N_PLY * (EVAL_N_WEIGHT + 2) * sizeof (int16_t));
	if (eval_weight == NULL) fatal_error("Cannot allocate evaluation weights.\n");
	EVAL_WEIGHT[0][0] = eval_weight + 1;
	EVAL_WEIGHT[0][1] = eval_weight + 1 + EVAL_N_WEIGHT + 1;
	for (ply = 1; ply < EVAL_N_PLY; ply++) {
		EVAL_WEIGHT[ply][0] = EVAL_WEIGHT[ply - 1][0] + 2 * (EVAL_N_WEIGHT + 1);
		EVAL_WEIGHT[ply][1] = EVAL_WEIGHT[ply][0] + EVAL_N_WEIGHT + 1;
	}

	// data reading
	w = (int16_t*) malloc(n_w * sizeof (int16_t)); // a temporary to read packed weights
	f = fopen(file, "rb");
	if (f == NULL) {
		fprintf(stderr, "Cannot open %s", file);
		exit(EXIT_FAILURE);
	}

	// File header
	r = fread(&edax_header, sizeof (int), 1, f);
	r += fread(&eval_header, sizeof (int), 1, f);
	if (r != 2 || (!(edax_header == EDAX || eval_header == EVAL) && !(edax_header == XADE || eval_header == LAVE))) fatal_error("%s is not an Edax evaluation file\n", file);
	r  = fread(&version, sizeof (int), 1, f);
	r += fread(&release, sizeof (int), 1, f);
	r += fread(&build, sizeof (int), 1, f);
	r += fread(&date, sizeof (double), 1, f);
	if (r != 4) fatal_error("Cannot read version info from %s\n", file);
	if (edax_header == XADE) {
		version = bswap_32(version);
		release = bswap_32(release);
		build = bswap_32(build);
	}
	// Weights : read & unpacked them
	for (ply = 0; ply < EVAL_N_PLY; ply++) {
		r = fread(w, sizeof (int16_t), n_w, f);
		if (r != n_w) fatal_error("Cannot read evaluation weight from %s\n", file);
		if (edax_header == XADE) for (i = 0; i < n_w; ++i) w[i] = bswap_16(w[i]);

		EVAL_WEIGHT[ply][0][-1] = 0;
		EVAL_WEIGHT[ply][1][-1] = 0;

		j = offset = 0;
		for (k = 0; k < EVAL_SIZE[0]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_C9[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_C9[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[0];
		for (k = 0; k < EVAL_SIZE[1]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_C10[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_C10[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[1];
		for (k = 0; k < EVAL_SIZE[2]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_S10[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_S10[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[2];
		for (k = 0; k < EVAL_SIZE[3]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_S10[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_S10[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[3];
		for (k = 0; k < EVAL_SIZE[4]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_S8[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_S8[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[4];
		for (k = 0; k < EVAL_SIZE[5]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_S8[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_S8[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[5];
		for (k = 0; k < EVAL_SIZE[6]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_S8[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_S8[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[6];
		for (k = 0; k < EVAL_SIZE[7]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_S8[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_S8[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[7];
		for (k = 0; k < EVAL_SIZE[8]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_S7[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_S7[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[8];
		for (k = 0; k < EVAL_SIZE[9]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_S6[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_S6[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[9];
		for (k = 0; k < EVAL_SIZE[10]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_S5[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_S5[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[10];
		for (k = 0; k < EVAL_SIZE[11]; k++, j++) {
			EVAL_WEIGHT[ply][0][j] = w[EVAL_S4[0][k] + offset];
			EVAL_WEIGHT[ply][1][j] = w[EVAL_S4[1][k] + offset];
		}

		offset += EVAL_PACKED_SIZE[11];
		EVAL_WEIGHT[ply][0][j] = w[offset];
		EVAL_WEIGHT[ply][1][j] = w[offset];

		EVAL_WEIGHT[ply][0][j + 1] = 0;
		EVAL_WEIGHT[ply][1][j + 1] = 0;
	}

	fclose(f);
	free(w);
	free_pack(EVAL_C10);
	free_pack(EVAL_S10);
	free_pack(EVAL_C9);
	free_pack(EVAL_S8);
	free_pack(EVAL_S7);
	free_pack(EVAL_S6);
	free_pack(EVAL_S5);
	free_pack(EVAL_S4);

	/*if (version == 3 && release == 2 && build == 5)*/ {
		EVAL_A = -0.10026799, EVAL_B = 0.31027733, EVAL_C = -0.57772603;
		EVAL_a = 0.07585621, EVAL_b = 1.16492647, EVAL_c = 5.4171698;
	}

	info("<Evaluation function weights version %u.%u.%u loaded>\n", version, release, build);
}

/**
 * @brief Free global resources allocated to the evaluation function.
 */
void eval_close(void)
{
	free(EVAL_WEIGHT[0][0] - 1);
	EVAL_LOADED = 0;
}

/**
 * @brief Initialize a new evaluation function.
 *
 * Allocate space to store the state of the evaluation function.
 *
 * @param eval Evaluation function.
 */
void eval_init(Eval *eval)
{
	eval->feature = (Feature*) aligned_alloc(64, adjust_size(64, EVAL_N_PLY * sizeof (Feature)));
	if (eval->feature == NULL) fatal_error("Cannot allocate eval features");
}

/**
 * @brief Free resources used by the evaluation function.
 *
 * @param eval Evaluation function.
 */
void eval_free(Eval *eval)
{
	free(eval->feature);
}

/**
 * @brief Set up evaluation features from a board.
 *
 * @param eval  Evaluation function.
 * @param board Board to setup features from.
 */
void eval_set(Eval *eval, const Board *board)
{
	assert(eval != NULL);
	assert(eval->feature != NULL);
	assert(board != NULL);

	uint32_t i, j, c;

	eval->player = 0;
	eval->ply = 60 - board_count_empties(board);

	uint16_t *feature = eval->feature[eval->ply].v1;

	for (i = 0; i <= EVAL_N_FEATURE; ++i) {
		feature[i] = 0;
		for (j = 0; j < EVAL_F2X[i].n_square; j++) {
			c = board_get_square_color(board, EVAL_F2X[i].x[j]);
			feature[i] = feature[i] * 3 + c;
		}
		feature[i] += FEATURE_OFFSET[i];
	}
}

/**
 * @brief Swap player's feature.
 *
 * @param eval  Evaluation function.
 */
static void eval_swap(Eval *eval)
{
	eval->player ^= 1;
}


/**
 * @brief Update the features after a player's move.
 *
 * @param eval  Evaluation function.
 * @param move  Move.
 */
void eval_update(Eval *eval, const Move *move)
{
	assert(eval != NULL);
	assert(eval->feature != NULL);
	assert(move != NULL);
	assert(move->flipped);
	assert(WHITE == eval->player || BLACK == eval->player);

	int x = move->x;
	uint64_t flip = move->flipped;

// AVX2 version: add 16 features at once
#if USE_SIMD && defined(__AVX2__)

	__m256i *feature_in = eval->feature[eval->ply].v16;
	__m256i *feature_out = eval->feature[++eval->ply].v16;

	__m256i f0 = feature_in[0];
	__m256i f1 = feature_in[1];
	__m256i f2 = feature_in[2];

	if (eval->player == 0) {
		f0 = _mm256_sub_epi16(f0, _mm256_slli_epi16(EVAL_FEATURE[x].v16[0], 1));
		f1 = _mm256_sub_epi16(f1, _mm256_slli_epi16(EVAL_FEATURE[x].v16[1], 1));
		f2 = _mm256_sub_epi16(f2, _mm256_slli_epi16(EVAL_FEATURE[x].v16[2], 1));

		foreach_bit (x, flip) {
			f0 = _mm256_sub_epi16(f0, EVAL_FEATURE[x].v16[0]);
			f1 = _mm256_sub_epi16(f1, EVAL_FEATURE[x].v16[1]);
			f2 = _mm256_sub_epi16(f2, EVAL_FEATURE[x].v16[2]);
		}
	} else {
		f0 = _mm256_sub_epi16(f0, EVAL_FEATURE[x].v16[0]);
		f1 = _mm256_sub_epi16(f1, EVAL_FEATURE[x].v16[1]);
		f2 = _mm256_sub_epi16(f2, EVAL_FEATURE[x].v16[2]);

		foreach_bit (x, flip) {
			f0 = _mm256_add_epi16(f0, EVAL_FEATURE[x].v16[0]);
			f1 = _mm256_add_epi16(f1, EVAL_FEATURE[x].v16[1]);
			f2 = _mm256_add_epi16(f2, EVAL_FEATURE[x].v16[2]);
		}
	}

	feature_out[0] = f0;
	feature_out[1] = f1;
	feature_out[2] = f2;

// SSE version: add 8 features at once
#elif USE_SIMD && defined(__SSE2__)

	__m128i *feature_in = eval->feature[eval->ply].v8;
	__m128i *feature_out = eval->feature[++eval->ply].v8;

	__m128i	f0 = feature_in[0];
	__m128i	f1 = feature_in[1];
	__m128i	f2 = feature_in[2];
	__m128i	f3 = feature_in[3];
	__m128i	f4 = feature_in[4];
	__m128i	f5 = feature_in[5];

	if (eval->player == 0) {
		f0 = _mm_sub_epi16(f0, _mm_slli_epi16(EVAL_FEATURE[x].v8[0], 1));
		f1 = _mm_sub_epi16(f1, _mm_slli_epi16(EVAL_FEATURE[x].v8[1], 1));
		f2 = _mm_sub_epi16(f2, _mm_slli_epi16(EVAL_FEATURE[x].v8[2], 1));
		f3 = _mm_sub_epi16(f3, _mm_slli_epi16(EVAL_FEATURE[x].v8[3], 1));
		f4 = _mm_sub_epi16(f4, _mm_slli_epi16(EVAL_FEATURE[x].v8[4], 1));
		f5 = _mm_sub_epi16(f5, _mm_slli_epi16(EVAL_FEATURE[x].v8[5], 1));

		foreach_bit (x, flip) {
			f0 = _mm_sub_epi16(f0, EVAL_FEATURE[x].v8[0]);
			f1 = _mm_sub_epi16(f1, EVAL_FEATURE[x].v8[1]);
			f2 = _mm_sub_epi16(f2, EVAL_FEATURE[x].v8[2]);
			f3 = _mm_sub_epi16(f3, EVAL_FEATURE[x].v8[3]);
			f4 = _mm_sub_epi16(f4, EVAL_FEATURE[x].v8[4]);
			f5 = _mm_sub_epi16(f5, EVAL_FEATURE[x].v8[5]);
		}
	} else {
		f0 = _mm_sub_epi16(f0, EVAL_FEATURE[x].v8[0]);
		f1 = _mm_sub_epi16(f1, EVAL_FEATURE[x].v8[1]);
		f2 = _mm_sub_epi16(f2, EVAL_FEATURE[x].v8[2]);
		f3 = _mm_sub_epi16(f3, EVAL_FEATURE[x].v8[3]);
		f4 = _mm_sub_epi16(f4, EVAL_FEATURE[x].v8[4]);
		f5 = _mm_sub_epi16(f5, EVAL_FEATURE[x].v8[5]);

		foreach_bit (x, flip) {
			f0 = _mm_add_epi16(f0, EVAL_FEATURE[x].v8[0]);
			f1 = _mm_add_epi16(f1, EVAL_FEATURE[x].v8[1]);
			f2 = _mm_add_epi16(f2, EVAL_FEATURE[x].v8[2]);
			f3 = _mm_add_epi16(f3, EVAL_FEATURE[x].v8[3]);
			f4 = _mm_add_epi16(f4, EVAL_FEATURE[x].v8[4]);
			f5 = _mm_add_epi16(f5, EVAL_FEATURE[x].v8[5]);
		}
	}

	feature_out[0] = f0;
	feature_out[1] = f1;
	feature_out[2] = f2;
	feature_out[3] = f3;
	feature_out[4] = f4;
	feature_out[5] = f5;

// NEON version: add 8 features at once
#elif USE_SIMD && defined(__ARM_NEON)

	int16x8_t *feature_in = eval->feature[eval->ply].v8;
	int16x8_t *feature_out = eval->feature[++eval->ply].v8;

	int16x8_t f0 = feature_in[0];
	int16x8_t f1 = feature_in[1];
	int16x8_t f2 = feature_in[2];
	int16x8_t f3 = feature_in[3];
	int16x8_t f4 = feature_in[4];
	int16x8_t f5 = feature_in[5];

	if (eval->player == 0) {
		f0 = vsubq_s16(f0, vshlq_n_s16(EVAL_FEATURE[x].v8[0], 1));
		f1 = vsubq_s16(f1, vshlq_n_s16(EVAL_FEATURE[x].v8[1], 1));
		f2 = vsubq_s16(f2, vshlq_n_s16(EVAL_FEATURE[x].v8[2], 1));
		f3 = vsubq_s16(f3, vshlq_n_s16(EVAL_FEATURE[x].v8[3], 1));
		f4 = vsubq_s16(f4, vshlq_n_s16(EVAL_FEATURE[x].v8[4], 1));
		f5 = vsubq_s16(f5, vshlq_n_s16(EVAL_FEATURE[x].v8[5], 1));

		foreach_bit (x, flip) {
			f0 = vsubq_s16(f0, EVAL_FEATURE[x].v8[0]);
			f1 = vsubq_s16(f1, EVAL_FEATURE[x].v8[1]);
			f2 = vsubq_s16(f2, EVAL_FEATURE[x].v8[2]);
			f3 = vsubq_s16(f3, EVAL_FEATURE[x].v8[3]);
			f4 = vsubq_s16(f4, EVAL_FEATURE[x].v8[4]);
			f5 = vsubq_s16(f5, EVAL_FEATURE[x].v8[5]);
		}
	} else {
		f0 = vsubq_s16(f0, EVAL_FEATURE[x].v8[0]);
		f1 = vsubq_s16(f1, EVAL_FEATURE[x].v8[1]);
		f2 = vsubq_s16(f2, EVAL_FEATURE[x].v8[2]);
		f3 = vsubq_s16(f3, EVAL_FEATURE[x].v8[3]);
		f4 = vsubq_s16(f4, EVAL_FEATURE[x].v8[4]);
		f5 = vsubq_s16(f5, EVAL_FEATURE[x].v8[5]);

		foreach_bit (x, flip) {
			f0 = vaddq_s16(f0, EVAL_FEATURE[x].v8[0]);
			f1 = vaddq_s16(f1, EVAL_FEATURE[x].v8[1]);
			f2 = vaddq_s16(f2, EVAL_FEATURE[x].v8[2]);
			f3 = vaddq_s16(f3, EVAL_FEATURE[x].v8[3]);
			f4 = vaddq_s16(f4, EVAL_FEATURE[x].v8[4]);
			f5 = vaddq_s16(f5, EVAL_FEATURE[x].v8[5]);
		}
	}
	feature_out[0] = f0;
	feature_out[1] = f1;
	feature_out[2] = f2;
	feature_out[3] = f3;
	feature_out[4] = f4;
	feature_out[5] = f5;

#else // add features that change only

	uint16_t *feature_in = eval->feature[eval->ply].v1;
	uint16_t *feature_out = eval->feature[++eval->ply].v1;
	const CoordinateToFeature *s = EVAL_X2F + move->x;
	int i, j;

	memcpy(feature_out, feature_in, sizeof(Feature));

	if (eval->player == 0) {

		for (i = 0; i < s->n_feature; ++i) {
			j = s->feature[i].i;
			feature_out[j] -= 2 * s->feature[i].x;
		}

		foreach_bit (x, flip) {
			s = EVAL_X2F + x;
			for (i = 0; i < s->n_feature; ++i) {
				j = s->feature[i].i;
				feature_out[j] -= s->feature[i].x;
			}
		}

	} else {

		for (i = 0; i < s->n_feature; ++i) {
			j = s->feature[i].i;
			feature_out[j] -= s->feature[i].x;
		}

		foreach_bit (x, flip) {
			s = EVAL_X2F + x;
			for (i = 0; i < s->n_feature; ++i) {
				j = s->feature[i].i;
				feature_out[j] += s->feature[i].x;
			}
		}
	}

#endif

	eval_swap(eval);
}

/**
 * @brief Restore the features as before a player's move.
 *
 * @param eval  Evaluation function.
 * @param move  Move.
 */
void eval_restore(Eval *eval)
{
	assert(eval != NULL);

	--eval->ply;
	eval_swap(eval);
}

/**
 * @brief Update/Restore the features after a passing move.
 *
 * @param eval  Evaluation function.
 */
void eval_pass(Eval *eval)
{
	assert(eval != NULL);

	eval_swap(eval);
}

/**
 * @brief raw addition of the feature weights
 *
 * @param eval the evaluation data;
 * @param player;
 * @param ply;
 */
int eval_accumulate(const Eval *eval) {

// the vectorised version is ~10% slower than the standard version below on zen3, so I (Richard Delorme) disabled it.
#if 0 && USE_SIMD && defined(__AVX2__)

	int *w_0 = (int*) EVAL_WEIGHT[eval->ply][eval->player];
	int *w_1 = (int*) (EVAL_WEIGHT[eval->ply][eval->player] + WEIGHT_OFFSET[4] - 1);
	const __m128i *f = eval->feature[eval->ply].v8;
	const __m256i o[] = {
		_mm256_set_epi32( 19682,  19682,  19682,  19682,     -1,     -1,     -1,     -1),
		_mm256_set_epi32(137780, 137780, 137780, 137780,  78731,  78731,  78731,  78731),
	};
	__m256i f8, fo, w8, s8;
	__m128i s4, s2;
	int32_t sum;

	f8 = _mm256_cvtepu16_epi32(f[0]); // dispatch the 8 int16_t into 8 int32_t inside f8 : f8  = [feature.v1[7] | feature.v1[6]  ... | feature v1[0]]
 	fo = _mm256_add_epi32(f8, o[0]); //	add f8 + o8
	w8 = _mm256_i32gather_epi32(w_0, fo, 2); // w8 = | w[f8+offset] | ...
	s8 = _mm256_srai_epi32(w8, 16);	// shift to the right by a short

	f8 = _mm256_cvtepu16_epi32(f[1]); // repeat
 	fo = _mm256_add_epi32(f8, o[1]);
	w8 = _mm256_i32gather_epi32(w_0, fo, 2);
	s8 = _mm256_add_epi32(s8, _mm256_srai_epi32(w8, 16));

	f8 = _mm256_cvtepu16_epi32(f[2]); // the offset is included in the feature (within 16 bit)
	w8 = _mm256_i32gather_epi32(w_1, f8, 2);
	s8 = _mm256_add_epi32(s8, _mm256_srai_epi32(w8, 16));

	f8 = _mm256_cvtepu16_epi32(f[3]);
	w8 = _mm256_i32gather_epi32(w_1, f8, 2);
	s8 = _mm256_add_epi32(s8, _mm256_srai_epi32(w8, 16));

	f8 = _mm256_cvtepu16_epi32(f[4]);
	w8 = _mm256_i32gather_epi32(w_1, f8, 2);
	s8 = _mm256_add_epi32(s8, _mm256_srai_epi32(w8, 16));

	f8 = _mm256_cvtepu16_epi32(f[5]);
	w8 = _mm256_i32gather_epi32(w_1, f8, 2);
	s8 = _mm256_add_epi32(s8, _mm256_srai_epi32(w8, 16));

	s4 = _mm_add_epi32(_mm256_castsi256_si128(s8), _mm256_extracti128_si256(s8, 1));
	s2 = _mm_hadd_epi32(s4, s4);
	sum = _mm_cvtsi128_si32(s2) + _mm_extract_epi32(s2, 1);

#else

	const uint32_t *o = WEIGHT_OFFSET;
	const int16_t *w0 = EVAL_WEIGHT[eval->ply][eval->player];
	const int16_t *w1 = w0 + o[1], *w2 = w0 + o[2], *w3 = w0 + o[3], *w4 = w0 + o[4];
	const uint16_t *f = eval->feature[eval->ply].v1;
	int sum;

	sum = w0[f[ 0]] + w0[f[ 1]] + w0[f[ 2]] + w0[f[ 3]]
	    + w1[f[ 4]] + w1[f[ 5]] + w1[f[ 6]] + w1[f[ 7]]
	    + w2[f[ 8]] + w2[f[ 9]] + w2[f[10]] + w2[f[11]]
	    + w3[f[12]] + w3[f[13]] + w3[f[14]] + w3[f[15]]
	    + w4[f[16]] + w4[f[17]] + w4[f[18]] + w4[f[19]]
	    + w4[f[20]] + w4[f[21]] + w4[f[22]] + w4[f[23]]
	    + w4[f[24]] + w4[f[25]] + w4[f[26]] + w4[f[27]]
	    + w4[f[28]] + w4[f[29]]
	    + w4[f[30]] + w4[f[31]] + w4[f[32]] + w4[f[33]]
	    + w4[f[34]] + w4[f[35]] + w4[f[36]] + w4[f[37]]
	    + w4[f[38]] + w4[f[39]] + w4[f[40]] + w4[f[41]]
	    + w4[f[42]] + w4[f[43]] + w4[f[44]] + w4[f[45]]
	    + w4[f[46]];

#endif

	return sum;
}


/**
 * @brief Compute the error-type of the evaluation function according to the
 * depths.
 *
 * A statistical study showed that the accuracy of the alphabeta
 * mostly depends on the depth & the ply of the game. This function is useful
 * to the probcut algorithm. Using a function instead of a table of data makes
 * easier to inter- or extrapolate new values.
 *
 * @param n_empty Number of empty squares on the board.
 * @param depth Depth used in alphabeta.
 * @param probcut_depth A shallow depth used in probcut algorithm.
 */
double eval_sigma(const int n_empty, const int depth, const int probcut_depth)
{
	double sigma;

	sigma = EVAL_A * n_empty + EVAL_B * depth + EVAL_C * probcut_depth;
	sigma = EVAL_a * sigma * sigma + EVAL_b * sigma + EVAL_c;

	return sigma;
}
