Please post your questions below
function getBoardString(gameBoard){
let BoardString = '';
for(let i = 0; i < gameBoard.length; i++){
BoardString = BoardString + `${gameBoard[i] ?? i+1}`;
if(i % 3 === 2){
BoardString = BoardString + '\n';
}
}
return BoardString;
}
function getUserInput(nextPlayerSymbol, gameBoard) {
return +prompt(`Board state: \n${getBoardString(gameBoard)} Enter ${nextPlayerSymbol}'s next move (1-9)`);
}
function isMoveValid(move, gameBoard) {
let boardIndex = move-1;
if(gameBoard[boardIndex] === null && move>=1 && move<=9 && typeof move === 'number') {
return true;
}
else
return false;
}
function makeAMove(gameBoard, nextPlayerSymbol) {
// clone the game board before placing moves in it
let move = getUserInput(nextPlayerSymbol);
let newGameBoard = [...gameBoard];
do {
move = getUserInput(nextPlayerSymbol, gameBoard);
} while ( !isMoveValid(move, gameBoard) );
let 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) {
// 1. check if there is a winner
const 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.includes(null)){
alert(`The game has ended in a draw`);
return true;
}
else {
return false;
}
// Return: winner/draw OR game is still in progress
}
function ticTacToe() {
// State space
let gameBoard = new Array(9).fill(null);
let currentPlayerSymbol = null;
// Computations
do {
currentPlayerSymbol = currentPlayerSymbol === 'X' ? 'O' : 'X';
gameBoard = makeAMove(gameBoard, currentPlayerSymbol);
} while ( !isGameOver(gameBoard, currentPlayerSymbol) );
}
This code is copied exactly from the solution videos, but I kept getting these errors in the console. Why is it unable to read the length of the gameBoard array? It is defined in the ticTacToe function.
I think all of the other errors are caused by this as well.
You are passing only one parameter for getUserInput function
, that function takes two parameters, if you look at the getUserInput function it receives two parameters
function getUserInput(nextPlayerSymbol, gameBoard) {
return +prompt(`Board state: \n${getBoardString(gameBoard)} Enter ${nextPlayerSymbol}'s next move (1-9)`);
}
}
And pass the second parameter to getBoardString
function So when this function is called you are not passing any thing, if you see that function it loops,
function getBoardString(gameBoard){
let BoardString = '';
for(let i = 0; i < gameBoard.length; i++){
BoardString = BoardString + `${gameBoard[i] ?? i+1}`;
if(i % 3 === 2){
BoardString = BoardString + '\n';
}
}
return BoardString;
}
if you don pass anything to that function, gameBoard
is undefined and thatβs why it is throwing cannot read properties of undefined (reading) length
Here is the code from the solution,
function renderBoard(board) {
let innerHtml = `<pre>${getBoardString(board)}</pre>`;
document.querySelector(".js-container").innerHTML = innerHtml;
}
function getBoardString(gameBoard) {
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${getBoardString(
gameBoard
)} Enter ${nextPlayerSymbol}'s next move (1-9):`
);
}
function isMoveValid(move, gameBoard) {
const boardIndex = move - 1;
// move is a number
// move is between 1 and 9 (inclusive)
// gameBoard does not contain a symbol at the place of the move
return (
typeof move === "number" &&
move >= 1 &&
move <= 9 &&
gameBoard[boardIndex] === null
);
}
function makeAMove(gameBoard, nextPlayerSymbol) {
const newGameBoard = [...gameBoard];
let move = null;
do {
move = getUserInput(nextPlayerSymbol, gameBoard);
} while (!isMoveValid(move, gameBoard));
const boardIndex = move - 1;
newGameBoard[boardIndex] = nextPlayerSymbol;
renderBoard(newGameBoard);
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
// if (draw) { alert(...); return true; }
if (gameBoard.every((element) => element !== null)) {
alert(`Draw. Game over.`);
return true;
}
return false;
}
function ticTacToe() {
// State space
let gameBoard = new Array(9).fill(null);
let currentPlayerSymbol = null;
// Computations
renderBoard(gameBoard);
do {
currentPlayerSymbol = currentPlayerSymbol === "X" ? "O" : "X";
gameBoard = makeAMove(gameBoard, currentPlayerSymbol);
} while (!isGameOver(gameBoard, currentPlayerSymbol));
}
ticTacToe();
I deviated from the way it was handled through the videos and made a different way using the DOM.
Here are my files.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Static Template</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>Prompt Tic-Tac-Toe</h1>
<div class="js-container">
<div class="next-player">
Current Turn: X
</div>
<div class="js-board board">
<div class="js-row row">
<div class="js-cell cell" data-cell="0">-</div>
<div class="js-cell cell" data-cell="1">-</div>
<div class="js-cell cell" data-cell="2">-</div>
</div>
<div class="js-row row">
<div class="js-cell cell" data-cell="3">-</div>
<div class="js-cell cell" data-cell="4">-</div>
<div class="js-cell cell" data-cell="5">-</div>
</div>
<div class="js-row row">
<div class="js-cell cell" data-cell="6">-</div>
<div class="js-cell cell" data-cell="7">-</div>
<div class="js-cell cell" data-cell="8">-</div>
</div>
</div>
<div class="js-winner"></div>
<button class="reset-game">Reset Game</button>
</div>
<script src="tictactoe.js"></script>
</body>
</html>
style.css
body {
box-sizing: border-box;
}
.board {
width: 150px;
border: 2px solid black;
}
.row {
display: flex;
}
.cell {
width: 50px;
height: 50px;
border: 1px solid black;
text-align: center;
line-height: 50px;
}
.reset-game {
margin-top: 12px;
display: none;
}
tictactoe.js - the good stuff!
let currentTurnSymbol = "X";
let gameBoard = [null, null, null, null, null, null, null, null, null];
let winner = null;
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]
];
const $cell = document
.querySelectorAll(".cell")
.forEach((elem) => document.addEventListener("click", handleClickMove));
const $resetGame = document
.querySelector(".reset-game")
.addEventListener("click", newGame);
function handleClickMove(e) {
if (winner) {
return false;
}
if (gameBoard[e.target.dataset.cell]) {
return false;
}
gameBoard[e.target.dataset.cell] = currentTurnSymbol;
e.target.innerHTML = currentTurnSymbol;
isGameOver(currentTurnSymbol, gameBoard);
currentTurnSymbol = currentTurnSymbol === "X" ? "O" : "X";
document.querySelector(
".next-player"
).innerHTML = `Current Turn: ${currentTurnSymbol}`;
}
function isGameOver(player, gameBoard) {
// Check for Winner
for (let [i1, i2, i3] of winnerCombos) {
if (
gameBoard[i1] === player &&
gameBoard[i1] === gameBoard[i2] &&
gameBoard[i1] === gameBoard[i3]
) {
winner = player;
document.querySelector(
".js-winner"
).innerHTML = `Congrats! ${winner} has won the game.`;
document.querySelector(".reset-game").style.display = "block";
}
}
// Check for draw
if (!gameBoard.includes(null)) {
document.querySelector(".js-winner").innerHTML =
"It's a draw! Click reset to play again!";
document.querySelector(".reset-game").style.display = "block";
}
return false;
}
function newGame() {
winner = null;
gameBoard = [null, null, null, null, null, null, null, null, null];
currentTurnSymbol = "X";
document.querySelector(".reset-game").style.display = "none";
document.querySelector(".js-winner").innerHTML = "";
document.querySelectorAll(".cell").forEach((elem) => (elem.innerHTML = "-"));
}
When Iβm learning this Section, Iβm trying so hard to display my work in the browser in Sandbox as below:
This image below should be displayed in the Sandbox browser:
How can I do it??? I would appreciate your help.
Have you try to run it on a local server? like the live server of the course using vs code?
Also, can you share your code in the following way so i can try to replicate the issue?
Carlos Z
I have a question about the use of βxβ in the tictactoe game (for Javascript). In the video, [βxβ, null, null] is used. But why use βxβ? Why not use [ null, null, null]?
I just found out, itβs in the video, and it should be [ null, null, null]
I copied the tictactoe solution given in the course, then pasted it into my browser console (inspect function). It did not work. What is the actual tictactoe solution that works?
Could you please share the link where you get the solution of the exercise?
Carlos Z
@thecil
I copied the tictactoe solution given in the course, then pasted it into my browser console (inspect function). It did not work. What is the actual tictactoe solution that works? (The code which I copied is in the next message, properly formatted.)
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) );
}
Hi Carlos,
The solution to the tictactoe game (which did not work for me) can be found with this link.
https://academy.moralis.io/lessons/writing-good-javascript-conclusion
It is under the video.
Sincerely,
Aaron
The exercise works as expected on the browser console, once you have paste the code on it, you just need to execute the initialize function which is ticTacToe()
, just type that one into the console and the game should start properly.
Carlos Z
Thank you Carlos! Now it works! I am new to programming!
can someone let me know where I can find the final solution for DOM manipulation becuse the link given in the last segment (under the title DOM conclusion) in the sandbox, is not a valid link