funzione minimax C ++
Domanda
Ho cercato Google e StackOverflow per questa domanda, ma io ancora non capisco come una funzione minimax lavori.
Ho trovato la voce di Wikipedia ha una versione pseudocodice della funzione:
function integer minimax(node, depth)
if node is a terminal node or depth <= 0:
return the heuristic value of node
α = -∞
for child in node: # evaluation is identical for both players
α = max(α, -minimax(child, depth-1))
return α
Diverse altre funzioni minimax ho trovato con Google sono fondamentalmente la stessa cosa; Sto cercando di implementare questo in C ++, e questo è quello che ho messo a punto finora:
double miniMax(Board eval, int iterations)
{
//I evaluate the board from both players' point of view and subtract the difference
if(iterations == 0)
return boardEval(eval, playerNumber) - boardEval(eval, opponentSide());
/*Here, playerTurn tells the findPossibleMoves function whose turn it is;
I mean, how do you generate a list of possible moves if you don't even know
whose turn it's supposed to be? But the problem is, I don't see where I can
get playerTurn from, as there are only 2 parameters in all the examples of
minimax I've seen*/
vector<int> moves = eval.findPossibleMoves(playerTurn);
//I'm assuming -∞ in the wikipedia article means a very low number?
int result = -999999999;
//Now I run this loop to evaluate each possible move
/*Also, the Lua example in the wiki article has
alpha = node.player==1 and math.max(alpha,score) or math.min(alpha,score)
Is alpha a boolean there?!*/
for(int i = 0; i * 2 < moves.size(); i++)
{
//I make a copy of the board...
Board temp = eval;
/*and make the next possible move... once again playerTurn crops up, and I
don't know where I can get that variable from*/
temp.putPiece(moves[i * 2], moves[i * 2 + 1], playerTurn);
/*So do I create a function max that returns the bigger of two doubles?*/
result = max(result, -miniMax(temp, iterations - 1));
}
return result;
/*So now I've returned the maximum score from all possible moves within a certain
# of moves; so how do I know which move to make? I have the score; how do I know
which sequence of moves that score belongs to?*/
}
Come si può vedere, sono abbastanza confuso su questa funzione minimax. Si prega di almeno darmi qualche suggerimento per aiutarmi con questo.
Grazie! :)
Soluzione
Questo esempio da Wikipedia sta facendo negamax con l'alfa / beta potatura .
Si può essere aiutato da ottenere la denominazione dritto:
-
La base è MiniMax, un'implementazione letterale comporterebbe 2 metodi che si alternano (mutuamente ricorsive), 1 per ogni lato.
-
programmatori pigri trasformano questo in negamax, un metodo con un operatore
-
posizione strategica. -
Alpha / potatura Beta è tenere traccia di una finestra di mosse migliori (su più profondità) per rilevare rami secchi.
Il playerTurn
viene utilizzato per determinare chi è il turno. In negamax è possibile derivare questo dalla profondità (iterazioni) essendo pari o dispari. Ma sarebbe più facile da usare 2 parametri (Mycolor, otherColor) e passare ad ogni livello.
Altri suggerimenti
Il tuo miniMax () dovrebbe ricordare la migliore mossa che ha trovato finora. Così, invece di questo codice:
/*So do I create a function max that returns the bigger of two doubles?*/
result = max(result, -miniMax(temp, iterations - 1));
Si dovrebbe fare qualcosa di simile:
/*So do I create a function max that returns the bigger of two doubles?*/
double score = -miniMax(temp, iterations - 1);
if (score > result)
{
result = score;
bestMove = i;
}
Naturalmente, è necessario una variabile "bestMove" e un modo per restituire la mossa migliore trovata al chiamante.
Aggiungere la variabile playerTurn
come argomento per miniMax
, e chiamata miniMax
che la mossa del giocatore di turno inizialmente e in modo ricorsivo.
Inoltre, le esigenze opponentSide
ad una funzione di playerTurn
.
Un buon posto per iniziare con l'albero di gioco di ricerca è il scacchi programmazione wiki . Per le tue domande su movimento: Penso che sia più comune avere due max-funzioni. La differenza tra le due funzioni max è che si ritorna solo il punteggio e gli altri ritorna il punteggio e la mossa migliore. Un ordine di chiamata ricorsiva sarebbe come segue:
maxWithBestMoveReturn(...) --> min(...) --> max(...) --> min(...)
Ci sono alcune carte buone con pseudocodice per l'algoritmo di Alpha Beta:
Per la tua domanda nel commento:?! e Math.max (alfa, punteggio) o Math.min (alfa, punteggio) c'è alfa un valore booleano
Non alfa è una finestra legato in un algoritmo alpha beta. Il valore alfa viene aggiornata con un nuovo valore. Perché alfa e beta vengono scambiati con la chiamata ricorsiva del negamax-Function la variabile alfa si riferisce alla variabile beta nella prossima chiamata ricorsiva.
Una nota alla variabile playerTurn: L'algoritmo minimax o alfa-beta non ha bisogno di queste informazioni. Quindi mi sento di dare le informazioni - chi è il prossimo -, nel Board-Structure. Le funzioni e le findPossibleMoves boardEval ottenere tutte le informazioni di cui hanno bisogno dal Board-struttura.
Una nota alla condizione di interruzione ricorsivo: se ho ben capito il codice giusto, allora hai solo quello con iterations == o
. Credo che questo mezzo l'algoritmo ha raggiunto la profondità desiderata. Ma cosa succede se non ci sono possibili mosse a sinistra befor l'algoritmo raggiunge questa profondità. Forse si dovrebbe scrivere seguente:
vector<int> moves = findPossibleMoves(...);
if (!moves.size())
return boardEval(...);
Nel vostro pseudocodice, la variabile nodo deve contenere tutte le informazioni relative alla posizione attuale consiglio (o qualsiasi altra cosa). Questa informazione dovrebbe includere chi è il turno di muoversi.