Tutorial: Craps… A Game of Dice

Hello. In this tutorial post I am going to show you how I made my simplified version of Craps. The purpose of this tutorial is to show the basics of using the HTML5 canvas tag and drawing simple 2D shapes. You can see the game in action on my website.

To start off lets lay out the simple rules so we know what we are trying to accomplish.

The player rolls two dice. The sum of the dice is the only thing that matters. (i.e. 1 and 3 is the same as 2 and 2)

Initial Roll

  • On a roll of 7 or 11 the player wins.
  • On a roll of 2, 3, or 12 the player looses.
  • Any other roll is stored as the players ‘Point’ and a Follow Up Roll is played.

Follow Up Roll

  • On a roll of 7 the player looses
  • On a roll of the players ‘Point’ the player wins.
  • Any other roll is discarded and play continues with another Follow Up Roll.

This is a very simplified version that only takes into account one player. If you want to expand this simple game with the full rules you can check out the wikipedia article for more info.

With the rules in place lets start digging into the code. On the first part we will go over the HTML and CSS that I use. Lastly I’ll go over the Javascript needed to implement the game logic and display the appropriate text when needed.

HTML/CSS

The HTML is pretty basic. We have a series of nested divs to control layout. Here is the full HTML:

<div id="craps_demo_wrapper" class="clearfix">

	<div id="craps_game_canvas_wrapper">
		<div>Your Roll</div>
		<canvas id="craps_game_demo" width="275" height="150"></canvas>
		<div id="craps_roll_button">
			<button type="button" onclick="igz_crapsRollDice();">Roll Dice!</button>
		</div>
		<div id="craps_setbet_button">
			$ <input type="text" id="craps_bet_input" value="10" size="3" /> &nbsp;&nbsp;
			<button type="button" onclick="igz_crapsSetBet();">Set Bet!</button>
		</div>
		<div id="craps_newGame_button">
			<button type="button" onclick="igz_crapsNewGame();">New Game!</button>
		</div>
	</div>
	<div id="craps_demo_infopanel">
		<div>Game Stats</div>
		<div id="craps_current_roll_div">
			<strong>Roll:</strong> <div id="craps_current_roll">&nbsp;</div>
		</div>
		<div id="craps_point_div"><strong>Point:</strong> <div id="craps_point">&nbsp;</div></div>

		<div id="craps_round_stage">&nbsp;</div>
		<div id="craps_winlose">YOU LOSE!</div>
	</div>

	<div id="craps_bet_loot">
		<div id="craps_bet">
			<strong>Current Bet:</strong> $<span id="craps_bet_span">???</span>
		</div>
		<div id="craps_loot">
			<strong>Total Loot:</strong> $<span id="craps_loot_span">???</span>
		</div>
	</div>

</div>

The most interesting part of this and the part that we will be focusing on is line 5:

<canvas id="craps_game_demo" width="275" height="150"></canvas>

This is the canvas tag. This is where we will be drawing out the dice when the player makes a roll. You can use the canvas tag to draw anything you need be it simple 2D graphics, 3D scenes, or just about anything you can think of. We will be covering how to draw basic 2D shapes.

I do not use anything out of the ordinary for the CSS so I won’t go over that in detail but for completeness here is the CSS code I use.

#craps_demo_wrapper { height: 210px; margin-top: 20px; margin-bottom: 20px; position: relative; border: 1px solid #CECECE; padding: 2px 20px; background-color: #F0F0F0; }
#craps_game_canvas_wrapper { width: 275px; height: 150px; float: left; margin-right: 35px; }
#craps_game_demo { }
#craps_demo_infopanel { width: 300px; float: left; height: 150px; position: relative; }

#craps_roll_button, #craps_setbet_button, #craps_newGame_button { text-align: center; border-top: 1px solid #CECECE; padding-top: 5px; }
#craps_roll_button button, #craps_setbet_button button, #craps_newGame_button button { width: 100px; }
#craps_roll_button, #craps_setbet_button { display: none; }

.craps_title { font-weight: bold; text-align: center; margin-bottom: 5px; border-bottom: 1px solid #CECECE; }

#craps_current_roll_div, #craps_point_div { position: absolute; width: 50px; top: 20px; text-align: center; font-size: 1.4em; }
#craps_current_roll_div div, #craps_point_div div { border: 1px solid #CECECE; height: 45px; font-size: 2.0em; padding-top: 5px; text-align: center; }
#craps_current_roll_div { left: 0; }
#craps_point_div { right: 0; }
#craps_round_stage { width: 300px; position: absolute; top: 50px; left: 0; font-size: 1.8em; text-align: center; }

#craps_winlose { width: 300px; height: 50px; position: absolute; top: 110px; left: 0; font-size: 3.0em; padding-top: 10px; text-align: center; display: none; }
#craps_bet_loot { width: 300px; position: absolute; right: 20px; bottom: 38px; border-top: 1px solid #CECECE; }
#craps_bet { width: 150px; position: absolute; left: 0; top: 10px; }
#craps_loot { width: 150px; position: absolute; right: 0; top: 10px; text-align: right; }

Before I move onto the Javascript and how to actually use the canvas element. You will notice one class in the HTML not listed here. It is the clearfix class attached to the main game wrapper div. This class is used to fix floated elements with no extra markup. You can read about it and obtain the CSS here.

Javascript

Now to go over the Javascript used. Before we get to the code lets go over the canvas tag and how to obtain it’s 2D context so you can start drawing.

Getting the canvas context

To get the canvas context you use the getContext method. We need to pass which context we want to use. to obtain the 2D context you pass the function the string ‘2d’. You call this method after obtaining the DOM element. Their are a couple ways of doing this depending on if you are using a javascript library or not. I personally use jQuery but you can use plain old Javascript as well. I will show both methods below.

// Using jQuery
ctx = $('#craps_game_demo')[0].getContext('2d');

// Using plain jane Javascript
ctx = document.getElementByID('craps_game_demo').getContext('2d');

While using jQuery notice the [0] after the selector. This is needed to get the context. If it is missing you will receive a Javascript error saying getContext is undefined. The canvas coordinate system starts with 0, 0, in the top left corner and counts up as you move right and down. Here is an illustration:

HTML5 Canvas Coordinate System
HTML5 Canvas Coordinate System

Now that we know how to obtain the canvas context I’ll go through the rest of the Javascript used in the game. I’ll post it piece by piece and go over each section in turn. The first part of the file is defining all the basic variables used.

var cwidth      = 275;       // Canvas width
var cheight     = 150;       // Canvas height
var dicex       = 25;        // Position of dice (x)
var dicey       = 25;        // Position of dice (y)
var dicew       = 100;       // Dice width
var diceh       = 100;       // Dice height
var dotrad      = 6;         // Radius of dots on dice face
var ctx;                     // Our context object
var roll1       = 0;         // Die 1 roll
var roll2       = 0;         // Die 2 roll
var rolltotal   = 0;         // Total roll
var point       = 0;         // Current 'Point' value
var round       = 'initial'; // The round we are on. Either 'initial' or 'followup'
var total_loot  = 100;       // Current 'loot' total
var current_bet = 0;         // Current bet amount

At the top of our javascript file we define all the variables used. The first two (cwidth, cheight) is the width and height of our canvas element. We use this to clear the canvas of all drawing when the game is reset. The next 5 variables define the dice. We start with dicex and dicey, this is the position on the canvas we will draw each die starting with it’s top left corner. Next we have dicew, and diceh. This defines the width and height of each die. Our dice will each be 100px wide and 100px high. Lastly we have dotrad. This is the radius of each dot on the dice.

Our next variable is ctx. This holds our canvas context object. We use this object to draw the dice onto the canvas. We will learn how to use it in more detail as we go over each function used in the game.

The last 7 variables holds various information needed to process each roll. We start with roll1, roll2, and rolltotal. Each of these store the current die roll and the total of the two. Next is point. This will store the current rounds ‘Point’ value. Then comes round. Here is a simple string to distinguish what round we are on. I could have used a boolean variable here which may be a better choice in the end. It’s not hard to change the code to use a boolean instead of a string so feel free to make the necessary adjustments. Next we store the players ‘total loot’ in a variable called total_loot. This will increase or decrease as the game goes by depending on if the player won or lost a round. The last variable needed is current_bet. This will keep track of the players current bet. The player wil have a chance to change this before each round starts.

After this I have a basic initialize function called when the page is loaded.

function crapsInit() {
	ctx	= $('#craps_game_demo')[0].getContext('2d');

	crapsNewGame(); // Initialize a new game

	// Reset some of the variables to the page open state
	$('#craps_roll_button').hide();
	$('#craps_setbet_button').hide();
	$('#craps_newGame_button').show();
	$('#craps_round_stage').html('');
}

This function gets our context using the jQuery method. It will next call crapsNewGame() (discussed next). Lastly is resets the buttons so only the ‘New Game’ button is displayed and then clears the stage value. (note: You do not have to use jQuery. If you have a preferred library you can easily replace the jQuery calls with the appropriate library calls.)

The next function in our file is crapsNewGame(). The purpose of this function is to set all the default values needed to start a new game of Craps. Below is the complete function:

function crapsNewGame() {

	// Reset the variables
	total_loot  = 100;
	current_bet = 0;
	round       = 'initial';
	point       = 0;
	roll1	    = 0;
	roll2	    = 0;
	rolltotal   = 0;

        // Update all the HTML elements so they will
        // be in their default state.
	$('#craps_bet_input').val('10');
	$('#craps_bet_span').html('???');
	$('#craps_loot_span').html(total_loot);
	$('#craps_point').html('&nbsp;');
	$('#craps_current_roll').html('&nbsp;');
	$('#craps_round_stage').html('Initial Throw');
	$('#craps_winlose').hide();
	$('#craps_newGame_button').hide();
	$('#craps_roll_button').hide();
	$('#craps_setbet_button').show();

        // Clear the canvas of any previous drawing
	ctx.clearRect(0,0,cwidth,cheight);

}

Here we reset all the Javascript variables and HTML layout elements to their default states. The most interesting part of this function is the call to clearRect() at the end of the function. This function is used to clear a rectangle shaped space on a canvas. It will remove any drawing done within that area. The function takes four arguments, the top (x) and left (y) and then the total width and height of the rectangle to clear. You pass the arguments in this order: clearRect(x, y, width, height). In this function we want to clear the entire canvas of any drawing so we can have a clean slate to draw on so we will be passing the following to the function: 0, 0, cwidth, cheight.

The next function used is crapsSetBet(). This function is called when the player sets their bet. Here is the complete function:

function crapsSetBet() {
	round = 'initial';
	current_bet = $('#craps_bet_input').val();

	if (current_bet > total_loot) {
		alert('You cannot bet less then your total loot. Please enter a different bet.');
		return;
	}

	$('#craps_bet_span').html(current_bet);
	$('#craps_point').html('&nbsp;');
	$('#craps_current_roll').html('&nbsp;');
	$('#craps_round_stage').html('Initial Throw');
	$('#craps_winlose').hide();
	$('#craps_newGame_button').hide();
	$('#craps_setbet_button').hide();
	$('#craps_roll_button').show();

	ctx.clearRect(0,0,cwidth,cheight);
}

We start off in this function by setting the round to the ‘initial’ string so we know we are going to be making the Initial Roll. Next we get the value the player inputs for their bet. We then check to make sure the bet is less then the players total_loot. If the player is trying to bet more then what they have available we give them a nice Javascript alert letting them know they cannot bet more then their available loot then return from the function early so the player can enter a new bet value. After this we set the HTML Elements to the state we need them in to have the player make the Initial Roll. Lastly you will notice we make another call to clearRect(). This is to make sure we clear the canvas of any drawing that might have taken place before we make the initial roll.

Our next function crapsRollDice() contains the core logic for the game. Below is the complete function:

function crapsRollDice() {

	// reset the dice x position
	dicex = 25;

	roll1 = 1 + Math.floor(Math.random() * 6);
	roll2 = 1 + Math.floor(Math.random() * 6);
	rolltotal = igz_roll1 + igz_roll2;

	if (round == 'initial') {
		switch (rolltotal) {

			// WIN
			case 7:
			case 11:
				$('#craps_winlose').html('YOU WIN!').show();
				setScore(true);
				break;

			// LOSE
			case 2:
			case 3:
			case 12:
				$('#craps_winlose').html('YOU LOSE!').show();
				setScore(false);
				break;

			default:
				point = igz_rolltotal;
				$('#craps_point').html(point);
				$('#craps_round_stage').html('Follow up Throw');
				round = 'followup';

		}

	} else {

		// LOSE
		if (rolltotal == 7) {
			$('#craps_winlose').html('YOU LOSE!').show();
			setScore(false);
		}
		// WIN
		else if (rolltotal == point) {
			$('#craps_winlose').html('YOU WIN!').show();
			setScore(true);
		}

	}

	if (total_loot <= 0) {
		total_loot = 0;
		$('#craps_roll_button').hide();
		$('#craps_setbet_button').hide();
		$('#craps_newGame_button').show();
	}

	$('#craps_current_roll').html(rolltotal);

	// Display the dice
	crapsDrawface(roll1); 	// Die 1

	dicex = dicew + 50;     // Move over the width plus 50
	crapsDrawface(roll2);	// Die 2

}

We start off this function by setting the dicex variable to it’s default of 25. This will make sure when when actually draw the dice the first die will be drawn in the correct position. Next we get two random numbers and assign them to roll1, and roll2.

We use the Javascript Math functions to do this. Here is the call we make: 1 + Math.floor(Math.random() * 6). Lets break this line down. The Math.random() function will return a value between 0.0 and 1.0. We then multiply this number by 6. For example lets say the function returns 0.4. The final value of the inner expression, Math.random() * 6, will be 2.4. We then use the Math.floor() function to strip away the decimal part of the number leaving us with 2. Lastly to get our random number between 1 and 6 we add 1 to the returned value of Math.floor(Math.random() * 6) giving us a final value of 3.

We repeat the above to get a random value for roll2. Next we add the two rolls together to get the value we will be using to check against for the rest of the function. You may wonder why I am getting two random numbers between 1 and 6 and not one random number between 2 and 12. I could have done this but I would have to split the number somehow in order to display the values of each individual die when we go to draw the dice. This way will make it much easier to call the drawing function to draw each individual die.

The next part of the function we determine what round we are in. If it is the Initial Roll we will be making different checks then if it is the Follow Up Roll. In the Initial Roll part of the if statement we use a switch() to see what the total roll is. If it is a 7 or 11 we display the message YOU WIN! then call the setScore() function to add the players bet to their total loot. If the total roll is either a 2, 3, or 12 we display the message YOU LOSE! then call setScore() to subtract the players bet from their total loot. If any other roll is found we set the point variable to the value of rolltotal and display the number in the Point box. We also update the round text to Follow Up Roll and update the round variable accordingly.

If we are already on the Follow Up Roll we check to see if the rolltotal is equal to 7. If it is we display the YOU LOSE! text and call setScore() to subtract the players bet from their total loot. If this isn’t true we check to see if the rolltotal equals the players point value. If it does we display YOU WIN! and call setScore() to update the score appropriately. If any other number is rolled we ignore it and move on.

Next we check to see if the players total_loot is less then or equal to 0. If it is we set the players total_loot to 0 then update the HTML Elements so the New Game button is showing. We then display the current totalroll in the appropriate spot.

After this we call the crapsDrawFace() function to draw the result of roll1 onto the canvas. Next we move dicex over the width of the die plus 50. Lastly we call crapsDrawFace() again to draw the results of roll2. crapsDrawFace() will take care of drawing the dice. I’ll be going over this function and it’s accompanying functions in a minute.

Before we get to the meat of the drawing code we have one more simple function to go over. The setScore() function. This function takes one argument, a boolean value. If we won the round and want to add the bet to the players total lot we pass true else we will pass false to subtract the bet from the players total loot. Here is the full function:

function setScore(win) {

	if (win) {
		total_loot = parseInt(total_loot,10) + parseInt(current_bet,10);
	} else {
		total_loot = parseInt(total_loot,10) - parseInt(current_bet,10);
	}

	$('#craps_loot_span').html(total_loot);
	$('#craps_roll_button').hide();
	$('#craps_newGame_button').hide();
	$('#craps_setbet_button').show();

}

This function is simple. We check to see if the player has won the round. If so we add the value of current_bet to the players total_loot and update the HTML Elements. I call parseInt() to make sure I am adding integer numbers and not strings as the javascript + operator is used for both addition and concatenation of strings. If you don’t use parseInt() you may end up with a number like 10010 instead of 110 when adding the players bet and total loot together.

Now we get to the fun part, crapsDrawFace(). This function will draw a die onto the canvas at dicex and dicey. This function will call other functions depending on the number we need to draw. These function are crapsDraw1(), crapsDraw2() and crapsDraw2mid(). I’ll go ever each in turn.

function crapsDrawface(n) {

	ctx.lineWidth = 5;
	ctx.clearRect(dicex,dicey,dicew,diceh);

	ctx.fillStyle = "#FFFFFF";
	ctx.fillRect(dicex,dicey,dicew,diceh);

	ctx.fillStyle = "#000000";
	ctx.strokeRect(dicex,dicey,dicew,diceh);

	ctx.fillStyle = "#009966";

	switch (n) {

		case 1:
			crapsDraw1();
			break;

		case 2:
			crapsDraw2();
			break;

		case 3:
			crapsDraw2();
			crapsDraw1();
			break;

		case 4:
			crapsDraw2();
			crapsDraw2(true);
			break;

		case 5:
			crapsDraw2();
			crapsDraw2(true);
			crapsDraw1();
			break;

		case 6:
			crapsDraw2();
			crapsDraw2(true);
			crapsDraw2mid();
			break;

	}

}

The first thing we do inside this function is set the line width we will be drawing with. We do this by setting the lineWidth data member of our ctx variable. This is the complete call: ctx.lineWidth = 5;. This is setting the width to 5px. The next function should look familiar. We used it in two previous functions. It’s the clearRect() function. The difference here is that w are clearing only the space that the dice is occupying. Next will set the fill color we want to use, in this instance #FFFFFF or white. We do this be setting the fillStyle data member of the ctx object. The next function is new, fillRect(). This function is identical to clearRect in all ways except one. the fillRect() function will fill the rectangle provided with the setting of fillStyle. This gives our dice a nice white background (if your game is on a white background you can skip this). Next we change the fillStyle so it is #000000 or black. We want this to be the color of the border for our dice. We create this by calling the function strokeRect(). Once again this takes the exact same parameters as clearRect() and fillRect(). The only difference here is that the function will stroke (put a border) around the outside of the rectangle with a width of lineWidth and the color stored in fillStyle. Lastly we set the fillStyle one last time to a nice green color, #009966. This color wil be used for the dots on the face of the dice.

The function then uses a switch() statement to determine how to draw the dots. It will call one of the crapsDraw?() functions or a combination of them to accomplish this. All of these functions are almost identical besides how they calculate the dot position. I will show all three functions then go over the most interesting parts.

/*
 * This function draws a dot in the center of the die.
 */
function crapsDraw1() {

	var dot_x;
	var dot_y;

	ctx.beginPath();
	dot_x = dicex + .5 * dicew;
	dot_y = dicey + .5 * diceh;
	ctx.arc( dot_x, dot_y, dotrad, 0, Math.PI * 2, true );
	ctx.closePath();
	ctx.fill();

}

/*
 * This function draws a dot in two oposit corners (lower right and upper left).
 * If reverse is true it draws the dots in the oposite corners.
 */
function crapsDraw2(reverse) {

	reverse = typeof(reverse) != 'undefined' ? reverse : false;

	var dot_x;
	var dot_y;

	ctx.beginPath();
	dot_x = dicex + 3 * dotrad;
	dot_y = reverse ? dicey + diceh - 3 * dotrad : dicey + 3 * dotrad;
	ctx.arc( dot_x, dot_y, dotrad, 0, Math.PI * 2, true );

	dot_x = dicex + dicew - 3 * dotrad;
	dot_y = reverse ? dicey + 3 * dotrad : dicey + diceh - 3 * dotrad;
	ctx.arc( dot_x, dot_y, dotrad, 0, Math.PI * 2, true );

	ctx.closePath();
	ctx.fill();

}

/*
 * This function draws two dots on either side (left and right) centered vertically
 * on the y axis. It is used to create the '6'.
 */
function crapsDraw2mid() {

	var dot_x;
	var dot_y;

	ctx.beginPath();
	dot_x = dicex + 3 * dotrad;
	dot_y = dicey + .5 * diceh;
	ctx.arc( dot_x, dot_y, dotrad, 0, Math.PI * 2, true );

	dot_x = dicex + dicew - 3 * dotrad;
	ctx.arc( dot_x, dot_y, dotrad, 0, Math.PI * 2, true );

	ctx.closePath();
	ctx.fill();

}

There are four functions  that we are concerned with that we need to look at, beginPath(), arc(), closePath(), and finally fill(). I will go over arc() last as that is the more interesting function of the bunch (Don’t forget to add ctx. in front of each function call). To tell the context we want to start drawing a path we use the  beginPath() function: We tell the context we are done when we call closePath(). We then can either use fill() or stroke() to either fill the path or stroke is accordingly. I do not use the stroke() function in this game but the work the same as fillRect() and strokeRect().

Now for the real work. We use the arc() function to create our path. arc() is used as follows: arc(cx, cy, radius, start_angle, end_angle, direction). cx is the center horizontal coordinate and cy is the vertical coordinate of the circle. radius is the radius we want to use. Now the arc method uses radians for the angle arguments. In a circle their are 2 * PI radians (a little more then 6). Luckily Javascripts Math  library has a PI function which returns PI with as many decibles as needed. So if we want to make a half circle we start at 0 and end at Math.PI. For a complete circle we start at 0 and end at Math.PI * 2. The last argument is the direction. This is either a true or false value. Setting it to true will draw counterclockwise and false is clockwise. This is more important when drawing arcs that are not whole circles. Since we are drawing a whole circle we can use either value.

Now that we know about the arc() function will pass it the calculated dot_x and dot_y variables along with the dotrad defined at the top of the file. The last three variables deals with the angles and since we are making a complete circle we pass 0, Math.PI * 2, and lastly the Javascript true value. The complete call is: ctx.arc( dot_x, dot_y, dotrad, 0, Math.PI * 2, true).

Finally at the end of the file we add the crapsInit() function to the document ready queue. I use jQuery but you can assign it in any manner that will work if you do not use the jQuery library.

$(document).ready(function () {
	crapsInit();
});

Thats about it for the code. When the page is initially loaded it will call the crapsInit() function. This will set the stage and display the New Game button. Once the player clicks this it will call the crapsNewGame() function and prompt the user to set the bet for the round. Once the player enters their bet and clicks the button the crapsSetButton() function is fired off. Next the player clicks the Roll Dice button to call crapsRollDice() until they either win or loose the round. At this point it prompts the player to enter another bet and play continues till either the player stops or looses all his loot.

I hope this tutorial on how to build my simplified version of Craps was useful. The main parts I wanted to make sure to hit was how to draw basic 2d shapes on a canvas. You can do so much more with the canvas then I did here but hopefully this gave any one just jumping into HTML 5 some useful info to help them along.

I plan on doing more tutorials based around more complex games that will take full advantage of the canvas. I will also do some 3D based ones as well. If you liked this let me know. If you found any mistakes or know how I can do something better don’t hesitate to submit a comment.

UPDATE:

Here are some screen shots of the finished game ( should have added this a while ago 🙂 ):

A screenshot of me winning a round!
This is a screenshot of me losing a round!

Thanks!

Advertisements

One thought on “Tutorial: Craps… A Game of Dice

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s