简体   繁体   English

JavaScript TicTacToe if... 获胜者检测

[英]JavaScript TicTacToe if… Winner detection

I just have a small problem.我只是有一个小问题。

The final assignment in my computer science class is to write a game of Tic-Tac-Toe in JavaScript.我的计算机科学课的最后一个任务是用 JavaScript 编写一个井字游戏。 The game works by clicking on cells within a table and using a function() to switch the img source (a blank image until clicked on) to an X or an O. It's just about done, but there's one thing I can't get.游戏的工作原理是点击表格中的单元格并使用 function() 将 img 源(点击之前的空白图像)切换为 X 或 O。它即将完成,但有一件事情我无法理解.

The game is played, obviously, by two players.显然,这场比赛是由两名球员进行的。 The last thing I need is to get it (a function) to detect when a player wins and kill the script when this happens.我需要做的最后一件事是让它(一个函数)来检测玩家何时获胜并在发生这种情况时杀死脚本。 I just can't figure this out.我就是想不通。 I know it involves if statements, and I've attempted several different codes, but everything I code just breaks the game.我知道它涉及 if 语句,并且我尝试了几种不同的代码,但是我编写的所有代码都破坏了游戏。

I do see that this question has been asked before, and I've tried clicking on several links in the 'similar questions' box to the right, but all of them are in languages I haven't learned anything about (such as C#).我确实看到以前有人问过这个问题,我已经尝试点击右侧“类似问题”框中的几个链接,但所有这些都是我没有学到任何东西的语言(例如 C#) .

Here is my script:这是我的脚本:

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

This is the table that the game takes place in, if it helps:如果有帮助,这是进行游戏的表:

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

The assignment is due tomorrow, and all I need is this last little bit of code.任务是明天到期,我需要的只是这最后一点代码。

Any help is greatly appreciated.任何帮助是极大的赞赏。 This is my last assignment of the semester.这是我本学期的最后一个作业。

Thanks,谢谢,

Kyle凯尔

EDIT: After some suggestions, here is what I've been trying.编辑:经过一些建议,这就是我一直在尝试的。 Entering this code will not allow the game to be played.输入此代码将不允许玩游戏。 If it's just a matter of missing semicolons, please forgive me.如果这只是缺少分号的问题,请原谅我。 It involves setting the img source in each cell to a variable, and checking to see if those variables match.它涉及将每个单元格中的 img 源设置为一个变量,并检查这些变量是否匹配。

There are 9 variables I created, one for each cell/X or O image:我创建了 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;

This is at the very end of the first script:这是在第一个脚本的最后:

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

This obviously only detects a win for the first row.这显然只检测到第一行的胜利。 If I can get this to work, I'll know what the rest of the code will have to be.如果我能让它工作,我就会知道剩下的代码是什么。 I still don't know how to kill the script, though.不过,我仍然不知道如何杀死脚本。

Edited to remove some unnecessary remarks and grammatical errors.编辑删除了一些不必要的注释和语法错误。

I write from begining code where you can check my version of checking who win game.我从代码开始编写,您可以在其中检查我的检查谁赢得比赛的版本。 Dont downvote if my version of game is another than you.如果我的游戏版本与您不同,请不要投票。 I just want to show you how you can write code without knowledge of any algorithm.我只想向您展示如何在不了解任何算法的情况下编写代码。

You just need motivation.你只需要动力。 Don't give up next time so fast.下次别这么快放弃。

jsFiddle js小提琴

My version for checking who win:我用于检查谁获胜的版本:

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

I see you said you have searched Stack Overflow for similar questions.我看到你说你已经在 Stack Overflow 上搜索过类似的问题。 I understand how being new to programming, it's not easy to read something in another language but the fundamental idea is there.我理解编程的新手,阅读另一种语言的东西并不容易,但基本思想就在那里。 Here is a link where this is already done: Algorithm for Determining Tic Tac Toe Game Over .这是一个已经完成的链接: Algorithm for Determining Tic Tac Toe Game Over

That being said, there are basically 3 ways to win in the game, and you are headed in the right direction with your vars.话虽如此,基本上有 3 种方法可以在游戏中获胜,而您的 vars 正朝着正确的方向前进。

The three ways to win are获胜的三种方式是

  1. 3 matches across 3场比赛
  2. 3 matches down 3场比赛下来
  3. 3 matches diagonal. 3 匹配对角线。

The easy parts are the rows and columns, simply for loop through each row/column and see if you get three matches, if you do, then you can declare a winner.简单的部分是行和列,只需循环遍历每一行/列,看看是否有三场比赛,如果有,那么你就可以宣布获胜者。

Non-efficient Pseudo-code Example:非高效伪代码示例:

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

Repeat for row 2, and row 3.重复第 2 行和第 3 行。

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

Repeat for column 2 and 3.重复第 2 列和第 3 列。

The diagonal can be done in a simple fashion as well, without using the two dimensional array in the example.对角线也可以以简单的方式完成,而无需使用示例中的二维数组。 There are basically only two diagonal win possibilities:基本上只有两种对角线获胜的可能性:

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

Anything else you can end the game in a draw.任何其他事情都可以以平局结束游戏。 I would recommend using the counter as shown in the link example.我建议使用链接示例中所示的计数器。

Good luck!祝你好运! -- edit for clarity -- -- 为清楚起见进行编辑 --

I can't in good faith give you the answer to this, but I can walk you through one way of thinking about this problem;我不能真诚地给你答案,但我可以引导你通过一种方式来思考这个问题; by no means is it the best solution, but it could get you at least a start.这绝不是最好的解决方案,但它至少可以让您开始。

To detect a winner, it must be true that one of the following holds:要检测获胜者,必须满足以下条件之一

  1. All three cells in any row are the same任何一行中的所有三个单元格都相同
  2. All three cells in any column are the same任何列中的所有三个单元格都相同
  3. All three cells traversing the board diagonally are the same.沿对角线穿过棋盘的所有三个单元格都是相同的。

Fortunately, you can loop over your table elements to make this check easily.幸运的是,您可以遍历表格元素以轻松进行此检查。

The if statement you provided is flawed.您提供的if语句有缺陷。 You do not need to precede your variables with var after you have declared them already.在你已经声明变量之后,你不需要在变量之前加上var Additionally, your use of && is wrong.此外,您对&&的使用是错误的。 What this will do is check to see if the left statement is true, which in this case is var pic1 == var pic2 , then checks if the right statement is also true, which is simply var pic3 .这将做的是检查左边的语句是否为真,在这种情况下是var pic1 == var pic2 ,然后检查右边的语句是否也为真,这就是var pic3 By itself, this is not a good statement, since it will be automatically cast to Javascript's best interpretation of a boolean, which in this case is true as long as pic3 is defined .就其本身而言,这不是一个好的声明,因为它会自动转换为 Javascript 对布尔值的最佳解释,在这种情况下,只要定义了 pic3 就true Instead, you will need something like if(pic1 == pic2 && pic2 == pic3) , but I would use something besides comparing the images, which is what you're doing.相反,您将需要if(pic1 == pic2 && pic2 == pic3)东西,但除了比较图像之外,我还会使用其他东西,这就是您正在做的事情。 You could change the class of each cell to "X" or "O" depending on which piece goes there, which would be a little more elegant.您可以将每个单元格的类更改为“X”或“O”,具体取决于哪个部分放在那里,这样会更优雅一些。

Class names can be accessed via the .className call:可以通过.className调用访问类名:

<div id="foo" class="bar"></div>

<script>
    document.getElementById("foo").className; //returns "bar"
</script>

Here is a more in-depth description of how to change an element's class. 这里更深入地描述了如何更改元素的类。

My version, but it lacks the tie game check:我的版本,但它缺少平局游戏检查:

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

Assume 'squares' is a Array of Arrays of square size with 0 for not filled , 1 for player 1 (x) and -1 for the other player (O).假设 'squares' 是一个正方形大小的数组,其中 0 表示未填充,1 表示玩家 1 (x),-1 表示其他玩家 (O)。

eg例如

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

would be the staring board.将是凝视板。

The following works for board size 1,2,3,4... where for a board of size n , n consecutive x 's or o 's need to be in a row , column or diagonal .以下适用于大小为1,2,3,4...的棋盘,其中对于大小为n的棋盘, n个连续的xo需要在行对角线上

Returns 0 if nobody won yet and 1 for player 1 and -1 for the other player.返回0 ,如果没有人赢了但和1玩家1-1为其他球员。

First defining two helper functions to make the code more readable.首先定义两个辅助函数,使代码更具可读性。

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

A few more optimizations.还有一些优化。

  1. Add mechanism to identify which "lines" on a board can never be winning because they contain at least 1 of both players' pieces.添加机制以识别棋盘上的哪些“线”永远不会获胜,因为它们至少包含两个玩家的棋子之一。 These are cached to prevent future checks of that line and improve speed.这些被缓存以防止将来检查该行并提高速度。
  2. Ignore expensive win check if there are not enough pieces for a win to be possible (while following the rules).如果没有足够的棋子可以获胜,则忽略昂贵的获胜检查(遵守规则)。 For example, the soonest a player could win on a 3x3 board is when marking the 5th square.例如,玩家在 3x3 棋盘上获胜的最快时间是标记第 5 个方格。

Depending on which way you prefer the board to be represented.取决于您更喜欢以哪种方式代表董事会。

I've coded a Tic-Tac-Toe game (in React ), and chose a flat array , because I believe it is easier to work with (also in other aspects of the game)我编写了一个Tic-Tac-Toe游戏(在React 中),并选择了一个flat array ,因为我相信它更容易使用(也在游戏的其他方面)

I've authored my win-detection code in a manner where all possible winning positions are pre-defined , and the Array representing the game board is converted into an array of two strings (one per player), so each of the strings has the cells indices of which this particular player had selected.我以预先定义所有可能获胜位置的方式编写了我的获胜检测代码,并且将表示游戏板的数组转换为两个字符串的数组(每个玩家一个),因此每个字符串都有该特定玩家选择的单元格索引。

 /** * * @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) ))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM