Что ж, у меня есть игра pacman с глобальным вектором … и символ [8], и символ [9] являются строкой и столбцом pacman.
Моя минимаксальфабетная реализация:
int minimaxAlphaBeta ( int mazeTemp[][COLUMNS], int alpha, int beta, int score, int direction, int depth, int jugador)
{
int bestValue, childValue;
int playerRow=2*jugador;
int playerColumn=(2*jugador)+1;
int sr= CharactersLocationsMaze[playerRow];
int sc= CharactersLocationsMaze[playerColumn];
bool restore=false;
if(mazeTemp[sr][sc] == WALL) //You cannot visit it, or is wall or is @ visited
return 0;
if( depth > 0)
{
//El fantasma gana ya que esta en la misma posicion que el pacman
if (sr == CharactersLocationsMaze.at(8) && sc == CharactersLocationsMaze.at(9) )
{
bestValue=10000;
return bestValue;
}
else if ( PacmanWin(mazeTemp))
{
bestValue=-10000;
return bestValue;
}
}
else if (depth==0)
{
bestValue= abs( CharactersLocationsMaze.at(0)- CharactersLocationsMaze.at(8) ) +
abs( CharactersLocationsMaze.at(2)- CharactersLocationsMaze.at(8) ) +
abs( CharactersLocationsMaze.at(4)- CharactersLocationsMaze.at(8) ) +
abs( CharactersLocationsMaze.at(6)- CharactersLocationsMaze.at(8) ) +
abs( CharactersLocationsMaze.at(1)- CharactersLocationsMaze.at(9) ) +
abs( CharactersLocationsMaze.at(3)- CharactersLocationsMaze.at(9) ) +
abs( CharactersLocationsMaze.at(5)- CharactersLocationsMaze.at(9) ) +
abs( CharactersLocationsMaze.at(7)- CharactersLocationsMaze.at(9));
// score se podria modificar ( penalizas mas perder puntos o alejarte del pacman
bestValue=((1/bestValue)*Number_MAX_VALUE)-(score*10);
return bestValue;
}
//puntuacion pacman si consigue puntos
else if (jugador < 4)
{ // Jugadores 0,1,2,3 son fantasmas maximizan valor
bestValue = alpha; //bestvalue es lmax y childValue l
bestMovementPath.push_back(direction);
//Row -- Norte: jugador Actualizo el valor de lmin porque l es menor que lmin
CharactersLocationsMaze[playerRow]=sr-1;
CharactersLocationsMaze[playerColumn]=sc;
childValue = minimaxAlphaBeta( mazeTemp, bestValue, beta, score, 1, depth-1, jugador+1);
if(childValue > bestValue) bestValue = childValue;
//Row ++ Sur
CharactersLocationsMaze[playerRow]=sr+1;
CharactersLocationsMaze[playerColumn]=sc;
childValue = minimaxAlphaBeta( mazeTemp, bestValue, beta, score, 2, depth-1, jugador+1);
if(childValue > bestValue) bestValue = childValue;
//Column -- Oeste West
CharactersLocationsMaze[playerRow]=sr;
CharactersLocationsMaze[playerColumn]=sc-1;
childValue = minimaxAlphaBeta( mazeTemp, bestValue, beta, score, 3, depth-1, jugador+1);
if(childValue > bestValue) bestValue = childValue;
//Column ++ Este
CharactersLocationsMaze[playerRow]=sr;
CharactersLocationsMaze[playerColumn]=sc+1;
childValue = minimaxAlphaBeta( mazeTemp, bestValue, score, 4, beta, depth-1, jugador+1);
if(childValue > bestValue)
{
bestValue = childValue;
if (beta <= bestValue) {
return bestValue; //00
}//Path.append("E");
}
//Restore
CharactersLocationsMaze[playerRow]=sr;
CharactersLocationsMaze[playerColumn]=sc;
bestMovementPath.pop_back();
return bestValue;
}else if ( jugador == 4)
{ // jUGADOR MIN
bestValue = beta; //bestvalue es lmax y childValue l
bestMovementPath.push_back(direction);
if(mazeTemp[sr][sc] == FOOD)
{
score=score+1;
mazeTemp[sr][sc] == PASSAGE;
restore=true;
}//Row -- Norte: jugador Actualizo el valor de lmin porque l es menor que lmin
CharactersLocationsMaze[playerRow]=sr-1;
CharactersLocationsMaze[playerColumn]=sc;
childValue = minimaxAlphaBeta( mazeTemp, alpha, bestValue, score, 1, depth-1, 0);
if(childValue < bestValue) bestValue = childValue;
//Row ++ Sur
CharactersLocationsMaze[playerRow]=sr+1;
CharactersLocationsMaze[playerColumn]=sc;
childValue = minimaxAlphaBeta( mazeTemp, alpha, bestValue, score, 2, depth-1,0);
if(childValue < bestValue) bestValue = childValue;
//Column -- Oeste
CharactersLocationsMaze[playerRow]=sr;
CharactersLocationsMaze[playerColumn]=sc-1;
childValue = minimaxAlphaBeta( mazeTemp, alpha, bestValue, score, 3, depth-1, 0);
if(childValue < bestValue) bestValue = childValue;
//Column ++ Este
CharactersLocationsMaze[playerRow]=sr;
CharactersLocationsMaze[playerColumn]=sc+1;
childValue = minimaxAlphaBeta( mazeTemp, alpha, bestValue, score, 4, depth-1,0);
if(childValue < bestValue)
{
bestValue = childValue;
if ( bestValue <= alpha) {
return bestValue;
}
}
//RESTORE MAZE !!!! restore score ???
CharactersLocationsMaze[playerRow]=sr;
CharactersLocationsMaze[playerColumn]=sc;
if ( restore) mazeTemp[sr][sc] == FOOD;
bestMovementPath.pop_back();
return bestValue; //if ( Path.size() > 2) Path.erase(Path.size() - 1);
}
}
Также, если jugador (player = 4), является pacman и если у него есть еда в лабиринте, он набирает очки.
У меня три сомнения: как получить первое движение (я думал об использовании глобальной переменной bestMovementpath и выдвигал каждую итерацию в направлении и после восстановления). Я не знаю, правильно ли это или есть другое решение лучше и чище. Каждый раз, когда я вызываю функцию, я очищаю вектор bestvaluemovement.
И другой — как восстановить еду, если игрок pacman (jugador = 4) находится в лабиринте с едой. Затем я должен снова вернуться к еде, в других случаях рекурсия работает хорошо.
Последний вопрос касается бета-версии, альфа-версии … я думаю, что я могу сократить только один раз, в зависимости от лучшего значения, или если мне придется сократить после каждого сравнения …
Любая помощь будет оценена … также я определил эвристику, если кто-то мог бы улучшить ее простым способом …
заранее спасибо
Чтобы получить первый ход из вашей рекурсии, вы можете попытаться сохранить его вместе с bestValue. Когда вы выбрали лучший ход и собираетесь вернуться из рекурсии, вы можете вернуть и bestValue, и первый ход, используя, например, std :: pair, чтобы сигнатура вашего метода была
std::pair<int, int> minimaxAlphaBeta(...);
Чтобы восстановить питание, вы сохраняете содержимое ячейки в переменной char prevValue, перезаписываете содержимое ячейки, вызываете рекурсию, восстанавливаете исходное значение ячейки из prevValue. Схема
char prevValue = mazeTemp[sr][sc];
mazeTemp[sr][sc] = ' ';
minimaxAlphaBeta(...);
minimaxAlphaBeta = prevValue;
Я не уверен, подходит ли здесь альфа-бета-обрезка. Он подходит для игр с двумя игроками, в которых оба игрока «делают одно и то же». В этой игре это не так.
Других решений пока нет …