2013-06-27 44 views
0

我想編程一個國際象棋遊戲,並花了幾天的時間來修復代碼。我甚至嘗試了最小值,但以相同的結果結束。人工智能總是從角落開始,並將一個棋子移開,然後每次轉動時,這隻車就會前後移動。如果它被吃掉,那麼AI會將每一塊從一側移動到另一側,直到所有食物都被吃掉。你知道下面的代碼有什麼問題嗎?negamax算法..有什麼不對?

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; 
} 
+0

是最好的移動全局變量?如果是,那就錯了。您的negamax函數的每個遞歸調用將使用bestmove的同一副本,而您希望每個調用都擁有它自己的副本。它不言而喻,但你應該(幾乎)不會使用全局變量。 –

+0

@MathieuPagé仔細觀察,似乎在他的案件中解決。他從不在搜索例程中使用最佳移動,並且搜索退出的最後一個節點將成爲根節點。 – Zong

+0

@宗正立你說得對。但它仍然不是一個好主意。 –

回答

0

此代碼:

public Move MakeMove(int depth) 
{ 
    bestscore = 0; 
    score = 0; 
    int maxDepth = depth; 
    negaMax(depth, maxDepth); 
    return bestmove; 
} 

注意,最好此舉是從來沒有!比較negaMax的回報分數以移動備選方案。你甚至沒有循環可能的舉動。

此外,當您提交的代碼不完全一致時,確實很難查找錯誤。 negaMax方法在代碼中佔用一個地方的兩個參數,那麼在遞歸調用中需要四個參數?

我也建議你在代碼中抽象得更好。單獨的棋盤表示,移動表示,移動生成和搜索算法。這會幫助你很多。舉一個例子:爲什麼你需要移動代中的深度計數器?

-Øystein

+0

我對代碼不一致表示歉意,由於我如何設置開發板而導致代碼更加複雜,我試圖簡化代碼,但忘記更改某些部分。我編輯了上面的代碼。 「bestmove」被設置爲全局變量,並在「negamax」函數內進行更改,並在每次調用「makemove」函數時進行重置。 – user2525395

0

你有兩個可能的問題:

  1. 這是有點曖昧,你不告訴我們你的變量聲明,但我認爲你正在使用太多的全局變量。 Negamax通過計算每個節點的最佳移動來進行工作,因此在搜索值和移動時應該是局部的。無論如何,最好儘量保持變量的範圍。遍歷遊戲樹時,更難以推斷代碼的變化如此之多。但是,您的搜索看起來應該返回正確的值。

  2. 您的評價似乎沒有區別誰正在上場。我不知道EvalPiece是否可以處理這個問題,但無論如何,評估應該從任何一方目前有權移動的角度進行。

您還具有不直接對你的問題的其他問題:

  1. 你我的行動產生是可怕的。你成對地遍歷棋盤上每一對可能的方塊。這是非常低效的,我不明白這種方法甚至會如何工作。您只需循環通過電路板上的所有部件,或者使用較慢的方法,電路板上的每個方塊(而不是4096個方塊)。

  2. MakeMove好像它可能是根節點的地方。現在,您的方案起作用,因爲搜索結果的最後一個節點將是root。但是,在根中使用特殊的例程(如迭代加深)是很常見的,所以在根目錄下有一個單獨的循環可能會很好。