Reputation: 1
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 class="tile" onclick="tileclick('tl',0,0)" id="tl">*</td>
<td class="tile" onclick="tileclick('tc',0,1)" id="tc">*</td>
<td class="tile" onclick="tileclick('tr',0,2)" id="tr">*</td>
</tr>
<tr id="middlerow">
<td class="tile" onclick="tileclick('cl',1,0)" id="cl">*</td>
<td class="tile" onclick="tileclick('cc',1,1)" id="cc">*</td>
<td class="tile" onclick="tileclick('cr',1,2)" id="cr">*</td>
</tr>
<tr id="bottomrow">
<td class="tile" onclick="tileclick('bl',2,0)" id="bl">*</td>
<td class="tile" onclick="tileclick('bc',2,1)" id="bc">*</td>
<td class="tile" onclick="tileclick('br',2,2)" id="br">*</td>
</tr>
<h3 id="turndisplay">current team is: X</h3>
Upvotes: 0
Views: 812
Reputation: 350272
Some comments on your code:
x
, y
and tile
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.teamcross
and teamcircle
, just define one variable for both: teams = "XO"
and then you can use currentteam-1
as an index in that string.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 on currentteam
.</table>
tag.td
elements an id
attribute: they are not used, and if needed you can always address then with their sequence number -- either in JavaScript or CSS.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.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 class="tile">*</td>
<td class="tile">*</td>
<td class="tile">*</td>
</tr>
<tr>
<td class="tile">*</td>
<td class="tile">*</td>
<td class="tile">*</td>
</tr>
<tr>
<td class="tile">*</td>
<td class="tile">*</td>
<td class="tile">*</td>
</tr>
</table> <!-- close the table tag! -->
<h3 id="turndisplay">current team is: X</h3>
([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.Upvotes: 1
Reputation: 1
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
}
Upvotes: 0