Простые шахматы минимакс

У меня проблема с моим собственным Chess Engine, использующим минимаксный алгоритм для поиска шахматных ходов. Я использую 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;
}

person Osama    schedule 29.04.2012    source источник
comment
Добавлен тег C++. Это C++ правильно?   -  person Cratylus    schedule 29.04.2012
comment
Если вы выполняете 5-слойный поиск, программа исправит любые проблемы, переместив потерянные 6 слоев вперед. Программы умные! Вы не можете позволить ему остановить поиск, когда некоторые части вот-вот будут захвачены.   -  person Bo Persson    schedule 30.04.2012


Ответы (3)


Вы не выполняете поиск бездействия, поэтому тупые ходы, вероятно, связаны с известным < href="http://en.wikipedia.org/wiki/Horizon_effect" rel="noreferrer">эффект горизонта, которому подвержен минимаксный поиск с фиксированной глубиной. Как минимум, вы должны расширить поиск любых вынужденных ходов, шахов или взятий, когда фигура берет фигуру равной или большей ценности.

person Kyle Jones    schedule 30.04.2012
comment
На самом деле, когда я сказал глупые движения, я имел в виду действительно глупые движения, такие как жертвование ценными предметами за меньшее количество, которых следует избегать даже при двухслойном поиске. - person Osama; 05.05.2012

Есть несколько вещей, которые можно улучшить с помощью вашего кода:

  1. Используйте формулировку negamax. Это устранит дублирование кода ваших minsearch и maxsearch.
  2. Используйте альфа-бета сокращение. Это удвоит глубину поиска за заданное время поиска.
  3. Используйте итеративное углубление в сочетании с хэш-таблица. Итеративное углубление будет постепенно уточнять ваш результат поиска (так что вы сможете прекратить поиск и сделать ход в любой момент), а хэш-таблица позволит вам избежать дублирования работы, если вы столкнетесь с транспозициями в дереве игры.
person TemplateRex    schedule 04.08.2012
comment
Последние две ссылки битые. - person Ekrem Dinçel; 28.12.2020
comment
@Kowalski исправлено, спасибо за отчет. - person TemplateRex; 28.12.2020

Разве функция поиска в исходной минимаксной функции не должна быть максимизирующей, а не минимизирующей?

person user2264327    schedule 03.01.2014
comment
На самом деле это не имеет значения, это зависит от того, какой игрок максимизирует, а кто минимизирует. - person Osama; 21.01.2014