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



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

游戏机制今天才刚刚开始,我刚刚开始学习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>

感谢一位贡献者展示我的错误!

一些问题:

  • border-length不是有效的 CSS,它应该border-width
  • 您不是在这个if语句中进行比较,而是

    在分配:
    if (!(id1="s1" ...
    

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

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

    var board = Array(9);
    

    。并在相应的正方形接收到"X"或"O"时在特定数组元素中放置 0 或 1。例如:

    board[0] = 1 
    
  • 通过数组演示,您可以将获胜配置作为该数组中的索引三元组列出。例如,如果索引 0、1 和 2 处的值均为 1,则玩家 1 ('O'( 获胜。所有此类演示文稿可以列出如下:

    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参数。

    函数 gotClicked(link, i, e( { e.preventDefault((; //...等。}

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

这是一个工作片段:

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;
      }
    }
  }
});
table,tr,td{
  border-style:solid;
  border-width:1px;
  text-align: center
}
/* ***Fix the size of the board */
td { width: 30px; height: 30px }
<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>

解释

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

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的第一个论点是gotClicked内部应该this。因为我不在乎这个,所以我通过null.但我确实关心传递给gotClicked的真正参数:link(单击的元素(和i(该元素的索引(。请注意,bind 不会调用函数,它只是创建对函数的引用,该函数已经指定了一旦调用它将作为参数传递的内容。

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

<!DOCTYPE html>
<html>
<head>
  <style>
    table,
    tr,
    td {
      border: 1px solid #000;
    }
  </style>
  <script>
    window.onload = function() {
      var winners = [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
        [1, 5, 9],
        [3, 5, 7],
        [1, 4, 7],
        [2, 5, 8],
        [3, 6, 9]
      ];
      var clicked = [];
      var p = document.querySelectorAll("table td p");
      for (el of p) {
        el.onclick = function() {
          if (this.innerHTML !== "x") {
            this.innerHTML = "x";
            clicked.push(+this.id.match(/d/).pop());
          };
          var win = winners.some(function(winner) {
            return winner.every(function(n) {
              return clicked.indexOf(n) > -1 
                     && document.querySelector("[id$='" + n + "']")
                        .innerHTML === "x"
            })
          });
          setTimeout(function() {
            if (win) {
              alert("winner");
              clicked.length = 0;       
              for (el of p) {
                el.innerHTML = "<a href='#'>N/A</a>"
              }
            }
          }, 1000)
        }
      }
    }
  </script>
</head>
<body>
  <table>
    <tr>
      <td>
        <p id="s1"><a href="#">N/A</a>
        </p>
      </td>
      <td>
        <p id="s2"><a href="#">N/A</a>
        </p>
      </td>
      <td>
        <p id="s3"><a href="#">N/A</a>
        </p>
      </td>
    </tr>
    <tr>
      <td>
        <p id="s4"><a href="#">N/A</a>
        </p>
      </td>
      <td>
        <p id="s5"><a href="#">N/A</a>
        </p>
      </td>
      <td>
        <p id="s6"><a href="#">N/A</a>
        </p>
      </td>
    </tr>
    <tr>
      <td>
        <p id="s7"><a href="#">N/A</a>
        </p>
      </td>
      <td>
        <p id="s8"><a href="#">N/A</a>
        </p>
      </td>
      <td>
        <p id="s9"><a href="#">N/A</a>
        </p>
      </td>
    </tr>
  </table>
</body>
</html>

最新更新