Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

dday9

Super Moderator
Joined
Mar 25, 2011
Messages
9,563
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:
<!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:

dee-u

Software Carpenter
Joined
Feb 24, 2005
Messages
11,038
Could you not upload it somewhere so we could try it already? :)
 

dee-u

Software Carpenter
Joined
Feb 24, 2005
Messages
11,038
No but I am really too lazy to cut and paste now! :p 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.
 

dday9

Super Moderator
Joined
Mar 25, 2011
Messages
9,563
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.
 

dday9

Super Moderator
Joined
Mar 25, 2011
Messages
9,563
Yep that's the one I mentioned earlier. I'm not sure what causes it though.
 

dee-u

Software Carpenter
Joined
Feb 24, 2005
Messages
11,038
Looks like you can add the highlighted code to fix the issue, can you try it?
Code:
//Draw an X
[HIGHLIGHT]context.beginPath();[/HIGHLIGHT]
context.moveTo(0, 0);
 

KGComputers

New member
Joined
Dec 7, 2005
Messages
1,949
@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!");
  [B]IncrementCPUWins(); [/B]//call function IncrementCPUWins()
  NewGame();
 }

Player Wins
Code:
if (win == false) { 
   
   if (Cat() == true) {
    alert("Cat!");
    NewGame();
   } else {
    AI();
   }
  } else {
   alert("Player wins!");
   [B]IncrementPlayerWins(); [/B]//call function IncrementPlayerWins()
   NewGame();
  }

KGC
 
Last edited:

dday9

Super Moderator
Joined
Mar 25, 2011
Messages
9,563
@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.
 

dee-u

Software Carpenter
Joined
Feb 24, 2005
Messages
11,038
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();
 
Top