Я работаю над этим так долго, что это уже не смешно. Я пытаюсь реализовать Minmax на Tic Tac Toe, и, хотя я получил несколько версий AI, которые делают разумные начальные шаги, я никогда не смогу сделать тот, который никогда не теряет.C++ Minmax Failing
Одной из проблем, которые я не могу разобраться, является эвристическое значение. В настоящий момент он возвращается как -10 по первому вызову Minmax, тогда как он должен возвращать 0 (он должен иметь возможность рисовать независимо от того, что происходит).
Другая проблема заключается в том, что она проходит через 400 000 итераций, тогда как 322 000 - это максимальная и заданная ранняя победная ситуация, должна даже остановиться около 250 000.
Любая помощь будет бесконечно оценена.
int MiniMax(TGameBoard _GameBoard)
{
//Always goes for max of course, just expanded in case you wanted two AIs
int iBestMove;
int iHeuristicReturned = 0;
if (_GameBoard.ePlayer == COMPUTER)
{
iHeuristicReturned = MaxMove(_GameBoard, iBestMove);
}
else
{
iHeuristicReturned = MinMove(_GameBoard, iBestMove);
}
//cout<<"\nHeuristic is "<<iHeuristicReturned<<endl;
g_iHeuristic = iHeuristicReturned;
return iBestMove;
}
int MaxMove(TGameBoard _GameBoard, int& _iMove)
{
//Logic
//If its an end node, calculate the score
//Otherwise, do minmax until the end node, and pass back the value
//If returned value is greater than v, then pass the move back upwards
++g_iIterations;
if(_GameBoard.CheckWinner(_GameBoard) || _GameBoard.IsFull())
{
int x;
x = EvaluateStaticPosition(_GameBoard, MAX);
return EvaluateStaticPosition(_GameBoard, MAX);
}
vector<int> moveList;
GenerateMoveList(_GameBoard, moveList);
int iNumMoves = moveList.size();
int v = -10000;
for(int i = 0; i < iNumMoves; ++i)
{
int iMove = moveList[i];
_GameBoard.Set(iMove, CROSS);
int opponentsBestMove;
++g_iDepth;
int curRating = MinMove(_GameBoard, opponentsBestMove);
--g_iDepth;
if (curRating > v)
{
v = curRating;
_iMove = iMove;
}
RetractMove(&_GameBoard, iMove);
}
return v;
}
int MinMove(TGameBoard _GameBoard, int& _iMove)
{
++g_iIterations;
if (g_iIterations > 320000)
{
int x = 0;
}
if(_GameBoard.CheckWinner(_GameBoard) || _GameBoard.IsFull())
{
return EvaluateStaticPosition(_GameBoard, MIN);
}
vector<int> moveList;
GenerateMoveList(_GameBoard, moveList);
int iNumMoves = moveList.size();
int v = 10000;
for(int i = 0; i < iNumMoves; ++i)
{
int iMove = moveList[i];
_GameBoard.Set(iMove, NAUGHT);
int opponentsBestMove;
++g_iDepth;
int curRating = MaxMove(_GameBoard, opponentsBestMove);
--g_iDepth;
if (curRating < v)
{
v = curRating;
_iMove = iMove;
}
RetractMove(&_GameBoard, iMove);
}
return v;
}
int EvaluateStaticPosition(TGameBoard _GameBoard, EGoal _eGoal)
{
if(_GameBoard.CheckWinner(_GameBoard, COMPUTER))
{
return 10;
}
if(_GameBoard.CheckWinner(_GameBoard, PLAYER))
{
return -10;
}
return 0;
}
Другие связанные функции можно проверить здесь, но я уверен, что они в порядке. http://pastebin.com/eyaNfBsq
Да, я знаю, что есть несколько ненужных параметров. После отказа от собственной версии я попробовал следовать учебному курсу из Интернета. К сожалению, они дают те же результаты.
Я был на этом в течение 12 часов, и это кажется такой простой задачей, не может узнать, что случилось
О количестве итераций, ваш счет неверен, вы подсчитываете количество символов «сыграно». Предположим, у вас есть две пустые ячейки, ожидаемый результат итерации - 2, но у вас будет 4. В моей версии я получил 265140 итераций и 9! = 362880. – Jarod42
MaxMove и MinMove могут быть факторизованы, предоставляя игроку и вычислительную оценку в соответствии с игроком (min (a, b, c, ...) == max (-a, -b, -c, -...)). – Jarod42
Спасибо Jarod В моей первоначальной версии у меня было это как единственная рекурсивная функция, но я разделил ее так, чтобы я мог легче следовать ей. Когда я заработаю, я верну все это в свою первоначальную версию. Я не совсем понял, почему я получаю двойные итерации. Можете ли вы объяснить больше? – Matt