#include <crtdbg.h>

#define ASSERT(a) _ASSERT(a)

using namespace std;

#ifdef _MSC_VER
	typedef unsigned __int64 BitBoard;
	typedef unsigned __int64 uint64;
	#define SINT64_FORMAT "%I64d"
	#define UINT64_FORMAT "%I64u"
	#define S64(u) (u##i64)
	#define U64(u) (u##ui64)
#else
	typedef unsigned long long BitBoard;
	typedef unsigned long long uint64;
	#define SINT64_FORMAT "%lld"
	#define UINT64_FORMAT  "%llu"
	#define S64(u) (u##LL)
	#define U64(u) (u##ULL)
#endif

#ifdef _DEBUG
	#undef DEBUG
	#define DEBUG true
	FILE *DebugFile = fopen("DEBUG FILE.txt","w+");
#else
	#define DEBUG false
#endif

typedef unsigned int uint;
typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
typedef signed short sint16;
typedef signed int sint32;
typedef signed char sint8;

#define BIT(s)		(BitMask[s])
#define BIT_L90(s)	(BitMaskL90[s])
#define BIT_L45(s)	(BitMaskL45[s])
#define BIT_R45(s)	(BitMaskR45[s])

#define WHITE				 0
#define BLACK				 1

#define EMPTY				 0
#define PAWN				 1
#define KNIGHT				 2
#define BISHOP				 3
#define ROOK				 4
#define QUEEN				 5
#define KING				 6
#define EN_PASSANT			 9 // hack see MakeMove()

// compact move bits
#define PROM_QUEEN			 0
#define PROM_KNIGHT			 1
#define PROM_ROOK			 2
#define PROM_BISHOP			 3
const int PromoteToPiece[] = {
QUEEN, KNIGHT, ROOK, BISHOP };

#define LIST_SIZE		   256
#define MAX_DEPTH		    64
#define MAX_KEYS		  1024
#define TRANS_MIN_SIZE	     8
#define TRANS_MAX_SIZE	   256
#define TRANS_DEFAULT_SIZE	16
#define MAX_MULTIPV		    16
#define DEFAULT_MULTIPV		 1
#define PAWN_INFO_SIZE	 16384
#define PAWN_SHELTER_SIZE 4096
#define PAWN_STORM_SIZE	  4096
#ifndef AUTO
	#define MAX_PERSONS		 1
#else
	#define MAX_PERSONS	   128
#endif

#define OPENING				 0
#define ENDGAME				 1
#define PHASE_NB			24

#define QUEENSIDE			 0
#define CENTER				 1
#define KINGSIDE			 2

#define PV_NODE		         1
#define NON_PV_NODE	         0

#define MAX(a,b)						((a)>=(b) ? (a) : (b))
#define MIN(a,b)						((a)<=(b) ? (a) : (b))
#define EVER							;;
#define ABS(a)							((a)>=0 ? (a) : -(a))
#define DEC_IF_RES_IS_POSITIVE(a,b)		((a)-(b)>0 ? (a)-(b) : (a))
#define MATH_SQUARE(a)					((a)*(a))

/* board
  _________________________
8| 56 57 58 59 60 61 62 63 |
7| 48 49 50 51 52 53 54 55 |
6| 40 41 42 43 44 45 46 47 |
5| 32 33 34 35 36 37 38 39 | 
4| 24 25 26 27 28 29 30 31 |
3| 16 17 18 19 20 21 22 23 | 
2|  8  9 10 11 12 13 14 15 |
1|  0  1  2  3  4  5  6  7 |
 |_________________________|
    A  B  C  D  E  F  G  H
*/

const uint a1 = 0,  b1 = 1,  c1 = 2,  d1 = 3,  e1 = 4,  f1 = 5,  g1 = 6,  h1 = 7,
		   a2 = 8,  b2 = 9,  c2 = 10, d2 = 11, e2 = 12, f2 = 13, g2 = 14, h2 = 15,
		   a3 = 16, b3 = 17, c3 = 18, d3 = 19, e3 = 20, f3 = 21, g3 = 22, h3 = 23,
		   a4 = 24, b4 = 25, c4 = 26, d4 = 27, e4 = 28, f4 = 29, g4 = 30, h4 = 31,
		   a5 = 32, b5 = 33, c5 = 34, d5 = 35, e5 = 36, f5 = 37, g5 = 38, h5 = 39,
		   a6 = 40, b6 = 41, c6 = 42, d6 = 43, e6 = 44, f6 = 45, g6 = 46, h6 = 47,
		   a7 = 48, b7 = 49, c7 = 50, d7 = 51, e7 = 52, f7 = 53, g7 = 54, h7 = 55,
		   a8 = 56, b8 = 57, c8 = 58, d8 = 59, e8 = 60, f8 = 61, g8 = 62, h8 = 63;

#define POW_2(x)   (U64(1)<<(x))
const BitBoard  A1 = POW_2(a1), B1 = POW_2(b1), C1 = POW_2(c1), D1 = POW_2(d1), E1 = POW_2(e1), F1 = POW_2(f1), G1 = POW_2(g1), H1 = POW_2(h1),
				A2 = POW_2(a2), B2 = POW_2(b2), C2 = POW_2(c2), D2 = POW_2(d2), E2 = POW_2(e2), F2 = POW_2(f2), G2 = POW_2(g2), H2 = POW_2(h2),   
				A3 = POW_2(a3), B3 = POW_2(b3), C3 = POW_2(c3), D3 = POW_2(d3), E3 = POW_2(e3), F3 = POW_2(f3), G3 = POW_2(g3), H3 = POW_2(h3),   
				A4 = POW_2(a4), B4 = POW_2(b4), C4 = POW_2(c4), D4 = POW_2(d4), E4 = POW_2(e4), F4 = POW_2(f4), G4 = POW_2(g4), H4 = POW_2(h4), 
				A5 = POW_2(a5), B5 = POW_2(b5), C5 = POW_2(c5), D5 = POW_2(d5), E5 = POW_2(e5), F5 = POW_2(f5), G5 = POW_2(g5), H5 = POW_2(h5),  
				A6 = POW_2(a6), B6 = POW_2(b6), C6 = POW_2(c6), D6 = POW_2(d6), E6 = POW_2(e6), F6 = POW_2(f6), G6 = POW_2(g6), H6 = POW_2(h6),   
				A7 = POW_2(a7), B7 = POW_2(b7), C7 = POW_2(c7), D7 = POW_2(d7), E7 = POW_2(e7), F7 = POW_2(f7), G7 = POW_2(g7), H7 = POW_2(h7), 
				A8 = POW_2(a8), B8 = POW_2(b8), C8 = POW_2(c8), D8 = POW_2(d8), E8 = POW_2(e8), F8 = POW_2(f8), G8 = POW_2(g8), H8 = POW_2(h8);

const BitBoard FileA = A1|A2|A3|A4|A5|A6|A7|A8;
const BitBoard FileB = B1|B2|B3|B4|B5|B6|B7|B8;
const BitBoard FileC = C1|C2|C3|C4|C5|C6|C7|C8;
const BitBoard FileD = D1|D2|D3|D4|D5|D6|D7|D8;
const BitBoard FileE = E1|E2|E3|E4|E5|E6|E7|E8;
const BitBoard FileF = F1|F2|F3|F4|F5|F6|F7|F8;
const BitBoard FileG = G1|G2|G3|G4|G5|G6|G7|G8;
const BitBoard FileH = H1|H2|H3|H4|H5|H6|H7|H8;

const BitBoard Rank_1 = A1|B1|C1|D1|E1|F1|G1|H1;
const BitBoard Rank_2 = A2|B2|C2|D2|E2|F2|G2|H2;
const BitBoard Rank_3 = A3|B3|C3|D3|E3|F3|G3|H3;
const BitBoard Rank_4 = A4|B4|C4|D4|E4|F4|G4|H4;
const BitBoard Rank_5 = A5|B5|C5|D5|E5|F5|G5|H5;
const BitBoard Rank_6 = A6|B6|C6|D6|E6|F6|G6|H6;
const BitBoard Rank_7 = A7|B7|C7|D7|E7|F7|G7|H7;
const BitBoard Rank_8 = A8|B8|C8|D8|E8|F8|G8|H8;

const int FILE_A = 0, FILE_B = 1, FILE_C = 2, FILE_D = 3, FILE_E = 4, FILE_F = 5, FILE_G = 6, FILE_H = 7;
const int RANK_1 = 0, RANK_2 = 1, RANK_3 = 2, RANK_4 = 3, RANK_5 = 4, RANK_6 = 5, RANK_7 = 6, RANK_8 = 7;

const BitBoard FileNotA	= ~FileA,
   FileNotH = ~FileH,
   FileNotAB = ~(FileA | FileB),
   FileNotGH = ~(FileG | FileH),
   OuterSquares = FileA | FileH | Rank_1 | Rank_8,
   InnerSquares	= ~OuterSquares,
   CornerSquares = A1 | A8 | H8 | H1,
   NotCornerSquares = ~CornerSquares;

#define BIT_UP(bb)				((bb)<<8)
#define BIT_TWO_UP(bb)			((bb)<<16)
#define BIT_UP_RIGHT(bb)		(((bb)<<9) & FileNotA)
#define BIT_RIGHT(bb)			(((bb)<<1) & FileNotA)
#define BIT_TWO_RIGHT(bb)		(((bb)<<2) & FileNotAB)
#define BIT_DOWN_RIGHT(bb)		(((bb)>>7) & FileNotA)
#define BIT_DOWN(bb)			((bb)>>8)
#define BIT_TWO_DOWN(bb)		((bb)>>16)
#define BIT_DOWN_LEFT(bb)		(((bb)>>9) & FileNotH)
#define BIT_LEFT(bb)			(((bb)>>1) & FileNotH)
#define BIT_TWO_LEFT(bb)		(((bb)>>2) & FileNotGH)
#define BIT_UP_LEFT(bb)			(((bb)<<7) & FileNotH)

#define RANK_COL(s,c)			((c == WHITE) ? Rank(s) : (7 - Rank(s)))
#define FILE_DIST(s1, s2)		(ABS(File(s1) - File(s2)))
#define RANK_DIST(s1, s2)		(ABS(Rank(s1) - Rank(s2)))
#define SQUARE_DIST(s1, s2)		(MAX(FILE_DIST(s1, s2), RANK_DIST(s1, s2)))
#define SQUARE_MAKE(f,r)		(((r)<<3)+(f))
#define ROTATE_LEFT_90(sq)		(SQUARE_MAKE(7-Rank(sq), File(sq)))
#define SHIFT_LEFT_45(sq)		((8 + (8*Rank(sq) + 8*File(sq) + (Rank(sq)>(7-File(sq)))*(Rank(sq)-(7-File(sq))))&63) + 1) 
#define ROTATE_LEFT_45(sq)		(SQUARE_MAKE(File(sq), 7&(Rank(sq) + File(sq) + 1))) 
#define SHIFT_RIGHT_45(sq)		(((64 + 7*Rank(sq) - 7*File(sq) + (Rank(sq)>File(sq))*(Rank(sq) - File(sq)))&63)+1)
#define ROTATE_RIGHT_45(sq)		(SQUARE_MAKE(File(sq), 7&(8 + Rank(sq) - File(sq))))
#define RANK_MIRROR_INIT(sq)    (SQUARE_MAKE(File(sq), 7-Rank(sq)))
#define FILE_MIRROR_LEFT(sq)    (SQUARE_MAKE(MIN(7-File(sq),File(sq)), Rank(sq)))
#define RANK_MIRROR_DOWN(sq)    (SQUARE_MAKE(File(sq), MIN(Rank(sq),7-Rank(sq))))
inline int File(int square)		{return square & 7 ;}
inline int Rank(int square)		{return square >> 3;}

BitBoard BitMask[64];
BitBoard BitMaskL90[64];
BitBoard BitMaskL45[64];
BitBoard BitMaskR45[64];

BitBoard Pawn[2][64];  
BitBoard Knight[64];
BitBoard BishopRR45[64][64];
BitBoard BishopRL45[64][64];
BitBoard RookR0[64][64];
BitBoard RookRL90[64][64];
BitBoard King[64];

BitBoard Line[64][64];		 // direction with sq1 and sq2
BitBoard Between[64][64];    // squares between sq1 and sq2
BitBoard BehindKing[64][64]; // square behind ksq; BehindKing[ksq][enemy] ... example event: q---K--k and move e1-f1(->)

BitBoard BishopPseudo[64];
BitBoard QueenPseudo[64];
BitBoard RookPseudo[64];

uint ShiftRL45[64];
uint RotateL45[64];
uint ShiftRR45[64]; 
uint RotateR45[64];

uint RankMirror[64];

uint8 KingWing[64];
BitBoard WingBB[3];

uint8 CastleMask[64];
uint64 CastleHashKey[16];
BitBoard KingZone[2][64];

const int sign[] = {1, -1};
const uint f1_f8[] = {f1, f8};
const uint g1_g8[] = {g1, g8};
const uint c1_c8[] = {c1, c8};
const uint d1_d8[] = {d1, d8};
const uint h4_h3[] = {h4, h3};
const uint h5_h2[] = {h5, h2};
const BitBoard E1_E8[] = {E1, E8};
const BitBoard F1_F8[] = {F1, F8};
const BitBoard D1_D8[] = {D1, D8};
const BitBoard AllSquares = 0xFFFFFFFFFFFFFFFF;
const BitBoard ShortCastleAttackedSquares[] = {(F1|G1), (F8|G8)};
const BitBoard LongCastleAttackedSquares[] = {(B1|C1|D1), (B8|C8|D8)};
const BitBoard EighthRank[] = {0xFF00000000000000, 0x00000000000000FF};
const BitBoard SeventhRank[] = {0x00FF000000000000, 0x000000000000FF00};
const BitBoard NonPromoteSquares[] = {0x00FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF00};
const BitBoard PromoteSafeSquares[] = {0x0000FFFFFFFFFFFF, 0xFFFFFFFFFFFF0000};
const BitBoard LightSquares = 0x55AA55AA55AA55AA;
const BitBoard DarkSquares = ~LightSquares;
const BitBoard LeftSide = FileA|FileB|FileC|FileD;
const BitBoard RightSide = FileE|FileF|FileG|FileH;
const BitBoard FriendlySide[] = {(Rank_1|Rank_2|Rank_3|Rank_4), (Rank_5|Rank_6|Rank_7|Rank_8)};
const BitBoard EnemySide[] = {(Rank_5|Rank_6|Rank_7|Rank_8), (Rank_1|Rank_2|Rank_3|Rank_4)};

const uint LastRankSquare[2][8] = {{a8, b8, c8, d8, e8, f8, g8, h8}, {a1, b1, c1, d1, e1, f1, g1, h1}};

const BitBoard FileBB[8] = {
	FileA, FileB, FileC, FileD, FileE, FileF, FileG, FileH
};
const BitBoard ContactFilesBB[8] = {
	FileB, FileA|FileC,	FileB|FileD, FileC|FileE, FileD|FileF, FileE|FileG,	FileF|FileH, FileG
};
const BitBoard LeftContactFilesBB[8] = {
	0, FileA, FileB, FileC, FileD, FileE, FileF, FileG
};
const BitBoard RightContactFilesBB[8] = {
	FileB, FileC, FileD, FileE, FileF, FileG, FileH, 0
};
const BitBoard RankBB[8] = {
	Rank_1, Rank_2, Rank_3, Rank_4, Rank_5, Rank_6, Rank_7
};
const BitBoard FrontRanks[2][8] = {	
	{	Rank_2 | Rank_3 | Rank_4 | Rank_5 | Rank_6 | Rank_7 | Rank_8,
		Rank_3 | Rank_4 | Rank_5 | Rank_6 | Rank_7 | Rank_8,
		Rank_4 | Rank_5 | Rank_6 | Rank_7 | Rank_8,
		Rank_5 | Rank_6 | Rank_7 | Rank_8,
		Rank_6 | Rank_7 | Rank_8,
		Rank_7 | Rank_8,
		Rank_8,		
		0
	}, 	{
		0,
		Rank_1,
		Rank_1 | Rank_2,
		Rank_1 | Rank_2 | Rank_3,
		Rank_1 | Rank_2 | Rank_3 | Rank_4,
		Rank_1 | Rank_2 | Rank_3 | Rank_4 | Rank_5,
		Rank_1 | Rank_2 | Rank_3 | Rank_4 | Rank_5 | Rank_6,
		Rank_1 | Rank_2 | Rank_3 | Rank_4 | Rank_5 | Rank_6 | Rank_7, }
};

BitBoard AntiPassedPawns[2][64];
BitBoard AntiOutpostPawns[2][64];

BitBoard DoubledPawnMask[2][64];
BitBoard IsolatedPawnMask[64];
BitBoard ChainPawnMask[2][64];
BitBoard HalfOpenFileMask[2][64];
BitBoard ProtectedPawnMask[2][64];
BitBoard CandidatePawnMask[2][64];
BitBoard CandidateOppPawnMask[2][64];
BitBoard LCandidatePawnMask[2][64];
BitBoard RCandidatePawnMask[2][64];
BitBoard LCandidateOppPawnMask[2][64];
BitBoard RCandidateOppPawnMask[2][64];
BitBoard BackwardPawnMask1[2][64];
BitBoard BackwardPawnMask2[2][64];
BitBoard UnstoppablePassed[2][64]; // hack: [colour][sq] - OPPONENTS TEMPO and our king is not blocker
BitBoard KingAssist[2][64];		   // if we have our king there we will promote a pawn
BitBoard PassedPair[2][64];

uint8 CharBitsCount[256]; // number of nonzero bits in int8 
uint8 CharFirstBit[256]; // position of first bit in int8
#define CHAR_BITS_COUNT(val)	(CharBitsCount[val & 0xFF])
#define FRONT_RANKS(col, sq)	(FrontRanks[col][Rank(sq)])
#define CONTACT_FILES_BB(sq)    (ContactFilesBB[File(sq)])
#define L_CONTACT_FILES_BB(sq)  (LeftContactFilesBB[File(sq)])
#define R_CONTACT_FILES_BB(sq)  (RightContactFilesBB[File(sq)])
#define FILE_BB(sq)				(FileBB[File(sq)])
#define RANK_BB(sq)				(RankBB[Rank(sq)])

#define ATT_RANK(s,o)											(RookR0[s][((o)>>(((s)&248)+1))&63]) // ~7 -> 248	
#define ATT_FILE(s,o)											(RookRL90[s][((o)>>((((s)&7)<<3)+1))&63])
#define ATT_R45(s,o)											(BishopRR45[s][((o)>>ShiftRR45[s])&63])
#define ATT_L45(s,o)											(BishopRL45[s][((o)>>ShiftRL45[s])&63])
#define ROOK_ATT(s)												(ATT_RANK(s,occupied)|ATT_FILE(s,occupied_rl90))
#define BISHOP_ATT(s)											(ATT_R45(s,occupied_rr45)|ATT_L45(s,occupied_rl45))
#define KNIGHT_ATT(s)											(Knight[s])
#define KING_ATT(s)												(King[s])
#define QUEEN_ATT(s)											(ROOK_ATT(s)|BISHOP_ATT(s))
#define ROOK_ATT_PSEUDO(s)										(RookPseudo[s])				
#define BISHOP_ATT_PSEUDO(s)									(BishopPseudo[s])
#define QUEEN_ATT_PSEUDO(s)										(QueenPseudo[s])
#define ROOK_ATT_MODEL(s, occ, occ_l90)							(ATT_RANK(s, occ)|ATT_FILE(s,occ_l90))
#define BISHOP_ATT_MODEL(s, occ_r45, occ_l45)					(ATT_R45(s,occ_r45) | ATT_L45(s,occ_l45))
#define QUEEN_ATT_MODEL(s, occ, occ_l90, occ_r45, occ_l45)		(ROOK_ATT_MODEL(s, occ, occ_l90) | BISHOP_ATT_MODEL(s, occ_r45, occ_l45))

#define OSI(col,name)											(opening += ((p->name)*sign[col]))				// opening single increment
#define OTI(col,name,nb)										(opening += ((*(p->name + (nb)))*sign[col]))	// opening table increment
#define OSIC(col,name,count)									(opening += ((p->name)*sign[col]*(count)))		// with count
#define OTIC(col,name,nb,count)									(opening += ((*(p->name + (nb)))*sign[col]*(count)))
#define OTIP(col,name,nb,percent)								(opening += ((*(p->name + (nb)))*sign[col]*(percent)/100)) // percents

#define ESI(col,name)											(endgame += ((p->name)*sign[col]))
#define ETI(col,name,nb)										(endgame += ((*(p->name + (nb)))*sign[col]))
#define ESIC(col,name,count)									(endgame += ((p->name)*sign[col]*(count)))				
#define ETIC(col,name,nb,count)									(endgame += ((*(p->name + (nb)))*sign[col]*(count)))
#define ETIP(col,name,nb,percent)								(endgame += ((*(p->name + (nb)))*sign[col]*(percent)/100))

#define MSI(col,name_op, name_eg)								{opening += ((p->name_op)*sign[col]); endgame += ((p->name_eg)*sign[col]);}// middlegame
#define MTI(col,name_op, name_eg, nb)							{opening += ((*(p->name_op + (nb)))*sign[col]); endgame += ((*(p->name_eg + (nb)))*sign[col]);}
#define GSI(col,name)											{opening += ((p->name)*sign[col]); endgame += ((p->name)*sign[col]);}// game
#define GTI(col,name,nb)										{opening += ((*(p->name + (nb)))*sign[col]); endgame += ((*(p->name + (nb)))*sign[col]);}
#define GSIC(col,name,count)									{opening += ((p->name)*sign[col]*(count)); endgame += ((p->name)*sign[col]*(count));}

class EvalInfo{	
public:	
	BitBoard checkers;	
	BitBoard victims[2];	// victims[WHITE] means all BLACK(!) pieces under attack
	BitBoard pinned_rooks;
	BitBoard pinned_bishops;
	sint32 value;
	sint16 pure_victim_delta;	// victims[WHITE] - victims[BLACK], don't counts pawns as victims
	sint16 pawn_victim_delta;	// victims[WHITE] - victims[BLACK], counts all
	sint16 passed_pawns[2];	
	sint16 king_safety[2];	
	uint16 lazy_used;
	uint16 in_check;	
	sint16 alpha;
	sint16 beta;	
};

class PawnInfo;
class PawnEntry;
struct position_t;


#define MEM_TEST(func) {\
	_CrtMemState s1, s2, s3;\
	_CrtMemCheckpoint( &s1 );\
	func;\
	_CrtMemCheckpoint( &s2 );\
	if ( _CrtMemDifference( &s3, &s1, &s2) ) {\
		_CrtMemDumpStatistics( &s3 );\
	}\
}
