Building a Housie/Bingo/Tambola Ticket Generator

I had created a Housie/Bingo/Tambola number generator some months back. Now I have also created a Housie/Bingo/Tambola Ticket Generator.

Housie is a group game. It is played when a bunch of friends and family have gathered. Everyone gets a Housie ticket and one person calls out numbers. The host picks up a number token and calls it out, those who have the number on their ticket mark it. There are prizes for the first person to mark 5 numbers on their ticket, for being the first one to mark all numbers on the top, middle and bottom row and then finally a full house – marking all numbers on the ticket.

Creating the Housie number generator was easy because it was only about generating a random number between 1-90.

Creating the ticket was a bit more complex. A Housie ticket has a set of rules

  • It has 3 rows and 9 columns.
  • Column 1 has numbers from 1-9, column 2 has from 21-29, column 3 has 31-39 and so on. Last column has numbers from 81-90.
  • Each row has 5 numbers, 15 numbers total on a ticket.
  • Each column can have 1 to 3 numbers.
  • Any column can’t be blank, any row can’t be blank.

This is what the House tickets look like

At first I thought it would be easy to generate. I would just have to generate 3 random numbers from each column falling between the minimum and maximum numbers for that column. But that would generate 27 numbers. I need only 15. Picking 15 random numbers from those 27 had a chance of one of tens (one column) not being picked at all.

I then decided to generate between 1 and 3 random numbers for each column. Again, it would not give me exact 15 numbers. It could generate any number between 9 and 27. So I put it in a loop to keep generating numbers till the final count of the numbers generated was 15. This would mean an uncertain number of iterations.

It gave me 15 numbers, but placing them was an issue.

Say it generated these numbers

1,3,
16,
21,22,
33,
42,45,48
55,59
63,68
74,
88

I have numbers for each column but how do I place them? Take first column. It has 1,3. I can place it as 1,3,blank or 1,blank,3 or blank,1,3. I could have randomize that placement but then I won’t be sure if I will get exactly 5 numbers in each row.

This is where the complexity comes in. The numbers have to be distributed such that each row has exactly 5 numbers. I concluded that if I generated numbers first and then tried to place them, I would have to do multiple passes to distribute them evenly. It would take multiple loops and would be very complicated.

So I chucked the idea of generating numbers first. I decided to mark the cells which will have numbers.

I created an array of 9 elements containing zeros and ones. It should have 5 ones. Because each row has 5 numbers. Zeros are blank cells with no numbers in them. After generating this array I counted the number of ones. If the count of ones is not 5, I recreated the array till I got an array with 5 ones. This gave me my one row. I repeated the process two more times and I had 3 rows, each having 5 ones and 4 zeros.

for (r = 0; r < 3; r++) {
    var row = [];
    var onecount = 0;
    while (onecount != 5) {
	onecount = 0;
	row = [];
	for (c = 0; c < 9; c++) {
	    n = getZeroOne();
	    if (n == 1) onecount++;
	    row.push(n);
	}
    }
    rows.push(row);
}

Now I put the 3 arrays into a larger array and checked if each column had at least 1 one. If one column was entirely blank, I would regenerate all the 3 arrays again.

for (c = 0; c < 9; c++) {
    if (rows[0][c] == 1 || rows[1][c] == 1 || rows[2][c] == 1) {
	columnok = true;
    }
    else {
	columnok = false;
	//$("#notes").append("Not OK<br>");
	break;
    }
}

There is a scope for optimization here, I will come to it later.

So finally I had a grid of zeros and ones where each row had exactly five numbers and each column had at least one number.

I replaced all zeros with blank. Now I just had to replace ones with numbers. I iterated from column 1 to 9, got the count of ones in that column. Say there were 2 ones in the column, I generated two random numbers between the minimum and maximum of that column and replaced the ones with those numbers. I had my final grid ready.

for (c = 0; c < 9; c++) {
    //get count of 1s in this column
    var nums = rows[0][c] + rows[1][c] + rows[2][c];
    var min = c * 10 + 1;
    var max = min + 8;
    if (c == 8) max = 90;
    var tmp = [];
    for (n = min; n <= max; n++) {
        tmp.push(n);
    }
    var arr = getRandom(tmp, nums).sort().reverse();
    for (r = 0; r < 3; r++) {
        if (rows[r][c] == 1) {
	    rows[r][c] = arr.pop();
        }
    }
}

I then added some bells and whistles like a random ticket colour every time you generate a new ticket. Added a confetti animation using confetti.js for marking first 5 numbers, and marking all the numbers in each of the rows. I also added a pure CSS shake animation on the ticket table.

Marking was just about adding a class on click on the TD. Instead of doing a simple jQuery toggleClass, I added a confirmation prompt for unmarking a number to prevent accidental unmarking.

Optimization

There is scope for optimizing and reducing the number of iterations in number generation.

As I mentioned above, I generate the row array repeatedly till I get exact 5 ones. Instead, I can start with a fixed array of 5 ones and 4 zeros and then randomise (shuffle) that array, this will eliminate the need for generating the array again and again.

I also regenerate all the 3 row arrays repeatedly till I get a grid where each column has at least 1 one. This can also be optimized. After I have generated first two rows, I can check which column is still blank and put a 1 in the bottom cell of that column. I will again have to iterate through the last row to see if has 5 ones and if there are less than 5, I will have to put missing ones in some random blank cells in the bottom row.

Check out the Housie/Bingo/Tambola Ticket Generator at https://yash.info/bingo-ticket.htm

Building a Housie/Bingo/Tambola Ticket Generator
Scroll to top