2017-09-26 100 views
3

作爲一個練習項目,我在JSFiddle上製作了Tic-Tac-Toe遊戲(因爲已經不夠了,對不對?),然後我開始添加無與倫比的AI。在大多數情況下,它可以工作,但是有一些組合(例如,將X設置爲5,9,3或5,7或9),導致計算機無法正確計算最佳移動。Javascript中的Minimax工作不正常

上的jsfiddle項目:https://jsfiddle.net/jd8x0vjz/

及相關函數開始行63:

function evaluateMove(move, player, depth) { 
var gameStatus = evaluateGameStatus(move); //get status of current board 
if (gameStatus < 2 && player) 
    return -1; //if human won, return -1 
if (gameStatus < 2 && !player) 
    return 1; //if human lost, return 1 

var returnValue = 0 //value to be returned later 

for (var z = 0; z < 3; z++) { //loop for row 
    for (var s = 0; s < 3; s++) { //loop for column 
     if (move[z][s]) //if current slot has an x or o, 
      continue; //skip it  
     var nextMove = cloneGameStatus(move); //create temporary array with base of current grid 
     nextMove[z][s] = !player ? "x" : "o"; //assign first free field the appropriate symbol 
     var value = evaluateMove(nextMove, !player, depth+1); //recursion but with switched player, to add the correct icon afterwards 
     if ((value > returnValue) && player) 
      returnValue = value;    
     if ((value < returnValue) && !player) 
      returnValue = value;     
    } 
} 
return returnValue; //return value of current simulation 
} 

我覺得最後兩個if子句是導致這些問題,因爲電腦無法計算正確的值(在調試器中可觀察到),但它們有時會被覆蓋,但我不確定這是否真的是問題的根源。任何幫助或提示,將不勝感激!

編輯:問題解決了!如果不是第一個,請在下面尋找我的答案。

回答

0

returnValue的默認值錯誤的想法明確地向我發送了正確的路徑;它並沒有讓所有的東西都變得神奇地工作(如果真的這樣做會太好),但它確實給我提供了正確的方法。因爲我們不希望,如果計算沒有返回任何價值,我調整了evaluateMove功能如下:

function evaluateMove(move, player, depth) { 
var gameStatus = evaluateGameStatus(move); //get status of current board 
if (gameStatus != 2) 
    return gameStatus; //if the game is not running anymore, return result 

var returnValue; //value to be returned later 

for (var z = 0; z < 3; z++) { //loop for row 
    for (var s = 0; s < 3; s++) { //loop for column 
     if (move[z][s]) //if current slot has an x or o, 
      continue; //skip it  
     var nextMove = cloneGameStatus(move); //create temporary array with base of current grid 
     nextMove[z][s] = !player ? "x" : "o"; //assign first free field the appropriate symbol 
     var value = evaluateMove(nextMove, !player, depth+1); //recursion but with switched player, to add the correct icon afterwards 
     if ((value > returnValue || returnValue == null) && player) 
      returnValue = value;    
     if ((value < returnValue || returnValue == null) && !player) 
      returnValue = value;     
    } 
} 
return returnValue; //return value of current simulation 
} 

現在默認爲空,因此不應該拋出的計算了。然而,它所做的卻是第一次檢查,所以我將其調整爲僅在遊戲結束時返回當前狀態,而不是進行任何詳細的檢查。但扔掉了結果,因爲我在兩種方法中使用了反轉的默認值,所以我不得不調整evaluateGameStatus。現在,如果人贏則返回-1,而不是1,如果電腦贏得它返回1,而不是-1:

function evaluateGameStatus(gameStatus) { //a clusterfuck of winning combinations 
if(
X Checks 
) 
return -1; //there's a successful combination of x's 

else if(
O Checks 
) 
return 1; //there's a successful combination of o's 

else { 
for (var z = 0; z < 3; z++) { 
    for (var s = 0; s < 3; s++) { 
     if (!gameStatus[z][s]) 
      return 2; //if there is an empty field neither has won, continue playing 
     } 
    } 

return 0; //there's no successful combination and max moves have been reached. it's a draw 
} 
} 

我必須做同樣的adjustmends爲checkGameEnd功能,效果顯着。
您會注意到我也更改了抽獎支票。這是因爲,出於某種原因,count == maxMoves的舊檢查不再工作,所以我改爲一個循環,它根本檢查是否有任何空字段,如果有則返回2,如果有則返回0沒有(它在這裏返回0,因爲此時它已經通過了所有的檢查:X沒有贏,O沒有贏,並且沒有剩餘空位,所以比賽必須是平局)。

合作項目,現在可以在這裏找到:
https://jsfiddle.net/h5zwzkm7/

1

我不能肯定地說這是問題的根源,但是肯定會在代碼中出現一個會產生奇怪結果的錯誤。該行:

var returnValue = 0 //value to be returned later 

不正確。除此之外你缺少一個分號事實上,正確的代碼應該是:

var returnValue = -1; 
if(!player){ 
    returnValue = 1; 
} 

你想要的最大玩家的默認值,以便他把最好的行動是消極的,併爲最小化球員積極,所以他採取了最壞的舉動。你這樣做的方式,如果最大化玩家只面對值爲-1的選項,因爲-1小於0,並且returnValue被初始化爲0,儘管要返回的正確值是-1,但返回0。