0

I am building a tic tac toe game using angular js and am now at the point where I need to see if there is a winner. I am doing this using two nested for loops which I know isn't always best practice and am wondering is there an easier way to set up this logic?

I call this function when someone selects a square and pass in their piece (X or O).

     function checkWinner(winningPiece){
      let i;
      let j;
      let winnerRows = [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
        [1, 5, 9],
        [3, 5, 7],
        [1, 4, 7],
        [2, 5, 8],
        [3, 6, 9]
        ];
      for (i=0; i < winnerRows.length; i++) {
        for (j=0; winnerRows[i].length; j++) {
         // code to check if their piece matches each element in the array
        }
      }
    }

I'm open to other ideas of logic. Here is the code: https://plnkr.co/edit/XGhX5zVWCjSnn3OaKNQ6?p=preview

Stack Juice
  • 137
  • 1
  • 2
  • 11
  • Smells like homework ;-) - this mostly happends on sunday. Mhm, does school start on monday? Hurry up, homework still not finished. – lin Mar 19 '17 at 12:27
  • Check your plnkr, it seems to have an infinite loop (crashes in my browser anyway). – cnorthfield Mar 19 '17 at 12:28
  • @lin not homework haha :) just trying to code better – Stack Juice Mar 19 '17 at 12:31
  • 1
    Possible duplicate of [Algorithm for Determining Tic Tac Toe Game Over](http://stackoverflow.com/questions/1056316/algorithm-for-determining-tic-tac-toe-game-over) – georgeawg Mar 19 '17 at 12:53
  • @georgeawg on first glance that already seems more complex. – Stack Juice Mar 19 '17 at 12:57
  • There are only 8 ways to win at Tic Tac Toe and that algorithm checks all of them. If there is a simpler way to do it, write the answer over there where it has more exposure and will likely get more upvotes. – georgeawg Mar 19 '17 at 13:02
  • @cnorthfield do you know how to set up the logic to do a check if there's a winner within a nested for loop? – Stack Juice Mar 19 '17 at 17:01

1 Answers1

1

Instead of building vm.squares with an array of objects with ID's, why not just use the index of the array as the ID? You could just subtract 1 from every value of your winnerRows array and remove the object access from your win checking code.

Despite that (and to be super nitpicky), every time your outer loop iterates, it is going to check winnerRows.length, and your inner loop is going to check winnerRows[i].length. It's not going to make any real noticeable difference in this application with the number of items in your array, but since we're talking about best practices, it is always faster to compare to a literal than to compare to the result of a function or an array access. Since we know that the outer loop is always going to run 8 times, we can replace winnerRows.length with 8. And since every array in winnerRows has 3 entries, we can replace winnerRows[i].length with 3.

We can cut this down even more slightly by taking out the inner loop altogether and use the transitive property (if a = b and b = c -> a = c) to declare a winner.

We can nitpick further and possibly eliminate the checks of each piece if the first square you are checking isn't the type of the winning piece. Loops will short circuit on && if the first condition is false and will not execute the rest of the logical expression.

The following code implements all of these changes using your current implementation of vm.squares:

for (i=0; i < 8; i++) {
    if (vm.squares[winnerRows[i][0]].piece === winningPiece &&
        vm.squares[winnerRows[i][0]].piece === vm.squares[winnerRows[i][1]].piece &&
        vm.squares[winnerRows[i][1]].piece === vm.squares[winnerRows[i][2]].piece) {
        alert ('winner');
    }
}

Of course, these are all just minor optimizations, and you probably won't see huge returns for an application of this size. Just some good practices in there and you eliminate the second loop.

Nick Tallents
  • 131
  • 1
  • 5