Пример #1
0
// zero window search - non pv nodes
int SimplePVSearch::zwSearch(Board& board, SearchInfo& si) {
	if (stop(si)) {
		return 0;
	}
	if (si.ply>maxPlySearched) {
		maxPlySearched=si.ply;
	}
	if (si.depth<=0) {
		si.update(0,si.nodeType,si.beta-1, si.beta, si.move);
		return qSearch(board, si);
	}
	if	(board.isDraw() || si.ply >= maxSearchPly-1) {
		return drawScore;
	}
	if (-maxScore+si.ply >= si.beta) {
		return si.beta;
	}
	if (maxScore-(si.ply+1) < si.beta) {
		return si.beta-1;
	}
	const bool isKingAttacked = board.isInCheck();
	bool isLazyEval = false;
	bool nmMateScore=false;
	bool okToPrune=false;
	int score = 0;
	int currentScore = -maxScore;
	TranspositionTable::HashData hashData;
	MoveIterator::Move hashMove;
	const Key key = si.partialSearch?board.getPartialSearchKey():board.getKey();
	// tt retrieve & prunning
	bool hashOk = agent->hashGet(okToPrune, key, hashData, si.ply, si.depth,
			si.allowNullMove, si.beta-1, si.beta);
	if (hashOk) {
		hashMove = hashData.move();
		if (okToPrune) {
			return hashData.value();
		}
	}
	if (!isKingAttacked) {
		if (hashOk && (hashData.flag() & TranspositionTable::NODE_EVAL)) {
			currentScore = hashData.evalValue();
		} else {
			currentScore = evaluator.evaluate(board,si.beta-1,si.beta);
			isLazyEval = evaluator.isLazyEval();
		}
	}
	//razoring
	if (si.depth < razorDepth && hashMove.none() && si.allowNullMove &&
			!isKingAttacked && !isMateScore(si.beta) &&
			!board.isPawnPromoting() && !si.move.none() &&
			currentScore < si.beta-getRazorMargin(si.depth)) {
		const int newBeta = si.beta-getRazorMargin(si.depth);
		SearchInfo newSi(si.allowNullMove,si.move,newBeta-1,newBeta,0,
				si.ply,CUT_NODE,si.splitPoint);
		score = qSearch(board, newSi);
		if (score < newBeta) {
			return score;
		}
	}
	//futility
	if (!isKingAttacked && si.allowNullMove &&
			si.depth < futilityDepth && !board.isPawnFinal() &&
			!isMateScore(si.beta) && !si.move.none() &&
			currentScore >= si.beta+getFutilityMargin(si.depth,0)) {
		return currentScore-getFutilityMargin(si.depth,0);
	}
	// null move
	if (si.depth>1 && !isKingAttacked && si.allowNullMove &&
			!board.isPawnFinal() && !isMateScore(si.beta) &&
			currentScore >= si.beta-(si.depth>=nullMoveDepth?nullMoveMargin:0)) {
		const int reduction = 3 + (si.depth > 4 ? si.depth/4 : 0);
		MoveBackup backup;
		board.doNullMove(backup);
		SearchInfo newSi(false,emptyMove,si.beta,1-si.beta, si.depth-reduction,
				si.ply+1,CUT_NODE,si.splitPoint);
		score = -zwSearch(board, newSi);
		board.undoNullMove(backup);
		if (stop(si)) {
			return 0;
		}
		if (score >= si.beta) {
			if (score >= maxScore-maxSearchPly) {
				score = si.beta;
			}
			bool okToPrune = true;
			if (si.depth>11) {
				SearchInfo newSi(false,emptyMove,si.alpha,si.beta,si.depth-reduction,
						si.ply+1,CUT_NODE,si.splitPoint);
				const int newScore = zwSearch(board, newSi);
				if (newScore<si.beta) {
					okToPrune = false;
				}
			}
			if (okToPrune) {
				const TranspositionTable::NodeFlag flag = currentScore!=-maxScore && !isLazyEval?
						TranspositionTable::NM_LOWER_EVAL:TranspositionTable::NM_LOWER;
				agent->hashPut(key,score,currentScore,si.depth,si.ply,flag,emptyMove);
				return score;
			}
		} else {
			if (score == -maxScore+si.ply+2) {
				nmMateScore=true;
			}
		}
	}
	//iid
	if (si.depth > allowIIDAtNormal &&	hashMove.none() &&
			currentScore >= si.beta-iidMargin) {
		SearchInfo newSi(false,emptyMove,si.alpha,si.beta,si.depth/2,si.ply,ALL_NODE,si.splitPoint);
		score = zwSearch(board,newSi);
		hashOk=agent->hashGet(key, hashData, si.ply);
		if (hashOk) {
			hashMove = hashData.move();
		}
	}
	MoveIterator moves = MoveIterator();
	MoveIterator::Move move;
	MoveIterator::Move bestMove=emptyMove;
	int moveCounter=0;
	int bestScore=-maxScore;
	while (true) {
		move = selectMove<false>(board, moves, hashMove, si.ply, si.depth);
		if (move.none()) {
			break;
		}
		if (si.partialSearch && move == si.move) {
			continue;
		}
		const bool isHashMove = move.type==MoveIterator::TT_MOVE;
		int extension=0;
		if (isKingAttacked) {
			extension++;
		} else if (isHashMove && si.depth > seNonPVDepth && hashOk && !hashMove.none() &&
				!si.partialSearch && hashData.depth() >= si.depth-3 &&
				(hashData.flag() & TranspositionTable::LOWER)) {
			if (abs(hashData.value()) < winningScore) {
				const int seValue = hashData.value() - seMargin;
				SearchInfo seSi(false, hashMove, true, seValue-1, seValue, si.depth/2, si.ply,
						si.nodeType, si.splitPoint);
				const int partialScore = zwSearch(board,seSi);
				if (partialScore < seValue) {
					extension++;
				}
			}
		}
		MoveBackup backup;
		board.doMove(move,backup);
		moveCounter++;
		const bool givingCheck = board.setInCheck(board.getSideToMove());
		const bool passedPawnPush = isPawnPush(board,move.to);
		const bool pawnOn7thRank = move.promotionPiece!=EMPTY;
		//futility
		if  (	move.type == MoveIterator::NON_CAPTURE &&
				!isKingAttacked &&
				!givingCheck &&
				!passedPawnPush &&
				!pawnOn7thRank &&
				!nmMateScore &&
				extension == 0) {

			if (getMoveCountMargin(si.depth) < moveCounter &&
					si.depth < moveCountDepth && !isMateScore(bestScore) ) {
				board.undoMove(backup);
				continue;
			}
			if (si.depth < futilityDepth) {
				const int futilityScore = currentScore + getFutilityMargin(si.depth,moveCounter);
				if (futilityScore < si.beta) {
					if (futilityScore>bestScore) {
						bestScore=futilityScore;
					}
					board.undoMove(backup);
					continue;
				}
			}
		}
		//reductions
		int reduction=0;
		if (extension==0 && !isKingAttacked && !givingCheck && si.depth>lmrDepthThreshold &&
				!nmMateScore && move.type == MoveIterator::NON_CAPTURE &&
				!isHashMove && moveCounter != 1 && killer[si.ply][0] != move && killer[si.ply][1] != move) {
			reduction=getReduction(false, si.depth, moveCounter);
			if (si.nodeType == CUT_NODE ||
					agent->getHistory(board.getPiece(move.from), move.to) <= 0) {
				reduction++;
			}
		}
		int newDepth=si.depth-1+extension;
		SearchInfo newSi(true,move,si.beta,1-si.beta,newDepth-reduction,
				si.ply+1,si.nodeType==CUT_NODE?ALL_NODE:CUT_NODE,si.splitPoint);
		score = -zwSearch(board, newSi);
		if (score >= si.beta && reduction>0) {
			bool research=true;
			if (reduction>2) {
				newSi.update(newDepth-1,si.nodeType==CUT_NODE?ALL_NODE:CUT_NODE,
						si.beta,1-si.beta,move);
				score = -zwSearch(board, newSi);
				research=(score >= si.beta);
			}
			if (research) {
				newSi.update(newDepth,si.nodeType==CUT_NODE?ALL_NODE:CUT_NODE,
						si.beta,1-si.beta,move);
				score = -zwSearch(board, newSi);
			}
		}
		board.undoMove(backup);
		if (stop(si)) {
			return 0;
		}
		nodes++;
		if (score>=si.beta) {
			bestScore=score;
			bestMove=move;
			break;
		}
		if (score>bestScore) {
			bestScore=score;
			bestMove=move;
		}
		if (!stop(si) && agent->getThreadNumber()>1 &&
				agent->getFreeThreads()>0 && si.depth>minSplitDepth) {
			if (agent->spawnThreads(board, &si, getThreadId(), &moves, &move, &hashMove,
					&bestScore, &si.alpha, &currentScore, &moveCounter, &nmMateScore)) {
				if (bestScore>=si.beta) {
					break;
				}
			}
		}
	}
	if (!moveCounter) {
		return si.partialSearch?si.beta-1:isKingAttacked?-maxScore+si.ply:drawScore;
	}
	TranspositionTable::NodeFlag flag;
	if (bestScore>=si.beta) {
		flag = currentScore!=-maxScore && !isLazyEval?
				TranspositionTable::LOWER_EVAL:TranspositionTable::LOWER;
		agent->updateHistory(board,bestMove,si.depth);
		updateKillers(board,bestMove,si.ply);
	} else {
		flag = currentScore!=-maxScore && !isLazyEval?
				TranspositionTable::UPPER_EVAL:TranspositionTable::UPPER;
		bestMove=emptyMove;
	}
	agent->hashPut(key,bestScore,currentScore,si.depth,si.ply,flag,bestMove);
	return bestScore;
}
Пример #2
0
int Engine::AlphaBeta(int depth, int alpha, int beta, vector<Move>* variation, bool cannull, bool dopv)
{
#ifdef BLITZKRIEG_DEBUG
	Bitset tablekey = pos.PawnKey;
	if (alpha > beta || alpha < CONS_NEGINF || beta > CONS_INF)
	{
		cout << "info string ERROR: alpha > beta" << alpha << " " << beta << " " << ply << endl;
	}
#endif

	if (isDraw()) return 0;

	///Quiescence
	if (depth == 0)
	{
		int value = QuiescenceSearch(alpha, beta); //go to quiescence
		/*if (value > alpha && value < beta)
			PvSize = ply - 1;*/
		//Table.Save(pos.TTKey,0,value,TT_EXACT,CONS_NULLMOVE);
		return value;
	}

	nodes++;
	if (nodes%CheckupNodeCount == 0)
	{
		checkup();
		//nodes = 0;
	}

	///Repetition
	if (ply != 0 && pos.isRepetition()) //check for repetition
	{
		//Table.Save(pos.TTKey,depth,0,TT_EXACT,CONS_NULLMOVE);
		return 0;
	}

	///Probe
	int probe = Table.Probe(pos.TTKey, depth, alpha, beta);
	Move ttbestmove = createNullMove(pos.epsquare);
	if (probe != CONS_TTUNKNOWN)
	{
		//cout << probe << " found " << pos.TTKey << endl;
		if (ply != 0)
		{
			tthitcount++;
			return probe;
		}
		/*else
		{
			ttbestmove = Table.getBestMove(pos.TTKey);
			if (!ttbestmove.isNullMove())
			{
				variation->push_back(ttbestmove);
				tthitcount++;
				return probe;
			}
		}*/
	}
	//if (probe.avoidnull) cannull = false;

	int leafevalprobe = Table.Probe(pos.TTKey, 0, alpha, beta);
	if (leafevalprobe!=CONS_TTUNKNOWN 
		//&& leafevalprobe.entry->bound==TT_EXACT
		)
	{
		Evaluation[ply] = leafevalprobe; //use TT probe as a better leafeval
	}
	else
	{
		if (ply > 0 && currentVariation[ply] == CONS_NULLMOVE) //if last move was a nullmove, just invert score
		{
			Evaluation[ply] = -Evaluation[ply-1];
			assert(!cannull);
		}
		else
		{
			Evaluation[ply] = LeafEval<false>();
		}	
	}

	///Razoring
	if (!dopv && ply != 0 && depth < 4 && !incheck[ply] &&
		(((Evaluation[ply] + getRazorMargin(depth)) <= alpha)))
	{
		prunednodes++;
		if (depth <= 1 && (Evaluation[ply] + getRazorMargin(3)) <= alpha)
			return QuiescenceSearch(alpha, beta);

		int ralpha = alpha - getRazorMargin(depth);
		int v = QuiescenceSearch(ralpha, ralpha + 1);
		if (v <= ralpha)
			return v;
	}

	///Futility
	if (depth < 5 && ply != 0 && !incheck[ply] && ((Evaluation[ply] - getFutilityMargin(depth)) >= beta))
	{
		futilitynodes++;
		return (Evaluation[ply] - getFutilityMargin(depth));
	}

	int bound = TT_ALPHA;
	/*vector<Move> dummyline;
	dummyline.reserve(128);*/
	/*vector<Move> lineptr;
	lineptr.reserve(128);*/
	vector<Move> line;
	line.reserve(128);
	Move m;
	int score = 0;

	///Null Move
	bool madenullmove = false;
	Bitset Pieces = pos.OccupiedSq ^ pos.Pieces[COLOR_WHITE][PIECE_PAWN] ^ pos.Pieces[COLOR_BLACK][PIECE_PAWN];
	int pieceCount = popcnt(Pieces);
	if (cannull && !dopv && depth >= 3 && incheck[ply] == false
		&& (pieceCount>2) //side to move does not have only pawns(to avoid zugzwang)
		//&& Evaluation[ply] >= beta
		)
	{
		madenullmove = true;

		//int R = depth > 5 ? 3 : 2; //dynamic depth-based reduction
		int R = ((823 + 67 * depth) / 256 + std::min(max(0, Evaluation[ply] - beta) / PieceMaterial[PIECE_PAWN], 3));
		m = createNullMove(pos.epsquare);
		ply++;

#ifdef BLITZKRIEG_DEBUG
		Bitset ttkeynull = pos.TTKey;
#endif

		pos.forceMove(m);

		/*bool fullnullmovesearch = true;

		if (depth >= 7)
		{
			score = -QuiescenceSearchStandPat(-beta, -beta+1);
			if (score < beta)
				fullnullmovesearch = false;
		}
		if(fullnullmovesearch)*/
		score = -AlphaBeta(max(0, depth - R), -beta, -beta+1, &line, false, false); //make a null-window search (we don't care by how much it fails high, if it does)
		ply--;
		pos.unmakeMove(m);
		if (line.empty()!=true)
			Threats[ply] = line.at(line.size() - 1);

#ifdef BLITZKRIEG_DEBUG
		if (ttkeynull != pos.TTKey)
		{
			cout << "info string ERROR: Null TT fail" << endl;
			_getch();
		}
#endif

		if (score >= beta)
		{
			//cout << "Null move cutoff " << beta << endl;
			/*if (probe.avoidnull)
				badavoidnull++;*/
			nullcutoffs++;
			return score;
		}
		//if (score < alpha - 100) //score is so bad, we are in danger, so increase depth
		//{
		//	depth++;
		//}
	}

	//futility pruning
	//bool futilityprune = false;

	//if (depth < 4 && !underCheck && 
	//	(((leafeval + FutilityMargin[depth]) <= alpha))) //futility pruning
	//{
	//	futilitynodes++;
	//	futilityprune = true;
	//}

	//movesort(vec,depth);
	bool alpharaised = false;
	bool foundlegal = false;
	Move alphamove = CONS_NULLMOVE;
	int finalalpha = -1;
	int firstalpha = -1;
	//vec = pos.generateMoves();
	vector<Move> vec;
	vec.reserve(128);
	//movegentime.Start();
	//if (futilityprune)
	//{
	//	pos.generateCaptures(vec); //search only captures in futility pruning
	//}
	//else
	//{
	pos.generateMoves(vec);
	//}
	//movegentime.Stop();
	/*vector<Move> line;
	line.reserve(128);*/
	/*vector<int> scores;
	scores.reserve(128);
	generateCaptureScores(vec, scores);*/

	if (probe==CONS_TTUNKNOWN && (dopv || Evaluation[ply] + 256 >= beta) && depth >= 2) //internal iterative deepening
	{
		int score = AlphaBeta(depth-2, alpha, beta, &line, false, dopv);
	}	

	int evaldiff = ply >= 2 ? Evaluation[ply] - Evaluation[ply - 2] : 0;
	
	vector<Move> quietmoves;
	quietmoves.reserve(128);
	int bestscore = CONS_NEGINF;
	//int oldsortphase = SORTPHASE_NONE;
	for (unsigned int i = 0;i < vec.size();i++) //search
	{
		line.clear();
		//dummyline.clear();
		//m = vec.at(i);
		//int tablekey2 = pos.TTKey;
		m = getHighestScoringMove(vec, i);

#ifdef BLITZKRIEG_DEBUG
		if (SortPhase == SORTPHASE_NONE)
			cout << "info string Sort Phase error" << endl;
#endif

		int capturedpiece = m.getCapturedPiece();
		int special = m.getSpecial();
		int movingpiece = m.getMovingPiece();
		int moveto = m.getTo();
		int movefrom = m.getFrom();

		int iscapture = isCapture(m);
		/*int see = 0;
		int evade_see = 0;
		Move smallestattckr = pos.getSmallestAttacker(getOpponent(pos.turn), movefrom);
		if (iscapture)
		{
			see = StaticExchangeEvaluation(moveto, movefrom, movingpiece, capturedpiece);
		}
		if (!smallestattckr.isNullMove())
		{
			evade_see = StaticExchangeEvaluation(movefrom, smallestattckr.getTo(), smallestattckr.getMovingPiece(), movingpiece);
		}*/

		//if (iscapture && depth <= 1 && see < 0)
		//{ //prune bad captures at low depths
		//	continue;
		//}

		//if (depth < 8
		//	&& !alpharaised
		//	&& noMaterialGain(m)
		//	//&& !incheck[ply]
		//	&& !incheck[ply - 1]
		//	&& movingpiece!=PIECE_PAWN
		//	)
		//{
		//	if (i >= 2+depth*depth)
		//	{
		//		continue;
		//	}
		//}

		if (!pos.makeMove(m))
		{
			continue;
		}
		//if (vec.size() == 1 || (foundlegal==false && i==vec.size()-1)) //singular extension, only 1 legal move, so extend
		//{
		//	depth++;
		//}
		foundlegal = true;
		ply++;
		currentVariation[ply] = m;
		
		score = 0;

		int reductiondepth = 1;

		///Check Extension
		if (pos.underCheck(pos.turn))
		{
			incheck[ply] = true;
			reductiondepth--;
		}
		else
		{
			incheck[ply] = false;
		}

		///Recapture Extension
		/*if (ply > 1 && m.getTo() == currentVariation[ply - 1].getTo() && iscapture && isCapture(currentVariation[ply - 1]))
		{
			reductiondepth--;
		}*/

		//extend when capturing the last piece
		/*if (isCapture(m) && getSquare2Piece(capturedpiece) != PIECE_PAWN
			&& popcnt(pos.Pieces[COLOR_WHITE][PIECE_PAWN]) + popcnt(pos.Pieces[COLOR_BLACK][PIECE_PAWN]) + 2 == popcnt(pos.OccupiedSq))
		{
			reductiondepth -= 3;
		}*/

		/*if (depth < 16)
		{
			if (!incheck[ply - 1]
				&& !incheck[ply]
				&& movingpiece != PIECE_PAWN
				&& noMaterialGain(m))
			{
				if(i > 3 + (1 << (depth-1)))
				{
					pos.unmakeMove(m);
					incheck[ply] = false;
					ply--;
					continue;
				}
			}
		}*/

		//if (!dopv && depth < 4 && ((Evaluation[ply] + getSmallRazorMargin(depth)) <= alpha)) //small forward razoring
		//{
		//	reductiondepth++;
		//}

		///Latemove Reduction
		if (!alpharaised
			//&& i >= 4
			&& depth >= 4
			//&& special!=PIECE_QUEEN
			//&& (see < 0 || !iscapture)
			&& SortPhase >= SORTPHASE_HISTORY
			//&& noMaterialGain(m)
			//&& (KillerMoves[0][ply].getTo() != moveto || KillerMoves[0][ply].getFrom() != movefrom)
			//&& (KillerMoves[1][ply].getTo() != moveto || KillerMoves[1][ply].getFrom() != movefrom)
			&& !incheck[ply]
			&& !incheck[ply-1]
			//&& (movingpiece!=PIECE_PAWN || getRank(getColorMirror(getOpponent(pos.turn), moveto))<6) //dont reduce pawn moves past 6th rank
			//&& m!=Threats[ply]
			)
		{
			if (evaldiff > 0)
				reductiondepth += min(depth - 4, min((int)i,4));
			else
				reductiondepth += min(depth - 4, min((int)i+1,5));
			assert((depth - reductiondepth) >= 3);
			if (!dopv && HistoryScores[movingpiece][moveto] < 0) //history reduction
			{
				reductiondepth++;
			}
			if (m == Threats[ply] && reductiondepth > 0) //decrease reduction if move is a threat
			{
				reductiondepth = max(reductiondepth - 1, 0);
			}
			//if (noMaterialGain(m) && !smallestattckr.isNullMove() && evade_see < 0) //decrease reduction if move evades a capture
			//{
			//	reductiondepth = max(reductiondepth - 1, 0);
			//}
		}

		//if (isCapture(m) && !dopv && see > 400 && depth>=5) //prune really good captures
		//{
		//	reductiondepth += 4;
		//}

		//if (alpha_counter != 0 && (depth-reductiondepth)>=3 && i>((double)alphalast_sum/alpha_counter) && capturedpiece == SQUARE_EMPTY && special == PIECE_NONE
		//	&& !pos.underCheck(pos.turn)
		//	&& (KillerMoves[0][ply].getTo() != m.getTo() || KillerMoves[0][ply].getFrom() != m.getFrom())
		//	&& (KillerMoves[1][ply].getTo() != m.getTo() || KillerMoves[1][ply].getFrom() != m.getFrom())) //latemove reduction
		//{
		//	reductiondepth += 2;
		//	/*reductiondepth ++;
		//	if (i >= 8 && depth >= 6)
		//	{
		//		reductiondepth++;
		//		if (i >= 12 && depth >= 9) 
		//			reductiondepth++;
		//	}*/
		//}
		
		///Search
		if(dopv && i>0 && depth>=3) //principal variation search
		{
			score = -AlphaBeta(max(depth - reductiondepth, 0), -alpha - 1, -alpha, &line, true, false);
			if(score > alpha && score < beta) //check for failure
			{
				line.clear();
				score = -AlphaBeta(depth - 1, -beta, -alpha, &line, true, true); //research
				alpharaised = false;
				pvresearch++;
				//cout << "pv research" << endl;
			}
		}
		else
		{
			score = -AlphaBeta(max(depth - reductiondepth,0), -beta, -alpha, &line, true, dopv);
			//cout << "latemove" << endl;
			if(score > alpha && score < beta && reductiondepth>1)
			{
				line.clear();
				score = -AlphaBeta(depth - 1, -beta, -alpha, &line, true, dopv);
				latemoveresearch++;
			}
		}
		currentVariation[ply] = CONS_NULLMOVE;
		incheck[ply] = false;
		ply--;
		pos.unmakeMove(m);

		assert(score > CONS_NEGINF && score < CONS_INF);
		assert(score >= CONS_MATED && score <= -CONS_MATED);

		if(score>=beta)
		{
			if(noMaterialGain(m))
			{
				//if(Table.getBestMove(pos.TTKey)!=m) //dont store hash move as a killer
				setKiller(m, depth, score);

				int bonus = depth*depth;
				HistoryScores[movingpiece][m.getTo()] += bonus;
				if (HistoryScores[movingpiece][m.getTo()] > 200000) //prevent overflow of history values
				{
					for (int i = 0;i < 6;i++)
					{
						for (int j = 0;j < 64;j++)
						{
							HistoryScores[i][j] /= 2;
						}
					}
				}
				for (int i = 0;i < quietmoves.size();i++)
				{
					/*if(HistoryScores[quietmoves.at(i).getMovingPiece()][quietmoves.at(i).getTo()] <= bonus)
						HistoryScores[quietmoves.at(i).getMovingPiece()][quietmoves.at(i).getTo()] = 0;
					else*/
						HistoryScores[quietmoves.at(i).getMovingPiece()][quietmoves.at(i).getTo()] -= bonus;
				}
			}
			Table.Save(pos.TTKey, depth, score, TT_BETA, m);

#ifdef BLITZKRIEG_STATS
			betacutoff_counter++;
			betacutoff_sum += i+1;
			if (i == 0)
				firstbetacutoffcount++;
#endif
			return score; //fail soft beta cutoff
		}
		else if(score>bestscore)
		{
			bestscore = score;
			if (score > alpha)
			{
				bound = TT_EXACT;
				alpha = score;
				alpharaised = true;
				alphamove = m;

				*variation = line;

				if (noMaterialGain(m))
					HistoryScores[movingpiece][m.getTo()] += depth;

#ifdef BLITZKRIEG_STATS
				if (firstalpha == -1)
				{
					firstalpha = i;
				}
				finalalpha = i;
#endif
			}
		}

		if (noMaterialGain(m))
		{
			quietmoves.push_back(m);
		}
	}
	if(!foundlegal)
	{
		//if(futilityprune)
		//{
		//	//movegentime.Start();
		//	vec.clear();
		//	pos.generateMoves(vec);
		//	//movegentime.Stop();
		//	int flag = 1;
		//	for(int i = 0;i<vec.size();i++)
		//	{
		//		if(pos.makeMove(m))
		//		{
		//			unmakeMove(m);
		//			flag = 0;
		//			break;
		//		}
		//	}
		//	if(flag)
		//	{
		//		if(pos.underCheck(pos.turn))
		//		{
		//			return CONS_MATED-ply;
		//		}
		//		else
		//		{
		//			return CONS_DRAW;
		//		}
		//	}
		//}
		//else
		{
			if(pos.underCheck(pos.turn))
			{
				return CONS_MATED+ply;
			}
			else
			{
				return CONS_DRAW;
			}
		}
	}
	if(!alphamove.isNullMove())
	{
		variation->push_back(alphamove);
		//if(dopv)
		//	PrincipalVariation[ply] = alphamove;
		/*if (depth == 1)
		{
			PvSize = ply;
			PvPly = ply;
		}*/
		/*else if (ply == PvPly - 1)
		{
			PrincipalVariation[ply] = alphamove;
			PvPly = ply;
		}*/
		//HistoryScores[alphamove.getFrom()][alphamove.getTo()] += depth+finalalpha;
#ifdef BLITZKRIEG_STATS
		alpha_counter++;
		alphalast_sum += (finalalpha + 1);
		alphafirst_sum += (firstalpha + 1);
#endif
	}
	Table.Save(pos.TTKey, depth, bestscore, bound, alphamove);
	/*if (ply == 0)
	{
		cout << "info string Stored: " << alphamove.toString() << " " << bound << " " << depth << endl;
	}*/

#ifdef BLITZKRIEG_DEBUG
	if (pos.PawnKey != tablekey)
	{
		cout << "info string ERROR: Pawn TT key doesnt match" << endl;
	}
#endif
	return bestscore;
}