2016-07-12 4 views
0

에 Minimax AI를 구현하려고 시도했습니다. http://neverstopbuilding.com/minimax과 같은 Minimax에 대한 몇 가지 블로그를 읽은 후 개념적으로 이해하지만 현재 코드로는 어려움을 겪고 있습니다.내 tic tac 발가락 (자바 스크립트)

현재 저는 현재 상태에서 사용 가능한 모든 동작을 무작위로 선택하는 매우 간단한 컴퓨터 AI를 보유하고 있습니다.

누구나 시작할 수있는 힌트/팁을 줄 수 있습니까? 나는 새로운 상태 개체 같은 있지만를 만드는 생각할 겁니다하지 않도록 ..

$(document).ready(function(){ 
 
    var human; 
 
    var computer; 
 
    var board = new Board() 
 
    var game; 
 

 
    function Human(symbol){ 
 
    this.name = "Player", 
 
    this.symbol = symbol; 
 
    } 
 
    function Computer(symbol){ 
 
    this.name = "Computer", 
 
    this.symbol = symbol; 
 
    } 
 

 
    //Modal opens when page is rendered. User can choose symbol 
 
    $("#myModal").modal() 
 

 
    $("#xPlayer").on('click',function(){ 
 
    human = new Human("X"); 
 
    computer = new Computer("O"); 
 
    board.initalize(); 
 
    game = new Game(human) 
 
    game.play(); 
 
    }) 
 
    $("#oPlayer").on('click',function(){ 
 
    human = new Human("O") 
 
    computer = new Computer("X"); 
 
    board.initalize(); 
 
    game = new Game(computer) 
 
    game.play(); 
 
    }) 
 

 
    //Board constuctor 
 
    function Board(){ 
 
    this.board = [] 
 
    this.status = ""; 
 
    } 
 

 
    //method calls for an empty board filled with "E" 
 
    Board.prototype.initalize = function(){ 
 
    $("td p").empty() 
 
    this.board = ["E","E","E","E","E","E","E","E","E"] 
 
    this.status = "New Game"; 
 
    } 
 
    //return true if there is a win. Otherwise, false 
 
    Board.prototype.win = function(){ 
 
    var B = this.board; 
 
    //check row 
 
    for (var i = 0; i <= 6; i = i + 3){ 
 
     if (B[i] !== "E" && (B[i] === B[i+1]) && (B[i+1] === B[i+2])){ 
 
     board.status = "Winner is: " + game.currentPlayer.name 
 
     return true 
 
     } 
 
    } 
 
    //check column 
 
    for (var i = 0; i <= 2 ; i++){ 
 
     if (B[i] !== "E" && (B[i] === B[i+3]) && (B[i+3] === B[i+6])){ 
 
     board.status = "Winner is: " + game.currentPlayer.name 
 
     return true 
 
     } 
 
    } 
 
    //check diagonal 
 
    for(var i = 0, j = 4; i <= 2 ; i = i + 2, j = j - 2) { 
 
     if(B[i] !== "E" && (B[i] == B[i + j]) && (B[i + j] === B[i + 2 * j])) { 
 
     board.status = "Winner is: " + game.currentPlayer.name 
 
     return true; 
 
     } 
 
    } 
 
    return false 
 
    } 
 

 
    //checks if the current status is draw. If so, updates the status to "Draw" 
 
    Board.prototype.draw = function(){ 
 
    //checks if the board itself is draw 
 
    for(var i = 0; i < this.board.length ; i++){ 
 
     if (this.board[i] === "E"){ 
 
     return false; 
 
     } 
 
    } 
 
    board.status = "Draw!" 
 
    return true; 
 
    } 
 
    //method returns array of indexes that are not empty cells in the board 
 
    Board.prototype.available = function(){ 
 
    var B = this.board; 
 
    var indexes = []; 
 
    for (var i = 0; i < B.length ; i ++){ 
 
     if (B[i] === "E"){ 
 
     indexes.push(i) 
 
     } 
 
    } 
 
    return indexes; 
 
    } 
 

 
    //checks first if the User Input is valid or not 
 
    Board.prototype.validMove = function(position){ 
 
    var availableCells = this.available(); 
 
    return availableCells.includes(position); 
 
    } 
 

 
    //updates the board when using jQuery click 
 
    Board.prototype.updateBoard = function(position,playerInput) { 
 
    var availableCells = this.available(); 
 
    if (availableCells.includes(position)){ 
 
     this.board[position] = playerInput 
 
    } 
 
    }; 
 

 
    function Game(firstPlayer){ 
 
    this.currentPlayer = firstPlayer; 
 
    this.over = false; 
 
    this.win = ""; 
 
    } 
 

 
    Game.prototype.switchPlayer = function(){ 
 
    this.currentPlayer = (this.currentPlayer === human) ? computer : human 
 
    } 
 

 
    Game.prototype.restart = function(){ 
 
    board.initalize(); 
 
    } 
 

 
    Game.prototype.gameover = function(){ 
 
    if (board.win() || board.draw()){ 
 
     alert(board.status) 
 
     game.restart(); 
 
    } 
 
    } 
 

 
    Game.prototype.play = function(){ 
 
    board.status = "Game playing" 
 
    if(game.currentPlayer === computer){ 
 
     computer.makeMove(); 
 
     game.switchPlayer(); 
 
    }; 
 
    // console.log(game.currentPlayer) 
 
    $("td").click(function(){ 
 
     var position = $(this).attr("id"); 
 
     var positionNumber = parseInt(position.slice(4,5)); 
 
     // This here renders to the board and updates board.board 
 

 
     if(board.validMove(positionNumber)){ 
 
     //Checks if the move is valid. If it is, append it. 
 
     //Otherwise, alert the user that it is taken 
 
     $(this).find("p").append(game.currentPlayer.symbol) 
 
     board.updateBoard(positionNumber, game.currentPlayer.symbol) 
 
     //Check if it the game is over or draw 
 
     //If either is true, play new game 
 
     game.gameover(); 
 
     game.switchPlayer(); 
 
     if (game.currentPlayer.name === "Computer"){ 
 
      computer.makeMove(); 
 
      game.gameover(); 
 
      game.switchPlayer(); 
 
     } 
 
     }else{ 
 
     alert("Try Again!") 
 
     } 
 
    }) 
 
    } 
 

 
    Computer.prototype.makeMove = function(){ 
 
    var availableMoves = board.available() 
 
    // random move without any AI implementation 
 
    var computerPosition = availableMoves[Math.floor(Math.random() * availableMoves.length)]; 
 
    $("#cell" + computerPosition + " p").append(game.currentPlayer.symbol); 
 
    board.updateBoard(computerPosition,game.currentPlayer.symbol) 
 
    } 
 

 
})
body { 
 
    background: skyblue; } 
 

 
#tictactoe { 
 
    max-width: 700px; 
 
    min-height: 300px; 
 
    margin: 68px auto; 
 
    display: flex; 
 
    width: 100%; } 
 
    #tictactoe table { 
 
    width: 100%; 
 
    font-size: 65px; 
 
    text-align: center; 
 
    vertical-align: middle; 
 
    table-layout: fixed; } 
 

 
td { 
 
    height: 115px; 
 
    color: #101935; 
 
    background: #F2FDFF; 
 
    border: 5px solid #DBCBD8; 
 
    border-radius: 12px; 
 
    cursor: pointer; 
 
    transition: background 0.5s ease-out, color 0.5s ease-out; } 
 
    td:hover { 
 
    background: #564787; 
 
    color: #F2FDFF; } 
 

 
.modal-dialog { 
 
    text-align: center; } 
 
    .modal-dialog .modal-footer { 
 
    text-align: center; }
<html lang="en"> 
 
<head> 
 
    <meta charset="UTF-8"> 
 
    <meta name="viewport" content="width=device-width, initial-scale=1"> 
 
    <title>TicTacToe FCC</title> 
 
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous"> 
 
    <link rel="stylesheet" href="css/styles.css"> 
 
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script> 
 
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> 
 
</head> 
 
    <body> 
 
    <div id="tictactoe"> 
 
     <table id="game-board"> 
 
     <tbody> 
 
      <tr id="row1"> 
 
      <td id="cell0"><p></p></td> 
 
      <td id="cell1"><p></p></td> 
 
      <td id="cell2"><p></p></td> 
 
      </tr> 
 
      <tr id="row2"> 
 
      <td id="cell3"><p></p></td> 
 
      <td id="cell4"><p></p></td> 
 
      <td id="cell5"><p></p></td> 
 
      </tr> 
 
      <tr id="row3"> 
 
      <td id="cell6"><p></p></td> 
 
      <td id="cell7"><p></p></td> 
 
      <td id="cell8"><p></p></td> 
 
      </tr> 
 
     </tbody> 
 
     </table> 
 
    </div> 
 
    <!--Modal Window --> 
 
    <div id="myModal" class="modal fade" role="dialog"> 
 
     <div class="modal-dialog"> 
 
      <div class="modal-content"> 
 
       <div class="modal-header"> 
 
        <h4 class="modal-title">Choose your character!</h4> 
 
       </div> 
 
       <div class="modal-body"> 
 
        <p>Have fun!</p> 
 
       </div> 
 
       <div class="modal-footer"> 
 
        <button type="button" id="xPlayer" class="btn btn-default" data-dismiss="modal">X</button> 
 
        <button type="button" id="oPlayer" class="btn btn-default" data-dismiss="modal">O</button> 
 
       </div> 
 
      </div> 
 
     </div> 
 
    </div> 
 

 

 
    </body> 
 
    <script src="js/javascript.js" type="text/javascript"></script> 
 
</html>

답변

1

이 기본적인 아이디어는, 당신은 아마 evaluate()board.isTerminal() 및 디버그에 대한 세부 정보를 입력해야한다 그것도 내가 그것을 점검하지 않았기 때문에 그것. 더 깨끗한 구현은 negamax라고하는 알고리즘으로 수행 할 수 있지만, 익숙해지기 전까지, 그리고 작동하는 이유와 작동 방법을 이해할 때까지 계속 사용하십시오.

Computer.prototype.makeMove = function() { 
    function evaluate(board) { 
     // if win for current player, return 1, loss return -1, tie return 0 
    } 
    function max(board) { 
     if (board.isTerminal()) return evaluate(board); 
     var successors = board.available(); 
     var best = Number.NEGATIVE_INFINITY; 
     for(var i = 0; i < successors.length; i++) { 
      var moveScore = min(successors[i]); 
      best = Math.max(best, moveScore); 
     } 
     return best; 
    } 
    function min(board) { 
     if (board.isTerminal()) return evaluate(board); 
     var successors= board.available(); 
     var best = Number.POSITIVE_INFINITY; 
     for(var i = 0; i < successors.length; i++) { 
      var moveScore = max(successors[i]); 
      best = Math.min(best, moveScore); 
     } 
     return best; 
    } 
    function selectMove(board) { 
     if (board.isTerminal()) throw "something went terribly wrong"; 
     var successors = board.available(); 
     var best = Number.NEGATIVE_INFINITY; 
     var bestMove = null; 
     for(var i = 0; i < successors.length; i++) { 
      var moveScore = min(successors[i]); 
      if (moveScore < best) { 
       bestMove = successors[i]; 
       best = moveScore; 
      } 
     } 
     return bestMove; 
    } 
    var computerPosition = selectMove(board); 
    $("#cell" + computerPosition + " p").append(game.currentPlayer.symbol); 
    board.updateBoard(computerPosition,game.currentPlayer.symbol) 
} 
+0

닉, 팁 주셔서 감사합니다! 나는 이것을 들여다 볼 것입니다 건배! – Alejandro

+0

업데이트 : minimax를 성공적으로 구현할 수있었습니다! Nick Larsen에게 기쁜 소식 결과 : http://codepen.io/neotriz/full/yJPLOO/ – Alejandro