Basically, I wrote a simple tic tac toe game. it uses a 2d array to represent the board (0 being empty, 1 being X and 2 being O)
I checked out solutions by other people but they used a whole different way to represent the board
here is the HTML
let board = [
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
];
//the team symbols
let teamcross = "x";
let teamcircle = "o";
//for the tileclick function
let x = 0;
let y = 0;
var tile = "test";
//1 is Team X and 2 is Team O
var currentteam = 1;
//the tileclick function
function tileclick(tile, y, x) {
switch (currentteam) {
case 1:
document.getElementById(tile).innerHTML = "x";
board[y][x] = 1;
console.log(board)
currentteam = 2;
document.getElementById("turndisplay").innerHTML = "current team is: O";
break;
case 2:
document.getElementById(tile).innerHTML = "o"
board[y][x] = 2;
console.log(board)
currentteam = 1;
document.getElementById("turndisplay").innerHTML = "current team is: X";
break;
default:
window.alert("something is broken. Current Team is " currentteam);
break;
}
}
<table id='gameboard'>
<tr id="toprow">
<td onclick="tileclick('tl',0,0)" id="tl">*</td>
<td onclick="tileclick('tc',0,1)" id="tc">*</td>
<td onclick="tileclick('tr',0,2)" id="tr">*</td>
</tr>
<tr id="middlerow">
<td onclick="tileclick('cl',1,0)" id="cl">*</td>
<td onclick="tileclick('cc',1,1)" id="cc">*</td>
<td onclick="tileclick('cr',1,2)" id="cr">*</td>
</tr>
<tr id="bottomrow">
<td onclick="tileclick('bl',2,0)" id="bl">*</td>
<td onclick="tileclick('bc',2,1)" id="bc">*</td>
<td onclick="tileclick('br',2,2)" id="br">*</td>
</tr>
<h3 id="turndisplay">current team is: X</h3>
CodePudding user response:
Some comments on your code:
x
,y
andtile
do not need to be defined as global variables. They are defined as local variables already in your function, and that is already what you need.- Instead of two variables
teamcross
andteamcircle
, just define one variable for both:teams = "XO"
and then you can usecurrentteam-1
as an index in that string. - The "something is broken" case really is not needed: this can never happen.
- Instead of a
switch
statement that has some code repetition, you can apply the logic for the two cases with one block of code, dynamically doing the right thing based oncurrentteam
. - The HTML is missing a closing
</table>
tag. - It is not needed to give the
td
elements anid
attribute: they are not used, and if needed you can always address then with their sequence number -- either in JavaScript or CSS. - Don't define
onclick
attributes, but add one event handler on the table level through JavaScript. That handler can then check which cell triggered the event and act accordingly. - There is no prevention of a user clicking a tile that was already played, replacing the previous move there.
- Besides detecting a win, you also need to detect a draw.
As to the question itself. One of the ways to do this, is to temporarily turn your board into a string (with 9 characters, "0", "1" and "2") and test for a three-in-a-row with a regular expression.
Here is an implementation:
const board = [
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
];
// the team symbols
const teams = "XO";
// 1 is Team X and 2 is Team O
let currentteam = 1;
let gameWon = false;
const output = document.getElementById("turndisplay");
document.getElementById("gameboard").addEventListener("click", function (e) {
const tile = e.target;
// ignore clicks when game is over or the click was not on a tile or it is occupied
if (gameWon || !tile.classList.contains("tile") || !tile.textContent.includes("*")) return;
// derive x and y dynamically -- no need for id attribute
const x = tile.cellIndex;
const y = tile.parentNode.rowIndex;
tile.textContent = teams[currentteam-1];
board[y][x] = currentteam;
// Update the gameWon boolean, using a regex to test the board
gameWon = /([12])(\1\1(...)*$|.\1.\1..$|..\1..\1|...\1...\1)/
.test(board.flat().join(""));
if (gameWon) {
output.textContent = teams[currentteam-1] " has won!";
} else if (!board.flat().includes(0)) { // Test for a draw
output.textContent = "It's a draw";
} else {
currentteam = 3 - currentteam; // toggle between 1 and 2
output.textContent = "current team is: " teams[currentteam-1];
}
});
td { width: 1em }
<table id='gameboard'>
<tr> <!-- no need for id or onclick attributes -->
<td >*</td>
<td >*</td>
<td >*</td>
</tr>
<tr>
<td >*</td>
<td >*</td>
<td >*</td>
</tr>
<tr>
<td >*</td>
<td >*</td>
<td >*</td>
</tr>
</table> <!-- close the table tag! -->
<h3 id="turndisplay">current team is: X</h3>
Explanation of the regex
([12])
this will match the first occurrence of "1" or "2". It is captured in a capture group so that the rest of the regex can reference that character with\1
.\1\1
checks whether that character appears three times in a row(...)*$
checks that a multiple of three characters follow (.
is any character) and then the end of the string ($
). This way we know the three consecutive characters (mentioned in the previous bullet point) are on a single row.|
: separates an alternative.\1.\1
: the character repeats with one intermediate character. This could be a diagonal from top-right to bottom left, provided that we are two characters away from the end of the string:..$
matches two characters and then the end of the string..\1..\1
matches the character reoccurring with 2 intermediate characters, i.e. it is a "vertical" three-in-a-row...\1...\1
matches the character reoccurring with 3 intermediate characters, i.e. it forms a diagonal from top-left to bottom-right.
CodePudding user response:
If you want to represent the tic tac toe as a 2d array, then this is roughly what the function would look like. Consider the different cases for winning a tic tac toe game. A player must have 3 of the same characters adjacent to win. A player can also win diagonally, but only when their character is in the center.
function isGameOver() {
// check upper row
if (board[0][1] == board[0][0] && board[0][1] == board[0][2] && board[0][1] != 0) {
return board[0][1]
}
// check lower row
if (board[2][1] == board[2][0] && board[2][1] == board[2][2] && board[2][1] != 0) {
return board[2][1]
}
// check left column
if (board[1][0] == board[0][0] && board[1][0] == board[2][0] && board[1][0] != 0) {
return board[1][0]
}
// check right column
if (board[1][2] == board[0][2] && board[1][2] == board[2][2] && board[1][2] != 0) {
return board[1][2]
}
// check center row, column, and diagonals
if (
board[1][1] != 0 &&
((board[1][1] == board[1][0] && board[1][1] == board[1][2]) ||
(board[1][1] == board[0][1] && board[1][1] == board[2][1]) ||
(board[1][1] == board[0][0] && board[1][1] == board[2][2]) ||
(board[1][1] == board[2][0] && board[1][1] == board[0][2]))
) {
return board[1][1]
}
return 0
}