Photo (c) Patrick Hendry

Free Code Camp: Tic Tac Toe Game

In this front end development project, we’re going to build a tic tac toe game using HTML, CSS and jQuery.

So make sure to link your jQuery CDN or if you downloaded it, link it now!

markup

<div class="board">
 <div class="intro">
 <h1>Play Tic Tac Toe</h1>
 
 <button>Let's Play!</button>
 </div>
 
 <div class="player">
 <div>
 <h2>Do you want to be X or O?</h2>
 <button class="x">X</button>
 <button class="o">O</button>
 </div>
 
 
 <div>
 <button class="back"><i class="fa fa-arrow-left" aria-hidden="true"></i> Back</button>
 </div>
 
 </div>
 
 <div class="game">
 <table>
 <tr>
 <td class="" id="1"></td>
 <td class="" id="2"></td>
 <td class="" id="3"></td>
 </tr>
 <tr>
 <td class="" id="4"></td>
 <td class="" id="5"></td>
 <td class="" id="6"></td>
 </tr>
 <tr>
 <td class="" id="7"></td>
 <td class="" id="8"></td>
 <td class="" id="9"></td>
 </tr>
 </table>
 </div>
 
 <div class="alert">
 <p class="close">x</p>
 <p class="msg">It's your turn.</p>
 </div>
</div>

styles

.clickable {
  pointer-events: auto;
  cursor: pointer;
}

.unclickable {
  pointer-events: none;
}

.player,
.game,
.alert {
  display: none;
}

.alert {
  font-size: 25px;
  text-align: center;
  background: #fc914e;
  padding: 5px;
  position: fixed;
  top: 100px;
  left: 50px;
  width: 300px;
  box-shadow: 0px 3px 10px 1px #222223;
}

.alert .close {
  margin: 0;
  text-align: right;
  padding: 0 15px;
  font-size: 30px;
  cursor: pointer;
}

body {
  text-align: center;
  font-family: 'Indie Flower', cursive;
  color: #fff;
  /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#ce8e52+0,ad4103+44,6d0019+100 */
  background: #ce8e52; /* Old browsers */
  background: -moz-linear-gradient(top, #ce8e52 0%, #ad4103 44%, #6d0019 100%); /* FF3.6-15 */
  background: -webkit-linear-gradient(top, #ce8e52 0%,#ad4103 44%,#6d0019 100%); /* Chrome10-25,Safari5.1-6 */
  background: linear-gradient(to bottom, #ce8e52 0%,#ad4103 44%,#6d0019 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ce8e52', endColorstr='#6d0019',GradientType=0 ); /* IE6-9 */
  width: 100%;
  height: 100%;
  margin: 0;
  background-repeat: no-repeat;
  background-attachment: fixed;
}

h1 {
  font-family: 'Shadows Into Light Two', cursive;
  font-size: 40px;
}

button {
  background: flesh;
  border: none;
  font-size: 35px;
  font-family: 'Indie Flower', cursive;
  color: #fff;
  padding: 8px 20px;
  background: #fc914e;
  box-sizing: border-box;
}

button:hover,
button:active {
  border-radius: 10px 8px 10px 8px;
  border: 2px dashed #ccc;
  background: transparent;
/*   transition: 0.3s; */
/*   font-weight: bold; */
    box-sizing: border-box;

}

.board {
  width: 400px;
  height: 390px;
/* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#2f3f24+7,111e00+55,010500+100 */
  background: #2f3f24; /* Old browsers */
  background: -moz-radial-gradient(center, ellipse cover, #2f3f24 7%, #111e00 55%, #010500 100%); /* FF3.6-15 */
  background: -webkit-radial-gradient(center, ellipse cover, #2f3f24 7%,#111e00 55%,#010500 100%); /* Chrome10-25,Safari5.1-6 */
  background: radial-gradient(ellipse at center, #2f3f24 7%,#111e00 55%,#010500 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2f3f24', endColorstr='#010500',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
  
  border: 20px solid #511f00;
  border-radius: 15px;
box-shadow: 0 1px 10px 0px #000;
  
  position: fixed;
  top: 50%;
  left: 50%;
  /* bring your own prefixes */
  transform: translate(-50%, -50%);
}

.intro,
.player {
  position: relative;
  margin: 0 auto;
  height: auto;
  width: 400px;
  top: 85px;
  left: 0px;
}

.player .back {
  display:block;
  
  font-size: 16px;
  margin: 0 auto;
  margin-top: 60px;
}

.game table {
  display: block;
  width: 100%;
  height: 100%;
  border-collapse: collapse;
  box-sizing: border-box;
}

th, td {
    border: 1px solid #fff;
}

th, td {
  width: 130px;
  height: 127px;
  font-size: 40px;
}

In this challenge, I based the design on the project example of Free Code Camp. That’s why it’s similar to that one. I like how the developer combined the colors to make that effect on the “blackboard”.

And I tried using gradients from Colorzilla. You can try it and generate your gradients.

script

Let’s get this started

In this game, there are nine boxes. And we’re going to label them as one through nine.

//  Variables
var player, computer;

var playerArray = [];
var computerArray = [];
var outerArray = [1,2,3,4,5,6,7,8,9];
var winningArrays = [[1, 2, 3], [4,5,6], [7,8,9], [1,4,7], [2,5,8], [3,6,9], [1,5,9], [3,5,7]];

In this part, we declared variables that we’re going to use as we go on to the game.

The player array is used to store the values of the player’s turns and same with the computer array.

The outer array is used as a base array to check if the board is already filled.

And the winning  arrays is a multidimensional array containing the right values that match winning patterns.

$(".intro button").click(function() {
  $(".intro").css("display", "none");
  $(".player").css("display", "block");
  outerArray = [1,2,3,4,5,6,7,8,9];
});

$(".back").click(function() {
  $(".player").css("display", "none");
  $(".intro").css("display", "block");
});

These are just to go next and to go back. Just for design. Haha.

$(".x").click(function() {
  $(".player").css("display", "none");
  $(".game").css("display", "block");
  $(".msg").text("It's your turn.");
  $(".alert").fadeIn("fast");
  // $("td").unbind("click");
  setPiece("x");
});

$(".o").click(function() {
  $(".player").css("display", "none");
  $(".game").css("display", "block");
  $(".msg").text("It's your turn.");
  $(".alert").fadeIn("fast");
  // $("td").unbind("click");
  setPiece("o");
});

Once the user chose a piece, the tic tac toe board and a message that says, “It’s your turn”, will appear.

function setPiece(piece) {
  player = piece;
  if(player === "x") {
    computer = "o";
  } else {
    computer = "x";
  }
}

We’re going to store which piece the user chose.

And then the game will begin.

$("td").on("click", function() {
  $(this).text(player);
  var num = $(this).attr("id");
  $(this).addClass("unclickable");
  startGame(num);
});

Each box in the board is a <td> element that has an id attribute that corresponds to one through 9.

So when the player clicked on one, the player’s piece will be displayed in that box.

The id of that box will be stored in a variable and passed as a parameter into the method, startGame().

Then, that box clicked will be unclickable.

function startGame(num) {
  if (outerArray.length !== 0) {
    $(".alerts").fadeOut("fast");
    playerArray.push(Number(num));
    removeElement(Number(num));

    if (outerArray.length !== 0) {
      processComputersTurn();
    } else {
      displayResults();
    }
    
    if (playerArray.length > 2  || computerArray.length > 2) {
      var state_player = checkWinningArray(playerArray);
      var state_computer = checkWinningArray(computerArray);
      
      if (state_player === "won" || state_computer === "won") {
        displayResults();   
      } else if (state_player === "draw" && state_computer === "draw") {
        displayResults();
      }
    }  
  } else {
    displayResults();
  }
}

This method is long and full of nested if statements. I suggest you divide them into functions and just call those functions here.

In this method, we’re checking if the outerArray is not yet empty or if the board is not yet filled, then we’ll continue playing the game.

If it’s empty, we’ll declare the winner.

The id that is passed as a parameter in this method will be stored in the player array. So each turn of the player and the computer will be stored in their respective arrays.

Then those turns will be removed from the outer array filling the board.

function removeElement(element) {
  var index = outerArray.indexOf(element);
  if (index > -1) {
    outerArray.splice(index, 1);
  }
}

This method, removeElement(), will be remove the turn made from the outerArray.

We’re going again if the outer array is not yet empty. In case there’s only one box left and yes, the board is not yet filled. But if we remove from the outer array, it’s going to be empty. And we have to declare the winner at that instant.

However, if the board is not yet filled, then we’re going to process the computer’s turn.


function generateNumber() {
  return Math.floor(Math.random() * (9 - 1 + 1)) + 1;
}

function processComputersTurn() {
  var turn;
  
  do {
    turn = generateNumber();
    if (outerArray.length === 0) {
      break;
    }
    
  } while (outerArray.indexOf(turn) < 0);
   
  
  if (outerArray !== 0) {
    removeElement(turn);
    $("#" + turn + "").text(computer);
    $("#" + turn + "").addClass("unclickable");
    computerArray.push(turn);
    $(".alert").fadeIn("fast");
  } else {
    displayResults();
  }
}

We’re going to generate a random number that is not yet filled up in the board.

If the outer array is empty, we’ll declare winner.

If not, then we remove that number from the outer array, display the computer’s piece on the board and make the box unclickable and store them in the computer array.

We’ll always check if there’s already a winner after each turn and as early as the length of the computer and player array greater than two.

function checkWinningArray(set) {
  var winner;
  var ctr = 0;
  
  checking : 
  for (var i = 0; i < winningArrays.length; i++) {
    ctr = 0;
    for (var j = 0; j < 3; j++) { if (set.indexOf(winningArrays[i][j]) >= 0) {
        ctr++;
      }
      if (ctr == 3) {
        winner = "won";
        break checking;
      }
    }
  }
  
  if (winner === undefined) {
    winner = "lost"
  }
  
  return winner;
}

In this method, we’re going to check if one of the arrays in the winning array is in the player or the computer’s array.

In short, if one of the patterns is filled by the computer or the player’s array. If they did, they’ll be the winner.

If there’s already a winner or it’s a draw or if the board is already filled, we’re going to display the results.

function displayResults() {
  var playerStatus = checkWinningArray(playerArray);
  var computerStatus = checkWinningArray(computerArray);

  console.log("Player: " + playerStatus);
  console.log("Computer: " + computerStatus);
  
  if (playerStatus === "won") {
    if (computerStatus === "won") {
      $(".msg").text("Draw");
    } else {
      $(".msg").text("You win");      
    }
  } else if (computerStatus === "won") {
    $(".msg").text("You lost");
  } else {
    if (playerStatus === "lost" && computerStatus === "lost") {
      $(".msg").text("Draw");
    } else {
      $(".msg").text("Something's wrong with your code.");
    }
  }
  
  $(".alert").fadeIn("fast", function() {
    $(".game").css("display", "none");
    $(".intro").fadeIn("fast");
    clearBoard();
  });

}

I don’t know why I’m checking who’s the winner again.

But you can fix it in your code so you’ll not check who’s the winner again.

You can just pass who won as a parameter in this function.

We’re just going to set the message that’s going to be displayed.

Then, the game is over.

We’re going to clear the board and reset everything.

function clearBoard() {
  $("td").each(function() {
    $(this).text("").removeClass("unclickable").addClass("clickable");
  });
  playerArray = [];
  computerArray = [];
  outerArray = [1,2,3,4,5,6,7,8,9];
}

 

You can check my whole code here.

And that’s it. That’s how we build a a tic tac toe game using jQuery.

I hope that you understand it.

Still, I recommend customizing and experimenting it to achieve your desired result.

Good luck!

 

Love,
Eirin

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s