Random BINGO Card Generator with Ajax Reset

bingo
Creative Commons License photo credit: Keees

This programming challenge is from a Lynda.com instructional video, featuring Dori Smith, which I studied/practiced last summer but once again spring 2009. I do not mean to just re-post the wonderful Lynda.com code, but rather add instructional value to it by way of clearer variable names and explanatory comments. The end result itself is not terribly sexy, but I liked the algorithm construction process.

I post these self-instructional challenges for a few reasons. One is to demonstrate my programming learning, experience, and progression. Another reason is to make sure my code and solutions are indexed by search engines, so that other beginning programmers may get help if they need it. Finally, self-instructional challenges are interesting and different than academic challenges because I sought, discovered, and performed them on my own volition without anyone else telling me to do so. I did it because I wanted to learn and practice.

Challenge: Create a BINGO card using HTML and JavaScript. Generate random integers between 1 and 75, and insert them into each of 24 squares, skipping the center FREE space. Integer ranges are as follow: B = 1-15, I = 16-30, N = 31-45, G = 46-60, O = 67-75. Ensure no two squares contain duplicate numbers. Bonus: After initial card load, enable resetting the card without a server call (quasi-Ajax-powered).

The HTML solution:

<html>
<head>
	<title>Make Your Own Bingo Card</title>
	<link rel="stylesheet" rev="stylesheet" href="script.css" />
	<script type="text/javascript" src="script.js">
	</script>
</head>
<body>
<h1>Create A Bingo Card</h1>
<table>
	<tr>
		<th width="20%">B</th>
		<th width="20%">I</th>
		<th width="20%">N</th>
		<th width="20%">G</th>
		<th width="20%">O</th>
	</tr>
	<tr>
		<td id="square0">&nbsp;</td>
		<td id="square1">&nbsp;</td>
		<td id="square2">&nbsp;</td>
		<td id="square3">&nbsp;</td>
		<td id="square4">&nbsp;</td>
	</tr>
	<tr>
		<td id="square5">&nbsp;</td>
		<td id="square6">&nbsp;</td>
		<td id="square7">&nbsp;</td>
		<td id="square8">&nbsp;</td>
		<td id="square9">&nbsp;</td>
	</tr>
	<tr>
		<td id="square10">&nbsp;</td>
		<td id="square11">&nbsp;</td>
		<td id="free">Free</td>
		<td id="square12">&nbsp;</td>
		<td id="square13">&nbsp;</td>
	</tr>
	<tr>
		<td id="square14">&nbsp;</td>
		<td id="square15">&nbsp;</td>
		<td id="square16">&nbsp;</td>
		<td id="square17">&nbsp;</td>
		<td id="square18">&nbsp;</td>
	</tr>
	<tr>
		<td id="square19">&nbsp;</td>
		<td id="square20">&nbsp;</td>
		<td id="square21">&nbsp;</td>
		<td id="square22">&nbsp;</td>
		<td id="square23">&nbsp;</td>
	</tr>
</table>
<p><a href="script.html" id="reload">Click here</a> to create a new card</p>
</body>
</html>

The CSS solution:

body {
	background-color: white;
	color: black;
	font-size: 20px;
	font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
}

h1, th {
	font-family: Georgia, "Times New Roman", Times, serif;
}

h1 {
	font-size: 28px;
}

table {
	border-collapse: collapse;
}

th, td {
	padding: 10px;
	border: 2px #666 solid;
	text-align: center;
	font-size: 24px;
}

#free {
	background-color: #ffff00;
}

The JavaScript solution:

window.onload = initializePage;

// even though arrays are 0-based, creating 76 positions generates elements 0-75, we will later ignore position 0
// note that newly created arrays have all elements set to false
var usedNumbers = new Array(76);

function initializePage() {
	// so older browsers do not get 24 error messages
	if (document.getElementById) {
		// enable creating a new card without reloading page
		document.getElementById("reload").onclick = anotherCard;
		// generate the new bingo card
		newCard();
	} else {
		alert("Sorry, but your browser is not running JavaScript, and this game requires it.");
	}
}

function newCard() {
	for (var i = 0; i < 24; i++) {
		// pass the current i as parameter to setSquare function
		setSquare(i);
	}
}

function setSquare(thisSquare) {
	// capture current corresponding html square (via id=)  to current digit that was passed over
	var currentSquare = "square" + thisSquare;

	// while bingo numbers are ranged 1-75, letter columns are restricted to specific number ranges
	// b = 1-15, i = 16-30, n = 31-45, g = 46-60, o = 67-75
	// OR mathematically we can generate a random number between 1-15 and add column-specific number
	// b = 0, i = 15, n = 30, g = 45, o = 60	

	// need 5 sets of numbers 0-4 (1 set for each letter)
	// note missing '2,' from third set, so as to skip the middle 'free' square
	var columnPlace = new Array(0,1,2,3,4,0,1,2,3,4,0,1,3,4,0,1,2,3,4,0,1,2,3,4);

	// capture appropriate column mulitple by referencing current square # as array element
	var columnMultiple = (columnPlace[thisSquare] * 15);

	// initialize variable to be used in following do-while loop
	var newNumber;

	// generate newNumber and check if it has been used already, if so loop again
	do {
		// add random number to the particular column multiple
		newNumber = columnMultiple + getNewNumber()  + 1;
	} while(usedNumbers[newNumber]);

	// prevent duplicate numbers by testing if the newNumber has already been used once on this card
	if (!usedNumbers[newNumber]) {
		// if duplicate was not found, this must be an original #, so set this element to true
		usedNumbers[newNumber] = true;

		// assign randomized newNum to current square
		document.getElementById(currentSquare).innerHTML = newNumber;
	}
}

function getNewNumber() {
	// capture random number between 1 and 15 for bingo values
		// math.random() returns random number between 0 and 1
		// math.floor() returns floor of a decimal number (ex. 1.75 becomes 1)
	return Math.floor(Math.random() * 15)
}

function anotherCard() {
	// housekeeping: reset the usedNumbers flag arrays to all false
	for (var i = 1; i < usedNumbers.length; i++) {
		usedNumbers[i] = false;
	}

	// generate the new bingo card
	newCard();
	return false;
}

And finally here is a screenshot of the end result:

BINGO card screenshot

BINGO card screenshot

Share




Leave a Reply