Javascript代码可识别所有可能的获胜组合

时间:2016-10-09 17:47:05

标签: javascript combinations tic-tac-toe

我正在为科学博览会制作一个井字游戏,我需要帮助识别所有可能的获胜方式,而不是用蛮力写下所有这些。

游戏机制刚刚开始,我刚开始学习javascript(大约5天前)所以我可能不是最好看的代码和最有效的代码。另外注意我还没有完成,因为这段代码不是100%完成但我只是把我的代码放在任何想看的人身上,因为我只需要所有可能获胜的组合。如果您想在我工作的时候看着我并帮助我,我很乐意邀请​​您在 Gitlab 上看到我的代码(我知道它不是最有名的,但非常好)。

<!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>

感谢一位撰稿人出示我的错误!

2 个答案:

答案 0 :(得分:1)

一些问题:

  • border-length不是有效的CSS,它应该是border-width
  • 您没有在此if声明中进行比较,而是分配:

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

    使用三重等号(===)执行(严格)字符串比较。

  • 如果您使用数组而不是9个单独的变量,您的代码将会大大改进:它将减少几乎相同代码的重复。例如,使用它作为董事会的代表:

    var board = Array(9);
    

    ...当相应的方格接收到&#39; X&#39;时,将0或1放在特定的数组元素中。或者和&#39;。例如:

    board[0] = 1 
    
  • 使用数组表示,您可以将获胜配置列为该数组中的三个索引。例如,如果索引0,1和2的值都是1,那么玩家1(&#39; O&#39;)就赢了。所有这些演示文稿都可以列出如下:

    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]
    ];
    

    检查获胜将是检查这些索引的board条目以查看它们包含全部1或全部0(请参阅下面的代码段中的代码)。

  • 最好不要在HTML onclick属性中编写JavaScript代码。首先,它会导致代码重复,但在发生错误时也更难调试。总的来说,将代码(JavaScript)与布局(HTML)分开会更好。

    删除onclick属性,并在脚本中使用addEventListener方法:

    Array.from(document.querySelectorAll('td a'), function (link, i) {
        link.addEventListener('click', gotClicked.bind(null, link, i));
    });
    
    function gotClicked(link, i) {
        // From the `turn` value we can know who the current player is:  0 or 1.
        // We use the modulo operator to get the remainder when dividing by 2: 
        var player = turn % 2; // alternates between 0 and 1.
        // Use this 0 or 1 as index in the XO string and display it.
        // When player is 0 this gives 'X', when 1 it gives 'O':
        link.parentNode.textContent = 'XO'[player];
        // Also put the 0 or 1 in our array
        board[i] = player;
        // Player played, so now increment `turn`.
        turn++;
    }
    

    为了实现这一点,您应该在结束</body>之前将脚本移动到文档的末尾。或者,如果您喜欢它在顶部,那么将代码包装在:

    document.addEventListener('DOMContentLoaded', function () {
        // your code that needs access to the document elements comes here
    });
    
  • 点击事件处理程序应阻止点击启动导航。为此,您可以使用e.preventDefault(),但您必须在函数中获得e参数。

    function gotClicked(link,i,e){     e.preventDefault();     // ......等 }

  • 当您只想放置文字时,请不要使用innerHTML。为此,textContent更适合。

这是一个工作片段:

&#13;
&#13;
document.addEventListener('DOMContentLoaded', function () {
  // *** Initialise board with "empty" cells -- we use -1 for that:
  var board = [-1,-1,-1,-1,-1,-1,-1,-1,-1];
  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'), function (link, i) {
    link.addEventListener('click', gotClicked.bind(null, link, i));
  });

  function gotClicked(link, i, e) {
    // Prevent the click on the link to initiate a navigation
    e.preventDefault();
    // *** call function to perform move: will return true when game is over
    if (doMove(i, 'You won!')) return;
    // ***Let AI play a move.
    randomAi();
  }

  // ***Separate function to perform a particular move: can be used for 
  // both players
  function doMove(i, msg) {
    // *** Get td-element that corresponds to the given index
    var td = document.querySelectorAll('td')[i];
    // From the `turn` value we can know who the current player is:  0 or 1.
    // We use the modulo operator to get the remainder when dividing by 2: 
    var player = turn % 2;
    // Use this 0 or 1 as index in the XO string and display it.
    // When player is 0 this gives 'X', when 1 it gives 'O':
    td.textContent = 'XO'[player];
    // Also put the 0 or 1 in our array
    board[i] = player;
    // Player played, so now increment `turn`.
    turn++;
    // Now board has changed, check if there is a 3-in-a-row for this player,
    // *** and return it as the result of this function
    if (isWinFor(player)) {
        // *** Show appropriate message
        alert(msg);
        return true; // signify end of game
    }
    // *** Detect a draw
    if (turn == 9) {
        alert("It's a draw");
        return true; // signify end of game
    }
  }

  // *** Modified completely
  function randomAi() {
    // ***Pick random number among the free cells. Make sure it is integer.
    var randomPick = Math.floor(Math.random()*(9-turn));
    // ***Find out its position on the board
    for (var i in board) {
        if (board[i] !== -1) continue; // used cell -- skip it
        if (randomPick == 0) break; // found it
        randomPick--;
    }
    // ***Perform this AI move
    doMove(i, 'You lost');
  }

  function isWinFor(player) {
    // Player is 0 or 1.
    // Iterate over all the 8 potential wins
    for (var win of wins) {
      // `win` is a triplet of indices, which when they contain the player's value
      // constitute a winning position. Let's count how many of those three
      // have the player's value (0 or 1)
      var count = 0;
      for (var index of win) {
        // Is the value on the board the value that corresponds to the player?
        if (board[index] !== player) break; // don't bother looking further.
        count++;
      }
      // If we have a count of 3 here, it is a winning position.
      if (count == 3) {
        // Don't try other wins: one is enough :-)
        // ***Remove all hyperlinked cells -- no move should be played anymore
        Array.from(document.querySelectorAll('td a'), function (link, i) {
          link.parentNode.innerHTML = ''; // remove link
        });
        return true;
      }
    }
  }
});
&#13;
table,tr,td{
  border-style:solid;
  border-width:1px;
  text-align: center
}
/* ***Fix the size of the board */
td { width: 30px; height: 30px }
&#13;
<table>
  <tr>
    <td>
      <a href="#">N/A</a>
    </td>
    <td>
      <a href="#">N/A</a>
    </td>
    <td>
      <a href="#">N/A</a>
    </td>
  <tr/>
  <tr>
    <td>
      <a href="#">N/A</a>
    </td>
    <td>
      <a href="#">N/A</a>
    </td>
    <td>
      <a href="#">N/A</a>
    </td>
  <tr/>
  <tr>
    <td>
      <a href="#">N/A</a>
    </td>
    <td>
      <a href="#">N/A</a>
    </td>
    <td>
      <a href="#">N/A</a>
    </td>
  <tr/>
</table>
&#13;
&#13;
&#13;

解释

在评论中,您询问了这段代码:

Array.from(document.querySelectorAll('td a'), function (link, i) {
    link.addEventListener('click', gotClicked.bind(null, link, i));
});

它会查找a元素后代的所有td元素,其中包含querySelectorAll

document.querySelectorAll('td a')

由于返回的列表不是数组,我使用Array.from将其转换为一个以便更容易循环:

Array.from(  )

以上返回我要访问的每个元素的数组。有很多方法可以做到这一点,但在这里我选择Array.from并使用可以提供给它的回调函数:为第一个参数中的每个元素调用回调。

在每次调用时,下一个数组元素作为第一个参数传递给它,序列号(数组索引)作为第二个参数传递给它:

function (link, i) {   }

在函数中,我在元素(a元素)上调用addEventListener来收听click事件:

link.addEventListener('click',   );

这确实与onclick属性类似。传递给它的第二个参数必须是每当点击此特定a元素时将被调用的函数。为此,我引用了您的gotClicked函数。但是,由于我想传递一些参数,我使用bind

gotClicked.bind(null, link, i)

bind的第一个参数是this应该在gotClicked内的任何内容。由于我不在乎,我通过null。但我确实关心传递给gotClicked的真实参数:link(点击的元素)和i(该元素的索引)。请注意bind不会调用该函数,它只是创建一个对函数的引用,该函数已经指定一旦被调用将作为参数传递的内容。

答案 1 :(得分:0)

您可以创建所有可能的获胜组合的数组;创建一个数组来存储点击元素id的数字;将click事件附加到p循环中的每个for..of元素;使用Array.prototype.some()Array.prototype.every()Array.prototype.indexOf()检查包含id的点击元素数字部分的数组中的每个元素是否在包含一组可能的获胜组合和元素{的数组中{1}}等于.innerHTML;利用"x"为最后setTimeout()时间留出时间,然后将"x"元素<p>重置为.innerHTML,设置包含{{{}的点击元素数字部分的数组1}}到<a href='#'>N/A</a> id

0