示例#1
0
std::string pgn::Ply::toStdString() const
{
	std::string res;
	if (isLongCastle())
	{
		res += "O-O-O";
		if (isCheckMate())
			res +=  "#";
		else if (isCheck())
			res += "+";
	}
	else if (isShortCastle())
	{
		res += "O-O";
		if (isCheckMate())
			res +=  "#";
		else if (isCheck())
			res += "+";
	}
	else
	{
		res +=  hdata->piece.toStdString();
		if (hdata->fromSquare != '-')
			res +=  hdata->fromSquare;
		if (isCapture())
			res += "x";
 		res += hdata->toSquare.col();
 		res += hdata->toSquare.row();
		if (hdata->promoted)
		{
			res += "=";
			res += hdata->promoted->toStdString();
		}
		if (isCheckMate())
			res += "#";
		else if (isCheck())
			res += "+";
	}

	if (hdata->comment)
		res += hdata->comment->toStdString();

	return res;
}
示例#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;
}