Assignment – Bottom-up Planning

Hi everybody!
Can anyone explain to me why this code continues repeating the alert box when I call ticTacToe function ??
I can’t figure out where is the mistake.

function printBoard(gameBoard) {
    //state space
    let boardString = '';
 
    for(let i=0; i<gameBoard.length; i += 1) {
        boardString += `${gameBoard[i] ?? i+1}`;
        if( i % 3 === 2) {
            boardString += '\n';
        }
    }
    return boardString;
}

function getUserInput(nextPlayerSymbol, gameBoard) {
    return +prompt(`Board:\n${printBoard(gameBoard)} Enter ${nextPlayerSymbol}'s next move (1-9):`);
}

function isMoveValid(move, gameBoard) {
    const boardIndex = move -1;

    return (
        typeof move === 'number' &&
        move >= 1 && move <= 9 &&
        gameBoard[boardIndex] === null
    );
}

function makeAMove(gameBoard, nextPlayerSymbol) {
    let newGameBoard = [...gameBoard];
    let move = null;

    do {
        move = getUserInput(nextPlayerSymbol, gameBoard);
    } while ( !isMoveValid(move, gameBoard) );
    const boardIndex = move -1;
    newGameBoard[boardIndex] = nextPlayerSymbol;
   
    return newGameBoard;

}

function hasLastMoverWon(lastMove, gameBoard) {

    let winnerCombos = [
        [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 [i1, i2, i3] of winnerCombos) {
        if (gameBoard[i1] === lastMove &&
            gameBoard[i1] === gameBoard[i2] && 
            gameBoard[i1] === gameBoard[i3] 
           ) {
            return true;
        }
    }

    return false;
}

function IsGameOver(gameBoard, currentPlayerSymbol){
      
        if(hasLastMoverWon(currentPlayerSymbol, gameBoard)) {
            alert(`Congratulations!, ${currentPlayerSymbol} are the winner.`);
            return true;
        }
       
        if(gameBoard.every(element => element != null)) {
            alert('Draw. Game over!');
            return true;
        }
        return false;
}

function ticTacToe() {
    let gameBoard = [
        [null, null, null, 
         null, null, null, 
         null, null, null]
    ];
    let currentPlayerSymbol = null;


    do {
        currentPlayerSymbol = currentPlayerSymbol === 'X' ? 'O' : 'X';
        gameBoard = makeAMove(gameBoard, currentPlayerSymbol);
    } while( !IsGameOver(gameBoard, currentPlayerSymbol) );
    
}

I copied the solution which was given under the video ( “Writing Good JavaScript Conclusion”), but it did not work. I just get “undefined”. This is what I copied:

function printBoard(gameBoard) {
let gameString = ‘’;
for (let i = 0; i <= 6; i += 3) {
gameString += ${gameBoard[i] ?? i+1}${gameBoard[i+1] ?? i+2}${gameBoard[i+2] ?? i+3}\n;
}
return gameString;
}

function getUserInput(nextPlayerSymbol, gameBoard) {
return +prompt(Board:\n${printBoard(gameBoard)} Enter your next move (1-9) :);
}

function isMoveValid(coordinates, gameBoard) {
return (
typeof coordinates === ‘number’ &&
coordinates >= 1 &&
coordinates <= 9 &&
gameBoard[coordinates - 1] === null
);
}

function makeAMove(gameBoard, nextPlayerSymbol) {
const newGameBoard = JSON.parse(JSON.stringify(gameBoard));
let coordinates;
do {
coordinates = getUserInput(nextPlayerSymbol, gameBoard);
} while ( !isMoveValid(coordinates, gameBoard) );
newGameBoard[coordinates - 1] = nextPlayerSymbol;
return newGameBoard;
}

function hasLastMoverWon(lastMove, gameBoard) {
let winnerCombos = [
[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 [i1, i2, i3] of winnerCombos) {
if (gameBoard[i1] === lastMove &&
gameBoard[i1] === gameBoard[i2] &&
gameBoard[i1] === gameBoard[i3]
) {
return true;
}
}
return false;
}

function isGameOver(gameBoard, currentPlayerSymbol) {
// 1. check if there is a winner
if (hasLastMoverWon(currentPlayerSymbol, gameBoard) ) {
// Write a message that last mover has won the game
alert(Congratulations, ${currentPlayerSymbol} has won the game);
return true;
}
// 2. check if the board is full
const isBoardFull = gameBoard.every(element => element !== null);
if (isBoardFull) {
alert(${printBoard(gameBoard)}\nDraw. Game Over.);
return true;
}
return false;
}

function ticTacToe() {
// State space
let gameBoard = new Array(9).fill(null);
let players = [‘X’, ‘O’];
let nextPlayerIndex = 1;

// Computations

do {
nextPlayerIndex = (nextPlayerIndex + 1) % 2;
currentPlayerSymbol = players[nextPlayerIndex];
gameBoard = makeAMove(gameBoard, currentPlayerSymbol);
} while ( !isGameOver(gameBoard, currentPlayerSymbol) );
}

1 Like

I copied the solution which was given under the video ( “Writing Good JavaScript Conclusion”), but it did not work. I just get “undefined”. This is what I copied:

function printBoard(gameBoard) {
let gameString = ‘’;
for (let i = 0; i <= 6; i += 3) {
gameString += ${gameBoard[i] ?? i+1}${gameBoard[i+1] ?? i+2}${gameBoard[i+2] ?? i+3}\n ;
}
return gameString;
}

function getUserInput(nextPlayerSymbol, gameBoard) {
return +prompt( Board:\n${printBoard(gameBoard)} Enter your next move (1-9) : );
}

function isMoveValid(coordinates, gameBoard) {
return (
typeof coordinates === ‘number’ &&
coordinates >= 1 &&
coordinates <= 9 &&
gameBoard[coordinates - 1] === null
);
}

function makeAMove(gameBoard, nextPlayerSymbol) {
const newGameBoard = JSON.parse(JSON.stringify(gameBoard));
let coordinates;
do {
coordinates = getUserInput(nextPlayerSymbol, gameBoard);
} while ( !isMoveValid(coordinates, gameBoard) );
newGameBoard[coordinates - 1] = nextPlayerSymbol;
return newGameBoard;
}

function hasLastMoverWon(lastMove, gameBoard) {
let winnerCombos = [
[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 [i1, i2, i3] of winnerCombos) {
if (gameBoard[i1] === lastMove &&
gameBoard[i1] === gameBoard[i2] &&
gameBoard[i1] === gameBoard[i3]
) {
return true;
}
}
return false;
}

function isGameOver(gameBoard, currentPlayerSymbol) {
// 1. check if there is a winner
if (hasLastMoverWon(currentPlayerSymbol, gameBoard) ) {
// Write a message that last mover has won the game
alert( Congratulations, ${currentPlayerSymbol} has won the game );
return true;
}
// 2. check if the board is full
const isBoardFull = gameBoard.every(element => element !== null);
if (isBoardFull) {
alert( ${printBoard(gameBoard)}\nDraw. Game Over. );
return true;
}
return false;
}

function ticTacToe() {
// State space
let gameBoard = new Array(9).fill(null);
let players = [‘X’, ‘O’];
let nextPlayerIndex = 1;

// Computations

do {
nextPlayerIndex = (nextPlayerIndex + 1) % 2;
currentPlayerSymbol = players[nextPlayerIndex];
gameBoard = makeAMove(gameBoard, currentPlayerSymbol);
} while ( !isGameOver(gameBoard, currentPlayerSymbol) );
}

1 Like

Please share your code in the following way so it can be easily copy/paste from out team :nerd_face:

Carlos Z

1 Like
var lastMove = null;
function getUserInput(nextPlayerSymbol) {
  return prompt(`Put ${nextPlayerSymbol} at coordinate 0-9: `);
}

function isMoveValid(coordinates, gameBoard) {
  return (
    gameBoard[coordinates] === null && Number(coordinates) < gameBoard.length
  );
}

function makeAMove(gameBoard, nextPlayerSymbol) {
  // clone the game board before placing moves in it
  let newGameBoard = [...gameBoard];
  let coordinates = getUserInput(nextPlayerSymbol);
  while (!isMoveValid(coordinates, gameBoard)) {
    coordinates = getUserInput(nextPlayerSymbol);
  }
  // return newGameBoard;
  newGameBoard[coordinates] = nextPlayerSymbol;

  return newGameBoard;
}

function hasLastMoverWon(lastMove, gameBoard) {
  let winnerCombos = [
    [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 [i1, i2, i3] of winnerCombos) {
    if (
      gameBoard[i1] === lastMove &&
      gameBoard[i1] === gameBoard[i2] &&
      gameBoard[i1] === gameBoard[i3]
    ) {
      return true;
    }
  }
  return false;
}

function isGameOver(gameBoard, currentPlayerSymbol) {
  const lastMove = currentPlayerSymbol;
  // 1. check if there is a winner
  if (hasLastMoverWon(lastMove, gameBoard)) {
    // Write a message that last mover has won the game
    alert(`Congratulations, ${currentPlayerSymbol} has won the game`);
    return true;
  }
  // 2. check if the board is full

  // Return: winner/draw OR game is still in progress
  if (!gameBoard.includes(null)) {
    alert("Game has ended in a draw!");
    return true;
  }
  return false;
}

function ticTacToe() {
  // State space
  let gameBoard = new Array(9).fill(null);
  let players = ["X", "O"];
  let nextPlayerIndex = 0;
  let currentPlayerSymbol = players[nextPlayerIndex];
  // Computations
  do {
    currentPlayerSymbol = players[nextPlayerIndex];
    gameBoard = makeAMove(gameBoard, currentPlayerSymbol);
    nextPlayerIndex = nextPlayerIndex % 2 === 0 ? 1 : 0;
    alert(`
      ${gameBoard[0]}|${gameBoard[1]}|${gameBoard[2]}
      ${gameBoard[3]}|${gameBoard[4]}|${gameBoard[5]}
      ${gameBoard[6]}|${gameBoard[7]}|${gameBoard[8]}
    `);
} while (!isGameOver(gameBoard, currentPlayerSymbol));

}

ticTacToe()
1 Like
function ticTacToe() {
    // State space
    let gameBoard = new Array(9).fill(null);
    let players = ["X", "O"];
    let nextPlayerIndex = 0;
  
    // Computations
    do {
      gameBoard = makeAMove(gameBoard, players[nextPlayerIndex]);
      nextPlayerIndex === 0 ? (nextPlayerIndex = 1) : (nextPlayerIndex = 0);
      alert(`
      ${gameBoard[0]}|${gameBoard[1]}|${gameBoard[2]}
      ${gameBoard[3]}|${gameBoard[4]}|${gameBoard[5]}
      ${gameBoard[6]}|${gameBoard[7]}|${gameBoard[8]}
    `);
    } while (!isGameOver(gameBoard, players[nextPlayerIndex]));
  }
  
  function makeAMove(gameBoard, nextPlayerSymbol) {
    // clone the game board before placing moves in it
    let newGameBoard = [...gameBoard];
    let coordinates = "";
  
    do {
      coordinates = getUserInput(nextPlayerSymbol);
    } while (!isMoveValid(coordinates, gameBoard));
  
    newGameBoard[coordinates] = nextPlayerSymbol;
  
    return newGameBoard;
  }
  
  function getUserInput(nextPlayerSymbol) {
    return prompt(`It is your turn ${nextPlayerSymbol}, what is your move 0-9?`);
  }
  
  function isMoveValid(coordinates, gameBoard) {
    if (
      coordinates >= 0 &&
      coordinates <= 8 &&
      !isSpaceTaken(coordinates, gameBoard)
    ) {
      return true;
    } else {
      return false;
    }
  }
  
  function hasLastMoverWon(lastMove, gameBoard) {
    let winnerCombos = [
      [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 [i1, i2, i3] of winnerCombos) {
      if (
        gameBoard[i1] === lastMove &&
        gameBoard[i1] === gameBoard[i2] &&
        gameBoard[i1] === gameBoard[i3]
      ) {
        return true;
      }
    }
    return false;
  }
  
  function isSpaceTaken(coordinates, gameBoard) {
    if (gameBoard[coordinates] === null) {
      return false;
    } else {
      return true;
    }
  }
  
  function isGameOver(gameBoard, currentPlayerSymbol) {
    let isBoardFull = false;
    let lastMove = currentPlayerSymbol === "X" ? "O" : "X";
    // 1. check if there is a winner
    if (hasLastMoverWon(lastMove, gameBoard)) {
      // Write a message that last mover has won the game
      alert(`YEET, you won the game ${lastMove}!`);
      return true;
    }
    // 2. check if the board is full
    if (!gameBoard.includes(null)) {
      isBoardFull = true;
    }
  
    if (isBoardFull) {
      alert("That's a tie! Play again?");
      return true;
    }
  
    return false;
  }
  
  // Initialize game
  
  ticTacToe();
  
1 Like

Why would we need to copy the gameboard?

function getUserInput(nextPlayerSymbol) {
  let input = prompt("Please enter your position");
  let position = parseInt(input, 10);
  return position;
}

function isMoveValid(coordinates, gameBoard) {
  if (coordinates > 8 || coordinates < 0 || gameBoard[coordinates] !== null) {
    alert("invalid position");
    return false;
  }
  return true;
}

function makeAMove(gameBoard, nextPlayerSymbol) {
  // clone the game board before placing moves in it

  let coordinates = getUserInput(nextPlayerSymbol);
  while (!isMoveValid(coordinates, gameBoard)) {
    coordinates = getUserInput(nextPlayerSymbol);
  }
  gameBoard[coordinates] = nextPlayerSymbol;
  return gameBoard;
  // return newGameBoard;
}

function hasLastMoverWon(lastMove, gameBoard) {
  let winnerCombos = [
    [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 [i1, i2, i3] of winnerCombos) {
    if (
      gameBoard[i1] === lastMove &&
      gameBoard[i1] === gameBoard[i2] &&
      gameBoard[i1] === gameBoard[i3]
    ) {
      return true;
    }
  }
  return false;
}

function isGameOver(gameBoard, currentPlayerSymbol) {
  // 1. check if there is a winner
  lastMove = currentPlayerSymbol;
  if (hasLastMoverWon(lastMove, gameBoard)) {
    // Write a message that last mover has won the game
    alert(`Congratulations, ${currentPlayerSymbol} has won the game`);
    return true;
  }
  // 2. check if the board is full
  const isNull = (element) => element === null;
  if (gameBoard.some(isNull)) {
    alert(`Game is still in progress`);
    return false;
  } else {
    alert(`Game is a draw`);
    return true;
  }

  // Return: winner/draw OR game is still in progress
}

function ticTacToe() {
  // State space
  let gameBoard = new Array(9).fill(null);
  let currentPlayerSymbol = "X";
  // Computations
  do {
    if (currentPlayerSymbol === "X") {
      currentPlayerSymbol = "O";
    } else {
      currentPlayerSymbol = "X";
    }
    gameBoard = makeAMove(gameBoard, currentPlayerSymbol);
    alert(`
      ${gameBoard[0]}|${gameBoard[1]}|${gameBoard[2]}
      ${gameBoard[3]}|${gameBoard[4]}|${gameBoard[5]}
      ${gameBoard[6]}|${gameBoard[7]}|${gameBoard[8]}
    `);
  } while (!isGameOver(gameBoard, currentPlayerSymbol));

  // Return value
  // return undefined;
}

  • I did my best; obviously I am a newbie here and had to check the answers; but try to do it myselfto understand and plan the same thing over over and over until i get a result on my own; I struggle with multiple minor mistakes, quoting null a misplaced bracket and running memory while testing…
    my jaw fell off when I saw the master exercise with bitwise (^) XOR example…
// tictac toe buttom up
// board status to display in prompt
function displayMatrix(mainBoard){
    let boardDisplay = '';
    for ( let i = 0; i< mainBoard.length; i+=1){
        boardDisplay += `${mainBoard[i] ?? i+1} `;
        if ( i % 3 === 2)
            boardDisplay += '\n';
    } 
    return boardDisplay;
}
// collecting inputs from user
function collectInput(nextPlayerSymbol, mainBoard){
    // grab with + an integer
    return +prompt(
        `Board Status: \n${displayMatrix(mainBoard)} \n
        it is ${nextPlayerSymbol}'s move (1-9)
    `);
}
// validate player move and random x and o's
function validateMove(newPosition, mainBoard){
const mainBoardIndex = newPosition -1 ;
// the board should have a null/empty position to validate move
return (
    typeof newPosition === 'number' && 
    newPosition >= 1 && newPosition <=9 &&
    mainBoard[mainBoardIndex] === null
    );
}
function SelectMove(nextPlayerSymbol, mainBoard){
    // clone the gameboard before placing moves
    const newMainBoard = [...mainBoard];
    // compute the move and check if is or not an empyt positon
    do {
     newPosition = collectInput(nextPlayerSymbol, mainBoard);
    } while (!validateMove(newPosition, mainBoard));
    // positions are 0 - 8 so minus 1 to match in matrix
    const mainBoardIndex = newPosition - 1; 
    newMainBoard[mainBoardIndex] = nextPlayerSymbol;
    return newMainBoard;
}
//check someone won
function someoneWon(lastMove, mainBoard) {
    // check the winning options rows, columns and diagonals
   let winningsequence = [
        [ 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 [ h1, h2, h3] of winningsequence){
        if (
            mainBoard[h1] === lastMove &&
            mainBoard[h1] === mainBoard[h2] &&
            mainBoard[h1] === mainBoard[h3]
        ) {
            return true;
        }
    }
    return false;
}
// check if game is over
function checkGameOver(playerSymbol, mainBoard){
    // call if the game is someone wins and check if board is full
    if(someoneWon(playerSymbol, mainBoard)){
    alert(`hey ${playerSymbol} dude you have won the game! Congrats`);
    return true;
    }
    if (mainBoard.every(element => element !== 'null')) {
    alert (`ups! I guess it's a draw`);
    return true;
    }
    return false;
}
// wait for next move
// display string
// call tictactoe game
function ticTacToe_own(){
    //initialize the gameboard with arrays and 
    let mainBoard = new Array(9).fill(null);
    let playerSymbol = null;
    // run the game calling function
    do {
        //set x to start and switch 
        playerSymbol = playerSymbol === 'x' ? 'o' : 'x';
        // start and move  then check if game is over
        mainBoard = SelectMove(playerSymbol, mainBoard);
    } while (!checkGameOver(playerSymbol, mainBoard));
}


With little changes to make it work for VsCode

function printBoard(game) {
  let gameArr = JSON.parse(JSON.stringify(game));
  for (let i = 0; i < gameArr.length; i++) {
    process.stdout.write(gameArr[i]);
    if (i % 3 === 2) {
      console.log();
    }
  }
}
//printBoard(["O", "X", "X", "O", "O", "X", "X", "O", "O"]);
//checking for winner
function hasLastMoverWon(lastMove, gameBoard) {
  let winnerCombos = [
    [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 [i1, i2, i3] of winnerCombos) {
    if (
      gameBoard[i1] === lastMove &&
      gameBoard[i1] === gameBoard[i2] &&
      gameBoard[i1] === gameBoard[i3]
    ) {
      return true;
    }
  }
  return false;
}

function isGameOver(gameBoard, currentPlayerSymbol) {
  if (hasLastMoverWon(currentPlayerSymbol, gameBoard)) {
    console.log(`Congratulations, ${currentPlayerSymbol} has won the game`);
    return true;
  }
  for (let i = 0; i < gameBoard.length; i++)
    if (gameBoard[i] !== "X" && gameBoard[i] !== "O") {
      return false;
    }
  console.log(`Congratulations, the game ended in draw!`);
  return true;
}
//making a move
function makeAMove(game, nextPlayerSymbol) {
  let gameBoard = JSON.parse(JSON.stringify(game));
  let coordinates = getUserInput();
  if (isMoveValid(coordinates, gameBoard)) {
    gameBoard[coordinates] = nextPlayerSymbol;
    return gameBoard;
  }
}
function getUserInput() {
  let column = readline.question("Write you move column(1-3): ") - 1;
  let row = readline.question("Write you move row(1-3): ") - 1;
  if (-1 < column < 3 && -1 < row < 3) {
    if (row == 0) return column;
    else if (row == 1) return column + 3;
    else if (row == 2) return column + 6;
  } else {
    console.log("Incorect value!");
  }
}
function isMoveValid(coordinates, game) {
  if (game[coordinates] === "X" || game[coordinates] === "O") {
    console.log("Incorrect Input!");
    return false;
  } else {
    return true;
  }
}

function ticTacToe() {
  let gameBoard = new Array(9).fill("-");
  let players = ["X", "O"];
  let nextPlayerIndex = 0;
  let nextPlayer;

  do {
    printBoard(gameBoard);
    if (nextPlayerIndex % 2 === 0) {
      nextPlayer = players[0];
    } else {
      nextPlayer = players[1];
    }
    gameBoard = makeAMove(gameBoard, nextPlayer);
    nextPlayerIndex++;
    console.log(nextPlayerIndex);
  } while (!isGameOver(gameBoard, nextPlayer));
}
ticTacToe();

1 Like
function getUserInput() {
  coordinates = prompt("Choose your coordinates from 1 to 9")
  return coordinates;
}

function isMoveValid(coordinates, gameBoard) {
  if (coordinates < 1 || coordinates > 9 || gameBoard[coordinates-1] !== "*") {
    return false;
  }
  else {
    return true;
  }
}

function makeAMove(gameBoard, currentPlayerSymbol) {
    // clone the game board before placing moves in it
    let newGameBoard = [...gameBoard];
    do {
        let coordinates = getUserInput();
    } while ( !isMoveValid(coordinates, newGameBoard) );
    // return newGameBoard;
    newGameBoard[coordinates-1] = currentPlayerSymbol;

    return newGameBoard
}

function hasLastMoverWon(currentPlayerSymbol ,gameBoard) {
    let winnerCombos = [
        [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 combo of winnerCombos) {
        if (gameBoard[combo[0]] === currentPlayerSymbol &&
            gameBoard[combo[1]] === currentPlayerSymbol && 
            gameBoard[combo[2]] === currentPlayerSymbol 
           ) {
            return true;
        }
    }

}

function changePlayer(currentPlayerSymbol, players) {
  if (currentPlayerSymbol === players[0]) {
    currentPlayerSymbol = players[1];
  }
  else {
    currentPlayerSymbol = players[0];
  }
  return currentPlayerSymbol;
}

function boardFull(gameBoard) {
  isFull = true;
  for (let i of gameBoard) {
    if (i !== null) {
      isFull = false
    }
  }
  return isFull;
}

function isGameOver(gameBoard, currentPlayerSymbol) {
    // 1. check if there is a winner 
    if (hasLastMoverWon(currentPlayerSymbol, gameBoard) ) {
        // Write a message that last mover has won the game
        alert(`Congratulations, ${currentPlayerSymbol} has won the game`);
        return true;
    }
    // 2. check if the board is full
    if (boardFull(gameBoard)) {
      alert("Board full! it's a tie")
      return true
    }
    // Return: winner/draw OR game is still in progress
    else {
      alert('Game still in progress')
      return false
    }
    
}

function displayBoard(gameBoard) {
  alert(`
      ${gameBoard[0]}|${gameBoard[1]}|${gameBoard[2]}
      ${gameBoard[3]}|${gameBoard[4]}|${gameBoard[5]}
      ${gameBoard[6]}|${gameBoard[7]}|${gameBoard[8]}
    `);
}

function ticTacToe() {
    // State space 
    let gameBoard = new Array(9).fill("*");
    let isValid = true;
    let players = ['X', 'O'];
    let currentPlayerSymbol = players[1]

    // Computations 
   do {
        currentPlayerSymbol = changePlayer(currentPlayerSymbol, players)
        gameBoard = makeAMove(gameBoard, currentPlayerSymbol);
        displayBoard(gameBoard)  
    } while ( !isGameOver(gameBoard, currentPlayerSymbol) );
    
    // Return value 
    // return undefined;
}

ticTacToe()

Made some adjustments to the code, specially to the hasLastMoveWon algorithm to make the code more readable. I also added a displayBoard function and moved changePlayer into a separate function.

Hope you like it :slight_smile:

const cells = document.querySelectorAll(".cell");
const statusText = document.querySelector("#statusText");
const restartBtn = document.querySelector("#restartBtn");
const winConditions = [
    [0,1,2],
    [3,4,5],
    [6,7,8],
    [0,3,6],
    [1,4,7],
    [2,5,8],
    [0,4,8],
    [2,4,6]
];
let options = ["", "", "", "", "", "", "", "", ""];
let currentPlayer = "X";
let running = false;

initializeGame();
    
function initializeGame(){

    cells.forEach(cell => cell.addEventListener("click",cellClicked))
    restartBtn.addEventListener("click", restartGame);
    statusText.textContent = `${currentPlayer}'s turn`;
    running = true;

}

function cellClicked(){
    const cellIndex = this.dataset.cellIndex;

    if(options[cellIndex] != "" || !running){
        return;
    }

    updateCell(this, cellIndex);
    
    checkWinner();

}

function updateCell(cell, index){
    options[index]= currentPlayer;
    cell.textContent = currentPlayer;

}

function changePlayer(){
    currentPlayer = (currentPlayer == "X") ? "O": "X";
    statusText.textContent =`${currentPlayer}'s turn`;
    

}

function checkWinner(){
    let roundWon = false;

    for(let i = 0 ; i < winConditions.length; i++){
        const condition = winConditions[i];
        const cellA = options[condition[0]];
        const cellB = options[condition[1]];
        const cellC = options[condition[2]];

        if (cellA =="" || cellB == "" || cellC == ""){
            continue;
        }

        if(cellA==cellB && cellB==cellC){
            roundWon = true;
            break;
        }

    }

    if (roundWon){
        statusText.textContent=`${currentPlayer} Wins!`
        running=false;
    }

    else if (!options.includes("")){
        statusText.textContent= `Draw!`
        running = false;
    } else {
        changePlayer();
    }


}

function restartGame(){

    currentPlayer = "X";
    options = ["","","","","","","","",""];
    statusText.textContent = `${currentPlayer}'s turn`;
    cells.forEach(cell => cell.textContent = "");
    running = true;

}
function getUserInput(nextPlayerSymbol, gameBoard) {
    let visualGameBoard = gameBoard.slice();
    for ( let index in visualGameBoard) {
        if ( visualGameBoard[index] === null ) {
            visualGameBoard[index] = index;
        }
    }
    return prompt(`Input integer from 0 to 8 representing next move:\n${visualGameBoard[0]} ${visualGameBoard[1]} ${visualGameBoard[2]}\n${visualGameBoard[3]} ${visualGameBoard[4]} ${visualGameBoard[5]}\n${visualGameBoard[6]} ${visualGameBoard[7]} ${visualGameBoard[8]}`);
}

function isMoveValid(coordinates, gameBoard) {
    return gameBoard[coordinates] === null;
}

function makeAMove(gameBoard, nextPlayerSymbol) {
    // clone the game board before placing moves in it
    let newGameBoard = gameBoard.slice();
    let coordinates = '';
    do {
        coordinates = getUserInput(nextPlayerSymbol, gameBoard);
        console.log(coordinates);
    } while ( !isMoveValid(coordinates, gameBoard) );
    console.log('setting new coordinate');
    newGameBoard[coordinates] = nextPlayerSymbol;

    return newGameBoard;
}

function hasLastMoverWon(lastMove, gameBoard) {
    let winnerCombos = [
        [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 [i1, i2, i3] of winnerCombos) {
        if (gameBoard[i1] === lastMove &&
            gameBoard[i1] === gameBoard[i2] && 
            gameBoard[i1] === gameBoard[i3] 
           ) {
            return true;
        }
    }
    return false;
}

function isGameOver(gameBoard, currentPlayerSymbol) {
    // 1. check if there is a winner 
    lastMove = currentPlayerSymbol;
    if (hasLastMoverWon(lastMove, gameBoard) ) {
        // Write a message that last mover has won the game
        alert(`Congratulations, ${currentPlayerSymbol} has won the game`);
        return true;
    }
    // 2. check if the board is full
    if (!gameBoard.some(element => element === null)) {
        return true;
    }

    // Return: winner/draw OR game is still in progress
    return false;
}

function ticTacToe() {
    // State space 
    let gameBoard = new Array(9).fill(null);
    let players = ['X', 'O'];
    let nextPlayerIndex = 0;

    // Computations 
   do {
        nextPlayerIndex = 1 - nextPlayerIndex; 
        currentPlayerSymbol = players[nextPlayerIndex];
        gameBoard = makeAMove(gameBoard, currentPlayerSymbol);
    } while ( !isGameOver(gameBoard, currentPlayerSymbol) );
    
    // Return value 
    // return undefined;
} 

I had problems caused by the ‘while’ loop and very inconvenient game-play with ‘prompt’. So instead used html buttons clicakable by mouse as an input, which made for a more linear code execution, and tried to stick to using arrays although objects form might have produced a sleeker code.

const players = ['X', 'O']
const winningArrays = [
    ['A1', 'B1', 'C1'],
    ['A2', 'B2', 'C2'],
    ['A3', 'B3', 'C3'],
    ['A1', 'A2', 'A3'],
    ['B1', 'B2', 'B3'],
    ['C1', 'C2', 'C3'],
    ['A1', 'B2', 'C3'],
    ['A3', 'B2', 'C1'],
]
let playerX = true
let winner
let gameBoard = [[], []]
let nextPlayerIndex = 0


function getBox(coordinates){
    return document.getElementById(coordinates)
}

function writeToBox(coordinates, gameBoard, nextPlayerIndex){
    gameBoard[nextPlayerIndex].push(coordinates)
    return (getBox(coordinates)).value = players[nextPlayerIndex]
}

function isTacTacToe(gameBoard, nextPlayerIndex){
    if( gameBoard === undefined ||
        nextPlayerIndex === undefined 
    ) return false


    const [...gameBoardCopy] = [...gameBoard]
    gameBoardCopy[nextPlayerIndex].sort()

    winningArrays.forEach(array =>{
        let arrayOfInterest = array

        if(
            gameBoardCopy[nextPlayerIndex].includes(arrayOfInterest[0]) &&
            gameBoardCopy[nextPlayerIndex].includes(arrayOfInterest[1]) &&
            gameBoardCopy[nextPlayerIndex].includes(arrayOfInterest[2])         
            ){
                arrayOfInterest.forEach(element =>{
                    const box = document.getElementById(element)
                    box.innerHTML = players[nextPlayerIndex].toLowerCase()
                    winner = players[nextPlayerIndex]
                })
                const message = document.getElementById('message')
                message.innerHTML = `${players[nextPlayerIndex]} WINS!` 
                
            } 

    })

    if (winner !== undefined){
        return true
    } 

    
 
}


function isMoveValid(coordinates, gameBoard){
    if(coordinates === null) return
//check that input is valid
    if(
        coordinates[0] !=='A' && 
        coordinates[0] !=='B' &&
        coordinates[0] !=='C' 
        ) return false
        
    if (coordinates[1] < 0 || coordinates[1] > 3) return false

 //parse gameboard for included coordinates
    if (gameBoard[0].includes(coordinates) ||
    gameBoard[1].includes(coordinates)) return false

    return true   
}

function isGameOver(gameBoard, nextPlayerIndex){
    //1.check for winner
    if(isTacTacToe(gameBoard, nextPlayerIndex) === true){
        return true
    }
    //2. check if board full
    if(gameBoard[0].length + gameBoard[1].length >= 9){ 
        const message = document.getElementById('message')
        message.innerHTML = `DRAW` 
        return true
    } 

    return false

}

function tictactoe(coordinates){

    //is move valid
    if (isMoveValid(coordinates, gameBoard)){
        let post = document.getElementById('message')
        post.innerHTML = '' 

        //write move
        writeToBox(coordinates, gameBoard, nextPlayerIndex)

        //check for win/game over
        if(isGameOver(gameBoard, nextPlayerIndex)){
            alert("Thank You for Playing!")
        }

        //switch player
        playerX = !playerX
        nextPlayerIndex = playerX ? 0 : 1

    } else { 
        let post = document.getElementById('message')
        post.innerHTML = 'Invalid Move' 

}
}

.gameBoardButtons {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    width:50vw;
    height:50vw;
    border: 1px solid black;
}
.buttonBox{
    border: 1px solid black;
    border-radius: 4px;
    width:14vw;
    height:14vw;
    font-size: 10vw;
    translate: 0px;
    cursor: pointer;

}
 
  .buttonBox:hover {
    background-color: #04AA6D;
    color: white;
  }
<body>
    <h1 >TIC TAC TOE</h1>


    <div class="gameBoardButtons">
        <form>
        <input type="button" class='buttonBox' id="A1" value="" onclick="tictactoe('A1')">
        <input type="button" class='buttonBox' id="A2" value="" onclick="tictactoe('A2')">
        <input type="button" class='buttonBox' id="A3" value="" onclick="tictactoe('A3')">
        <input type="button" class='buttonBox' id="B1" value="" onclick="tictactoe('B1')">
        <input type="button" class='buttonBox' id="B2" value="" onclick="tictactoe('B2')">
        <input type="button" class='buttonBox' id="B3" value="" onclick="tictactoe('B3')">
        <input type="button" class='buttonBox' id="C1" value="" onclick="tictactoe('C1')">
        <input type="button" class='buttonBox' id="C2" value="" onclick="tictactoe('C2')">
        <input type="button" class='buttonBox' id="C3" value="" onclick="tictactoe('C3')">

        </form>
    </div>
    <h2 id="message">Message Board</h2>

    
</body>```