Хорошо, моя проблема должна звучать довольно знакомо всем, кто играл в программирование настольных игр, так что вот оно:
Итак, вот мой код MiniMax:
Move* Board::miniMax(int depth)
{
return this->maxMove(1, depth);
}
Move* Board::maxMove(int ply, int depth)
{
vector<Move*> moves = this->possibleMoves();
int movesSize = moves.size();
Move* maxMove = new Move(MINUS_INF);
for (int i=0; i<movesSize; i++)
{
Move* move = moves[i];
HASHMAKE(move,this);
move->value = (ply<depth) ? (this->minMove(ply+1, depth))->value
: this->eval();
maxMove = MAXMOVE(maxMove,move);
UNHASHMAKE(move,this);
}
return maxMove;
}
Move* Board::minMove(int ply, int depth)
{
vector<Move*> moves = this->possibleMoves();
int movesSize = moves.size();
Move* minMove = new Move(PLUS_INF);
for (int i=0; i<movesSize; i++)
{
Move* move = moves[i];
HASHMAKE(move,this);
move->value = (ply<depth) ? (this->maxMove(ply+1, depth))->value
: this->eval();
minMove = MINMOVE(minMove,move);
UNHASHMAKE(move,this);
}
return minMove;
}
Есть идеи, как можно настроить вышеуказанную вещь так, чтобы это был альфа-бета-поиск?
И вот моя попытка преобразования альфа-бета (которая терпит неудачу):
Move* Board::alphaBeta(int depth)
{
return this->alphaMax(1,depth,MINUS_INF,PLUS_INF);
}
Move* Board::alphaMax(int ply, int depth, int a, int b)
{
vector<Move*> moves = this->possibleMoves();
int movesSize = moves.size();
Move* maxMove = new Move(MINUS_INF);
for (int i=0; i<movesSize; i++)
{
Move* move = moves[i];
HASHMAKE(move,this);
move->value = (ply<depth) ? (this->alphaMin(ply+1, depth,a,b))->value
: this->eval();
maxMove = MAXMOVE(maxMove,move);
if (maxMove->value>=b) return maxMove;
a = MAXVAL(a,maxMove->value);
UNHASHMAKE(move,this);
}
return maxMove;
}
Move* Board::alphaMin(int ply, int depth, int a, int b)
{
vector<Move*> moves = this->possibleMoves();
int movesSize = moves.size();
Move* minMove = new Move(PLUS_INF);
for (int i=0; i<movesSize; i++)
{
Move* move = moves[i];
HASHMAKE(move,this);
move->value = (ply<depth) ? (this->alphaMax(ply+1, depth,a,b))->value
: this->eval();
minMove = MINMOVE(minMove,move);
if (minMove->value<=a) return minMove;
b = MINVAL(b,minMove->value);
UNHASHMAKE(move,this);
}
return minMove;
}
HINTS (чтобы избежать недоразумений) :
this->eval()
Функция возвращает счет с точки зрения игрока А. Например. +100 очков означает, что позиция в пользу игрока A, а -100 очков означает, что позиция в пользу игрока B.
MINUS_INF
а также PLUS_INF
были определены как некоторые произвольно малые и большие значения, соответственно.
Это не что-то вроде домашней работы или чего-то еще (если бы я, скорее всего, никогда не имел бы интереса играть с такими вещами … смеется)
Move
простой класс, содержащий сведения о перемещении, а также его соответствующее значение (назначенное eval
функция.
HASHMAKE
а также UNHASHMAKE
это всего лишь два макроса перемещения (не) создания и перемещения (не) хэширования, которые не должны иметь большого значения.
MAXMOVE
определяется так: #define MAXMOVE(A,B) (((A)->value>=(B)->value)?(A):(B))
MINMOVE
определяется так: #define MINMOVE(A,B) (((A)->value<=(B)->value)?(A):(B))
Не уверен, что это так, но я думаю, что в alphaMin
if (minMove->value<=a) return minMove;
b = MINVAL(b,minMove->value);
UNHASHMAKE(move,this);
должно быть
UNHASHMAKE(move,this);
if (minMove->value<=a) return minMove;
b = MINVAL(b,minMove->value);
а также аналогичные изменения в alphaMax
,
Других решений пока нет …