[英]The negamax algorithm..what's wrong?
我正在嘗試編寫一個國際象棋游戲,並花了幾天時間嘗試修復該代碼。 我什至嘗試了min max,但結果卻相同。 AI總是從拐角處開始,將棋子移開,然后車子每轉一圈就來回移動。 如果被食用,則AI將每一塊從一側移到另一側,直到全部吃掉。 您知道以下代碼有什么問題嗎?
public Move MakeMove(int depth)
{
bestmove.reset();
bestscore = 0;
score = 0;
int maxDepth = depth;
negaMax(depth, maxDepth);
return bestmove;
}
public int EvalGame() //calculates the score from all the pieces on the board
{
int score = 0;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
if (AIboard[i, j].getPiece() != GRID.BLANK)
{
score += EvalPiece(AIboard[i, j].getPiece());
}
}
}
return score;
}
private int negaMax(int depth, int maxDepth)
{
if (depth <= 0)
{
return EvalGame();
}
int max = -200000000;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
for (int k = 0; k < 8; k++)
{
for (int l = 0; l < 8; l++)
{
if(GenerateMove(i, j, k, l)) //generates all possible moves
{
//code to move the piece on the board
board.makemove(nextmove);
score = -negaMax(depth - 1, maxDepth);
if( score > max )
{
max = score;
if (depth == maxDepth)
{
bestmove = nextmove;
}
}
//code to undo the move
board.undomove;
}
}
}
}
}
return max;
}
public bool GenerateMove(int i, int j, int k, int l)
{
Move move;
move.moveFrom.X = i;
move.moveFrom.Y = j;
move.moveTo.X = k;
move.moveTo.Y = l;
if (checkLegalMoves(move.moveTo, move.moveFrom)) //if a legal move
{
nextMove = move;
return true;
}
return false;
}
這段代碼:
public Move MakeMove(int depth)
{
bestscore = 0;
score = 0;
int maxDepth = depth;
negaMax(depth, maxDepth);
return bestmove;
}
請注意,永遠不會設置最佳動作! 將negaMax
的返回得分與移動替代negaMax
進行比較。 您甚至沒有循環可能的動作。
另外,當您提交的代碼不完全一致時,很難發現錯誤。 negaMax
方法在代碼negaMax
兩個參數放在一個位置,然后在遞歸調用中將四個參數放在一個位置?
我還建議在代碼中使用更好的抽象。 單獨的板表示,移動表示,移動生成和搜索算法。 這將對您有很大幫助。 例如:為什么在移動生成中需要深度計數器?
Østein
您有兩個可能的問題:
因為您沒有向我們展示您的變量聲明,所以它有點模棱兩可,但是我認為您使用了太多的全局變量。 Negamax通過計算每個節點上的最佳移動來工作,因此在搜索值時,移動應該是局部的。 無論如何,優良作法是保持變量的范圍盡可能緊湊。 當遍歷游戲樹更改了如此多的變量時,很難對代碼進行推理。 但是,您的搜索看起來應該返回正確的值。
您的評估似乎無法區分是哪一方。 我不知道EvalPiece
是否EvalPiece
處理此事,但是無論如何,評估應該從當前有權移動的一方的角度進行。
您還遇到其他與您的問題不直接相關的問題:
您的舉動令人恐懼。 您要成對遍歷板上的每對可能的從/到正方形。 這是非常低效的,我什至不知道這種方法如何工作。 您只需要遍歷板上的所有塊,或者以較慢的方法遍歷板上的每個正方形(而不是4096正方形)。
MakeMove
似乎可能是根節點的位置。 現在,您的方案起作用了,因為搜索退出的最后一個節點將是root。 但是,通常在根目錄使用特殊例程(例如迭代加深),因此在根目錄使用單獨的循環可能會很好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.