/* interface macros to coefficient fit softawre */

#ifdef FIT_MODE
static int fit_cnt;		/* used in scan's */

extern int rook_ti[8];		/* rook table indeces */
extern int wpawn_ti[8];		/* w-pawn table indeces */
extern int bpawn_ti[8];		/* b-pawn table indeces */
extern int wpp_ti[8];		/* w-pawn promote table indeces */
extern int bpp_ti[8];		/* b-pawn promote table indeces */
extern int piece_ti[32];	/* piece/placement table indeces */

extern int n_ppt;		/* # of entries used in pp-tab */

extern int fit_const;		/* parameter free part of the eval func */

struct fit_param {		/* parameter subject to be fit */
    char *name;				/* name */
    int	init;				/* initial value */
    int	act;				/* actual value (after fit) */
    int coef;				/* coefficient in current evaluation */
    int last;				/* for incremental screen updates */
    unsigned on:1;			/* = 1: participate in fit */
    unsigned used:1;			/* = 1: has been non-zero on occation */
    unsigned table:1;			/* = 1: has a table attached to it */
    unsigned tab_on:1;			/* = 1: is active in table fit mode */
    struct tab_descr *tp;		/* pointer to table structure */
};

struct tab_descr {		/* table descriptor */
    short *data;			/* pointer to data */
    int dim;				/* number of dimensions 1..4 */
    int rng[4];				/* number ranges for each index */
    int	deg[4];				/* degree of approximation for each dimension */
    int	n_p;				/* number of approximation parameter */
};

#endif

#ifdef FIT_MODE

extern int stm;
#define WHITE_TO_MOVE (!stm)

#define scan_rook_tab(x) for(fit_cnt = 0; x=rook_ti[fit_cnt], fit_cnt < 8; fit_cnt++)
#define scan_wpawn_tab(x) for(fit_cnt = 0; x=wpawn_ti[fit_cnt], fit_cnt < 8; fit_cnt++)
#define scan_bpawn_tab(x) for(fit_cnt = 0; x=bpawn_ti[fit_cnt], fit_cnt < 8; fit_cnt++)
#define scan_wpp_tab(x) for(fit_cnt = 0; x=wpp_ti[fit_cnt], fit_cnt < 8; fit_cnt++)
#define scan_bpp_tab(x) for(fit_cnt = 0; x=bpp_ti[fit_cnt], fit_cnt < 8; fit_cnt++)
#define scan_piecep_tab(x) for(fit_cnt = 0; x=piece_ti[fit_cnt], fit_cnt < n_ppt; fit_cnt++)
#else

#define WHITE_TO_MOVE (!(movesmade & 1))

#define scan_rook_tab(x) for(x = 0; x < ROOKTABLESIZE; x++)
#define scan_wpawn_tab(x) for(x = 0; x < PAWNTABLESIZE; x++)
#define scan_bpawn_tab(x) for(x = 0; x < PAWNTABLESIZE; x++)
#define scan_wpp_tab(x) for(x = 0; x < PPTABLESIZE; x++)
#define scan_bpp_tab(x) for(x = 0; x < PPTABLESIZE; x++)
#define scan_piecep_tab(x) for(x = 0; x < PCPLACESIZE; x++)
#endif


/*
 *  addto_pcpl_tab(piece, square, expr);
 *
 *           is the same as:
 *
 *  pieceplacement(piece, square) += expression;
 *
 *  expr: must be one or more scaled parameter. To sum, use "PLUS"
 *
 *  Note: the "pieceplacement" - macro can be used too, but it will not
 *        be recognized as a parameter-dependent experession. It will
 *        be treated as a constant.
 *
 *  scale(parameter, a, b)
 *
 *  parameter: must be one of the eval-func parameters.
 *  a, b: are normal integer expression. parameter will be weighted with a/b.
 *
 *  Note2: use a negative 'b' to subtract (it's usually a constant...)
 */
#ifdef FIT_MODE
#define decl_param(name, init_value) \
			    struct fit_param name = {"name", init_value, 0, 0, 0x7fffffff, 1, 0, 0, 0, 0};

#define decl_1tab(name, init_value, r1, o1) \
			    short name/**/_dat[r1];\
			    struct tab_descr name/**/_tab = {&(name/**/_dat[0]), 1, {r1, 1, 1, 1}, {o1, 0, 0, 0}, o1+1};\
			    struct fit_param name = {"name", init_value, 0, 0, 0x7fffffff, 1, 0, 1, 0, &name/**/_tab};\
			    short name/**/_dat[r1]

#define decl_2tab(name, init_value, r1, r2, o1, o2) \
			    short name/**/_dat[r2][r1];\
			    struct tab_descr name/**/_tab = {&(name/**/_dat[0][0]), 2, {r1, r2, 1, 1}, {o1, o2, 0, 0}, (o1+1)*(o2+1)};\
			    struct fit_param name = {"name", init_value, 0, 0, 0x7fffffff, 1, 0, 1, 0, &name/**/_tab};\
			    short name/**/_dat[r2][r1]

#define decl_3tab(name, init_value, r1, r2, r3, o1, o2, o3) \
			    short name/**/_dat[r3][r2][r1];\
			    struct tab_descr name/**/_tab = {&(name/**/_dat[0][0][0]), 3, {r1, r2, r3, 1}, {o1, o2, o3, 0},\
							     (o1+1)*(o2+1)*(o3+1)};\
			    struct fit_param name = {"name", init_value, 0, 0, 0x7fffffff, 1, 0, 1, 0, &name/**/_tab};\
			    short name/**/_dat[r3][r2][r1]

#define decl_4tab(name, init_value, r1, r2, r3, r4, o1, o2, o3, o4) \
			    short name/**/_dat[r4][r3][r2][r1];\
			    struct tab_descr name/**/_tab = {&(name/**/_dat[0][0][0][0]), 4, {r1, r2, r3, r4}, {o1, o2, o3, o4},\
							     (o1+1)*(o2+1)*(o3+1)*(o4+1)};\
			    struct fit_param name = {"name", init_value, 0, 0, 0x7fffffff, 1, 0, 1, 0, &name/**/_tab};\
			    short name/**/_dat[r4][r3][r2][r1]

#define scale(param, a, b) param.coef += ((a) << 8) / (b)

#define add_1tab(name, x1)		{name.coef += name/**/_dat[x1];\
					 if(name.tab_on) tbl_1upd (name.tp, x1, 1);}
#define sub_1tab(name, x1)		{name.coef -= name/**/_dat[x1];\
					 if(name.tab_on) tbl_1upd (name.tp, x1, -1);}
#define add_2tab(name, x1, x2)		{name.coef += name/**/_dat[x2][x1];\
					 if(name.tab_on) tbl_2upd (name.tp, x1, x2, 1);}
#define sub_2tab(name, x1, x2)		{name.coef -= name/**/_dat[x2][x1];\
					 if(name.tab_on) tbl_2upd (name.tp, x1, x2, -1);}
#define add_3tab(name, x1, x2, x3)	{name.coef += name/**/_dat[x3][x2][x1];\
					 if(name.tab_on) tbl_3upd (name.tp, x1, x2, x3, 1);}
#define sub_3tab(name, x1, x2, x3)	{name.coef -= name/**/_dat[x3][x2][x1];\
					 if(name.tab_on) tbl_3upd (name.tp, x1, x2, x3, -1);}
#define add_4tab(name, x1, x2, x3, x4)	{name.coef += name/**/_dat[x4][x3][x2][x1];\
				         if(name.tab_on) tbl_4upd (name.tp, x1, x2, x3, x4, 1);}
#define sub_4tab(name, x1, x2, x3, x4)	{name.coef -= name/**/_dat[x4][x3][x2][x1];\
				         if(name.tab_on) tbl_4upd (name.tp, x1, x2, x3, x4, -1);}

#define addto_pcpl_tab(piece, square, expr)  if(backup[square]==piece) {expr;};
#define assign_pcpl_tab(piece, square, expr)  if(backup[square]==piece) {expr;};
#define PLUS ;
#define pieceplacement(pc,nsq) if (backup[nsq] == pc) fit_const

#define addto_WPT(i, expr) {expr;}
#define addto_BPT(i, expr) {expr;}
#define addto_WPPT(i, expr) {expr;}
#define addto_BPPT(i, expr) {expr;}
#define addto_RookT(i, expr) {expr;}

#else					/* non-fit mode definitions follow */

#define decl_param(name, init_value) int name = init_value;
#define decl_1tab(name, init_value, r1, o1) \
			    int name = init_value;\
			    short name/**/_tab[r1]
#define decl_2tab(name, init_value, r1, r2 , o1, o2) \
			    int name = init_value;\
			    short name/**/_tab[r2][r1]
#define decl_3tab(name, init_value, r1, r2, r3, o1, o2, o3) \
			    int name = init_value;\
			    short name/**/_tab[r3][r2][r1]
#define decl_4tab(name, init_value, r1, r2, r3, r4, o1, o2, o3, o4) \
			    int name = init_value;\
			    short name/**/_tab[r4][r3][r2][r1]

#define scale(param, a, b) (((param * (a)) << 8) / (b))

#define add_1tab(name, x1)		(name * name/**/_tab[x1])
#define sub_1tab(name, x1)		(-name * name/**/_tab[x1])
#define add_2tab(name, x1, x2)		(name * name/**/_tab[x2][x1])
#define sub_2tab(name, x1, x2)		(-name * name/**/_tab[x2][x1])
#define add_3tab(name, x1, x2, x3)	(name * name/**/_tab[x3][x2][x1])
#define sub_3tab(name, x1, x2, x3)	(-name* name/**/_tab[x3][x2][x1])
#define add_4tab(name, x1, x2, x3, x4)	(name* name/**/_tab[x4][x3][x2][x1])
#define sub_4tab(name, x1, x2, x3, x4)	(-name * name/**/_tab[x4][x3][x2][x1])

#define addto_pcpl_tab(piece, square, expr) (PieceTable[((piece << 6) | Lsq[square])]) += expr
#define assign_pcpl_tab(piece, square, expr) (PieceTable[((piece << 6) | Lsq[square])]) = expr
#define PLUS +
#define pieceplacement(pc,nsq) (PieceTable[((pc << 6) | Lsq[nsq])])

#define addto_WPT(i, expr) rWPTable[i] += expr;
#define addto_BPT(i, expr) rBPTable[i] += expr;
#define addto_WPPT(i, expr) rWPPTable[i] += expr;
#define addto_BPPT(i, expr) rBPPTable[i] += expr;
#define addto_RookT(i, expr) rRookTable[i] += expr;
#endif

				/* scale and round towards 0:   ..-128][-127..+127][+128.. => ..,-1,0,+1,.. */
				/* code is reasonable (no div, etc) when compiled with -O, but could be better: one less branch */
#define unscale(x) (((x) >= 0) ? ((x) + 2048) / 4096 : ((x) - 2048) / 4096)

/*
 * The castling bonus stuff needs a bit attention:
 *
 * FIT_cast = -1: no castle move
 *	       0: WS  1: WL  2: BS  3: BL
 */
#ifdef FIT_MODE
extern int FIT_cast;
#define assign_WSbonus(expr) {if(FIT_cast == 0) expr;}
#define assign_WLbonus(expr) {if(FIT_cast == 1) expr;}
#define assign_BSbonus(expr) {if(FIT_cast == 2) expr;}
#define assign_BLbonus(expr) {if(FIT_cast == 3) expr;}
#else
#define assign_WSbonus(expr) WSbonus = unscale(expr);
#define assign_WLbonus(expr) WLbonus = unscale(expr);
#define assign_BSbonus(expr) BSbonus = unscale(expr);
#define assign_BLbonus(expr) BLbonus = unscale(expr);
#endif
