I've been working on this for such a long time that it isn't funny anymore. I'm trying to implement Minmax on Tic Tac Toe and while I have gotten several versions of AI that make reasonable initial moves, I can never make one that never loses.
One of the issues which I cannot sort out is the heuristic value. It is currently returning as -10 on the first Minmax call, whereas it should be returning 0 (It should be able to draw no matter what happens).
Another issue is that it runs through 400,000 iterations, whereas 322,000 is the max and given early win situations, should even stop around 250,000.
Any help would be infinitely appreciated.
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;
}
The other related functions can be checked here, but I'm pretty sure they're okay. http://pastebin.com/eyaNfBsq
Yes I'm aware there's a few unnecessary parameters - After failing my own version I tried follow a tutorial off the internet. Unfortunately they're giving the same results.
I've been on this for 12 hours and it seems such a simple task, can't find out what's wrong
Following code may help you:
(Bonus: alphabeta with less than 8000 boards examined.)
The count of "iterations" is the number of final board examined.