#include <stdio.h>
#include <setjmp.h>
#include <string.h>
#include "hardware.h"
#include "piece.h"

/* Debuging and tracing flags */
#define VERB 1			/* Verbose output */
#define MOVEPERF 1		/* Count number of moves made */
/*#define DEBUG*/

#define MAXORDER 4		/* keep order of best few moves at root */

/* Parameters controlling hashtable (transposition table) */
#define HASHTABLE 1
#define HASHSPECIAL 1	/* hash special move status into hash index */
#define SINGHASH 2		/* use seperate hashtable for singular 
					entries */
#define HASH_BITS 20
#define SINGHASH_BITS 16

#define LBUF 10240
#define LEARN 0		/* remember all exact entries of depth >= learnmin,
			but no more than learnmax deep from the root 
			(learnmax=1 remember at most the root) */
extern int learnmin,learnmax;
#define USE_LEARN 0	/* always 0 : there for historical reasons */
#define USE_LEARN_EXACT 1 /* use remembered hash entries in search
		if entry is OLD_EXACT and deeper than current search */
#define BOOK_LEARN 1	/* use remembered hash entries only as book */
#define LEARNFILE "/usr/chess/bin/learn/ch.learn"
#define LEARNDIR "/usr/chess/bin/learn"
#define LEARNBUF 10240

/* if the following constant is changed old hashtables must be fixed
by calling "ch -F<i>" where <i> = (old NDEPTHMIN - new NDEPTHMIN) */
#define NDEPTHMIN	2	/* minimum microcode searchdepth -1 */

/* Parameters controlling search mechanism */
#define OFFSET 32768
extern int DRAWVALUE;
#define REPVALUE (DRAWVALUE-1)	/* to mark score as history sensitive */
#define WINDOW_LOW  30
#define WINDOW_HIGH 30

#define mask(n) (~((~0)<<(n)))
#define testbit(k,n) ((k)&(1<<(n)))
#define field(k,m,n) ((m)==0 ? ((k)&mask(n)) : (((k)>>(m))&mask(n)))
#define setfield(k,m,n,val) ((k &= (~(mask(n)<<(m)))), (k |= ((val)<<(m))))

#define empty(j) (!(j&7))
#define piece(j) (j&7)
#define whitepiece(j) (j && !(j&8))
#define blackpiece(j) (j>8)
#define whiteking(j) (j==WKING)
#define blackking(j) (j==BKING)
#define king(j) ((j&7)==KING)
#define pawn(j) ((j&7)==PAWN)
#define QueenBishopRook(j) ((j&6)==ROOK || (j&7)== BISHOP)
#define rook(j) ((j&7)==ROOK)
#define piece_eq(p1,p2) (p1==p2 || (empty(p1)&& empty(p2)))

/* value of pieces */
#define PAWNVAL 128
#define KNIGHTVAL 410
#define BISHOPVAL 422
#define ROOKVAL 640
#define QUEENVAL 1152

#define ILLDEPTH mask(8)	/* illegal depth value */
#define MAXDEPTH 127		/* maximum search depth : <=127 */
#ifdef DEBUG
#define MAXMOVEHISTORY 200
#else
#define MAXMOVEHISTORY 2000	/* maximum number of total moves + MAXDEPTH */
#endif
#define MAXSCORE 15000
#define MAXMOVES 300		/* maximum moves from a single position */

/* Normal Exit messages */
#define WHITE_WIN "White Wins\nQUIT\n"
#define BLACK_WIN "Black Wins\nQUIT\n"
#define STALEMATE_DRAW "Game Drawn (Stalemate)\nQUIT\n"
#define REPETITION_DRAW "Game Drawn (Repetition)\nQUIT\n"
#define WHITE_RESIGNS "I resign\nBlack Wins\nQUIT\n"
#define BLACK_RESIGNS "I resign\nWhite Wins\nQUIT\n"

struct hashtype {
	int hindex1;
	int hindex2;
};

#define FBITS 0	/* fractional bits in hashentry->sdepth */

struct hashentry {
	int hindex2;
	int bestmove;
	int bestmove2;
	unsigned char type;
	unsigned char sdepth;
	short score;
};

/* code for type field of hashentry */
#define TYPESIZ 3

#define VACANT 0	/* nothing valid */
#define OLD 1		/* bestmove(s) valid */
#define CHECKMATE 2	/* score valid (either side could be checkmated) */
#define STALEMATE 3	/* nothing else valid */
#define FAIL_LOW 4	/* score (upper bound) valid */
#define EXACT 5		/* score and bestmove valid */
#define FAIL_HIGH 6	/* score (lower bound) and bestmove valid */
#define OLD_EXACT 7	/* bestmove and score valid */

#define HASHGC(hashpt) {\
	if(hashpt->type==6)hashpt->type=OLD;\
	else hashpt->type &= 3;\
}

#define BUSY (1<<TYPESIZ)
#define RESTORE (2<<TYPESIZ)
#define HIST (4<<TYPESIZ)
#define IGNORE (8<<TYPESIZ)

struct sticky_struct {
    unsigned char next;	/* to mark singular extension nodes */
    unsigned char depth;  /* extension depth */
    short check;	/* singular checkevasion credit bit */
};

union sticky_type {
    int all;
    struct sticky_struct s;
};

struct state {
    int hindex1;
    int hindex2;
    int oldhindex2;
    struct hashentry *hashpt;
    int firstmove;		/* first move after hash move */
    int firstnorm;		/* first non capture move */
    int bestmove;		/* best move so far if not FL */
    int bestmove2;		/* second best move so far if >= 0 */
    int status;			/* call status of internal node */
    int move;			
    int castle_status;		/* bits 2..5*/
    int movestatus;		/* value returned by MOVESTATUS() */
    int rootscore;
    int curscore;		/* incremental score offset */
    int enpmove;		/* used for enp moves only */
    int singmove;		/* possible singular move */
    int killermove;		/* possible sing killer move */
    int killermove2;		/* second possible sing killer move */
    int killer1;		/* high priority killer move */
    int killer2;		/* low priority killer move */
    int countmask;		/* summary of piece count */
    int andmask;		/* used for software stalemate detection */
    int marginshift;		/* see threatevade.h */
    short bestscore;		/* either min or max */
    short oldbestscore;		
    short max;
    short min;
    int bonus;			/* bonus along line upto parent move */
    int fh_ext;		/* flag : extend all fail high
				moves by 1 ply (as if they were marked
				singular in the hashtable).
				Location is used to store the last
				such extended move, to avoid repeated
				extendsions of the same move */
    int ext_inhibit;		/* flag : inhibit fh-singular and threat
				extensions at the next lower level */
    union sticky_type sticky; /* for singular extension */
    short s_ext;	/* set to 1 if TERM_EXT>0 && SING_TEST_EX()
			   was executed at this depth */
    unsigned char depth;
/* constants which are function of search depth */
    unsigned char cdepth;
    short checkmate;
    short softscore;	/* used if FAILSOFT >= 1 */
#ifdef DEBUG
    int movelist[MAXMOVES];
    int oppmovelist[MAXMOVES];
#endif
};

/* Score computation tables, the first is currently a constant */
extern int PieceValue[16];
extern int castletable[1<<10];

extern unsigned int pawnvalue[1<<16];
extern unsigned int pawntable[1<<10];
extern int counttable[1<<10];

extern short abcval[1<<16];
extern short deval[1<<16];
extern short fghval[1<<16];
extern short insufftab[1<<14];

extern int rootorder[MAXORDER+1],iroot,jroot;

/* transposition tables */
extern struct hashtype movehash[1<<16],piecehash[1<<10];
extern int specialhash[64];
extern struct hashentry hashtable[1<<HASH_BITS];

/* singular entry hash table */
extern struct hashentry singhash[1<<SINGHASH_BITS];

/* speciel move tables */
extern int castlemap[64]; /* map from internal TO square of king move to
				 rook move */

/* Search tree */
extern struct state stack[MAXMOVEHISTORY];
extern int movesmade,movesmadestart;/*the number of moves made, starts at 0*/
extern int depth;

extern int sing_min,sing_margin;
extern int singfh_min,singfh_margin,singfh_rtest;
extern int null_plies;
extern int sing_min_opp,sing_margin_opp;
extern int singfh_min_opp,singfh_margin_opp,singfh_rtest_opp;
extern int threatevade_rtest;
extern int threatevade_margin;
extern int null_plies_opp;

extern int display;
extern int mate;/* if 1 search of checkmate only */
extern int rootmove;	/* bestmove from last completed ply  */
extern int rootscore;	/* score for rootmove */
extern int laststatus;	/* status from last search */
extern int lastmove;	/* status of last top level move (0 : normal,
			 != 0 : failing high,  -1 : in etime) */
extern int lastdepth;
extern int micro;	/* use microengine */
extern int searchrec;

/* search statistics */
extern int moves, qmoves;
extern int mintry, minterm;
extern int nullcutoff;
extern int sing_fh,s_sing_fh,singext_fh;
extern int threatevade,threatevade_ext,threatevade_ext2,threatevade_ext3,
	threatevade_rec,threatevade_rec2,threatevade_rec3,threatevade_rec4,
	s_threatevade;
extern int mflag1,mflag2,mflag3;
extern int eflag1;
extern int iter_deep,iter_deep2;
extern int sing, singext, singredo, singforce, singforce_d, singspurious, singforce2, singentry, rehash,
	singforce3, singexact, singpers, singpers1;
extern int speculate_margin,speculate_margin2,speculate_depth;
extern int recapt;
extern int termredo,termrestore;
extern int killertest, singkiller, killermiss;
extern int insuff;
extern int singcapt;
extern int term,termext;
extern int hashmiss,hashconflict,hash_ex,hash_fh,hash_fl,hash_old,hash_old2,hash_rep,
hash_cm,hash_sm,hash_ign,hash_fl_poor,hash_fl_p,fs_count,fs_sum,fs_mate;
extern int old2_noref;
extern int failedhigh,failedlow;
extern int lowscore,verb,slowterm;
extern int singlemove;
extern int hashmove;
extern int hashdepth;
extern int hashscore;

/* look ahead */
extern int thinkahead;
extern int guessmove;
extern int opptime;	/* boolean; true if thinking on opponents time */
extern jmp_buf return_buf;
extern int movelist[MAXMOVES];

/* timing control */
#define CONTROLINTERVAL 10 /* number of moves between time corrections */
extern int timed;	/* boolean */
extern int start;	/* time current move began : for clock*/
extern int start2;	/* time thinkahead began 
			(or == start if no thinkahead) */
extern int timecontrol; /* total time allowed to next time control */
extern int opptimecontrol;/* total time allowed for opponent */
extern int movescontrol;/* number of moves to next time control */
extern int lastsearchtime;

extern char *unparse();

extern int maxmovestart;
extern int rehashed;

extern int strategy;

extern struct hashsave {
	struct hashentry entry;
	int hindex1;
};

extern struct hashsave hsave[LEARNBUF];
extern struct hashsave hbuf[LEARNBUF];
extern struct hashsave hrefresh[LEARNBUF];
extern struct hashsave *hcur,*hend;
extern int refresh;
extern int savefile;
extern int maxsave;

extern int use_learn;
extern int book_learn;
extern int testopp,testtime,processtime;

extern int hashmove,hashdepth;

extern int gsearchdepth;

extern int maxtimeout;

extern int Tmargin;

extern int filelog;
extern FILE *fileoutput ;
extern char *fileoutputname;
extern FILE oldstdout;

extern int bestmove2;

extern int te_sensitize;
extern int te_singext;

extern int kcount;
extern int bonus1,bonus2,bonus3,bonus4;
extern int singbonus; /* singular bonus <= 0 */
extern int maxbonus_move,maxbonus_line;
extern int minbonus,maxbonus;

/* see eval.h */

extern int WSbonus,WLbonus,BSbonus,BLbonus;
