Beispiel #1
0
void
doBattle(batstat *batstats, bprotocol *aProtocol, int phase)
{
  int             attackingShip;
  int             targetShip;
  group          *attackingGroup;
  group          *targetGroup;
  batstat        *attackingSide;
  batstat        *targetSide;
  int             gun;

  pdebug(DFULL, "doBattle\n");

  resetSides(batstats);
  while (!isDraw(batstats) && !isWon(batstats)) {
    while (attackersLeft(batstats)) {
      attackingGroup =
          selectAttackingGroup(batstats, &attackingSide, &attackingShip);
      assert(attackingGroup);
      attackingGroup->flags |= phase;

      for (gun = 0; gun < attackingGroup->type->attacks; gun++) {
        targetGroup =
            selectTargetGroup(attackingSide, &targetSide, &targetShip);
        if (targetGroup) {
          targetGroup->flags |= phase;
          attack(aProtocol,
                 attackingSide, attackingGroup, attackingShip,
                 targetSide, targetGroup, targetShip);
        }
      }
    }
    resetSides(batstats);
  }
}
Beispiel #2
0
int Evaluation::evaluate(ChessBoard& cb, int alpha, int beta)
{
	int score,i;
	evalFunction efunc;

	if (cb.move50draw > 98)
		return drawscore[cb.toMove];

	scanBoard(cb);


	if (gamestage < 3000)
		isEndgame = true;
	else
		isEndgame = false;

	evalPawnstructure(cb);

	if (isEndgame)
	{
		if (isDraw(cb))
			return drawscore[cb.toMove];
		evalStaticEndgame(cb);

		// try a alphabeta cut
		score = (cb.toMove == WHITE) ? (position[WHITE] - position[BLACK]) : (position[BLACK] - position[WHITE]);
		if ((score < (alpha - 300)) || (score > (beta + 300)))
			return score;

		i = 0;
		while (efunc = fEndGame[i++])
			(this->*efunc)(cb);

		score = (cb.toMove == WHITE) ? (position[WHITE] - position[BLACK]) : (position[BLACK] - position[WHITE]);

		// Correct the score if there isn't any winchances to force 3 fold rep.
		if (cantWin(cb))
			score = drawscore[cb.toMove] - 1;
		else if (cantLose(cb))
			score = drawscore[cb.toMove] + 1;
	}
	else
	{
		evalStatic(cb);

		// try a alphabeta cut
		score = (cb.toMove == WHITE) ? (position[WHITE] - position[BLACK]) : (position[BLACK] - position[WHITE]);
		if ((score < (alpha - 300)) || (score >(beta + 300)))
			return score;

		i = 0;
		while (efunc = fMiddleGame[i++])
			(this->*efunc)(cb);
		score = (cb.toMove == WHITE) ? (position[WHITE] - position[BLACK]) : (position[BLACK] - position[WHITE]);
	}


	return score;
}
Beispiel #3
0
int heuristicForState(GameState* gs, int player, int other) {
	if (isDraw(gs))
		return 0;

	int term_stat = getWinner(gs);
	if (term_stat == player)
		return 1000;

	if (term_stat)
		return -1000;

	
	return getHeuristic(gs, player, other);
		     
}
Beispiel #4
0
void checkWin(GameState* gs) {
	int win = getWinner(gs);
	
	if (win) {
		printf("Game over! %d wins!\n", win);
		printGameState(gs);
		exit(0);
	}

	if (isDraw(gs)) {
		printf("Game over! Draw!\n");
		printGameState(gs);
		exit(0);
	}
	     
}
/*!
  Slot to check if the current game is over, returns boolean value.
*/
bool TicTacEngine::isGameOver()
{
    bool gameOver(false);

    int theWinner = winner();

    if (theWinner != GameModel::None) {
        qDebug() << "TicTacEngine::isGameOver(): Yes!";
        gameOver = true;
        setStatus(GameOver);
    }
    else if (isDraw()) {
        gameOver = true;
        setStatus(GameOver);
    }

    return gameOver;
}
int findDrawLocation(){
    int cycle =currentState.round - twoOfPowerState.round;
    State state1;
    State state2;
    copyState(&state1, &initState);
    copyState(&state2, &initState);

    int cycleCount = cycle;
    while(cycleCount-- /** debugging , cycle--**/ ){
        dispatchOneCard( &state2);
        darwCardsFromPack( &state2);
        state2.round++;
        getWhichTurn( &state2);
    }

    int i=15;  /** int i=14;  debugging, because round is start by 1**/

    for ( ;i<=currentState.round;i++  ){

        dispatchOneCard( &state1);
        darwCardsFromPack( &state1);

        dispatchOneCard( &state2);
        darwCardsFromPack( &state2);

        if (isDraw(&state1 , &state2) ==1 ){
            return state1.round + cycle; /**debugging  return state1.round; **/
        }

        state1.round++;
        state2.round++;
        getWhichTurn( &state1);
        getWhichTurn( &state2);
    }


    return -1;
}
int main(){

    #if !defined(ONLINE_JUDGE)
        freopen("246.in","r",stdin);
        ///freopen("error_input.txt","r",stdin);
        freopen("output.txt","w",stdout);
    #endif

    currentState = getNewState();
    initState = getNewState();
    twoOfPowerState = getNewState();

    int i=0;


    int topCard=0;
    while ( scanf("%d",&topCard) != EOF && topCard ){

        clearState(&currentState);
        clearState(&initState);
        clearState(&twoOfPowerState);

        currentState.handCard[51] = topCard;
        for(i=0;i<51;i++){
            scanf("%d",&currentState.handCard[50-i]);
        }
        currentState.handCardLength =52;

        currentState.round = 1; /** debugging for round start with 1 **/

        for (i=1;i<=14;i++){

           /** turn = getWhichTurn( &currentState);  debug for all cardsLength is zero **/



           int handCard = currentState.handCard[ (currentState.handCardLength -1) ];
           int cardLength = currentState.cardsLength[currentState.whichTurn];

           currentState.cards[currentState.whichTurn][ cardLength] =handCard;

           currentState.handCardLength--;
           currentState.cardsLength[currentState.whichTurn]++;


           if ( is2OfPower(i) >0 ){
                copyState( &twoOfPowerState , &currentState);
           }

           outputForDebug(&currentState);

           /** debugging , put on the last part after dispatching card.**/
           currentState.whichTurn= (currentState.whichTurn +1 ) % 7;
           currentState.round ++;  /** debugging put it than copyState **/


        }

        copyState(&initState, &currentState);  /** use initSate when try to find loop's location. **/


        while (1){

              /** for debugging
              if ( currentState.round == 82  ){
                 int bbb=1;
              }
              **/


               dispatchOneCard( &currentState);
               darwCardsFromPack( &currentState);


               if ( currentState.handCardLength == 52){
                   printf("Win : %d\n",  currentState.round);
                   break;
               }else if ( currentState.handCardLength ==0 ){
                   printf("Loss: %d\n",  currentState.round);
                   break;
               }else if (isDraw(&currentState, &twoOfPowerState)>0 ){
                   int roundLocation = findDrawLocation();
                   printf("Draw: %d\n", roundLocation);
                   break;
               }

               /** debugging, should be put behind isDraw()!!
                    before copying  currentState to towOfPowerState,
                    it should be done the isDraw action.
                **/
               if ( is2OfPower(currentState.round  ) >0  ){  /**debugging is2OfPower(i) **/
                    copyState( &twoOfPowerState , &currentState);
               }

               currentState.round++;
               getWhichTurn( &currentState );

        }


    }


    return 0;
}
Beispiel #8
0
int isGameDraw() {
	return isDraw(globalState);
}
Beispiel #9
0
int getWeight(GameTreeNode* node, int movesLeft) {
	int toR, move, best_weight;
	if (getWinner(node->gs) || isDraw(node->gs) || movesLeft == 0)
		return heuristicForState(node->gs, node->player, node->other_player);

	GameState** possibleMoves = (GameState**) malloc(sizeof(GameState*) * node->gs->width);
	int validMoves = 0;
	for (int possibleMove = 0; possibleMove < node->gs->width; possibleMove++) {
		if (!canMove(node->gs, possibleMove)) {
			continue;
		}
		
		possibleMoves[validMoves] = stateForMove(node->gs, possibleMove, (node->turn ? node->player : node->other_player));
		validMoves++;
	}

	// order possibleMoves by the heuristic
	g_node = node;
	if (node->turn) {
		// qsort_r is apparently non-standard, and won't work with emscripten. So we'll need to use a global.
		qsort(possibleMoves, validMoves, sizeof(GameState*), ascComp); 
	} else {
		qsort(possibleMoves, validMoves, sizeof(GameState*), desComp); 
	}

	best_weight = (node->turn ? INT_MIN : INT_MAX);

	for (move = 0; move < validMoves; move++) {
		// see if the game state is already in the hash table
		GameState* inTable = lookupInTable(node->ht, possibleMoves[move]);
		int child_weight;
		int child_last_move;
		if (inTable != NULL) {
			child_weight = inTable->weight;
			child_last_move = possibleMoves[move]->last_move;

		} else {
			GameTreeNode* child = newGameTreeNode(possibleMoves[move], node->player, node->other_player, !(node->turn),
							      node->alpha, node->beta, node->ht);
			child_weight = getWeight(child, movesLeft - 1);
			child_last_move = child->gs->last_move;
			free(child);
		}

	

		possibleMoves[move]->weight = child_weight;
		addToTable(node->ht, possibleMoves[move]);

		if (movesLeft == LOOK_AHEAD)
			printf("Move %d has weight %d\n", child_last_move, child_weight);

		// alpha-beta pruning
		if (!node->turn) {
			// min node
			if (child_weight <= node->alpha) {
				// MAX ensures we will never go here
				toR = child_weight;
				goto done;
			}
			node->beta = (node->beta < child_weight ? node->beta : child_weight);
		} else {
			// max node
			if (child_weight >= node->beta) {
				// MIN ensures we will never go here
				toR = child_weight;
				goto done;
			}
			node->alpha = (node->alpha > child_weight ? node->alpha : child_weight);
		}

		if (!(node->turn)) {
			// min node
			if (best_weight > child_weight) {
				best_weight = child_weight;
				node->best_move = child_last_move;
			}
		} else {
			// max node
			if (best_weight < child_weight) {
				best_weight = child_weight;
				node->best_move = child_last_move;
			}
		}

		
	}
	toR = best_weight;
done:
	for (int i = 0; i < validMoves; i++) {
		freeGameState(possibleMoves[i]);
	}

	free(possibleMoves);
	return toR;
}
Beispiel #10
0
int Engine::QuiescenceSearch(int alpha,int beta)
{
	//quisctime.Start();

	if (isDraw()) return 0;

	nodes++;
	if(nodes%CheckupNodeCount == 0)
	{
		checkup();
		//nodes = 0;
	}
	/*if(pos.getGameStatus()!=STATUS_NOTOVER)
	{
		int val = LeafEval(alpha,beta);
		if(val >= beta)
			return beta;
		else if(val < alpha)
			return alpha;
		return val;
	}*/
	int stand_pat = 0;
	//ProbeStruct probe = Table.Probe(pos.TTKey, -1, alpha, beta);
	//if (probe.found && probe.entry->bound == TT_EXACT)
	//{
	//	return probe.score;
	//	stand_pat = probe.score; //use TT probe as leafeval
	//}
	//else
	//{
		stand_pat = LeafEval<false>();
	//} 
	if(stand_pat >= beta) //standpat
	{
		return stand_pat;
	}
	if(stand_pat <= alpha-PieceMaterial[PIECE_QUEEN]) //big delta pruning
	{
		return stand_pat;
	}
	if(alpha < stand_pat)
	{
		alpha = stand_pat;
	}
	Move m;
	int score = 0;

    vector<Move> vec; //generate moves
	vec.reserve(128);
	//movegentime.Start();
	pos.generateCaptures(vec);
	//pos.generatePawnPushes(vec);
	//movegentime.Stop();

	//vector<int> scores; //generate move scores
	//scores.reserve(128);
	//generateCaptureScores(vec, scores);

	int material = getBoardMaterial<COLOR_WHITE>()+getBoardMaterial<COLOR_BLACK>();
	Move bestmove = CONS_NULLMOVE;
	int bound = TT_ALPHA;
	for(int i = 0;i<vec.size();i++)
	{
		//m = getHighestScoringMove(vec,i);
		m = vec[i];
		int special = m.getSpecial();
		int captured = m.getCapturedPiece();
		if ((stand_pat + PieceMaterial[getSquare2Piece(captured)] + 200 < alpha) //delta pruning
			&& (special != PIECE_QUEEN && special != PIECE_KNIGHT  && special != PIECE_ROOK && special != PIECE_BISHOP) //not a promotion
			//&& (material > EndgameMaterial)
			)
		{
            continue;
		}
		if (StaticExchangeEvaluation(m.getTo(), m.getFrom(), m.getMovingPiece(), captured) < 0)
			continue;
			//break; //since moves are sorted by SEE, we know remaining moves will also have SEE<0
		//if (getSquare2Piece(m.getCapturedPiece()) == PIECE_KING) //captured opponent king
		//	return CONS_INF;
		if(!pos.makeMove(m))
		{
			continue;
		}
		//pos.forceMove(m);
		ply++;
		if (ply > SelectiveDepth)
		{
			SelectiveDepth = ply;
		}
		score = -QuiescenceSearch(-beta,-alpha);
		pos.unmakeMove(m);
		ply--;
		if (score >= beta)
		{
			//Table.Save(pos.TTKey, -1, score, TT_BETA, m);
			return score;
		}
			
		if (alpha < score)
		{
			alpha = score;
			bestmove = m;
			bound = TT_EXACT;
		}
			
	}
	//Table.Save(pos.TTKey, -1, alpha, TT_ALPHA, bestmove);
	//quisctime.Stop();
	return alpha;
}
Beispiel #11
0
void GameCycle::assertDraw() const
{
    if (!isDraw())
        throw BadGamePlayStateException(m_state, GAMEPLAYSTATE_DRAW);
}
Beispiel #12
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;
}