Skip to content

Instantly share code, notes, and snippets.

@njsubedi
Created May 30, 2013 07:14
Show Gist options
  • Save njsubedi/5676199 to your computer and use it in GitHub Desktop.
Save njsubedi/5676199 to your computer and use it in GitHub Desktop.
This is a simple Two-player TicTacToe game developed by me using HTML and JS in one night. I could have used X and O instead of colors but I tried to make it different, hence made it worse. Anyways, it would give an idea to do similar stuff using HTML and Javascript.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="author" content="Nj Subedi" />
<meta name="http-equiv" content="charset: utf-8" />
<meta name="description" content="Tic Tac Toe game developed using HTML and Javascript. Simple- commented and uncompressed." />
<meta name="generator" content="Bluefish Editor (Ubuntu OS, Version 12.04 LTS)" />
<title>Tic Tac Toe - HTML and Javascript</title>
<style type="text/css"><!--
body{margin: 0; padding: 0; border: 0;}
td,th{background-color: #FFF;width: 20px; height: 20px;margin:0; padding: 3px;}
em{background-color: #333333; padding: 0 5px; margin: 0 5px; color: #FFF}
input[type=text]{border: 1px solid #CCC; padding: 3px 5px;}
input[type=checkbox]{
cursor: pointer; opacity: 0.01; filter: alpha(opacity=1);
-ms-transform: scale(2); /* For IE */
-moz-transform: scale(2); /* For Firefox */
-webkit-transform: scale(2); /* For Safari and Chrome */
-o-transform: scale(2); /* For Opera */
}
.infoboxeach{overflow: hidden; font-size: 9pt; border-top: 1px solid #FFF; border-bottom: 1px solid #CCC; margin: 10px 0;}
--></style>
<script type="text/javascript">
// put all the javascript code within same block ( for variable scope - see details online )
{
// declare variables before using them ( pColor1 = Color for player1 | pColor2 = Color for player2 ...)
var pColor1, pColor2, pName1, pName2, turn;
// we have 9 boxes: <td id="box1"> ... <td id="box4"> ...
// each box has id="box"+number attribute, starting from 1, ending in 9
// The condition for game to be won/end is if one of the following:
// [1,2,3], [4,5,6], [7,8,9], [1,4,7], [2,5,8], [3,6,9], [1,5,9], [3,5,7]
// is marked by same user... To hack the array index beginning with zero,
// addded one [0] before each box's condition, and [0,0,0,0] in the array of boxes
//
// boxes is multidimensional array, containing conditions for game winning
// draw a tic tac toe on paper, mark each boxes as box1, box2, etc.. and see
// how the game can be won.. (see above)
boxes = [
[0,0,0,0],[0,1,2,3], [0,4,5,6],
[0,7,8,9],[0,1,4,7],[0,2,5,8],
[0,3,6,9],[0,1,5,9],[0,3,5,7]
];
// this is to avoid writing document.getElementById() everywhere
// this function returns the return value of that function, hence
// dgi('some-id') will work as document.getElementById('some-id')
function dgi( a ){
return document.getElementById(a);
}
// takes player (int) and color (string)
// checks if the colors of both players match - if yes, show warning and disable the 'start game' button
// else set the colors for players.
function setPlayerColor( player, color ){
dgi('errBox').innerHTML = '';
dgi('startButton').disabled = false;
switch(player){
case 1: // for player 1
if( color == pColor2 ){ // check if the color chosen matches with color of player 2
dgi('errBox').innerHTML = 'Two players cannot have the same name!';
dgi('startButton').disabled = true;
return false;
}
// set the color
pColor1 = color;
return true;
break;
case 2:
if( color == pColor1 ){ // check if the color chosen matches with color of player 1
dgi('errBox').innerHTML = 'Two players cannot have the same color!';
dgi('startButton').disabled = true;
return false;
}
// set the color
pColor2 = color;
return true;
break;
}
// p1Color is the color shown in the right-side table while the game is being played,
// set the background color of the table data to the respective colors chosen
dgi('p1Color').style.backgroundColor = pColor1;
dgi('p2Color').style.backgroundColor = pColor2;
}
// works exactly as the setPlayerColor() function
function setPlayerName( player, name ){
dgi('errBox').innerHTML = '';
dgi('startButton').disabled = false;
switch(player){
case 1:
if( name == pName2 ){
dgi('errBox').innerHTML = 'Two players cannot have the same name!';
dgi('startButton').disabled = true;
return false;
}
pName1 = name;
return true;
break;
case 2:
if( name == pName1 ){
dgi('errBox').innerHTML = 'Two players cannot have the same color!';
dgi('startButton').disabled = true;
return false;
}
pName2 = name;
return true;
break;
}
dgi('p1Name').innerHTML = name;
dgi('p2Name').innerHTML = name;
}
// the main logic of the game... takes the input checkbox that was clicked
// and then checks whose turn it was... updates the information being showed
// and then checks if any one of the user has won the game or not...
// finally it checks if all the fields are selected or not...
function checkThis( target ){
// from the checkbox, find the <td> which happens to be the parent of chosen checkbox
ourTarget = target.parentNode;
if( turn == 1 ){
turn = 2; // shift the turn
target.value = 1; // target means 'checkbox' that was clicked, hence make it's value = 1 (ie. player1)
dgi('playerTurn').innerHTML = pName2 + ' Playing...';
ourTarget.style.backgroundColor = pColor1;
checkWinner(1);
}
else if( turn == 2 ){
turn = 1;
target.value = 2; // same as above, if turn was of player 2, set the checkbox's value = 2
dgi('playerTurn').innerHTML = pName1 +' Playing...';
ourTarget.style.backgroundColor = pColor2;
checkWinner(2);
}
// lets check if the match has been draw (if all fields are checked but no one is winner)
allFieldsChecked();
}
// checks if the player has won the game or not.
// using the 'turn (int)' as parameter, finds the value of checkboxes, named 'inp1', 'inp2', etc..
// Assume, if first row was all selected by player1, value of inp1, inp2 and inp3 would be 1
// traversing the multidimensional array of game winning condition above, it checks
// whether one player has selected all the three boxes (any one of the 8 possible combinations: horizontal, vertical and diagonal)
// first loop: traverses through the 8 conditions... setting score = 0
// second loop: traverses through 3 boxes in serial, incrementing score by 1
// in case the score reaches 3, the player had satisfied one of the conditions for game winning
// if one of the boxes has not been selected, score will be set back to 0, and will check for another combination
function checkWinner(turn){
for( eachCase = 1; eachCase <= 8; eachCase++ ){
score = 0;
for( eachBox = 1; eachBox <= 3; eachBox++ ){
// boxToCheck will take values from boxes[][] array
boxToCheck = boxes[eachCase][eachBox];
// if turn was of player 1, value of turn will be 1, hence check if the target box has value = 1 or not.
// same in case turn was of 2nd player... see if the boxes had value 2, serially 3 times
if( dgi('inp' + boxToCheck ).value == turn ){
score++;
}
// could have used ( score == 3 ) but javascript's floating point approximation needs to be hacked
// see details about floating point approximation of javascript
// using ( score > 2 ) works perfect, anyways.
if( score > 2 ){
// if three boxes are serially checked, re-traverse those boxes
// and mark them by green borders
for( eachBox = 1; eachBox <= 3; eachBox++ ){
boxToCheck = boxes[eachCase][eachBox];
dgi('box' + boxToCheck).style.border = '2px solid #0C0';
}
// set pName = player (turn)'s name
if( turn == 1){
pName = pName1;
}
else if( turn == 2){
pName = pName2;
}
// save game report to the 'Game Records' section
saveGame(pName);
// ask if the user wants to play with same names again..
// if yes, let the turn of 2nd player come first this time, by swapping their turns
// and start the game again,
// if they want to reset, reset the game
if( confirm(pName + " wins the game!\n\nRe-play between same players?\n\n[Ok] Play Again\t[Cancel] Reset Game") == true ){
swapValues();
startGame();
return;
}
else{
resetGame();
return;
}
return;
}
}
}
}
// checks if all the fields are checked or not
// going from inp1 to inp9.. if any of them is not checked (ie. checked = false means not selected) it returns false
// if all of them are checked, the parser goes beyond the for-loop
function allFieldsChecked(){
allChecked = true;
for( i = 1; i <= 9; i++ ){
if( dgi('inp' + i).checked == false ){
allChecked = false;
}
}
// in case all the boxes are already checked
if( allChecked == true ){
// save the game with blank string argument (this string denotes the winner's name - see the function)
saveGame('');
// again, ak as above (winning condition)... rematch or re-set?
if( confirm("\tThe game ends in draw!\n\nRe-play between same players?\n\n[Ok] Play Again\t[Cancel] Reset Game") == true ){
swapValues();
startGame();
return;
}
else{
resetGame();
return;
}
}
}
// Saves the game...
// takes ' winner (string) as parameter
// if winner's name is empty, assumes game ended in draw
// else winner's name will be displayed as 'Winner : winner'
function saveGame(winner){
dgi('infobox').innerHTML += '<div class="infoboxeach">';
dgi('infobox').innerHTML += '<em>' + pName1 + '</em> vs <em>' + pName2 + '</em>';
if( winner == '' ){
dgi('infobox').innerHTML += '<center>Game ended in draw.</center>';
}
else{
dgi('infobox').innerHTML += '<center>Winner: <b>' + winner + '</b></center>';
}
dgi('infobox').innerHTML += '</div>';
// after adding a new game record, make sure the div is properly scrolled
// (like in chatbox or shoutbox)
dgi('infobox').scrollTop = dgi('infobox').scrollHeight;
}
// starts the game
// it actually sets the color and name values, unchecks all the checked boxes
function startGame(){
dgi('playground').style.display = 'block';
dgi('playoptions').style.display = 'none';
dgi('p1Name').innerHTML = dgi('p1NameInput').value;
dgi('p2Name').innerHTML = dgi('p2NameInput').value;
dgi('playerTurn').innerHTML = pName1 + ' \'s First Move';
dgi('p1Color').style.backgroundColor = dgi('p1ColorInput').value;
dgi('p2Color').style.backgroundColor = dgi('p2ColorInput').value;
for( i = 1; i <= 9; i++){
dgi('box' + i).style.backgroundColor = '#FFF';
dgi('inp' + i).value = '';
dgi('inp' + i).disabled = false;
dgi('inp' + i).checked = false;
dgi('box' + i).style.border = '1px solid #999';
}
dgi('box1').style.borderLeft = dgi('box1').style.borderTop = dgi('box2').style.borderTop =
dgi('box3').style.borderTop = dgi('box3').style.borderRight = dgi('box4').style.borderLeft =
dgi('box3').style.borderTop = dgi('box6').style.borderRight = dgi('box7').style.borderLeft =
dgi('box7').style.borderBottom = dgi('box8').style.borderBottom = dgi('box9').style.borderBottom =
dgi('box9').style.borderRight = 'none';
turn = 1;
}
// resets the game
// this function is called as soon as the page is loaded.
// it sets all the un-initialized variables with default values
function resetGame(){
pColor0 = '#FFF';
pColor1 = '#CCCCFF';
pColor2 = '#CCFFCC';
pName1 = 'Player One';
pName2 = 'Player Two';
turn = 0;
dgi('playground').style.display = 'none';
dgi('playoptions').style.display = 'block';
for( i = 1; i <= 9; i++){
dgi('box' + i).style.backgroundColor = '#FFF';
dgi('inp' + i).value = '';
dgi('inp' + i).disabled = false;
dgi('inp' + i).checked = false;
dgi('box' + i).style.border = '1px solid #CCC';
}
}
// swaps the values of players' names and colors
// uses simple trick: [ dummyVariable c = a, a = b, b = c ] technique of swapping
function swapValues(){
a = dgi('p1NameInput').value;
pName1 = dgi('p1NameInput').value = dgi('p2NameInput').value;
pName2 = dgi('p2NameInput').value = a;
a = dgi('p1ColorInput').value;
pColor1 = dgi('p1ColorInput').value = dgi('p2ColorInput').value;
pColor2 = dgi('p2ColorInput').value = a;
}
// clears the record by replacing the 'Game records' div with nothing but a header and a button
function clearRecords(){
dgi('infobox').innerHTML = '<h2>Game Records</h2><button onClick="clearRecords();">Clear Records</button>';
}
}
</script>
</head>
<body>
<div style="background-color: #F5F5F5; margin: 50px 0 0 300px; border-radius: 10px; width: 480px; padding: 10px; overflow: hidden;">
<h1 style="border-bottom: 1px solid #CCC">Tic Tac Toe</h1>
<!-- initially hidden, shown when game starts -->
<div id="playground" style="overflow: hidden; display: none; clear: both; margin: 30px 0;">
<h3 id="playerTurn"></h3>
<table class="checkboxTable" style="float: left;" cellspacing="0" cellpadding="0" border="0">
<tr>
<td id="box1"><input type="checkbox" id="inp1" onclick="this.disabled=true; checkThis(this);" /></td>
<td id="box2"><input type="checkbox" id="inp2" onclick="this.disabled=true; checkThis(this);" /></td>
<td id="box3"><input type="checkbox" id="inp3" onclick="this.disabled=true; checkThis(this);" /></td>
</tr>
<tr>
<td id="box4"><input type="checkbox" id="inp4" onclick="this.disabled=true; checkThis(this);" /></td>
<td id="box5"><input type="checkbox" id="inp5" onclick="this.disabled=true; checkThis(this);" /></td>
<td id="box6"><input type="checkbox" id="inp6" onclick="this.disabled=true; checkThis(this);" /></td>
</tr>
<tr>
<td id="box7"><input type="checkbox" id="inp7" onclick="this.disabled=true; checkThis(this);" /></td>
<td id="box8"><input type="checkbox" id="inp8" onclick="this.disabled=true; checkThis(this);" /></td>
<td id="box9"><input type="checkbox" id="inp9" onclick="this.disabled=true; checkThis(this);" /></td>
</tr>
</table>
<table style="float: right; width: 300px; border: 1px solid #CCC;">
<tr>
<th width="20px">No.</th><th>Player's Name</th><th>Color</th>
</tr>
<tr>
<td>1.</td><td id="p1Name"></td><td id="p1Color"></td>
</tr>
<tr>
<td>2.</td><td id="p2Name"></td><td id="p2Color"></td>
</tr>
</table>
<div style="clear:both; margin: 20px 0; float: right;">
<button onClick="resetGame();">Restart Game</button>
</div>
</div>
<!-- initially shown, hidden after game is started -->
<div id="playoptions" style=" margin: 30px 0;">
<h4>Choose your name and color to play with</h4>
<p>
Player-1
<input type="text" id="p1NameInput" value="Player One" onClick="this.select()" onChange="setPlayerName(1, this.value)" />
<select id="p1ColorInput" onChange="setPlayerColor(1, this.value);">
<option value="#CCCCFF" selected="selected">Light Blue</option>
<option value="#FF9900">Orange</option>
<option value="#FFCCCC">Light Red</option>
<option value="#660000">Brown</option>
<option value="#99CCFF">Sky Blue</option>
<option value="#CCFFCC">Light Green</option>
<option value="#FFCCFF">Pink</option>
</select>
</p>
<p>
Player-2
<input type="text" id="p2NameInput" value="Player Two" onClick="this.select()" onChange="setPlayerName(2, this.value)" />
<select id="p2ColorInput" onChange="setPlayerColor(2, this.value)">
<option value="#FFCCCC">Light Red</option>
<option value="#CCCCFF">Light Blue</option>
<option value="#FF9900">Orange</option>
<option value="#660000">Brown</option>
<option value="#99CCFF">Sky Blue</option>
<option value="#CCFFCC" selected="selected">Light Green</option>
<option value="#FFCCFF">Pink</option>
</select>
</p>
<p id="errBox" style="color: red;">
</p>
<p>
<button id="startButton" onClick="startGame()">Start Game</button>
<button id="swapButton" onClick="swapValues()">Swap Players</button>
</p>
</div>
<div id="infobox" style="position: absolute; width: 240px; top: 0; left: 0; height: 400px; overflow: auto; background-color: #F5F5F5;">
<h2>Game Records</h2><button onClick="clearRecords();">Clear Records</button>
</div>
<div style="clear: both; width: 100%; position: absolute; bottom: 20px; left: 0; text-align: center;">
<a href="http://njs.com.np/tictactoe.html">Tic Tac Toe - HTML and Javascript</a> | Free to use, modify and share for any purpose. January 30, 2013
</div>
<script type="text/javascript">
// actually, initializes the game with default values
resetGame();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment