#define TEST_END	{NULL, 0, NULL, 0}

const float HardwareRatio = 1.0; 

struct position_t {
	char *fen;		// fen string
	int depth;		// max depth
	char *move;		// best move
	int max_time;	// max time to find best move 
};

position_t perft_positions[] = {
	{"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -"				, 6-0, "", 0},	
	{"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -"	, 5-0, "", 0},
	{"8/PPP4k/8/8/8/8/4Kppp/8 w - -"									, 6-0, "", 0},
	{"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -"							, 7-0, "", 0},
	TEST_END
};

position_t search_positions[] = {
	// combinations
	{"r2qrbk1/5ppp/pn1p4/np2P1P1/3p4/5N2/PPB2PP1/R1BQR1K1 w - - 0 1"	, MAX_DEPTH, "c2h7", 20},
	{"1rb1r1k1/p1p1qppp/2pb4/8/2P3n1/4P1P1/PB2BP1P/R1QN1RK1 b - - 0 1"	, MAX_DEPTH, "g4h2", 20},
	{"1q2k2r/1b1n2pp/3bNn2/8/1p2P3/5N2/1P2QPPP/2B2RK1 b k - 0 2"		, MAX_DEPTH, "h7h6", 20},	
	{"8/8/4b3/2Bp2Pp/7P/1pK1Pk2/8/8 b - - 0 1"							, MAX_DEPTH, "d5d4", 20},
	{"r3k2r/pp1qn1pp/2p2p2/8/3P4/5N2/PP2QPPP/2R1R1K1 w k - 0 17"		, MAX_DEPTH, "d4d5", 20},
	{"r1b1kb1r/1p4pp/p2ppn2/8/2qNP3/2N1B3/PPP3PP/R2Q1RK1 w k - 0 13"	, MAX_DEPTH, "f1f6", 20},
	{"r3r1k1/pp1bp2p/1n2q1P1/6b1/1B2B3/5Q2/5PPP/1R3RK1 w - - 0 1"		, MAX_DEPTH, "b4d2", 20},
	// depth
	{"4k3/7p/1pr1np2/p1p1pNpP/P1P1K1P1/1P2P3/3R1P2/8 w - - 0 1"			, 18	   , "d2d6", 20},
	{"6k1/1p1q1rpp/3p4/Q3p3/3P4/1b2B2P/1P3PP1/3R2K1 w - -"				, 14       , ""    , 20},
	{"2r1b1r1/4k3/p1p1p2p/1pR5/2P1B2P/8/P4PP1/3R1K2 w - -"				, 13       , ""    , 20},
	{"3rr1k1/2p3p1/1pp2p1p/p7/1n2PRP1/1P1P1NKP/1PP2R2/8 b - -"			, 15       , ""    , 20},
	{"r4rk1/pp1qpp1p/3p2p1/3NP1b1/8/8/PPP2PPP/R2QR1K1 w - -"			, 13       , ""    , 20},
	{"8/2R5/p3kpp1/1p5p/4PBnP/3P2P1/1qP3K1/5R2 w - -"					, 16       , ""    , 20},
	{"r7/1pp4p/p2k2p1/3P1b1n/P1PBrp2/2P2N2/5P1P/R2K2R1 w - -"			, 13       , ""    , 20},
	{"8/8/3k2pp/3p1p2/1K6/4PPPP/8/8 w - -"								, 20       , ""    , 20},
	TEST_END
};

position_t debug_positions[] = {
	{"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -"				, MAX_DEPTH, "",  0},	// init 
//	{"rnbqkb1r/pp2pppp/2p2n2/8/QPpP4/5N2/P3PPPP/RNB1KB1R b KQkq b3 0 0"	, MAX_DEPTH, "",  0},	// bug in GenLegalMoves
//	{"r4rk1/4pp1p/2bp2p1/1p2n1Bq/4P3/2P2P2/P1PQB1PP/R2R2K1 b - -"		, MAX_DEPTH, "",  0},	// tactic training
//	{"r3r1k1/pppq2bp/1n1p1pp1/n7/2PP4/1PN2N1P/P2QBPKB/R4R2 w - - 0 16"	, MAX_DEPTH, "",  0},	// test king safety
//	{"8/1B3p2/4p1pp/pKP5/P2k4/4nP2/6PP/8 w - - 0 1"						, MAX_DEPTH, "",  0},	// pin test
//	{"6k1/5qp1/5p1p/6n1/8/8/R4PPP/R4NK1 w - -"							, MAX_DEPTH, "",  0},	// shelter must be about +0.80
//	{"r1b2rk1/ppq2ppp/2p5/8/5PPP/2P5/PPQ5/R1B2RK1 w - -"				, MAX_DEPTH, "",  0},	// shelter must be about -0.60
//	{"r3kbnr/2p4p/p4p2/1pp5/4P1P1/1PN1B3/1PP3PP/R2R2K1 w kq -"			, MAX_DEPTH, "",  0},	// new pawn eval test must be ~ +4.00
//	{"r4rk1/2pqbp1p/pp2p1p1/n2pPn2/3P1P2/P1N1BN1P/1PP1Q1P1/2KR3R w - -"	, MAX_DEPTH, "",  0},	// opposite castling
//	{"8/5b1p/6p1/k7/7P/6P1/7B/7K w - -"									, MAX_DEPTH, "",  0},	// simple endgame
	TEST_END
};

// Benchmark()

void Searcher::Benchmark(position_t *position, bool view = false) {
	Board b[1];
	MoveList ml[1];
	position_t *pos;
	int max_time = 0,
		full_time = 0,
		i,time,ms_time;

	// lock data output
	locked_view = !view;	
		
	for(pos = &position[0]; pos->fen != 0; pos++) {
		
		b->FromFEN(pos->fen);
		b->Print();
		ml->Clear();
		data->bench_move->Parse(pos->move, b->type);
		ms_time = pos->max_time * 1000.0 * HardwareRatio;	
		printf("%s\n move to find %s   time %.1f sec\n", pos->fen, pos->move, ms_time / 1000.0);
		
		// search
		timer->Restart();
		RootSearch(b, 0, 0, 0, 0, pos->depth, 0, 0, 0, ms_time, 0, ms_time == 0, ml);
		time = timer->SearchTime();
		time = MIN(time, ms_time);
		
		// output
		printf(" found move   ");
		stack[0]->pv[0].Print();
		printf("  time %.2f sec\n\n",time/1000.0);
		
		// time
		full_time += time;
		max_time += ms_time;
	}	
	printf("Bench time %d min %d sec\n", full_time/60000, (full_time/1000)%60);
	printf("Benchmark %.2f\n", 100.0*(max_time - full_time) / max_time);
}


