Javascript代码识别所有可能的获胜组合 [英] Javascript code to recognize all possible combinations of winning

查看:53
本文介绍了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;
函数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;
转++;
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< / p>
< / td>

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

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

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

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

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

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



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

解决方案

一些问题:




  • 边框长度无效的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')获胜。所有这些演示文稿都可以列出如下:

     无胜数= [
    [0,1,2],
    [3,4,5],
    [6,7,8],
    [0,3,6],
    [1,4,7],
    [2,5,8],
    [0,4,8],
    [2,4,6]
    ];

    赢钱的支票将是检查棋盘的问题条目可以看到它们包含全部1或全部0(请参见下面的代码段)。


  • 最好不要编写JavaScript HTML onclick 属性中的代码。一方面,它再次导致代码重复,但是当发生错误时,也更难调试。总体而言,最好将代码(JavaScript)与布局(HTML)分开。



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

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

    函数gotClicked(link,i){
    //从 turn值中我们可以知道当前玩家是谁:0或1。
    //我们使用模运算符除以2得到余数:
    var player = turn%2; //在0和1之间切换。
    //使用0或1作为XO字符串中的索引并显示它。
    //玩家为0时会给出 X,而玩家为1时会给出 O:
    link.parentNode.textContent =‘XO’[player];
    //将0或1放入我们的数组
    board [i] =玩家;
    //玩家玩了,所以现在增加 turn。
    转++;
    }

    要执行此操作,应将脚本移动到文档末尾,恰好在结束< / body> 之前。或者,如果您希望将其放在顶部,则将代码包装在:

      document.addEventListener('DOMContentLoaded',function( } {
    //您需要访问文档元素的代码在这里
    });


  • 单击事件处理程序应防止单击启动导航。为此,您可以使用 e.preventDefault(),但是您还必须在函数中获取该 e 参数。



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


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




这里是一个有效的代码段:



  document.addEventListener('DOMContentLoaded',function() {// ***用空单元格初始化板-为此,我们使用-1:var board = [-1,-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));});函数gotClicked(link,i,e){//防止单击链接以启动导航e.preventDefault(); // ***调用函数以执行移动:如果(doMove(i,'You won !!))re转; // ***让AI行动起来。 randomAi(); } // ***执行特定动作的单独函数:可用于//两个播放器函数doMove(i,msg){// ***获取与给定索引var td = document对应的td元素。 querySelectorAll('td')[i]; //从`turn`值中我们可以知道当前玩家是谁:0或1。//当除以2时,我们使用取模运算符得到余数:var player = turn%2; //使用此0或1作为XO字符串中的索引并显示它。 //当播放器为0时,它会给出 X;当播放器为0时,它会给出 O:td.textContent =‘XO'[player]; //也将0或1放入我们的阵列板[i] =播放器; //玩家玩了,所以现在增加 turn。转++; //现在板子已经换了,检查该玩家是否有三合一,// ***并返回该函数的结果,如果(isWinFor(player)){// ***显示适当的消息警报(msg);返回true; //表示游戏结束} // ***如果(turn == 9){alert(这是平局);返回true; //表示游戏结束}} // ***完全修改后的函数randomAi(){// ***在空闲单元格中选择随机数。确保它是整数。 var randomPick = Math.floor(Math.random()*(9-turn)); // ***找出(var i in board){如果(board [i]!== -1)继续; //使用的单元格-如果(randomPick == 0)中断则跳过它; //找到它randomPick--; } // ***执行此AI动作doMove(i,‘您输了’); }函数isWinFor(player){//玩家为0或1。//迭代所有8个潜在的获胜(var wins of wins){//`win`是一个三元组索引,当它们包含玩家的值时//构成获胜位置。让我们计算这三者中有多少//玩家的值(0或1)var count = 0; for(获胜指数){//棋盘上的值是玩家所对应的值吗?如果(board [index]!==玩家)休息; //不要再看了。数++; } //如果此处的计数为3,则为获胜位置。 if(count == 3){//不要尝试其他获胜:一个就足够了:-) // ***删除所有超链接的单元格-不再播放任何动作Array.from(document.querySelectorAll('td a'),函数(链接,i){link.parentNode.innerHTML =''; //删除链接});返回true; }}}});  

  table,tr,td {边框样式:实心; border-width:1px;文本对齐:居中} / * ***固定板子尺寸* / td {width:30px;高度:30像素}  

 < 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 并使用可以提供给它的回调函数:第一个元素中的每个元素都会调用该回调



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

 函数(链接,i){} 

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

  link.addEventListener('click',); 

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

  gotClicked.bind(null,link, i)

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


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!

解决方案

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'), 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++;
    }
    

    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
    });
    

  • The click event handler should prevent the click from initiating a navigation. For that you can use e.preventDefault(), but you must then also get that e argument in your function.

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

  • 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 () {
  // *** 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>

Explanation

In comments you asked about this piece of code:

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

It looks for all a elements that are descendants of td elements with querySelectorAll:

document.querySelectorAll('td a')

As the returned list is not an array, I convert it to one for easier looping, using Array.from:

Array.from(  )

The above returns array that I want to visit each element of. There are many ways to do this, but here I chose Array.from and using the callback function that can be provided to it: that callback is called for each element in the first argument.

At each call the next array element is passed to it as first argument, and a sequence number (the array index) is passed to it as second argument:

function (link, i) {   }

Within the function I call addEventListener on the element (an a element) to listen to the click event:

link.addEventListener('click',   );

This really does something similar as the onclick attribute. The second argument passed to it must be the function that will be called whenever there is a click on this particular a element. For that I reference your gotClicked function. But as I want to pass it some arguments I use bind:

gotClicked.bind(null, link, i)

The first argument of bind is whatever this should be inside gotClicked. As I don't care about that, I pass null. But I do care about the real arguments passed to gotClicked: link (the element clicked) and i (the index of that element). Note that bind does not call the function, it just creates a reference to the function already specifying what will be passed as arguments once it will get called.

这篇关于Javascript代码识别所有可能的获胜组合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆