[Home]   [Puzzles & Projects]    [Delphi Techniques]   [Math topics]   [Library]   [Utilities]



Search WWW


As of October, 2016, Embarcadero is offering a free release of Delphi (Delphi 10.1 Berlin Starter Edition ).     There are a few restrictions, but it is a welcome step toward making more programmers aware of the joys of Delphi.  They do say "Offer may be withdrawn at any time", so don't delay if you want to check it out.  Please use the feedback link to let me know if the link stops working.


Support DFF - Shop

 If you shop at Amazon anyway,  consider using this link. 


We receive a few cents from each purchase.  Thanks


Support DFF - Donate

 If you benefit from the website,  in terms of knowledge, entertainment value, or something otherwise useful, consider making a donation via PayPal  to help defray the costs.  (No PayPal account necessary to donate via credit card.)  Transaction is secure.

Mensa Daily Puzzlers

For over 15 years Mensa Page-A-Day calendars have provided several puzzles a year for my programming pleasure.  Coding "solvers" is most fun, but many programs also allow user solving, convenient for "fill in the blanks" type.  Below are Amazon  links to the two most recent years.

Mensa 365 Puzzlers  Calendar 2017

Mensa 365 Puzzlers Calendar 2018

(Hint: If you can wait, current year calendars are usually on sale in January.)


Feedback:  Send an e-mail with your comments about this program (or anything else).

Search only



Problem Description

Write a program to emulate Keno games as played at casinos.  Display "house percentages"  and allow users to define custom  payout tables. 

Game #1
You selected: 24,35,46,57,68
Drawn numbers: 65, 53, 35, 34, 29, 71, 22, 23, 9, 79, 7, 41, 52, 66, 37, 43, 77, 54, 20, 15
1 hit(s): 35      Payout: $0.41     Tot payout:$0.41

Background & Techniques

Keno is an ancient game that has made its way into casinos.  It is a game of chance.  As far as I know, no skill or strategy can reduce your chances of losing in the long run.  All games offered by casinos count on the fact that you will lose "in the long run". 

To play Keno, pay some money for each game, typically $1, and then select from 1 to 10 numbers (15 in some versions) from 1 to 80.  The game operator then selects 20 numbers from the pool of 80.  You are paid based on two factors:  the number of  numbers you selected and the number that matched the 20 numbers drawn.  A payout table specifies  how much is returned to you for each outcome.

Keno Terminology 

Keno has a small vocabulary of its own:

bulletSpots are the numbers chosen for a game.
bulletThe pool is set of  numbers from which spot are are selected.  Integers 1 though 80 in all cases I've seen.
bulletThe draw is the numbers drawn for matching against the spots.
bulletCatches are the spots which match numbers in the draw. 
bulletThe Payout or rate table specifies how much money you receive for each winning outcome.  If it's not in the table, your payout is zero. 
bulletThe "House percentage" identifies how much of the money taken in is paid back as winnings.  That may range from 5% to 30%.  

Program features

The program allows you to play 1 to 10 spot games.  You may select the spots on your own or let the program select numbers randomly.  Buttons allow you to play a single game, a round of 5 games where the same spots are retained from game to game, 20 5-game rounds to simulate 100 games at a time, or 100,000 games to help check statistical results.  For all except the 100,000 game button, result of each individual game are listed including the payout and total payout for all games since the last time statistics were cleared.

The initial payout table is a "fair" table with the payout based on the probability of each outcome and no profit for the house.  A separate tab sheet allows you to modify the table and save it or to reload saved payout tables. Several sample tables found on the web are included.       

A little math

The most interesting part of the project was determining the probabilities for each possible outcome.   The probability for any event is defined as the number of successful outcomes for the event divided by the total number of possible outcomes.   Say we are playing a 5-spot game and want to calculate the probability that 3 catches occur.  The total number of successful outcomes is the number of ways we can select our 3 catches from the 20 numbers drawn multiplied by the number of ways that the  2 non-matching numbers could have been drawn from the other 60 numbers not in the draw.  The " combinations" function gives these numbers.    If we use the common terminology C(N,R) to represent choosing R of N items,  then C(20,3) x C(60,2) represents the number of possible outcomes.   The total number of outcomes is C(80,5) and the probability will be C(20,3) x C(60,2) /C(80,5). 

Since order does not matter by definition,C(20,3), is the product of the 20 choices for the first number, 19 choices for the second and  18 choices for the 3rd   all divided by the number of orderings of  the 3 numbers (denoted as 3 factorial =  3! = 3x2x1 = 6).  So C(20,3) = 20x19x18/6=1140.  Similarly C(60,2) = 60x59/2 = 1770 and the total possible successful out comes  =  1140 x 1770 =   2,017,800.  The divisor C(5,80) is a computer job and equals  24,040,016. So C(20,3) x C(60,2) / C(80,5) = 2017800 / 24040016 = 0.08393505 or about 8 games out of every hundred played.    Whew!  Do that 65 more times and we'll have the probabilities for all outcomes for 0 to N catches for all N from 1 to 10. 

 Non-programmers are welcome to read on, but may want to skip to the bottom of this page to download executable version of the program.

Notes for Programmers

Except for figuring out the math, not much new here.

I used a, 10x8  TStringGrid for the Keno card and used an OnSelect exit to identify user clicks.  OnSelect has the advantage over OnClick because it provides the column and row directly.   Successive clicks will select then deselect a number.  Selected numbers , the  "spots" are tracked two ways:  Entries in a 10X8 Boolean array, Board, are set to true for selected numbers.  Selected numbers are also kept in a separate Selected ;array to simplify checking  during the playing phase.   An OnDrawCell exit for the Stringgrid handles coloring the background to visually identify the spots.   

The random draw during play-in is accomplished by "shuffling" an array containing the integers 1 through 80.   Procedure Shuffle  swaps positions from 80 down to 2 with the number from a random position less than or equal to the position being set.   I do this 3 times although some studies say that 6 or 7 such shuffles are required to ensure true randomness.   After the shuffle, the first 20 numbers constitute the "Draw".   

In counting matches after the draw, I pass the 20 numbers in the draw against the  against the selected spots array.  It seems to me to be a wash whether spots are checked against the draw or the draw numbers are checked against the spots, but I haven't really checked that.

The PayOutTable   is a two dimensional array filled initially with probabilities and "fair" payout for all 10 choices for number selected,  and for number matched from 0 to the max for that size game.  The "fair" payout is simply 1/probability for each outcome.  The probabilities are fixed ,  but the payout values may be modified by the user.   

 A separate tabsheet  manages the Payout table.  Users can load or save a set of records representing the non-zero payouts for each   (spots, catches) combination.  Entries are displayed in a TMemo which contains the 3 values, spots, catches and payout on each line.   The Save button saves these line without further checking.  At Load  time, simple checking ensures that two positive integers plus a valid floating point number are contained on each line and the payout table is modified accordingly.       

My StrToFloatDef function included here which is one of the "missing" standard Delphi functions, at least in Delphi 5.  StrToFloatDef  tries to convert a string to an extended type floating point value and returns a specified default value if the conversion fails.  I use it here to return -1.0 if the string is not a valid payout value.  A check for  negative payout at load time can trigger an error message and skip the record.    

Keno uses our UComboV2 unit to calculate combinations for the outcomes.  UComboV2 is used in many programs here on DFF and, to make my maintenance job easier, it is contained  on a Library zip file along with other commonly used routines.  To recompile Keno you will need to do a one-time download of DFFVLib04 or later versions, if you have not already done so.   

Addendum February 25, 2008:  It has been  three years since we visited the world of Keno.  A recent email from a fellow in Brazil prompted  Version 2 posted today.  The Brazilian national lottery is a version of Keno which they call "Lotomania".  In this game the Pool is 100 numbers, 20 Spots are selected and the Draw is 50 numbers.  I expanded Keno V1 to allow user selection  of Pool, Draw, and Spots values.   I also expanded the Payout results table to include theoretical and observed odds as well as probability for the number of "catches".

The new version with the larger Pool uses needed a routine borrowed from TBigCombos to calculate payout probabilities.   I also added more flexibility and significant speed increase in running game simulations.  A 100% payout table file matching the payouts for Lotomania  (for 0, 16, 17, 18, 19, and 20 catches)   is also included.  

I have not yet generalized the decimal separator/thousands separator values to handle the European/Brazilian standard, so you may have to manually modify the provided payout files if you live in one of those countries that refuse to "do it our way".  There is a page documenting the code changes required on this International Separator page.     

Running/Exploring the Program 

bulletDownload  executable
bulletDownload source
bulletDownload current DFF Library source code file (DFFLibV15 ) (One time download required to recompile Keno.) 

Suggestions for Further Explorations

Done Feb 2008:There are other Keno variations not implemented here. Games up to 15-spot, multiple games on a single card,  etc.
I just noticed that changes made to a payout table only become effective after the table is saved and reloaded.  Let's see - rather than a bug, I could call this a "feature" to ensure that users really intended to make the change :>) 
Done Feb 2008: What is the effect of the drawn set size on the chances of winning?  For example what if matches were against 40 or all 80 numbers rather than 20? 


Original Date: December 10, 2005 
  [Feedback]   [Newsletters (subscribe/view)] [About me]
Copyright 2000-2017, Gary Darby    All rights reserved.