【问题标题】:JavaScript TicTacToe if... Winner detectionJavaScript TicTacToe if... 获胜者检测
【发布时间】:2021-05-13 02:00:13
【问题描述】:

我只是有一个小问题。

我的计算机科学课的最后一项任务是用 JavaScript 编写一个井字游戏。游戏通过单击表格中的单元格并使用 function() 将 img 源(单击之前的空白图像)切换到 X 或 O 来工作。它即将完成,但有一件事我无法得到.

这个游戏显然是由两个玩家玩的。我需要做的最后一件事是获取它(一个函数)来检测玩家何时获胜并在发生这种情况时终止脚本。我就是想不通。我知道它涉及 if 语句,并且我尝试了几种不同的代码,但我编写的所有代码都会破坏游戏。

我确实看到以前有人问过这个问题,并且我尝试点击右侧“类似问题”框中的几个链接,但所有这些链接都是我没有学过的语言(例如作为 C#)。

这是我的脚本:

<script type="text/javascript" charset="ISO-8859-1">
function placeMove(value)
{
    if (document.getElementById(value).src.indexOf("FC")!=-1) //"FC" because of the FC contained in the file name. I intended for it to stand for "free cell", for easy indentification.
    {
        var turn = document.getElementById("playerturn").innerHTML;
        if (turn == "X")
        {
            document.getElementById(value).src="../Images/TicTacToeX.jpg";
            document.getElementById("playerturn").innerHTML="O";
        }
        if (turn == "O")
        {
            document.getElementById(value).src="../Images/TicTacToeO.jpg";
            document.getElementById("playerturn").innerHTML="X";
        }
    }
    else
    {
        window.alert("Tile is in use. Please select another tile.");
    }
}
function detectWin()
{

}
</script>

如果有帮助,这是游戏发生的桌子:

<table class="gametable" id="gametable" border="1">
<tr>
    <td><img onclick="placeMove('r1c1')" id="r1c1" class="blank" alt="blank space" src="../Images/TicTacToeFC.jpg"></img></td>
    <td><img onclick="placeMove('r1c2')" id="r1c2" class="blank" alt="blank space" src="../Images/TicTacToeFC.jpg"></img></td>
    <td><img onclick="placeMove('r1c3')" id="r1c3" class="blank" alt="blank space" src="../Images/TicTacToeFC.jpg"></img></td>
</tr> 
<tr>
    <td><img onclick="placeMove('r2c1')" id="r2c1" class="blank" alt="blank space" src="../Images/TicTacToeFC.jpg"></img></td>
    <td><img onclick="placeMove('r2c2')" id="r2c2" class="blank" alt="blank space" src="../Images/TicTacToeFC.jpg"></img></td>
    <td><img onclick="placeMove('r2c3')" id="r2c3" class="blank" alt="blank space" src="../Images/TicTacToeFC.jpg"></img></td>
</tr>
<tr>
    <td><img onclick="placeMove('r3c1')" id="r3c1" class="blank" alt="blank space" src="../Images/TicTacToeFC.jpg"></img></td>
    <td><img onclick="placeMove('r3c2')" id="r3c2" class="blank" alt="blank space" src="../Images/TicTacToeFC.jpg"></img></td>
    <td><img onclick="placeMove('r3c3')" id="r3c3" class="blank" alt="blank space" src="../Images/TicTacToeFC.jpg"></img></td>
</tr>
</table>

明天就要交作业了,我只需要最后一点代码。

非常感谢任何帮助。这是我这个学期的最后一个作业。

谢谢,

凯尔

编辑:经过一些建议,这是我一直在尝试的。输入此代码将无法进行游戏。如果只是缺少分号的问题,请见谅。它涉及将每个单元格中的 img 源设置为一个变量,并检查这些变量是否匹配。

我创建了 9 个变量,每个单元格/X 或 O 图像一个:

var pic1 = document.getElementById("r1c1").src;
var pic2 = document.getElementById("r1c2").src;
var pic3 = document.getElementById("r1c3").src;
var pic4 = document.getElementById("r2c1").src;
var pic5 = document.getElementById("r2c2").src;
var pic6 = document.getElementById("r2c3").src;
var pic7 = document.getElementById("r3c1").src;
var pic8 = document.getElementById("r3c2").src;
var pic9 = document.getElementById("r3c3").src;

这是第一个脚本的最后:

function detectWin()
{
if (var pic1 == var pic2 && var pic3)
{
window.alert("Game won. Please reset the game.");
}
}

这显然只检测到第一行的胜利。如果我能让这个工作,我会知道其余的代码必须是什么。不过,我仍然不知道如何杀死脚本。

编辑删除了一些不必要的注释和语法错误。

【问题讨论】:

  • 如果没有你自己的尝试,这个问题几乎没有潜力。在你尝试过之后,我们可以为你指点;) Stackoverflow 不只是做你的功课
  • 把这些图片放到网上,这样我就可以在我的小提琴中使用jsfiddle.net/4Fjby
  • 您需要在每次移动后调用 js 方法,该方法应该使用您可以计算的 td id 获得 8 个获胜概率。
  • @Jazzy663 不过,我不想打破你的泡沫,但检查谁赢了是这场比赛的主要部分。恐怕你还不到一半。
  • @Joost 不,不是他做了一些工作,他被卡住了,stackoverflow 是为了帮助

标签: javascript


【解决方案1】:

我从头开始编写代码,您可以在其中检查我的版本,检查谁赢了比赛。如果我的游戏版本与您不同,请不要投反对票。我只是想告诉你如何在不了解任何算法的情况下编写代码。

你只需要动力。下次别这么快就放弃了。

jsFiddle

我的检查谁获胜的版本:

var checkResult = function(){
    $("table tr").each(function(i, val){
        $(this).find('td').each(function(j, val2){
            arr[i][j] = parseInt($(this).attr("data-points"));
        });
    });

    for(var i = 0; i<3;i++){
        var rowSum = 0;
        for(var j = 0; j<3;j++){
            rowSum += arr[i][j];
        }
        if(rowSum === 3)
            alert("Circle WIN!");
        else if(rowSum === -3)
            alert("Cross WIN!");
    }

    for(var i = 0; i<3;i++){
        var colSum = 0;
        for(var j = 0; j<3;j++){
            colSum += arr[j][i];
        }
        if(colSum === 3)
            alert("Circle WIN!");
        else if(colSum === -3)
            alert("Cross WIN!");
    }

    if(arr[0][0] + arr[1][1] + arr[2][2] === 3)
        alert("Circle WIN!");
    else if(arr[0][0] + arr[1][1] + arr[2][2] === -3)
        alert("Cross WIN!");

    if(arr[2][0] + arr[1][1] + arr[0][2] === 3)
        alert("Circle WIN!");
    else if(arr[2][0] + arr[1][1] + arr[0][2] === -3)
        alert("Cross WIN!");
};

【讨论】:

  • 我不会考虑否决任何善意的答案,即使它没有意义。很抱歉我们一开始就遇到了敌意,我很抱歉这么快就来到 Stack Overflow。我现在意识到我不应该那样做,但我从来没有打算让别人给我答案。我想这是我的错,没有说出来。您的代码确实与我的想法不同,因此我将使用其他代码,但这并不意味着它没有帮助,所以,谢谢您的帮助。
【解决方案2】:

取决于您喜欢哪种方式来代表董事会。

我编写了一个 Tic-Tac-Toe 游戏(在 React 中),并选择了一个平面数组,因为我相信它更容易使用(也在其他游戏的各个方面)

我编写了我的 win-detection 代码,其中所有可能的获胜位置都是预定义的,并且表示游戏板的数组被转换为两个字符串的数组(每个玩家一个),所以每个字符串都有这个特定玩家选择的单元格索引。

/**
 * 
 * @param {Array} board - flat array representation of the board, 
 * from right to left, top to bottom, Ex.
 * [1,2,2,1,1,2,1,2,1] 
 */
function checkWin(board){
  // all possible winning combinations (of cells filled by the same player)
  const winMap = [123, 456, 789, 147, 258, 369, 357, 159]

  // convert the board to array represening the filled cells, per player.
  // each array item is a string of only the cells (indices) filled by a player
  const moves = board.reduce((players, v, i) => {
    if(v) players[v-1] += i+1
    return players
  }, ['', ''])

// console.log(JSON.stringify(moves))

  // find & return the winning combination
  const winningMove = winMap.find(comb =>
    moves.some(m => // there are only 2 sets of moves, one for each player
      // break down the current combination to array and check if every item exists
      // also in the current set of moves. quit on first match.
      comb.toString().split('').every(c => m.includes(c))
    )
  )

  return winningMove ?
    { // get the first number of the winning-move, 
      // substract 1 from it, and use as index to find which
      // player played that move from the board Array
      player: board[winningMove.toString()[0] - 1],
      move: winningMove
    } 
    : false
}


// sample tests:
[
  [1,1,1,2,2,2],       // player 1 wins, horizontal, row 1
  [1,2,2,1,,,1],       // player 1 wins, vertical, col 1
  [2,1,1,1,2,1,2,1,2], // player 2 wins, diagonal to right
  [1,1,2,1,2,1,2,1,2], // player 2 wins, diagonal to left
  [1,2,1,1,2,1,2,1,2]  // no win
].forEach(board => console.log(
  checkWin(board)
))

【讨论】:

    【解决方案3】:

    我不能真诚地给你答案,但我可以引导你思考这个问题的一种方式;这绝不是最好的解决方案,但它至少可以让你开始。

    要检测获胜者,必须满足以下一个

    1. 任何一行的三个单元格都相同
    2. 任何列中的所有三个单元格都相同
    3. 对角线穿过电路板的所有三个单元格都是相同的。

    幸运的是,您可以遍历表格元素以轻松进行此检查。

    您提供的if 声明存在缺陷。在你已经声明它们之后,你不需要在你的变量前面加上var。此外,您对&amp;&amp; 的使用是错误的。这将检查左语句是否为真,在本例中为var pic1 == var pic2,然后检查右语句是否也为真,即var pic3。就其本身而言,这不是一个好的声明,因为它会自动转换为 Javascript 对布尔值的最佳解释,在本例中为 true只要定义了 pic3。相反,您将需要if(pic1 == pic2 &amp;&amp; pic2 == pic3) 之类的东西,但除了比较图像之外,我还会使用其他东西,这就是您正在做的事情。您可以将每个单元格的类别更改为“X”或“O”,具体取决于那里的哪个部分,这会更优雅一些。

    可以通过.className调用访问类名:

    <div id="foo" class="bar"></div>
    
    <script>
        document.getElementById("foo").className; //returns "bar"
    </script>
    

    Here 更深入地描述了如何更改元素的类。

    【讨论】:

    • 这个回复和另一个基本一样,不过还是谢谢你。
    • 这就是思想相似的程序员的副作用。希望对您有所帮助。
    【解决方案4】:

    我看到你说你已经在 Stack Overflow 上搜索过类似的问题。我了解编程新手,用另一种语言阅读内容并不容易,但基本思想就在那里。这是一个已经完成的链接:Algorithm for Determining Tic Tac Toe Game Over

    话虽如此,在游戏中基本上有 3 种取胜方式,而你的 vars 正朝着正确的方向前进。

    三种取胜方式

    1. 3 场比赛
    2. 3 场比赛失败
    3. 3 匹配对角线。

    简单的部分是行和列,只需 for 循环遍历每一行/列,看看你是否得到三个匹配,如果你得到了,那么你可以宣布获胜。

    非效率伪代码示例:

    if pic1, pic2, and pic3 are the same
    alert user X or O has won
    end the game.
    

    重复第 2 行和第 3 行。

    if pic1, pic4, and pic7 are the same
    alert user X or O has won
    end the game.
    

    对第 2 列和第 3 列重复。

    对角线也可以用简单的方式完成,在示例中不使用二维数组。基本上只有两种对角线获胜的可能性:

    1. var 1、5、9 匹配
    2. var 3、5、7 匹配。

    任何其他你可以以平局结束比赛的事情。我建议使用链接示例中所示的计数器。

    祝你好运! -- 为清楚起见进行编辑 --

    【讨论】:

    • 谢谢。这让我很困惑,但我会完整阅读这篇文章并尝试完成我的脚本。对于没有发布我已经尝试过的内容,我深表歉意。我最初的想法是它只会引起混乱。我在 Stack Overflow 上发布的第一个问题没有任何内容,只是一个脏脚本,我什至不知道如何正确格式化。
    • 啊哈,当我说这令人困惑时,我指的是你链接到的帖子,而不是这个。如果这就是您进行更改的目的,那么为了清晰而进行的编辑并不是真正必要的。如果我发送了错误的信息,我深表歉意。
    【解决方案5】:

    假设 'squares' 是一个正方形数组,其中 0 表示未填充 , 1 代表玩家 1 (x),-1 代表其他玩家 (O)。

    例如

    let squares= Array(3).fill(Array(3).fill(0))
    

    将是注视板。

    以下适用于电路板大小1,2,3,4...,其中对于大小为nn 的电路板连续xo 需要在行中 , 对角线

    如果没有人获胜,则返回 0玩家 1 返回 1,其他玩家返回 -1

    先定义两个辅助函数,让代码更具可读性。

    const add = (a, b) => a + b
    
    function sum(array){  
       return array.reduce(add);
    }
    
    function calculateWinner(squares) {
      // check for horizontal wins along rows and diagonals
      let winner = calculateWinnerInner(squares);
      if (winner !== 0) return winner;
      // check for possible vertical wins as well
      const stranspose = squares.map((col, i) => squares.map(row => row[i]));
      return calculateWinnerInner(stranspose);
    }
     
    function calculateWinnerInner(squares) {
      for (let r = 0; r < squares.length; r++) {
        if (squares[r].length === sum(squares[r])) {
          return 1;
        }
        if (squares[r].length === - sum(squares[r])) {
          return -1;
        }
      }
    
      const diagonal = squares.map((row, r) => squares[r][r]);
    
      if (squares[0].length === sum(diagonal)) {
        return 1;
      }
      if (squares[0].length === -sum(diagonal)) {
        return -1;
      }
      
     const len=squares.length;
     const crossdiagonal = squares.map((row, r) => squares[r][len-r-1]);
    
     if (squares[0].length === sum(crossdiagonal)) {
      return 1;
     }
     if (squares[0].length === -sum(crossdiagonal)) {
      return -1;
     }
    
      return 0;
    }

    【讨论】:

    • 似乎没有必要转置矩阵,因为所有板都是正方形的给定规则。
    • 搜索只检查水平和对角线以及交叉对角线。
    • 我不得不返回代码来验证这一点。 Sum(square(r)) 仅搜索行 r 上的胜利。所以转置检查垂直获胜。仍然需要交叉对角线,因为转置后的对角线仍然是对角线。 (转置不是从上方在板上旋转 90 度,而是围绕对角线的 3D 旋转 - 如果您将对角线想象为某种轴。)。我添加了一些 cmets。
    【解决方案6】:

    我的版本,但缺少平局检查:

    var table = [
        ['', '', ''],
        ['', '', ''],
        ['', '', '']
    ]
    
    function GameIsOver(player) {
        var result = true;
        for (var j = 0; j < 3; j++) {     //first diagonal
            result = result && (table[j][j] == player);
        }
        if (result) {
            return gameResult = {
                result: result,
                player: player
            };
        }
        result = true;
        for (var j = 0; j < 3; j++) {  //second diagonal
            result = result && (table[2 - j][j] == player);
        }
        if (result) {
            return gameResult = {
                result: result,
                player: player
            };
        }
        for (var k = 0; k < 3; k++) {
            result = true;
            for (var j = 0; j < 3; j++) {      //lines 
                result = result && (table[k][j] == player);
            }
            if (result) {
                return gameResult = {
                    result: result,
                    player: player
                };
            }
            result = true;
            for (var j = 0; j < 3; j++) {      //colums
                result = result && (table[j][k] == player);
            }
            if (result) {
                return gameResult = {
                    result: result,
                    player: player
                };
            }
        }
        return false;
    }
    

    【讨论】:

      【解决方案7】:

      更多优化。

      1. 添加机制来识别棋盘上的哪些“线”永远不会获胜,因为它们至少包含两个玩家的棋子之一。这些被缓存以防止将来检查该行并提高速度。
      2. 如果没有足够的棋子可以获胜,则忽略昂贵的获胜检查(同时遵守规则)。例如,玩家最快可以在 3x3 棋盘上获胜是在标记第 5 格时。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-20
        • 1970-01-01
        • 2021-03-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多