Skip to main content

Simple AngularJS app TicTacToe Game

[PLACEHOLDER]


A note from the author
: “After checking AngularJS I said to my colleague let’s blog about it… so here we are”.

This article is based on a simple example that it was quickly done with this MVC library. We started reading the book AngularJS from O’Reilly, by Brad Green & Shyam Seshadri and we wanted to use it right away. We are used to the MVC pattern because of MVC.net, when we saw AngularJS we immediately wanted to try it; also we had some influence from our front-end developers (Just to let you know part of our background is back-end development).

Basically we wanted to focus to the initial part of our study around this book providing examples around simple items. In this case we selected an example that can illustrate data binding, the watch function and CSS classes. We did not wanted to do the “Hello world” example from the book; as always we tried to do something fun, so we thought, let’s do a simple TIC-TAC-TOE game experience, THAT YOU PLAY ON THE SAME DEVICE (the 2 users should share it... yes I little to simple, we know!).

It had to be quick as well, so just a simple example would do the trick. Keep in mind this code can be refactor and make it way much better. There is a potential to use ng-repeat, which we did not include it here. I believe refactoring can reduce the amount of lines of code in our example. This was thought –created-done in less than 2 hours. Writing this article took us longer.

Download it from here: https://github.com/consultingti/simpletictactoe


What you won't find in this article
  • as I mentioned before this is a basic example, no complex work, but rather demonstrating the $watch function. No security discussion, we might work on that later on. But if you are interest and want to read or learn more about sanitizing or how to make your app more secure when using angularjs then this is a good place to start: http://www.youtube.com/watch?v=18ifoT-Id54 . In that youtube video the host is using laravel, which is a php framework, but you can do the same thing by using .Net (which is my preference because of my .Net background) or any other language and framework you feel comfortable.
  • Another good read with good comments and suggestions here: http://blog.brunoscopelliti.com/deal-with-users-authentication-in-an-angularjs-web-app
  • There is no API calls or back-end functionality (data, authorization functionality, etc.). Perhaps in the future if we move to a second version of this example.

For our little experiment we used AngularJS (of course, the star of the article) and also BootStrap as we wanted to play a little more and combined tools. Below you can find a brief definition of both items. After we’ll go into the example:

  1.  AngularJS: open-source javascript framework, maintained by Google that assists with running single-page applications. Its goal is to augment browser-based applications with MVC capability, in an effort to make both development and testing easier. – definition from Wikipedia.
  2.  $watch: this is from AngularJS. It is a $scope function that is called with an expression to observe and a callback that gets invoked whenever that expression changes.
  3. Bootstrap: sleek, intuitive and powerful mobile front-end framework for faster and easier web development. – definition from Bootstrap.

The Example:

It is about a web-base, simple Tic-Tac-Toe game.

Some requirements:

  •       Responsive app, so you can load it in your phone (this is where BootStrap comes into play)
  •       MVC (angularJS role)
  •       2 users: 1 named “X” the other named “O”. The site will make it clear the turn for each user.
  •       Honor the rule of the game:  two players, X and O, who take turns marking the spaces in a 3×3 grid. The player who succeeds in placing three respective marks in a horizontal, vertical, or diagonal row wins the game.

What do you need?

  1. Download Bootstrap from http://getbootstrap.com
  2. Download AngularJS from http://angularjs.org
  3. Some knowledge about HTML, CSS, Javascript. But no expert level is required for this simple example.

Some key part from the code:

  1. The ng-app attribute tells Angularjs which parts of the page it should manage. Since we’ve placed it on the <html> element, we’re telling Angularjs that we want it to manage the whole page.<html lang="en" ng-app>
  2. The bootstrap css was added, along with a custom table.css that I created for the tic-tac-toe html section.
  3. The angular.js.  <script src="./assets/js/angular.js"></script>
  4. The code that makes the little game possible. It may need refactoring and you may even want to put it in a different file and not in the same HTML as I did. As I said this is just a simple example, introduction level.  I’ll describe the code on the next section.
  5. The ng-controller. With it you manage areas of the page with JavaScript classes called controllers. By including a controller in the body tag, you will manage everything inside the <body> area.<body ng-controller="simpleGameController" onload="inigame();" >
  6.  <div id="d11" class="cell"><a  style="color:red" href="/" ng-click="clickrow('d11')" ng-class="{playing: row1[0].played == 'true'}">{{row1[0].title}}</a></div> The ng-click. A call to action to a method of the controller when you click this element.    The ng-class. In this case we have a condition that if an object has a particular value then we’ll add the “playing” class to the element.    {{object}}. To display the value.

Explanation of the Controller code:

  • simpleGameController: is our AngularJS controller receiving the scope object, which refers to the application model.
  • Player variable: to flag if is “X” or “O” that is playing. In our example “X” is the starting user always. As I said it is a simple demo so in this example you don’t get to choose who plays first, in this case the “X” will always play first.
  • There are 3 arrays (row1, row2, row3) for the rows. In each array you have:
    • Title. Initialize with string ”xod”. As the player clicks this value will change either to “X” or “O”, depending on the user.
    • Played. Initialize to “false”. As the player clicks it will change to “true” indicating you cannot click again on that cell.
  • Winner: function that indicates if a user won.
  • Clickrow: it is triggered when you click a cell where the user is playing. It received the parameter rowCoord, which indicates what cell was clicked. It also loads the modal window indicating the turn of the user.
  • Inigame: just called when the page loads to start the game, indicating the first player.
  • $watch: angularjs goodie that we use to observe the player variable. When this variable changes the value the winner function gets trigger to check if there was a winner or not.

The controller code:
<script>
     
     function simpleGameController($scope)
     {
     $scope.test = "1";
     $scope.player="X";
     $scope.win = "";
     $scope.lost="";
   
   
      $scope.row1 =  [{title: 'xod', played: 'false'},
                       {title: 'xod',played: 'false'},
                       {title: 'xod',played: 'false'}];
      $scope.row2 =  [{title: 'xod',played: 'false'},{title: 'xod',played: 'false'},{title: 'xod',played: 'false'}];
      $scope.row3 = [{title: 'xod',played: 'false'},{title: 'xod',played: 'false'},{title: 'xod',played: 'false' }];
                      
          
       $scope.winner = function()
       {
          var a = [
                    [$scope.row1[0].title,$scope.row1[1].title, $scope.row1[2].title],
                    [$scope.row2[0].title,$scope.row2[1].title, $scope.row2[2].title],
                    [$scope.row3[0].title,$scope.row3[1].title, $scope.row3[2].title]
                   
                  ]
          var matches = 1;
          //check the winner by evaluating who hit 3 in a line (vertical, horizontal, diagonal)
          //check horizontal
             //a. checking 1st array
             //b. checking 2nd array
             //c. checking 3rd array
           for (var i=0; i< 3;i++)
           {
             for (var j=0; j<3;j++)
             {
               if ((matches<=2)&& (j>0))
                {
                  if ((a[i][j-1]==a[i][j])&&(a[i][j-1]!="xod"))
                  {
                    matches=matches+1;
                  }
                }
             }
             if (matches<3)
                  matches=1;
             else
                {
                   $scope.test="winner";
                   $scope.lost = $scope.player;
                if ($scope.player=="X")
                     $scope.win = "O";
                     else
                     $scope.win = "X";
                return "winner";                    
                }
           }
            
          //check vertical
          for (var i=0; i< 3;i++)
           {
             for (var j=0; j<3;j++)
             {
               if ((matches<=2)&& (j>0))
                {
                  if ((a[j-1][i]==a[j][i])&&(a[j-1][i]!="xod"))
                  {
                    matches=matches+1;
                  }
                }
             }
             if (matches<3)
                  matches=1;
             else
              {
                $scope.test="winner";
                $scope.lost = $scope.player;
                if ($scope.player=="X")
                     $scope.win = "O";
                     else
                     $scope.win = "X";
               
                return "winner";           
              }
           }
          //check diagonal
          for (var i=0; i< 3;i++)
           {
            // for (var j=0; j<3;j++)
             //{
               if ((matches<=2)&& (i>0))
                {
                  if ((a[i-1][i-1]==a[i][i])&&(a[i-1][i-1]!="xod"))
                  {
                    matches=matches+1;
                  }
                }
             //}
             if (i==2)
             {
             if (matches<3)
                  matches=1;
             else
              {
                $scope.test="winner";
                $scope.lost = $scope.player;
                if ($scope.player=="X")
                     $scope.win = "O";
                     else
                     $scope.win = "X";
                return "winner";           
              }
              }
           }
        if (!($scope.test=="winner"))
        {
         $('#myModal').modal('show');
         }
       }
      
   
       $scope.clickrow = function(rowCoord)
       {
         //$scope.row1[0].title="wao";
         if (($scope.player.length > 0)&& !($scope.test=="winner"))
         {
          
            if (rowCoord.length >0)
            {
                var s = rowCoord.split("");
             
                if (s[1]=="1")
                {
                //row1
                     if ($scope.row1[parseInt(s[2])-1].title=="xod")
                     {
                         $scope.row1[parseInt(s[2])-1].title = $scope.player; 
                         //turn the value visible by chaging the background to white
                         $scope.row1[parseInt(s[2])-1].played="true";
                     }   
                }
                if (s[1]=="2")
                {
                //row2
                 if ($scope.row2[parseInt(s[2])-1].title=="xod")
                     {
                         $scope.row2[parseInt(s[2])-1].title = $scope.player; 
                         //turn the value visible by chaging the background to white
                         $scope.row2[parseInt(s[2])-1].played="true";
                     }   
                }
                if (s[1]=="3")
                {
                //row3
                 if ($scope.row3[parseInt(s[2])-1].title=="xod")
                     {
                         $scope.row3[parseInt(s[2])-1].title = $scope.player; 
                         //turn the value visible by chaging the background to white
                         $scope.row3[parseInt(s[2])-1].played="true";
                     }   
                }
               
                 
                  if ($scope.player=="X")
                     $scope.player="O";
                     else
                     $scope.player="X";
            }
         }
       
       }
      
       $scope.userturn = function(turn)
       {
          if (turn==null)
          {
            
             $('#myModal').modal('show');
             }
       }
      
       $scope.$watch('player',$scope.winner);
     }
   
     function inigame()
     {
     //$scope.player="X";
         $('#myModal').modal('show');
     }
   
      function restart()
       {
         location.reload();
       }
   
    </script>

Trending posts

Democratizing AI

Democratizing AI is all about empowering others to use it, by making it available to them. Audiences, such as marketers in a company, will be able to access AI capabilities as part of their MarTech solutions, without the need of being technical. It could also be schools, where the younger generations are learning how to use it in responsible, secure, innovative, and creative ways. This is the year where companies, after discovery phases and teams experimenting, are looking to activate and take advantage of the AI advances. Generated with Microsoft Designer   And so, questions emerge, such as “What to democratize when leveraging AI?” There are common scenarios, as well as specific ones, that will depend on the company, and the industry they belong to. A common scenario, seen in many industries, when democratizing data is the data visualization and reporting . In digital marketing, as an example, data scientists and data analysts can automate reporting, making them available to the c...

Productivity framework for 2024

Recently I was at a Christmas party and I found myself giving advice to a friend on being more productive. I shared the approaches that I take which helped me become more productive at work and in my personal life. The conversation with my friend inspired me to share my approaches in this blog .  Photo by Moose Photos from Pexels   My productivity framework has five key pillars and to remember them I use the mnemonic, POFOR = P lan your tasks, O rganize yourself, F ocus on your tasks, O ptimize yourself with habits and R eflect to ensure you are being productive on the right tasks. Plan Planning is very crucial as it sets the tone for the rest of the pillars. I always found I was more productive when I planned my tasks compared to when I didn’t, and hence planning has become my rule of thumb. I recommend taking 30 minutes at the end of each day to plan your next day. This means prioritizing your tasks and blocking your calendar accordingly. By not doing so, you are at risk o...

SRE, DevOps and ITOps

 If you are wondering what the differences between the SRE and DevOps are, as well as how these roles work with ITOps within an organisation then you are not alone; and best of all you are on the right blog post. Often enough business units in a company get confused, assigning the ServiceNow or Jira tickets or any other ticketing system of your preference, to the wrong group, and even having the incorrect expectations when doing resourcing. Let us go through definitions, insights and scenarios that will help you understand the difference. DevOps software development operations - AI Generated When it comes to DevOps and SRE, then you might be wondering which practice came first. While SRE may have originated a bit earlier, internally at Google, DevOps came first publicly as a practice and started to be used by companies. A few years later was when Google decided to open SRE to the world after the publication of the "Site Reliability Engineering" book. Therefore, technically sp...

Effective framework to resolve conflict in the Workplace

 Conflicts are a part of our daily lives and are often unavoidable at work. Therefore, it's essential to have the tools to effectively manage conflicts and leverage them to our advantage - to spur new ideas, challenge and strengthen our beliefs, and evolve our perspectives when necessary. However, conflicts often trigger our fight-or-flight response and can cause chronic stress and mental fatigue and diminish our productivity. Having the right tools can help us face conflicts confidently.  AI Generated with Microsoft Copilot + Designer by Beolle   Recently, I took a course from Harvard ManageMentor® * to enhance my conflict resolution skills. I summarized the key takeaways from the course in the framework below to help you better prepare for resolving conflicts. The framework consists of six (6) parts Identify the type of conflict   Identify your own and your counterpart's conflict styles   Determine how you want to address the conflict   Prepare to resolve...

This blog uses cookies to improve your browsing experience. Simple analytics might be in place for pageviews purposes. They are harmless and never personally identify you.

Agreed