The World’s Most Empowering Tic-Tac-Toe JavaScript Tutorial

Making a mark means that there is a place for the mark to be made:/*—– app's state (variables) —–*/let board;Making a mark means that a game has been initiated.

Let’s use a function to initiate the board as an array of 9 empty strings.

Our JS doesn’t know anything about the HTML document yet.

Each position in the JS array will correspond to a square on the HTML board.

Let’s give ourselves a visual aid by mimicking the 3 x 3 grid from our HTML.

The 3 x 3 structure of the array changes nothing.

It could be written on one single line!function init() {board = ['', '', '','', '', '','', '', ''];};//be sure to call the init function!init();Making a mark means rendering a change in the game.

Let’s stub up a render function:function render() {}Now, let’s think about what we want to do.

This render function will need to iterate over our board array and “inject” the mark into the correct div.

Let’s use a handy little function called .


This function accepts a callback function that it will call on each element in the array:function render() {board.

forEach(function(mark, index){console.

log(mark, index);});};Call render():function init() {board = ['', '', '','', '', '','', '', ''];// new code hererender();};Go ahead and open a server then hit cmd + opt + i to check out your console!.You should see all the index numbers from the board!.Try throwing something into the empty strings on the board array and see what happens in the console.

Making a mark means that the mark shows up on the page.

Grab our squares:/*—– cached element references —–*/const squares = Array.


querySelectorAll('#board div'));The Array.

from() function will make an array from all elements returned by querySelectorAll.

Notice that querySelectorAll is finding the element with the id of .

board and selecting all the div children of that element.

This way, we didn’t have to give each square an id, select them individually, and build a new array.

JavaScript did that for us!.Pretty cool!Pass those to render():function render() {board.

forEach(function(mark, index) {//this sets the text content of the square of the same position to the mark on the board.


textContent = mark;});};And now, you have made a mark, Cheryl!.Treat yourself!Take turnsWhat does it mean to take turns?.Taking a turn means that there is a turn.

Head back to the state section and throw down your turn variable like a boss:/*—– app's state (variables) —–*/let board;let turn = 'X';Taking a turn means that an event (such as ‘click’) has occurred.

Listen for the click on the board.

We will need to “grab” an HTML element using getElementbyId() and then chain the event listener onto it:/*—– event listeners —–*/document.


addEventListener('click', handleTurn);addEventListener() takes two arguments, the event to listen for and a callback function to execute when the event is heard.

We need to write that callback function:/*—– functions —–*/function handleTurn(event) {let idx = squares.

findIndex(function(square) {return square === event.

target;});};The ‘event’ is the click, the ‘target’ is the element on which the event took place — the square we’ve clicked on.

findIndex() finds the index of the square in our squares array that matches the square the user clicked!Excellent work!.You can change the world, Cheryl.

Did I say world?.I meant board.

Change the board we’re holding in state:function handleTurn(event) {let idx = squares.

findIndex(function(square) {return square === event.

target;});// new code belowboard[idx] = turn;// check your console logs to make sure it's working!console.

log(board);};Has your state changed?.You’re on the right track in this game and in your life.

You’ve got this.

You can change the board for the better!“X” and “O”We still don’t have “O” included in this game which makes it easy to win, but not much fun to play.

So, we’ll just update that bit of state using a ternary.

Ternaries seem to confuse people.

Learn to write one today and thank yourself for all time.

Here’s our logic: If it is X’s turn, then assign the turn to O; if it is not X’s turn, assign the turn to X.

Let’s put that logic into the ternary structure:<condition>?.<if condition is true, this> : <else if condition is false, this>Place the assignment “turn =” in front of that ternary and try console logging it out.

It’s ok if this takes a minute.

Just breathe, Cheryl.

Don’t forget to call that render() function once you’re all through.

All together it should look like this:function handleTurn() {let idx = squares.

findIndex(function(square) {return square === event.

target;});board[idx] = turn;// This is tidyturn = turn === 'X'?.'O' : 'X';// In an if statement it would look like: // if (turn === 'X') {// turn = 'O' // } else {// turn = 'X' // };// writing the ternary saved you from all that.

render();};Ta-freaking-da!.Now we have a Tic-Tac-Toe game!. More details

Leave a Reply