2017-09-26 11 views
3

実践的なプロジェクトとして、私はJSFiddleでTic-Tac-Toeゲームを作った(既に十分ではないので正しい?)、無敵のAIを追加するように進んだ。ほとんどの場合、それは機能しますが、コンピュータが最適な移動を適切に計算しないように導くいくつかの組み合わせ(フィールド5,9,3、またはフィールド3,7,9にXを設定するなど)があります。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 
} 

値は(デバッガでは観測可能ですが)上書きされることもありますが、これが本当に問題の根源かどうかはわかりません。どんな助けやヒントもありがとう!

EDIT:問題解決済み!それが最初のものでない場合は、私の答えを探してください。

答えて

0

returnValueのデフォルト値が間違っているという考えは、間違いなく正しいパスを私に送りました。それはすべてのことを魔法のように動かすことはできませんでしたが(それができたらあまりにも素晴らしかったでしょうが)、それは私に正しいナッジを与えました。

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 
} 

今デフォルトはnullで、そのような計算を投げるべきではありません。私たちは何も計算されていない場合、任意の値を返すようにしたくないので、私は次のようevaluateMove機能を調整します。しかし、それが捨てたのは最初の小切手だったので、精巧なチェックをするのではなく、試合が終わったら現状を返すように調整しました。しかしが2つのメソッドで逆のデフォルト値を使用しているので結果をスローしてしまったので、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 
} 
} 

私は明らかに、checkGameEnd機能のために同じadjustmendsをしなければなりませんでした。
私は描画のチェックを変更したことに気づくでしょう。これは何らかの理由で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を0にしてreturnValueを0に初期化したため、返される正しい値は-1ですが0が返されます。

関連する問題