我已经为此工作了很长时间,以至于不再有趣了。我正在尝试在Tic Tac Toe上实现Minmax,虽然我已经获得了一些可以做出合理初始举动的AI版本,但我永远也做不出任何失败的想法。
我无法解决的问题之一是启发式值。当前在第一个Minmax调用中返回的值为-10,而应该返回0(无论发生什么情况,它都应该能够绘制)。
另一个问题是它要运行40万次迭代,而最大迭代数为322,000,并且在早期获胜的情况下,甚至应该停止在25万左右。
任何帮助将不胜感激。
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个小时了,看来任务很简单,无法找出问题所在
最佳答案
以下代码可以帮助您:
(奖金:字母少于8000板。)
#include <algorithm>
#include <array>
#include <cassert>
#include <iostream>
enum class Square
{
Empty,
O,
X
};
Square other(Square c) {
switch (c) {
case Square::O: return Square::X;
case Square::X: return Square::O;
default: assert(0); return Square::Empty;
};
}
template <typename STREAM>
STREAM& operator << (STREAM& stream, Square c)
{
switch (c)
{
case Square::Empty: stream << "."; break;
case Square::X: stream << "X"; break;
case Square::O: stream << "O"; break;
}
return stream;
}
class Board
{
public:
Board() : board({{Square::Empty, Square::Empty, Square::Empty,
Square::Empty, Square::Empty, Square::Empty,
Square::Empty, Square::Empty, Square::Empty}})
{}
void display() const {
for (int y = 0; y != 3; ++y) {
for (int x = 0; x != 3; ++x) {
std::cout << board[3 * y + x] << " ";
}
std::cout << std::endl;
}
}
void play(unsigned int x, unsigned int y, Square c)
{
assert(x < 3);
assert(y < 3);
board[3 * y + x] = c;
}
void play(unsigned int offset, Square c)
{
assert(offset < 9);
board[offset] = c;
}
bool isFull() const {
return std::find(board.cbegin(), board.cend(), Square::Empty) == board.cend();
}
int computeScore(Square c) const
{
for (int i = 0; i < 3; ++i) {
if (board[3 * i] != Square::Empty && board[3 * i] == board[3 * i + 1] && board[3 * i] == board[3 * i + 2]) {
return board[3 * i] == c ? 1 : -1;
}
if (board[i] != Square::Empty && board[i] == board[i + 3] && board[i] == board[i + 6]) {
return board[i] == c ? 1 : -1;
}
}
if (board[4] == Square::Empty) {
return 0;
}
if ((board[4] == board[0] && board[4] == board[8])
|| (board[4] == board[2] && board[4] == board[6])) {
return board[4] == c ? 1 : -1;
}
return 0;
}
int minmax(Square c, unsigned int* counter, unsigned int* pos = NULL)
{
const int currentScore = computeScore(c);
if (currentScore != 0 || isFull()) {
if (counter) {++*counter; }
return currentScore;
}
int bestScore = -10;
for (unsigned int i = 0; i != 9; ++i) {
if (board[i] != Square::Empty) { continue; }
play(i, c);
int score = -minmax(other(c), counter);
if (bestScore < score) {
bestScore = score;
if (pos) { *pos = i; }
}
play(i, Square::Empty);
}
return bestScore;
}
int alphabeta(Square c, int alpha, int beta, unsigned int* counter, unsigned int* pos = NULL)
{
const int currentScore = computeScore(c);
if (currentScore != 0 || isFull()) {
if (counter) {++*counter; }
return currentScore;
}
for (unsigned int i = 0; i != 9; ++i) {
if (board[i] != Square::Empty) { continue; }
play(i, c);
int score = -alphabeta(other(c), -beta, -alpha, counter);
if (beta <= score) {
if (pos) { *pos = i; }
play(i, Square::Empty);
return score;
}
if (alpha < score) {
alpha = score;
if (pos) { *pos = i; }
}
play(i, Square::Empty);
}
return alpha;
}
private:
std::array<Square, 9> board;
};
int main()
{
Board b;
Square c = Square::X;
while (b.computeScore(Square::X) == 0 && b.isFull() == false) {
std::cout << c << " to play" << std::endl;
b.display();
unsigned int counter = 0;
unsigned int pos;
const int s = b.minmax(c, &counter, &pos);
//const int s = b.alphabeta(c, -10, 10, &counter, &pos);
b.play(pos, c);
std::cout << "score for "<< c <<" = " << s << std::endl;
std::cout << "#final boards examined = " << counter << std::endl;
std::cout << "----------------" << std::endl;
c = other(c);
}
std::cout << "Final score for X = " << b.computeScore(Square::X) << std::endl;
b.display();
return 0;
}
“迭代”的数量是所审查的最终董事会的数量。
关于c++ - C++ Minmax失败,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18590305/