简体   繁体   中英

how to avoid recursion or to fix the problem?

Teaching JS trying to do a ticatactoe game and got a problem with recursion, specifically with 'Maximum call stack size exceeded'.

When I try to make a random move by the computer player I make a random number, which then will be checked of his value in array called gameState. So, if this value has defined already (there are X or O mark in a cell), I need to generate a random number again. So I need to stop this infinite loop when all cells are marked or I'll get an error 'Maximum call stack size exceeded'.

Can you please take a look, am I do the right thing or it is generally wrong? Actually, I thought about another implementation of this game scene, but I thought if i've started with that I should lead this to the end


let gameState = ["", "", "", "", "", "", "", "", "",];
let playerAi = "O";

// ai's turn
function playerAiTurn() {
    let randomNum = Math.floor(Math.random() * gameState.length);
    if (gameState[randomNum] === '') {
    gameState[randomNum] = playerAi;
    document.getElementById(randomNum).innerHTML = playerAi;
    resultCheck();
    } else {
        playerAiTurn()
    };
};

You have to check when the game has ended and stop the recursive calls. I don't know the implementation of resultCheck but it should return information about whether the game is finished or not. If it is finished, don't do the recursive call.

That being said, the performance of your code is unpredictable because it generates random numbers even before knowing if the resulting slot is available. You could optimize it like this:

const gameState = ["", "", "", "", "", "", "", "", "",];
const playerAi = "O";

function playerAiTurn() {
    const emptySlots = Array.from(gameState.entries()).filter(([, x]) => x === '');
    if(!emptySlots.length)
        return; //Game over
    const randomNum = Math.floor(Math.random() * emptySlots.length);
    const [index] = emptySlots[randomNum];
    gameState[index] = playerAi;
    document.getElementById(index).innerHTML = playerAi;
    resultCheck();
};

There's a very slim chance that repeated random calls will keep on getting the same number, so it's not strictly speaking correct to simply keep rolling random numbers (even though in practice it's highly unlikely to ever be encountered).

To avoid the situation with certainty, one should only take a random number based on the unused places. For example:

let gameState = ["", "", "", "", "", "", "", "", "",];
let playerAi = "O";

// ai's turn
function playerAiTurn() {
  let unusedPlaces = [];
  for(let i=0; i<gameState.length; i++) {
    if( gameState[i] === "") unusedPlaces.push(i); 
  }
  if( unusedPlaces.length > 0 ){
    let randomUnusedPlace = unusedPlaces [ Math.floor(Math.random() * unusedPlaces.length) ];
    gameState[randomUnusedPlace] = playerAi
    document.getElementById(randomUnusedPlace).innerHTML = playerAi; 
  }

  resultCheck();
}

No recursive calls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM