2017-09-26 2 views
3

실습 프로젝트로 JSFiddle에서 Tic-Tac-Toe 게임을 만들었습니다 (이미 충분하지 않았기 때문에 맞습니까?) 나는 탁월한 AI를 추가하는 방향으로 진행했습니다. 대부분의 경우 작동하지만 컴퓨터가 최적의 이동을 올바르게 계산하지 못하게하는 일부 조합 (예 : X를 필드 5, 9, 3 또는 필드 3, 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 
} 

값 (디버거에서 관찰 가능)이지만, 때로는 덮어 씌여 지지만, 이것이 정말로 문제의 근원인지 확실하지 않습니다. 어떤 도움이나 조언을 부탁드립니다!

편집 : 문제가 해결되었습니다. 처음 대답이 아닌 경우 아래에서 내 대답을 찾으십시오.

답변

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 
} 

을 이제 기본이 null 및 오프 계산을 던져하지 말아야한다. 그러나 그것이 던져 버린 것은 수표의 첫 번째 블록 이었기 때문에 정교한 수표 대신 게임이 끝나면 현재 상태를 반환하도록 조정했습니다. 그러나 내가 두 개의 메서드에서 inversed 기본값을 사용하고 있기 때문에 결과를 던져서 너무 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이면 if 거기에 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이 반환됩니다.

관련 문제