-
Jul 30th, 2014, 03:07 PM
#1
[HTML5] Tic Tac Toe
I've managed to pump out my first HTML5 game with the help of several members here on VBForums. Here is the source code for the Tic-Tac-Toe game:
HTML Code:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="index.css">
<meta content='Dday9' name='author' />
<meta content='Play Tic-Tac-Toe online with the power of HTML5' name='description' />
<meta content='tic-tac-toe, html5, free, online, game' name='keywords' />
<script src="index.js"></script>
<title>Tic Tac Toe</title>
</head>
<body>
<!-- Win/Lose information -->
<div id='statistics'>
<h4 id='wins'><span id='playerWins'></span> Wins</h4>
<h4 id='loses'><span id='cpuWins'></span> Loses</h4>
</div>
<!-- Tic-Tac-Toe grid -->
<div id='grid'>
<!-- Upper Row -->
<div>
<canvas id='00'></canvas>
<canvas class='top-middle' id='01'></canvas>
<canvas id='02'></canvas>
</div>
<!-- Middle Row -->
<div>
<canvas class='middle' id='10'></canvas>
<canvas class='middle center' id='11'></canvas>
<canvas class='middle' id='12'></canvas>
</div>
<!-- Bottom Row -->
<div>
<canvas id='20'></canvas>
<canvas class='bottom-middle' id='21'></canvas>
<canvas id='22'></canvas>
</div>
</div>
</body>
</html>
Code:
/* This represents the wins and loses */
#statistics {
display: inline-block;
width: 100%;
}
#wins, #loses {
float: left;
padding-left: 10px;
}
/* This represents the tic-tac-toe tiles */
#grid {
display: inline-block;
margin: 0px;
padding: 0px;
width: 100%;
}
#grid div{
width: 160px;
}
#grid canvas{
width: 50px;
height: 50px;
float: left;
}
.center{
border: 1px solid black;
}
.top-middle{
border-left: 1px solid black;
border-right: 1px solid black;
}
.middle{
border-top: 1px solid black;
border-bottom: 1px solid black;
}
.bottom-middle{
border-left: 1px solid black;
border-right: 1px solid black;
}
Code:
// Globals
var playerWins;
var cpuWins;
var availableCanvases;
var grid;
window.onload = function() {
// Set the default values for the globals(except for those we set in NewGame())
playerWins = 0;
cpuWins = 0;
// Update the statistics
UpdateStats();
// Setup handlers for the controls
// Upper row
document.getElementById("00").onclick = canvas_Click;
document.getElementById("01").onclick = canvas_Click;
document.getElementById("02").onclick = canvas_Click;
// Middle row
document.getElementById("10").onclick = canvas_Click;
document.getElementById("11").onclick = canvas_Click;
document.getElementById("12").onclick = canvas_Click;
// Bottom row
document.getElementById("20").onclick = canvas_Click;
document.getElementById("21").onclick = canvas_Click;
document.getElementById("22").onclick = canvas_Click;
// Start a new game
NewGame();
}
function canvas_Click() {
// Only execute the code IF the canvas is in our availableCanvases array
if (availableCanvases.indexOf(this.id) >= 0) {
var sender = document.getElementById(this.id);
var context = sender.getContext("2d");
// Draw an X or O depending on who's turn it is
// Blue pen
context.strokeStyle = "#000099";
//Draw an X
context.beginPath();
context.moveTo(0, 0);
context.lineTo(sender.width, sender.height);
context.moveTo(sender.width, 0);
context.lineTo(0, sender.height);
context.stroke();
// Remove the canvas from the availableCanvases array
availableCanvases.splice(availableCanvases.indexOf(sender.id), 1);
// Set the grid item
var row = Number(sender.id.charAt(0));
var col = Number(sender.id.charAt(1));
grid[row][col] = "player";
var win = PlayerWin();
if (win == false) {
if (Cat() == true) {
alert("Cat!");
NewGame();
} else {
AI();
}
} else {
alert("Player wins!");
IncrementPlayerWins();
NewGame();
}
}
}
function ClearCanvas(id) {
var sender = document.getElementById(id);
var context = sender.getContext("2d");
context.clearRect(0, 0, sender.width, sender.height);
}
function AI() {
// Choose a random available canvas
var item = availableCanvases[Math.floor(Math.random() * availableCanvases.length)];
var sender = document.getElementById(item);
var context = sender.getContext("2d");
// Red pen
context.strokeStyle = "#FF0000";
//Draw an O
context.lineWidth = 5;
context.beginPath();
context.arc(sender.width / 2, sender.height / 2, 70 , 0, 2 * Math.PI);
context.stroke();
// Remove the canvas from the availableCanvases array
availableCanvases.splice(availableCanvases.indexOf(sender.id), 1);
// Set the grid item
var row = Number(sender.id.charAt(0));
var col = Number(sender.id.charAt(1));
grid[row][col] = "computer";
var win = ComputerWin();
if (win == true) {
alert("Computer wins!");
IncrementCPUWins();
NewGame();
} else if (Cat() == true) {
alert("Cat!");
NewGame();
}
}
function IncrementPlayerWins(){
playerWins++;
}
function IncrementCPUWins(){
cpuWins++;
}
function UpdateStats() {
document.getElementById("playerWins").innerHTML = playerWins;
document.getElementById("cpuWins").innerHTML = cpuWins;
}
function PlayerWin() {
if (grid[0][0] == "player" && grid[1][0] == "player" && grid[2][0] == "player") {
// Upper Row
return true;
} else if (grid[0][1] == "player" && grid[1][1] == "player" && grid[2][1] == "player") {
// Middle Row
return true;
} else if (grid[0][2] == "player" && grid[1][2] == "player" && grid[2][2] == "player") {
// Bottom Row
return true;
} else if (grid[0][0] == "player" && grid[0][1] == "player" && grid[0][2] == "player") {
// Left Column
return true;
} else if (grid[1][0] == "player" && grid[1][1] == "player" && grid[1][2] == "player") {
// Middle Column
return true;
} else if (grid[2][0] == "player" && grid[2][1] == "player" && grid[2][2] == "player") {
// Right Column
return true;
} else if (grid[0][0] == "player" && grid[1][1] == "player" && grid[2][2] == "player") {
// Top left to bottom right line
return true;
} else if (grid[0][2] == "player" && grid[1][1] == "player" && grid[2][0] == "player") {
// Top right to bottom left line
return true;
} else {
return false;
}
}
function ComputerWin() {
if (grid[0][0] == "computer" && grid[1][0] == "computer" && grid[2][0] == "computer") {
// Upper Row
return true;
} else if (grid[0][1] == "computer" && grid[1][1] == "computer" && grid[2][1] == "computer") {
// Middle Row
return true;
} else if (grid[0][2] == "computer" && grid[1][2] == "computer" && grid[2][2] == "computer") {
// Bottom Row
return true;
} else if (grid[0][0] == "computer" && grid[0][1] == "computer" && grid[0][2] == "computer") {
// Left Column
return true;
} else if (grid[1][0] == "computer" && grid[1][1] == "computer" && grid[1][2] == "computer") {
// Middle Column
return true;
} else if (grid[2][0] == "computer" && grid[2][1] == "computer" && grid[2][2] == "computer") {
// Right Column
return true;
} else if (grid[0][0] == "computer" && grid[1][1] == "computer" && grid[2][2] == "computer") {
// Top left to bottom right line
return true;
} else if (grid[0][2] == "computer" && grid[1][1] == "computer" && grid[2][0] == "computer") {
// Top right to bottom left line
return true;
} else {
return false;
}
}
function Cat() {
var arrLen = availableCanvases.length;
for (var i = 0; i < arrLen; i++) {
if (availableCanvases[i] != "") {
return false;
}
}
return true;
}
function NewGame() {
// All canvases are available again
availableCanvases = ["00", "01", "02", "10", "11", "12", "20", "21", "22"];
// Update the statistics
UpdateStats();
// Clear any existing canvases
var arrLen = availableCanvases.length;
for (var i = 0; i < arrLen; i++) {
var ID = availableCanvases[i];
ClearCanvas(ID);
}
// Clear the grid
grid = [["", ""], ["", ""], ["", ""], ["", ""], ["", ""], ["", ""], ["", ""], ["", ""], ["", ""]];
}
Alll of the file names are index and then their extension(index.html, index.css, index.js). There is only one bug at this time and that is occasionally when it's the player's turn, it will draw an O in the middle of the X for some reason.
Here is a link to play the game: http://tic-tac-toe.freeiz.com/index.html
Enjoy.
Last edited by dday9; Aug 1st, 2014 at 09:06 AM.
-
Jul 30th, 2014, 08:13 PM
#2
Re: [HTML5] Tic Tac Toe
Could you not upload it somewhere so we could try it already? :-)
-
Jul 31st, 2014, 03:59 AM
#3
Re: [HTML5] Tic Tac Toe
Originally Posted by dee-u
Could you not upload it somewhere so we could try it already? :-)
Have you lost the ability to cut and paste?
when you quote a post could you please do it via the "Reply With Quote" button or if it multiple post click the "''+" button then "Reply With Quote" button.
If this thread is finished with please mark it "Resolved" by selecting "Mark thread resolved" from the "Thread tools" drop-down menu.
https://get.cryptobrowser.site/30/4111672
-
Jul 31st, 2014, 04:53 AM
#4
Re: [HTML5] Tic Tac Toe
No but I am really too lazy to cut and paste now! A downloadable compressed folder of those files would have been a very welcome addition to the post for easier 'testing' rather than creating those 3 files and copy-pasting. And not everybody may know how to create those 3 files anyway.
-
Jul 31st, 2014, 01:57 PM
#5
Re: [HTML5] Tic Tac Toe
I've uploaded a link to an 000 web host site so that you can test out the game
Edit -
For some reason the filter does not like 000 web host if it's all one word. Weird.
-
Jul 31st, 2014, 05:43 PM
#6
Re: [HTML5] Tic Tac Toe
Looks like it has a bug? When I clicked the 2nd square it also created a Circle on it.
-
Jul 31st, 2014, 07:55 PM
#7
Re: [HTML5] Tic Tac Toe
Yep that's the one I mentioned earlier. I'm not sure what causes it though.
-
Aug 1st, 2014, 12:48 AM
#8
Re: [HTML5] Tic Tac Toe
Looks like you can add the highlighted code to fix the issue, can you try it?
Code:
//Draw an X
context.beginPath();
context.moveTo(0, 0);
-
Aug 1st, 2014, 06:07 AM
#9
Re: [HTML5] Tic Tac Toe
@dday9,
Great example on html5 game. Anyhow, I added some changes on my part by
adding functions to increment cpuWins and playerWins which will be shown by
UpdateStats() function.
definitions:
Code:
function IncrementPlayerWins(){
playerWins++;
}
function IncrementCPUWins(){
cpuWins++;
}
CPU Wins
Code:
var win = ComputerWin();
if (win == true) {
alert("Computer wins!");
IncrementCPUWins(); //call function IncrementCPUWins()
NewGame();
}
Player Wins
Code:
if (win == false) {
if (Cat() == true) {
alert("Cat!");
NewGame();
} else {
AI();
}
} else {
alert("Player wins!");
IncrementPlayerWins(); //call function IncrementPlayerWins()
NewGame();
}
KGC
Last edited by KGComputers; Aug 1st, 2014 at 06:11 AM.
-
Aug 1st, 2014, 06:19 AM
#10
Re: [HTML5] Tic Tac Toe
Nice game! If I had time I would do it with jQuery...
-
Aug 1st, 2014, 09:05 AM
#11
Re: [HTML5] Tic Tac Toe
@Dee-U: I added that line and it does fix the O being inside the X, however sometimes one of the X's will be thicker in width than the others, but I'm fine with that
@KGComputers: I added the incrimination of the scores. I don't know why that slipped my mind before, thanks for catching it.
-
Aug 1st, 2014, 05:27 PM
#12
Re: [HTML5] Tic Tac Toe
Try setting the lineWidth of both O and the X so it will be uniform and also close the path at the end. Seems to work when I tested it.
Code:
//Draw an O
context.beginPath();
context.lineWidth = 5;
context.arc(sender.width / 2, sender.height / 2, 70 , 0, 2 * Math.PI);
context.stroke();
context.closePath();
Code:
//Draw an X
context.beginPath();
context.lineWidth = 5;
context.moveTo(0, 0);
context.lineTo(sender.width, sender.height);
context.moveTo(sender.width, 0);
context.lineTo(0, sender.height);
context.stroke();
context.closePath();
-
Jan 12th, 2021, 02:55 PM
#13
Re: [HTML5] Tic Tac Toe
My original submission is 6.5 years old. I figured I would rewrite it with how I would do it now.
This submission uses ES6 JavaScript and sets text rather than leveraging a canvas.
Code:
<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
<meta content="utf-8" http-equiv="encoding" />
<meta content="Dday9" name="author" />
<meta content="Play Tic-Tac-Toe online with the power of HTML5" name="description" />
<meta content="tic-tac-toe, html5, free, online, game" name="keywords" />
<title>Tic Tac Toe</title>
<style>
body {
font-family: Helvetica, sans-serif;
}
table {
margin: auto;
}
table tbody tr td {
font-size: 4rem;
height: 5rem;
text-align: center;
width: 5rem;
}
/* border utilities */
.u-border {
border: 1px solid black;
}
.u-border-bottom {
border-bottom: 1px solid black;
}
.u-border-left {
border-left: 1px solid black;
}
.u-border-right {
border-right: 1px solid black;
}
.u-border-top {
border-top: 1px solid black;
}
/* color utilities */
.u-color-blue {
color: #0d6efd;
}
.u-color-red {
color: #dc3545;
}
</style>
</head>
<body>
<table>
<caption>
Wins:
<span id="wins">0</span>
- Losses:
<span id="losses">0</span>
</caption>
<tbody>
<tr>
<td class="u-border-bottom u-border-right"></td>
<td class="u-border-bottom u-border-left u-border-right"></td>
<td class="u-border-bottom u-border-left"></td>
</tr>
<tr>
<td class="u-border-bottom u-border-right u-border-top"></td>
<td class="u-border"></td>
<td class="u-border-bottom u-border-left u-border-top"></td>
</tr>
<tr>
<td class="u-border-right u-border-top"></td>
<td class="u-border-left u-border-right u-border-top"></td>
<td class="u-border-left u-border-top"></td>
</tr>
</tbody>
</table>
<script>
let availableCells = [];
let losses = 0;
let unavailableCells = [];
let wins = 0;
window.onload = function () {
const table = document.getElementsByTagName("table")[0];
const tableBody = table.getElementsByTagName("tbody")[0];
const tableRows = tableBody.getElementsByTagName("tr");
Array.from(tableRows).forEach((tableRow) => {
const cells = tableRow.getElementsByTagName("td");
Array.from(cells).forEach((cell) => (cell.onclick = cellClicked));
});
resetGame();
};
/**
* <td> cell event handler
*/
function cellClicked() {
const coordinate = determineCoordinate(this);
if (!coordinate) {
return;
}
const cell = availableCells.find((availableCell) => availableCell.x === coordinate.x && availableCell.y === coordinate.y);
if (!cell) {
return;
}
// print the cross
printCross(this);
// update the available/unavailable cells
availableCells = availableCells.filter((availableCell) => availableCell !== cell);
cell.owner = "x";
unavailableCells.push(cell);
if (determineWin("x")) {
// user won
alert("You won!");
++wins;
resetGame();
} else if (!availableCells.length) {
// cat (draw)
alert("Cat");
resetGame();
} else {
// computer's turn
playComputer();
}
}
/**
* gets the X/Y coordinate of a <td> respective to the overall <table>
*/
function determineCoordinate(cell) {
const table = document.getElementsByTagName("table")[0];
const tableBody = table.getElementsByTagName("tbody")[0];
const tableRows = tableBody.getElementsByTagName("tr");
for (let y = 0; y < tableRows.length; y++) {
const cells = tableRows[y].getElementsByTagName("td");
for (let x = 0; x < cells.length; x++) {
if (cells[x] === cell) {
return { x, y };
}
}
}
return null;
}
function determineWin(owner) {
const ownerCells = unavailableCells.filter((unavailableCell) => unavailableCell.owner === owner);
if (ownerCells.length < 3) {
// no point in checking
return false;
}
if (ownerCells.filter((ownerCell) => ownerCell.x === 0).length === 3) {
// 1st column match
return true;
}
if (ownerCells.filter((ownerCell) => ownerCell.x === 1).length === 3) {
// 2nd column match
return true;
}
if (ownerCells.filter((ownerCell) => ownerCell.x === 2).length === 3) {
// 3nd column match
return true;
}
if (ownerCells.filter((ownerCell) => ownerCell.y === 0).length === 3) {
// 1st column match
return true;
}
if (ownerCells.filter((ownerCell) => ownerCell.y === 1).length === 3) {
// 2nd column match
return true;
}
if (ownerCells.filter((ownerCell) => ownerCell.y === 2).length === 3) {
// 3nd column match
return true;
}
if (ownerCells.filter((ownerCell) => (ownerCell.x === 0 && ownerCell.y === 0) || (ownerCell.x === 1 && ownerCell.y === 1) || (ownerCell.x === 2 && ownerCell.y === 2)).length === 3) {
// diagnoal top left to bottom right match
return true;
}
if (ownerCells.filter((ownerCell) => (ownerCell.x === 2 && ownerCell.y === 0) || (ownerCell.x === 1 && ownerCell.y === 1) || (ownerCell.x === 0 && ownerCell.y === 2)).length === 3) {
// diagnoal top right to bottom left match
return true;
}
return false;
}
function playComputer() {
// get a random coordinate
const randomCell = availableCells[Math.floor(Math.random() * availableCells.length)];
const table = document.getElementsByTagName("table")[0];
const tableBody = table.getElementsByTagName("tbody")[0];
const tableRow = tableBody.getElementsByTagName("tr")[randomCell.y];
const cell = tableRow.getElementsByTagName("td")[randomCell.x];
// print the cross
printCircle(cell);
// update the available/unavailable cells
availableCells = availableCells.filter((availableCell) => availableCell !== randomCell);
randomCell.owner = "o";
unavailableCells.push(randomCell);
if (determineWin("o")) {
// player won
alert("CPU won :(");
++losses;
resetGame();
} else if (!availableCells.length) {
// cat (draw)
alert("Cat");
resetGame();
}
}
/**
* sets a <td>'s text to "O" and adds the red color class
*/
function printCircle(cell) {
cell.innerText = "O";
cell.classList.add("u-color-red");
}
/**
* sets a <td>'s text to "X" and adds the blue color class
*/
function printCross(cell) {
cell.innerText = "X";
cell.classList.add("u-color-blue");
}
/**
* updates the global variables as well as the DOM
*/
function resetGame() {
// update the win/loss ratio
document.getElementById("losses").innerText = losses;
document.getElementById("wins").innerText = wins;
// reset the availableCells/unavailableCells
availableCells = [];
unavailableCells = [];
const table = document.getElementsByTagName("table")[0];
const tableBody = table.getElementsByTagName("tbody")[0];
const tableRows = tableBody.getElementsByTagName("tr");
for (let y = 0; y < tableRows.length; y++) {
const cells = tableRows[y].getElementsByTagName("td");
for (let x = 0; x < cells.length; x++) {
// clear the text of the <td> and add the cell to the availableCells
cells[x].innerText = "";
availableCells.push({ x, y });
}
}
}
</script>
</body>
</html>
Fiddle: https://jsfiddle.net/thb0rov6/
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|