JavaScript Fun Code Web Dev

Build a Tic Tac Toe Game in 10 Lines with JavaScript

Tic tac toe game JavaScript

Tic Tac Toe game or Noughts and Crosses or Xs and Os is a popular game around the world, played between two players, player X, and player O, making turns by marking a grid in a 3X3 grid matrix, the player who first make a horizontal, vertical or diagonal marking in a row wins. Tic tac toe has been ancient as 1300 BC and has been one of the oldest games still around in the 21st century because of its simplicity. Many regions around the world have adopted it and gave it different local names.

However, Tic Tac Toe has moved from a pencil-and-paper game to a real computer game over the years. Giving developers reasons to build different kinds of this game for computers.

There are lots of codes and demonstrations of the tic-tac-toe game online, in fact, just Google "Tic tac toe" and you will see Google's version of the game.

Tic Tac Toe on the Web

It's quite interesting as a web developer, to program games in JavaScript. Trust me, more interesting if it is a game like the Tic Tac Toe. My first tic-tac-toe game was made in 2018. This does not thusly mean that that was when I got the skill to make it, but was when I first thought about making it. It was fun to make it, made use of the latest standards around then. It was class-based, and I also leveraged the use of syntactic-sugary ES6 features. The game logic was to store the possible indices that makes a win in each rows, then check at every play attempt, to see if a player's markings have matched any of the stored indices. This seems to be one of the easiest approaches to code the game, and that is what we will yet use for our 10-line Tic Tac Toe game. Are you ready?

Tic Tac Toe Game in 10 lines of JavaScript Code

The script in this first game is 164 lines, and it worked well (basically as a tic tac toe game). I can guess that your thought right now is how the heck can this be reduced to 10 lines? I also asked myself this!

There are some things to consider in this game, it is just fun coding, so we have stripped out some basic features of the game, and leave to its logic.

  • There is no game score count.
  • When a player wins or draws, the page reloads.
  • This no way to reset the game.

Do you still wonder how this is done in 10 lines? Let's go!

The HTML

As normal, we have added some markups to define the game grids.

<!DOCTYPE html><html>
  <head>
    <title>Tic Tac Toe Game</title>
  </head>
  <body>
  <div id="console">
      <div id="panel">
      <div id="0" class="grid"></div>
      <div id="1" class="grid"></div>
      <div id="2" class="grid"></div>
    
      <div id="3" class="grid"></div>
      <div id="4" class="grid"></div>
      <div id="5" class="grid"></div>
    
      <div id="6" class="grid"></div>
      <div id="7" class="grid"></div>
      <div id="8" class="grid"></div>
  </div></div>  </body></html>

The #console is the container for the game.

The #panel is the semantic container for the grids.

The index attribute on each grids .

Let's continue on this later.

The CSS

To draw out a grid, we used the grid property on the #panel element.

We added borders, gave some thoughts about mobile responsiveness, and some colors to make it look nice.

body {
  margin: 0;
  background: linear-gradient(red 10%, yellow) no-repeat;
  font-family: 'Trebuchet Ms', sans-serif;
}
#console {
  padding: 3vw;
}
#console,
#panel {
  margin: auto;
}

#panel {
  width: clamp(200px, 5vw, 200px);
  height: clamp(200px, 5vw, 200px);
  display: grid;
  grid-template-rows: repeat(3, 1fr);
  gap: 0;
}
.row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
}
.grid {
  border: solid 1px #000;
  justify-content: center;
  align-items: center;
  display: flex;
  font-size: 25px;
  user-select: none;
  font-weight: 400;
}

Consider the above code as an attempt to make our game look good. Here is what it looks like:

Tic Tac Toe Game

The Logic

Here comes the backbone of the game.

This is a summary of what was done.

  • Each time a player clicks on a grid, it checks if that grid is not yet marked, then marks the grid and gives the second player a turn.
  • Each time a grid is marked:
    • It stores the corresponding player label ("X" or "O") in an array of records in the same index as the grid marked.
    • It also checks if no grids are left to mark, shows an alert "Players draw." if true, and reloads the page.
    • It also checks if a winner is found, shows an alert "Player {label} wins!" if true, and reloads the page.

The Script

Here comes the backbone of our code.

Note: The readability score of this code is near to zero. This is a fun code, and should not be used for tutorial purposes.

We start by creating a single-line function that initializes the game.

The first line defines the needed variables for the game:

var playMarks, winLines, playCount, nextPlayer;
var initGame = (reload, winner) => {playMarks = Array(9).fill(null), winLines = [[0, 1, 2],[2,5,8],[6,7,8],[0, 3, 6],[3, 4, 5],[1, 4, 7],[0, 4, 8],[2, 4, 6]], playCount = 0, nextPlayer = localStorage.getItem('nextPlayer') || 'X'; ['X','O'].includes(winner) ? (alert(`Player ${winner} wins!`), location.reload()) : reload ? (alert('Players draw.'), location.reload()) : null;}

The next line defines an arrow function that initializes the game. The function will also be used to determine the winner and reload the page when a player wins or draws.

marks is the array that records player marks, this array is initialized with 9 elements having null values.

winLines holds rows of possible win indices.

playCount counts the number of times the players have marked. Basically to determine when the game is drawn and reloads the page. Initialized to 0.

nextPlayer holds the label of the next turn player. Initialized to "X", making "X" the first player in the game. Because we need to keep this record even when a page reloads, we store the value of the nextPlayer variable inside a Local Storage and retrieve it once a page reloads.

Line 3, starts with a dirty ternary operation that checks if there's a winner, reloads the page with the winning message `Player ${winner} wins!` else reloads the page with a draw message 'Players draw.'.

['X','O'].includes(winner) ? (alert(`Player ${winner} wins!`), location.reload()) : reload ? (alert(`Players draw.`), location.reload()) : null;}

I call it dirty because more lines could have been added to make it more readable, besides this, we could have just used the if/else operation instead. Ternary operation is not the best to use here as it doesn't return a value. We only use it to favor our promise 10-line code.

Note the } at the end of line 3, which closes the body of the initGame() function.

A better way to write this code might be:

if(['X','O'].includes(winner)) {
  alert(`Player ${winner} wins!`);
  location.reload();
} else if(reload) {
  alert(`Players draw.`);
  location.reload();
}

Declaring the Winner

There are eight chances of wining the tic tac toe game.

Tic Tac Toe Game Explained

This is why we have 8 rows in the winLines array, having a 2-dimensional array, with the inner arrays holding the indices that make up the game rows.

winLines = [
  [0, 1, 2],
  [2, 5, 8],
  [6, 7, 8],
  [0, 3, 6],
  [3, 4, 5],
  [1, 4, 7],
  [0, 4, 8],
  [2, 4, 6],
];

Here is the function that gets the winner.

var getWinner = (playerLabel) => winLines.some((winLine) => winLine.every((index) => playMarks[index] == playerLabel)); 

The getWinner() function takes an argument playerLabel which supplies the current player's label ("X" or "O").

When a grid is marked:

  • The getWinner() function loops through winLines and picks the inner array.
  • Runs another loop on the inner array and picks the values [a,b,c].
  • It references the values of the playMarks array, using the values picked from winLines as index.
  • It checks if each values gotten from playMarks[a], playMarks[b], and playMarks[b] is equal to playerLabel.
  • Boom! We found a winner.

We are able to get over the game logic in just three lines!

On the fourth line, we added a click event listener to each .grid elements, to run some checks and conditionally performs actions that cooks the game!

document.querySelectorAll('.grid').forEach((grid, index) => {
      grid.addEventListener('click', (e) => {
        if (!grid.innerText) {
          grid.innerText = nextPlayer;
          playMarks[grid.id] = nextPlayer;
          if (getWinner('X') || getWinner('O')) initGame(true, nextPlayer);
          if(++playCount == 9) initGame(true); nextPlayer == 'X' ? 'O' : 'X'; localStorage.setItem('nextPlayer', nextPlayer);}});});

The above is basically the code side of what was explained here. Let's recall that in a few lists.

  • Checks if clicked grid is empty:
    • And then records it's label in the playMarks array, in the exact index as the clicked grid.
    • Calls the getWinner() passing the current player's label as the argument.
    • Checks is marks is up to nine, and assumes game draw if no winner.
    • Stores the next player label in JavaScript local storage to retrieve this on reload.

We are done. Here is the full code in an HTML file.

<!DOCTYPE html>
<html>
  <head>
    <title>Tic Tac Toe JavaScript Game in 10 Lines</title>
  </head>
  <body>
    <style>
body {
  margin: 0;
  background: linear-gradient(orange 10%, pink) no-repeat;
  font-family: 'Trebuchet Ms', sans-serif;
  font-size: 33px;
}
#console {
  padding: 3vw;
}
#console,
#panel {
  margin: auto;
}

#panel {
  width: clamp(200px, 5vw, 200px);
  height: clamp(200px, 5vw, 200px);
  display: grid;
  grid-template-rows: repeat(3, 1fr);
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
}
.grid {
  border: solid 1px #000;
  justify-content: center;
  align-items: center;
  display: flex;
  font-size: 25px;
  user-select: none;
  font-weight: 400;
}
    </style>
<div id="console">
  <div id="panel">
    
      <div id="0" class="grid"></div>
      <div id="1" class="grid"></div>
      <div id="2" class="grid"></div>
    
      <div id="3" class="grid"></div>
      <div id="4" class="grid"></div>
      <div id="5" class="grid"></div>
    
      <div id="6" class="grid"></div>
      <div id="7" class="grid"></div>
      <div id="8" class="grid"></div>
  </div>
</div>
    <script>
    var playMarks, winLines, playCount, nextPlayer;
    var initGame = (reload, winner) => {playMarks = Array(9).fill(null), winLines = [[0, 1, 2],[2,5,8],[6,7,8],[0, 3, 6],[3, 4, 5],[1, 4, 7],[0, 4, 8],[2, 4, 6]], playCount = 0, nextPlayer = localStorage.getItem('nextPlayer') || 'X'; 
    ['X','O'].includes(winner) ? (alert(`Player ${winner} wins!`), location.reload()) : reload ? (alert('Players draw.'), location.reload()) : null;}
    var getWinner = (playerLabel) => winLines.some((winLine) => winLine.every((index) => playMarks[index] == playerLabel));
    document.querySelectorAll('.grid').forEach((grid, index) => {
      grid.addEventListener('click', (e) => {
        if (!grid.innerText) { grid.innerText = nextPlayer; playMarks[grid.id] = nextPlayer;
          if (getWinner('X') || getWinner('O')) initGame(true, nextPlayer);
          if(++playCount == 9) initGame(true); nextPlayer = nextPlayer == 'X' ? 'O' : 'X'; localStorage.setItem('nextPlayer', nextPlayer);}});});
    initGame();
    </script>
  </body>
</html>

We have added this to our JavaScript examples. View the live demo below.

When player draws or wins, you can rerun the code to reload the game.

What Is Missing In This Game?

We have to strip some general functions of a game because we want to obey the 10-line rule. For example, a normal 2-player game should have a counter indicating the score of each player. This can be done by creating two variables playerXScore and playerOScore then incrementing it in the getWinner() function, whenever X or O wins respectively.

We can also add a "reset" button to reset the game anytime and remove the 'nextPlayer' value from localStorage.

Having the page intact without reload is also the best option.

For another version of Tic Tac Toe (written in 2018) which has more rich in nature. Check here.

Conclusion

This tutorial demonstrates how you can be creative and make things that will surprise even you. Note that this is a fun code and should not be used for tutorial purposes.

Do you also have anything mind blowing and also funny, or any idea to even reduce the lines to even 7 or 5?

Share it in the comments section below.

Leave a comment

Your email address will not be published.*

Comments (0)