Простой Шахматный Минимакс
У меня есть проблема с моим собственным шахматным движком, использующим алгоритм минимакса для поиска шахматных ходов я использую поиск глубины 5 слоев и только с оценкой материала/бонуса/мобильности , но он также делает глупые ходы и жертвует ценными фигурами, даже когда я даю им бесконечность (что, несомненно, проблема поиска), я не использую какие-либо типы обрезки и дает результат поиска глубины 5 за несколько секунд.
Я застрял в этой проблеме в течение недели, я уверен, что проблема заключается в обратном отслеживании не шахматная логика (поэтому любой, у кого нет шахматного фона, решил бы это :)), и я много искал, это мой первый вопрос в переполнении стека, и я надеюсь, что вы, ребята, не разочаруете меня:)
вот простой код поиска
int GameControl::Evaluate(ChessBoard _B)
{
int material=0,bonus=0,mobility=0;
for(int i=0;i<8;i++)
for(int j=0;j<8;j++)
{
if(_B.Board[i][j]!=EMPTY)
{
if(_B.Board[i][j]->pieceColor==WHITE){
material+=-_B.Board[i][j]->Weight;
bonus+=-_B.Board[i][j]->bonusPosition[i][j];
mobility+=-_B.Board[i][j]->getPossibleMovesList(i,j,B).size();
}
else {
material+=_B.Board[i][j]->Weight;
bonus+=_B.Board[i][j]->bonusPosition[i][j];
mobility+=_B.Board[i][j]->getPossibleMovesList(i,j,B).size();
}
}
}
return material+bonus/10+mobility/20;
}
pair<pair<int,int>,pair<int,int>> GameControl::minimax( int depth , ChessBoard _B )
{
short int i,j;
int bestValue = -INFINITY;
pair<pair<int,int>,pair<int,int>> bestMove;
vector< pair<int,int> > ::iterator it;
vector< pair<int,int> > Z;
for( i = 0; i < 8; i++ )
for( j = 0; j < 8; j++ )
{
if(_B.Board[i][j]!=EMPTY && _B.Board[i][j]->pieceColor==BLACK )
{
Z=_B.Board[i][j]->getPossibleMovesList(i,j,_B);
for(it=Z.begin();it!=Z.end();it++)
{
pair<int,int> temp;
temp.first=i,temp.second=j;
ChessPieces* DestinationPiece;
DestinationPiece=_B.Board[(*it).first][(*it).second];
//Moving
_B.Board[(*it).first][(*it).second]=_B.Board[i][j];
_B.Board[i][j]=EMPTY;
//
int value = minSearch( depth-1 , _B );
if( value > bestValue )
{
bestValue = value;
bestMove.first.first = i;
bestMove.first.second = j;
bestMove.second.first = (*it).first;
bestMove.second.second = (*it).second;
}
//Undo Move
_B.Board[i][j]=_B.Board[((*it).first)][(*it).second];
_B.Board[(*it).first][(*it).second]=DestinationPiece;
}
}
}
return bestMove;
}
int GameControl::minSearch( int depth , ChessBoard _B )
{
short int i;
short int j;
if(depth==0)
return Evaluate(_B);
int bestValue = INFINITY;
for( i = 0; i < 8; i++ )
for( j = 0; j < 8; j++ )
{
vector< pair<int,int> > ::iterator it;
vector< pair<int,int> > Z;
if(_B.Board[i][j]!=EMPTY && _B.Board[i][j]->pieceColor==WHITE && !_B.Board[i][j]->V.empty())
{
Z=_B.Board[i][j]->getPossibleMovesList(i,j,_B);
for(it=Z.begin();it!=Z.end();it++)
{
pair<int,int> temp;
temp.first=i;
temp.second=j;
ChessPieces* DestinationPiece;
DestinationPiece=_B.Board[(*it).first][(*it).second];
// Moving
_B.Board[(*it).first][(*it).second]=_B.Board[i][j];
_B.Board[i][j]=EMPTY;
//
int value = maxSearch( depth-1 , _B );
if( value < bestValue )
bestValue = value;
//Undo Move
_B.Board[i][j]=_B.Board[(*it).first][(*it).second];
_B.Board[(*it).first][(*it).second]=DestinationPiece;
//
}
}
}
return bestValue;
}
int GameControl::maxSearch( int depth , ChessBoard _B )
{
short int i;
short int j;
if(depth==0)
return Evaluate(_B);
vector< pair<int,int> > ::iterator it;
vector< pair<int,int> > Z;
int bestValue = -INFINITY;
for( i = 0; i < 8; i++ )
for( j = 0; j < 8; j++ )
{
if(_B.Board[i][j]!=EMPTY && _B.Board[i][j]->pieceColor==BLACK )
{
Z=_B.Board[i][j]->getPossibleMovesList(i,j,_B);
for(it=Z.begin();it!=Z.end();it++)
{
pair<int,int> temp;
temp.first=i,temp.second=j;
ChessPieces* DestinationPiece;
DestinationPiece=_B.Board[(*it).first][(*it).second];
//Moving
_B.Board[(*it).first][(*it).second]=_B.Board[i][j];
_B.Board[i][j]=EMPTY;
//
int value = minSearch( depth-1 , _B );
if( value > bestValue )
bestValue = value;
//Undo Move
_B.Board[i][j]=_B.Board[((*it).first)][(*it).second];
_B.Board[(*it).first][(*it).second]=DestinationPiece;
}
}
}
return bestValue;
}
3 ответов
ты не делаешь короткошерстные поиск, поэтому глупые ходы, вероятно, из-за известного эффект горизонта что фиксированная глубина минимаксные поиски подвержены. Как минимум, вы должны расширить поиск любых принудительных ходов, проверок или захватов, где кусок захватывает одно из равных или больших значений.
есть несколько вещей, которые могут быть улучшены с вашим кодом:
- использовать negamax формулировку. Это устранит дублирование кода вашего
minsearch
иmaxsearch
. - использовать альфа-бета обрезка. Это удвоит глубину поиска за заданное количество времени поиска.
- использовать итеративным углублением в сочетании с хэш-таблицы. Итеративное углубление будет постепенно уточняться ваш результат поиска (так что вы можете прекратить поиск и сделать ход в любое время), и хэш-таблица позволит вам избежать дублирования работы, если вы столкнетесь с транспозициями в дереве игры.