2017-05-28 128 views
1

我對使用React的項目有問題。這是一個tic tac腳趾遊戲,我正在嘗試實現電腦播放器。React.JS中的遞歸函數組件類

當人類玩家點擊一個正方形(場分量)時,會在板組件中觸發函數updateField()。它還調用computerMove()函數,該函數又調用minimax()函數。

minimax函數是遞歸定義的。但是,當代碼執行到達minimax(possibleGame)被調用的行時,我收到以下錯誤消息。

[ERROR] react-dom Uncaught TypeError: Cannot read property 'minimax' of undefined 

顯然該功能是未知的,我不明白,因爲我將它綁定到董事會的範圍。

class Field extends React.Component{ 

    render(){ 
    return(
     <button className='field' onClick={this.props.clickFunc}>{this.props.value}</button> 
    ); 
    } 
} 

class Board extends React.Component{ 
    constructor(){ 
    super(); 
    this.state = { 
     fields: Array(9).fill(null), 
    }; 
    this.minimax = this.minimax.bind(this); 
    this.updateField = this.updateField.bind(this); 
    this.computerMove = this.computerMove.bind(this); 
    } 

    updateField(id){ 
    const fields = this.state.fields.slice(); 

    // only proceed if field hasn't been taken yet 
    if (fields[id] == null && this.props.winner == null){ 
     fields[id] = this.props.playerSymbol; 
     this.setState({fields: fields}); 

     this.computerMove(fields); 
    } 
    } 

// check if somebody won the game 
    checkWinner(squares){ 
    const lines = [ 
    [0, 1, 2], 
    [3, 4, 5], 
    [6, 7, 8], 
    [0, 3, 6], 
    [1, 4, 7], 
    [2, 5, 8], 
    [0, 4, 8], 
    [2, 4, 6], 
    ]; 
    for (let i = 0; i < lines.length; i++) { 
    const [a, b, c] = lines[i]; 
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { 
     return squares[a]; 
    } 
    } 
    return null; 

    } 

    computerMove(fields){ 
    var computerSymbol = (this.props.playerSymbol == "X" ? "O" : "X"); 
    var game = {fields: fields,turn:computerSymbol}; 
    var result = this.minimax(game); 
    var newBoard = fields.slice(); 
    newBoard[result[1]] = computerSymbol; 
    this.setState({fields: newBoard}); 

    } 

    score(game){ 
    // check for winner 
    var result = this.checkWinner(game.fields); 
    if (result !== null){ 
     if (result == this.props.playerSymbol){ 
     return -10; 
     } else{ 
     return 10; 
     } 
    }else{ 
     return 0; 
    } 
    } 

    minimax(game) { 
    var score = this.score(game); 
    if (score !== 0){ 
     return score; 
    } 
    var scores = []; 
    var moves = []; 

    game.fields.forEach(function(value,index,arr){ 
     if (value==null){ 
     var newField = arr.slice(); 
     newField[index] = game.turn; 

     var nextTurn = (game.turn == "X" ? "O" : "X"); 
     var possibleGame = {fields: newField,turn:nextTurn}; 
     var result = this.minimax(possibleGame); 
     scores.push(result[0]); 
     moves.push(index); 
     } 
    }); 
    if (game.turn == this.props.playerSymbol){ 
     var max_ind = scores.indexOf(Math.max(...scores)); 
     return [scores[max_ind],moves[max_ind]]; 
    } else{ 
     var min_ind = scores.indexOf(Math.min(...scores)); 
     return [scores[min_ind],moves[min_ind]]; 
    } 
    } 

    render(){ 
    var fields = this.state.fields; 

    // check if somebody won 

    const winner = this.checkWinner(fields); 
    if (winner){ 
     this.props.declareWinner(winner); 
    } 


    return (
     <div className="animated fadeInUp board-container"> 
     <div className='row'> 
      <Field value={fields[0]} clickFunc={() => this.updateField(0)} /> 
      <Field value={fields[1]} clickFunc={() => this.updateField(1)}/> 
      <Field value={fields[2]} clickFunc={() => this.updateField(2)}/> 
     </div> 
     <div className='row'> 
      <Field value={fields[3]} clickFunc={() => this.updateField(3)} /> 
      <Field value={fields[4]} clickFunc={() => this.updateField(4)}/> 
      <Field value={fields[5]} clickFunc={() => this.updateField(5)}/> 
     </div> 
     <div className='row'> 
      <Field value={fields[6]} clickFunc={() => this.updateField(6)}/> 
      <Field value={fields[7]} clickFunc={() => this.updateField(7)}/> 
      <Field value={fields[8]} clickFunc={() => this.updateField(8)}/> 
     </div> 
     </div> 
    ) 
    } 
} 

整個代碼可以在這裏進行測試: https://codepen.io/miga89/pen/pPqmra

我也試圖拿出一個MWE(https://codepen.io/miga89/pen/XRQBjP)然而,這個例子適用於某些原因。

謝謝你的幫助!

+2

'game.fields.forEach((值,指數,ARR)=> {' – dfsq

回答

1

this的值取決於函數被調用的方式和位置。

在大多數情況下,this的值由函數的調用方式決定。它不能在執行過程中通過賦值來設置,並且每次調用該函數時都可能會有所不同。 ES5引入了綁定方法來設置函數的this值,無論它如何調用,ES2015引入了箭頭函數,這些函數的範圍在詞彙上(它被設置爲封閉執行上下文的這個值)。 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/this

你需要明確綁定this要在函數內部統一使用。

game.fields.forEach(function(value,index,arr){ 
    if (value==null){ 
    var newField = arr.slice(); 
    newField[index] = game.turn; 

    var nextTurn = (game.turn == "X" ? "O" : "X"); 
    var possibleGame = {fields: newField,turn:nextTurn}; 
    var result = this.minimax(possibleGame); 
    scores.push(result[0]); 
    moves.push(index); 
    } 
}.bind(this)); 

,或者使用箭頭功能:

game.fields.forEach((value,index,arr) => { 
    if (value==null){ 
    var newField = arr.slice(); 
    newField[index] = game.turn; 

    var nextTurn = (game.turn == "X" ? "O" : "X"); 
    var possibleGame = {fields: newField,turn:nextTurn}; 
    var result = this.minimax(possibleGame); 
    scores.push(result[0]); 
    moves.push(index); 
    } 
}); 

箭頭函數表達式具有比函數表達式較短的語法和不結合其自身的此,自變量,超級或new.target 。這些函數表達式最適合非方法函數,並且它們不能用作構造函數。 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions