Smail Barkouch Smail Barkouch - 2 months ago 5
Javascript Question

Javascript code to recognize all possible combinations of winning

I am working on making a tic-tac-toe game for the science fair and I need help for recognizing all possible ways of finding a win rather than writing all of them down with brute force.

The game mechanics were just started today and I just started learning javascript (about 5 days ago) so I might not be the best looking code and the most efficent one. Also take notice i'm not done yet as this code is not 100% finished but i'm just putting my code for anyone who would like to look as I only need the combinations for all the possible wins. If you would like to watch me and help me while I work I would gladly invite you to see my code on Gitlab (I know its not the most famous but its very nice).

<!DOCTYPE html>
<html>
<head>
<style>
table,tr,td{
border-style:solid;
border-length:1px;
}
</style>
<script>
var s1="s1";
var s2="s2";
var s3="s3";
var s4="s4";
var s5="s5";
var s6="s6";
var s7="s7";
var s8="s8";
var s9="s9";
var turn=0;
function gotClicked(s1,s2,s3,s4,s5,s6,s7,s8,s9) {
if (!(id1="s1" || id2="s2" || id3="s3" || id4="s4" || id5="s5" || id6="s6" || id7="s7" || id8="s8" || id9="s9")) {
switch(x1 || x2 || x3 || x4 || x5 || x6 || x7 || x8 || x9) {
case x1:
var x1=NA1;
turn++;
if(turn=3) {
if(s1=NA1 && s2=NA3 )
}
}
}
}
</script>
</head>
<body>
<table>
<tr>
<td>
<p id="s1" onclick="document.getElementById('s1').innerHTML='x';var id1=x1;gotClicked();"><a href="#">N/A</a></p>
</td>

<td>
<p id="s2" onclick="document.getElementById('s2').innerHTML='x';var id2=x2;gotClicked();"><a href="#">N/A</a></p>
</td>

<td>
<p id="s3" onclick="document.getElementById('s3').innerHTML='x';var id3=x3;gotClicked();"><a href="#">N/A</a></p>
</td>
<tr/>
<tr>
<td>
<p id="s4" onclick="document.getElementById('s4').innerHTML='x';var id4=x4;gotClicked();"><a href="#">N/A</a></p>
</td>

<td>
<p id="s5" onclick="document.getElementById('s5').innerHTML='x';var id5=x5;gotClicked();"><a href="#">N/A</a></p>
</td>

<td>
<p id="s6" onclick="document.getElementById('s6').innerHTML='x';var id6=x6;gotClicked();"><a href="#">N/A</a></p>
</td>
<tr/>
<tr>
<td>
<p id="s7" onclick="document.getElementById('s7').innerHTML='x';var id7=x7;gotClicked();"><a href="#">N/A</a></p>
</td>

<td>
<p id="s8" onclick="document.getElementById('s8').innerHTML='x';var id8=x8;gotClicked();"><a href="#">N/A</a></p>
</td>

<td>
<p id="s9" onclick="document.getElementById('s9').innerHTML='x';var id9=x9;gotClicked();"><a href="#">N/A</a></p>
</td>
<tr/>
</table>
</body>
</html>




Thanks to one contributor for showing my mistakes!

Answer

Some issues:

  • border-length is not valid CSS, it shoud be border-width
  • You are not doing comparisons in this if statement, but assignments:

    if (!(id1="s1" ...
    

    Use triple equality signs ( === ) to perform (strict) string comparisons.

  • Your code would greatly improve if you would use an array instead of 9 separate variables: it will result in less duplication of almost identical code. For example, use this as your representation of the board:

    var board = Array(9);
    

    ... and put a 0 or 1 in a particular array element when the corresponding square receives and 'X' or and 'O'. For instance:

    board[0] = 1 
    
  • With the array presentation you can list a winning configuration as a triplet of indices in that array. For instance, if the values at index 0, 1 and 2 are all 1, then player 1 ('O') has won. All such presentations can be listed as follows:

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

    The check for a win would be a matter of checking board entries at these indices to see they contain all 1 or all 0 (see code in snippet below).

  • It is better not to write JavaScript code in HTML onclick attributes. For one, it results again in duplication of code, but it is also harder to debug when errors happen. Overall, it is considered better to separate code (JavaScript) from layout (HTML).

    Remove the onclick attributes and use addEventListener method instead inside your script:

    Array.from(document.querySelectorAll('td a')).forEach( function (link, i) {
        link.addEventListener('click', gotClicked.bind(null, link, i));
    });
    
    function gotClicked(link, i) {
        var player = turn % 2;
        link.parentNode.textContent = 'XO'[player];
        board[i] = player;
        turn++;
    }
    

    For this to work, you should move your script to the end of your document, just before the closing </body>. Or, if you prefer it at the top, then wrap the code in:

    document.addEventListener('DOMContentLoaded', function () {
        // your code that needs access to the document elements comes here
    });
    
  • Don't use innerHTML when you just want to put text. For that purpose textContent is more suited.

Here is a working snippet:

document.addEventListener('DOMContentLoaded', function () {
  var board = Array(9);
  var wins = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6] ];
  var turn = 0;
  Array.from(document.querySelectorAll('td a')).forEach( function (link, i) {
    link.addEventListener('click', gotClicked.bind(null, link, i));
  });

  function gotClicked(link, i) {
    var player = turn % 2;
    link.parentNode.textContent = 'XO'[player];
    board[i] = player;
    if (isWinFor(player)) alert('Winning move!');
    turn++;
  }

  function isWinFor(player) {
    for (var win of wins) {
      var count = 0;
      for (var index of win) {
        if (board[index] !== player) break;
        count++;
      }
      if (count == 3) return true;
    }
  }
});
table,tr,td{
  border-style:solid;
  border-width:1px;
  text-align: center
}
<table>
  <tr>
    <td>
      <p><a href="#">N/A</a></p>
    </td>
    <td>
      <p><a href="#">N/A</a></p>
    </td>
    <td>
      <p><a href="#">N/A</a></p>
    </td>
  <tr/>
  <tr>
    <td>
      <p><a href="#">N/A</a></p>
    </td>
    <td>
      <p><a href="#">N/A</a></p>
    </td>
    <td>
      <p><a href="#">N/A</a></p>
    </td>
  <tr/>
  <tr>
    <td>
      <p><a href="#">N/A</a></p>
    </td>
    <td>
      <p><a href="#">N/A</a></p>
    </td>
    <td>
      <p><a href="#">N/A</a></p>
    </td>
  <tr/>
</table>