Table of Contents
The symbol returns the reader to the top of the Table of Contents.
1. Introduction
At last, this article is the third of three articles describing the Bingo game suite that I developed over the past few months.
The articles are published in the hope that the software may prove useful to the articles' readers.
The three articles address the 75-ball version of Bingo.
This article discusses the bolded items in the preceding figure. The Bingo card file must have already been generated by the Generate_Cards [^] program and a set of Bingo Cards must have already been printed by the Print_Cards [^] program.
2. Playing Bingo
Bingo is played in thousands of locations, big and small, across North America. The game that is played (and discussed in this article) is the 75-ball version of Bingo (as opposed to the 90-ball version).
2.1. Background
Players purchase Bingo game cards that are usually printed three cards to a sheet. Each sheet forms one game and is printed in a different color. A session is usually made up of six differently colored sheets. There may be many sessions during a day.
The caller (game host) randomly draws balls from a hopper. Each ball in the hopper is numbered from 1 to 75 and is usually colored according to the number on them:
- Blue 1 - 15
- Red 16 - 30
- White 31 - 45
- Green 46 - 60
- Yellow 61 - 75
The caller announces the number of the ball drawn. If ball numbered 37 was drawn, the number would be announced as "N 37". In most locations, the ball is placed into a numbered hole in a board. When the ball is inserted, the number on a called board (in this case 37) lights.
2.2. Patterns
Normally just having the called number on your card does not win the game.
The called number must usually appear in a pattern announced by the caller at the start of the game.
For the purpose of this article, there are two types of pattern: static and dynamic.
Note that this article does not enumerate all possible patterns; rather, it discusses just a
few for demonstration purposes. The Roanoke VA Moose Lodge has a set of Bingo Patterns [^] that is rather complete.
The best way to describe patterns is to display some examples. The following are the static patterns supported by the software described in this article.
The following are the dynamic patterns supported by the software described in this article.
The patterns display the locations on a Bingo card where called numbers must appear in order to win.
2.3. Stars
Bingo with Stars is an addition to the normal Bingo game. It was introduced to increase excitement during the initial play of a Bingo game.
During a normal Bingo game, if a player can mark all three stars on the sheet in the first three numbers called, the player calls "Stars". If the Bingo cards on the sheet contain a valid stars pattern, the player is awarded a prize and the Bingo game continues.
2.4. Simulate a Game
To put it all together, let's simulate the play of a game. Assume
- The caller has required that the game be played on LightCoral-colored Bingo cards (this implies that the group_face must begin with a "2")
- The pattern is the "letter-x"
- 17 numbers have been called
- The called board looks like:
The value in red is the last ball called and that number must be on the winning Bingo card. Now let's look at a player's Bingo card.
The green circles are the marks that the player made on the card as each number was called. The SeaShell-colored circle is the last number called. When the last number was called, the player called "Bingo" and the game was suspended pending confirmation. The player, at the request of the caller, identifies the Bingo card as "2066057" (the group_face in the center square). When entered into the Bingo software by the caller, the program confirms that the Bingo card is a winner.
Of course there are other outcomes in which a player who calls "Bingo" does not win: the last number called is not on the card (the player may not have realized the Bingo before another number was called - known as "sleeping"); all of the positions in the pattern were not marked; the first digit in the group_face does not equate to the color of the card being played; etc.
3. Play_Bingo Implementation
3.1. Subordinate Form Template
This implementation uses a number of forms to collect information. I use a simple template for the invocation of a subordinate form.
A subordinate form is created in the same directory as the form that will invoke it. The subordinate form is added to the project as a Windows Form with the same namespace as the form that will invoke it. At a minimum, the subordinate form must contain a public method named initialize_form in addition to its constructor. The signature of initialize_form is:
public bool initialize_form ( )
The skeleton for the Retrieve_And_Open_Bingo_Card_File is:
namespace Play_Bingo
{
public partial class Retrieve_And_Open_Bingo_Card_File : Form
{
⋮
bool initialize_GUI_controls ( )
{
bool successful = true;
⋮
return ( successful );
}
void close_form ( )
{
this.Close ( );
}
public bool initialize_form ( )
{
bool successful = false;
if ( !initialize_GUI_controls ( ) )
{
successful = false;
}
else
{
successful = true;
}
if ( !successful )
{
close_form ( );
}
return ( successful );
}
public Retrieve_And_Open_Bingo_Card_File ( )
{
InitializeComponent ( );
⋮
}
}
}
In the Play_Bingo main form Retrieve_And_Open_Bingo_Card_File is invoked by the method retrieve_and_open_bingo_card_file:
void retrieve_and_open_bingo_card_file ( )
{
Form form = null;
if ( form == null )
{
form = new Retrieve_And_Open_Bingo_Card_File ( );
}
if ( ( ( Retrieve_And_Open_Bingo_Card_File ) form ).
initialize_form ( ) )
{
form.ShowDialog ( );
}
form.Dispose ( );
form = null;
}
If additional statements are needed in the invoking method, they may be inserted before and after the form.ShowDialog ( ) statement.
3.2. Insuring Randomness
In the real world, Bingo balls are drawn at random by the very nature of the equipment from which they are drawn.
To simulate that randomness, Play_Bingo uses the same type of Pseudo Random Number Generator [^] (PRNG) as did Generate_Cards.
The list of 75 random Bingo ball face numbers, balls, is found in the Global_Values class of the Utilities project (along with a number of other global variables).
public static List < int > balls = new List < int > ( );
⋮
public static void initialize_balls ( )
{
List < int > allowed = Enumerable.Range (
1,
MAXIMUM_BALLS ).ToList ( );
balls.Clear ( );
called_int.Clear ( );
while ( allowed.Count > 0 )
{
int index = random.Next ( allowed.Count );
balls.Add ( allowed [ index ] );
allowed.RemoveAt ( index );
}
}
initialize_balls is invoked at the beginning of each game.
3.3. ThreadPauseState
Before I describe the background workers in Play_Bingo, the mechanism by which background threads are paused and resumed needs to be addressed.
Play_Bingo requires that, upon caller command, it pause and resume the execution of its background workers.
This is signaled by the caller clicking on a button or pressing a registered keyboard key. Internal to each thread is code that recognizes that it is being suspended. For example:
using TPS = Utilities.ThreadPauseState;
⋮
TPS thread_pause_state = new TPS ( );
⋮
thread_pause_state.Wait ( );
The ThreadPauseState class of the Utilities project contains the methods that manage the pause/resume operations. These are implemented as invocations of the Monitor [^] Enter and Exit methods that acquire or release an exclusive lock.
using System.Threading;
using GV = Utilities.Global_Values;
namespace Utilities
{
public class ThreadPauseState
{
bool paused = false;
public bool Paused
{
get { return ( paused ); }
set {
if( paused != value )
{
if( value )
{
Monitor.Enter ( GV.thread_pause_lock );
paused = true;
}
else
{
paused = false;
Monitor.Exit ( GV.thread_pause_lock );
}
}
}
}
public void Wait ( )
{
lock ( GV.thread_pause_lock )
{
}
}
}
}
For example, during the execution of Play_Bingo the caller may want to change the winning pattern.
To do so, the caller clicks the pattern_BUT button or presses the keyboard key "P". The event
handler for that button click or key press invokes the patterns method.
using BT = Utilities.Build_Templates;
using GV = Utilities.Global_Values;
⋮
void patterns ( )
{
BT.Patterns current_pattern = GV.pattern_wanted;
thread_pause_state.Paused = true;
open_choose_pattern ( );
disable_all_buttons ( );
bingo_BUT.Enabled = true;
pause_BUT.Enabled = true;
settings_BUT.Enabled = true;
reinitialize_BUT.Enabled = true;
exit_BUT.Enabled = true;
thread_pause_state.Paused = false;
}
The first action of patterns is to pause the execution of Play_Bingo's background workers.
thread_pause_state.Paused = true;
When all of the work required to change patterns has been completed, patterns resumes the execution of Play_Bingo's background workers.
thread_pause_state.Paused = false;
Within each background worker appears
thread_pause_state.Wait ( );
If thread_pause_state.Paused is true the thread is suspended, otherwise the tread continues its execution.
3.4. Background Workers
In order to keep the main User Interface (UI) responsive,
two background workers
[^]
exist: one flashes a number on the called board;
the other displays the pattern in the pattern_PAN (recall that patterns may be dynamic).
When program initialization has been completed, Play_Bingo invokes initialize_background_workers. Note that this method creates the background workers, it does not cause them to execute; rather RunWorkerAsync must be invoked on each worker.
void initialize_background_workers ( )
{
draw_flash_BW = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
draw_flash_BW.DoWork += draw_flash_DoWork;
draw_flash_BW.RunWorkerCompleted +=
draw_flash_WorkerCompleted;
draw_flash_BW.ProgressChanged +=
draw_flash_ProgressChanged;
draw_pattern_BW = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
draw_pattern_BW.DoWork += draw_pattern_DoWork;
draw_pattern_BW.RunWorkerCompleted +=
draw_pattern_WorkerCompleted;
draw_pattern_BW.ProgressChanged +=
draw_pattern_ProgressChanged;
}
3.4.1. draw_flash_DoWork
void draw_flash_DoWork ( object sender,
DoWorkEventArgs e )
{
int balls_called = 0;
Label label;
Panel panel;
int panel_index = 0;
BackgroundWorker worker = ( BackgroundWorker ) sender;
while ( total_calls < GV.MAXIMUM_BALLS )
{
thread_pause_state.Wait ( );
if ( worker.CancellationPending )
{
e.Cancel = true;
return;
}
do
{
ball_to_display = GV.balls [ total_calls++ ];
} while ( excluded.Contains ( ball_to_display ) );
refresh_control ( ball_PB );
Thread.Sleep ( ( int ) ( 1000M *
GV.drawn_to_flash ) );
say_the_bingo_ball ( ball_to_display );
if ( balls_called > 0 )
{
panel_index = ( GV.last_called );
panel = ( Panel ) balls_called_PAN.Controls [
panel_index ];
label = ( Label ) panel.Controls [ 0 ];
panel.BackColor = Color.White;
label.BackColor = Color.White;
label.ForeColor = Color.Black;
refresh_control ( panel );
}
GV.called_int.Add ( ball_to_display );
balls_called++;
worker.ReportProgress ( balls_called,
ball_to_display );
flash_bingo_card_board ( );
GV.last_called = ball_to_display - 1;
}
e.Result = GV.MAXIMUM_BALLS;
}
draw_flash_DoWork is the workhorse of Play_Bingo:
- Enters a paused state if required
- Draws the next ball number ball_to_display from the GV.balls list, ignoring ball numbers that do not appear in the current pattern
- Draws the ball image on the monitor
- Speaks the ball_to_display
- Sleeps for the number of seconds specified by GV.drawn_to_flash
- If there was an earlier ball drawn, resets the called board panel that flashed earlier from a White foreground with a Red background to a Black foreground with a White background.
- Invokes its ReportProgress method to update the last_called_PAN and total_calls_PAN
- Invokes flash_bingo_card_board to cause the new ball number to flash on the called board
- Saves the number of the last-called ball
- If all balls have not been drawn, returns to step 1
Because draw_flash_DoWork is on a different thread than the User Interface (UI) thread, it invokes refresh_control whenever the need arises to redraw a UI thread control. The control's InvokeRequired [^] property is accessed to determine if the control's Invoke method is required.
void refresh_control ( Control control )
{
if ( control.InvokeRequired )
{
control.Invoke (
new EventHandler (
delegate
{
refresh_control ( control );
}
)
);
}
else
{
control.Refresh ( );
}
}
When refresh_control invokes
control.Refresh
[^], the control is invalidated, the Control.Paint [^] event is raised, and the control is redrawn. For a ball, the ball_PB_Paint event handler [^] is executed.
using DOB = Play_Bingo.Draw_One_Ball;
DOB dob = new DOB ( );
⋮
void ball_PB_Paint ( object sender,
PaintEventArgs e )
{
Image image = null;
e.Graphics.Clear ( BALL_BACKGROUND );
if ( ball_to_display == 0 )
{
image = Properties.Resources.bingo_image;
}
else
{
image = dob.draw_ball ( ball_to_display );
}
e.Graphics.DrawImage ( image, new Point ( 0, 0 ) );
}
ball_PB_Paint determines if the Bingo logo (icon) is to be displayed or if a numbered ball is to be drawn. In the latter case, it invokes draw_ball that creates the image of the numbered Bingo ball. To do so, draw_ball performs the following steps to create the image to be drawn.
Recall that objects drawn later overwrite objects drawn earlier.
Lastly, ball_PB_Paint uses the PaintEventArgs Graphics.DrawImage to actually draw the image.
3.4.2. draw_pattern_DoWork
draw_pattern_DoWork is responsible for drawing the pattern that is displayed in the pattern_PAN. Recall that there are dynamic patterns as well as static patterns. Each pattern is created as a list of 25 bytes. Static patterns have a single list; dynamic patterns have as many lists as are required to display all of the variations of a pattern. The lists are created as needed and are referred to as templates.
For example, one of the simplest dynamic patterns is the diagonal pattern. Its template is created by build_diagonal_templates found in the Build_Templates class in the Utilities project.
public List < List < byte > > build_diagonal_templates ( )
{
List < byte > template;
List < List < byte > > templates;
templates = new List < List < byte > > ( );
template = new List < byte > { 1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1 };
templates.Add ( template );
template = new List < byte > { 0, 0, 0, 0, 1,
0, 0, 0, 1, 0,
0, 0, 1, 0, 0,
0, 1, 0, 0, 0,
1, 0, 0, 0, 0 };
templates.Add ( template );
return ( templates );
}
Here the leftward (downward) diagonal is specified first with the rightward (upward) diagonal specified second. Both of the templates are added to the templates list of lists and templates is returned.
In Play_Bingo appears the declaration of the list of lists
List < List < byte > > templates;
that receives the results of the build_diagonal_templates invocation. What we desire is the diagonal pattern to change every specified time interval as follows.
The value of the class variable template_count determines which template will be drawn. retrieve_dynamic_template returns the list of bytes that contains the next template to draw.
List < byte > retrieve_dynamic_template (
BT.Patterns pattern )
{
if ( first_time )
{
switch ( pattern )
{
⋮
case BT.Patterns.DIAGONAL:
templates =
bt.build_diagonal_templates ( );
break;
⋮
default:
templates =
bt.build_empty_templates ( );
break;
}
template_count = templates.Count;
first_time = false;
}
template_count++;
if ( template_count >= templates.Count )
{
template_count = 0;
}
return ( templates [ template_count ] );
}
The event handler for the pattern_PAN Paint event is pattern_PAN_Paint.
void pattern_PAN_Paint ( object sender,
PaintEventArgs e )
{
if ( first_paint )
{
first_paint = false;
}
else
{
template = retrieve_a_template ( );
create_pattern_buffer ( );
draw_the_template ( template );
pattern_buffer.RenderGraphicsBuffer ( e.Graphics );
this.Icon = Icon.FromHandle (
pattern_buffer.Bitmap_Image.
GetHicon ( ) );
}
}
After pattern_PAN_Paint has retrieved the template, it creates a buffer into which to draw the template by invoking create_pattern_buffer.
void create_pattern_buffer ( )
{
if ( pattern_buffer != null )
{
pattern_buffer =
pattern_buffer.DeleteGraphicsBuffer ( );
}
pattern_buffer = new GraphicsBuffer ( );
pattern_buffer.CreateGraphicsBuffer (
TEMPLATE_BITMAP_EDGE,
TEMPLATE_BITMAP_EDGE );
pattern_buffer.Graphic.SmoothingMode =
SmoothingMode.HighQuality;
pattern_buffer.ClearGraphics ( PANEL_BACKCOLOR );
}
create_pattern_buffer obtains a new graphics buffer from the class GraphicsBuffer in the namespace Play_Bingo.
using System.Drawing;
namespace Play_Bingo
{
public class GraphicsBuffer
{
Bitmap bitmap;
Graphics graphics;
int height;
int width;
public GraphicsBuffer ( )
{
width = 0;
height = 0;
}
public bool CreateGraphicsBuffer ( int width,
int height )
{
bool success = true;
if ( graphics != null )
{
graphics.Dispose ( );
graphics = null;
}
if ( bitmap != null )
{
bitmap.Dispose ( );
bitmap = null;
}
this.width = 0;
this.height = 0;
if ( ( width == 0 ) || ( height == 0 ) )
{
success = false;
}
else
{
this.width = width;
this.height = height;
bitmap = new Bitmap ( this.width, this.height );
graphics = Graphics.FromImage ( bitmap );
success = true;
}
return ( success );
}
public GraphicsBuffer DeleteGraphicsBuffer ( )
{
if ( graphics != null )
{
graphics.Dispose ( );
graphics = null;
}
if ( bitmap != null )
{
bitmap.Dispose ( );
bitmap = null;
}
width = 0;
height = 0;
return ( null );
}
public Graphics Graphic
{
get
{
return ( graphics );
}
}
public Bitmap Bitmap_Image
{
get
{
return ( bitmap );
}
}
public bool GraphicsBufferExists
{
get
{
return ( graphics != null );
}
}
public Color ColorAtLocation ( Point location )
{
Color color = Color.Black;
if ( ( ( location.X > 0 ) &&
( location.X <= this.width ) ) &&
( ( location.Y > 0 ) &&
( location.Y <= this.height ) ) )
{
color = this.bitmap.GetPixel ( location.X,
location.Y );
}
return ( color );
}
public void RenderGraphicsBuffer ( Graphics graphic )
{
if ( bitmap != null )
{
graphic.DrawImage (
bitmap,
new Rectangle ( 0, 0, width, height ),
new Rectangle ( 0, 0, width, height ),
GraphicsUnit.Pixel );
}
}
public void ClearGraphics ( Color background_color )
{
Graphic.Clear ( background_color );
}
}
}
pattern_PAN_Paint then invokes draw_the_template to draw the template to the pattern_buffer.
void draw_the_template ( List < byte > template )
{
Graphics graphic = pattern_buffer.Graphic;
int i = 0;
Pen pen = new Pen ( PANEL_BORDER_COLOR, 1.0F );
SolidBrush solidbrush = new SolidBrush (
GV.marker_color );
int x = 0;
int y = 0;
foreach ( byte item in template )
{
Point marker_location = new Point ( ( x + 5 ),
( y + 4 ) );
Rectangle rectangle = new Rectangle ( x, y, 40, 40 );
graphic.FillRectangle ( new SolidBrush (
PANEL_BACKCOLOR ),
rectangle);
graphic.DrawRectangle ( pen, rectangle);
if ( item >= 1 )
{
graphic.FillEllipse (
solidbrush,
new Rectangle ( marker_location,
MARKER_SIZE ) );
}
x += PANEL_EDGE;
i++;
if ( ( i % PANEL_COLUMNS ) == 0 )
{
x = 0;
y += PANEL_EDGE;
}
}
solidbrush.Dispose ( );
pen.Dispose ( );
}
Once the template has been drawn, pattern_PAN_Paint renders the image. Just for cosmetics, pattern_PAN_Paint changes the Play_Bingo icon to the new pattern.
3.5. Speech Synthesis
As mentioned above, as draw_flash_DoWork "draws" a new Bingo ball, it announces the value drawn by invoking say_the_bingo_ball
public void say_the_bingo_ball ( int ball_to_call )
{
string ball_label = ", ,";
PromptBuilder prompt = new PromptBuilder ( );
SpeechSynthesizer voice = null;
try
{
if ( voice != null )
{
voice.Dispose ( );
voice = null;
}
voice = new SpeechSynthesizer ( );
ball_label += CONST.BALL_LABELS [
( ( ball_to_call - 1 ) / 15 ) ];
prompt.StartSentence ( );
prompt.AppendTextWithHint ( ball_label,
SayAs.Text );
prompt.AppendTextWithHint ( ball_to_call.ToString ( ),
SayAs.NumberCardinal );
prompt.EndSentence ( );
voice.Speak ( prompt );
voice.Dispose ( );
voice = null;
}
catch ( Exception ex )
{
}
}
The try-catch construct is used to capture those cases in which the computer on which Play_Bingo is executing does not have an audio device for output. In that case, say_the_bingo_ball is a NUL statement.
say_the_bingo_ball utilizes SpeechSynthesizer Class [^] to announce the Bingo ball using the default system voice.
3.6. Confirming Bingo
When a player calls "Bingo", Play_Bingo must determine if the player's card is, in fact, a winner. The software that performs this test is contained in the class Confirm_Bingo in the namespace Play_Bingo. Within this section of this article, all referenced code can be found in that class.
To determine if a Bingo card is a winner, the caller must supply the following information:
- The color of the Bingo cards being used
- The card number of the player's card
When these items are supplied, Play_Bingo validates the Bingo card color. There are a number of outcomes:
- Success - The card color is valid
- NOT A BINGO - UNRECOGNIZED CARD COLOR
- NOT A BINGO - WRONG COLOR CARD
If the card color is valid, Play_Bingo extracts the card_number and uses it to compute the card_offset into the Bingo card file. If the card is retrieved successfully, Play_Bingo invokes encode_user_card to convert the card to a representation that can be used for determining if the player's card is a winner.
List < byte > encode_user_card ( List < byte > user_card,
List < byte > called )
{
List < byte > encoded = new List < byte > {
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0 };
for ( int i = 0; ( i < user_card.Count ); i++ )
{
if ( called.Contains ( user_card [ i ] ) )
{
encoded [ i ] = 1;
}
}
encoded [ CONST.CENTER_CELL_INDEX ] = 1;
return ( encoded );
}
The resulting user_card_bitmap now represents the called numbers on the Bingo card identified by its group_face by the player. Play_Bingo now uses this bitmap to determine if that Bingo card contains the pattern.
bool validate ( )
{
bool equal = false;
foreach ( List < byte > template in templates )
{
equal = true;
for ( int i = 0; ( i < template.Count ); i++ )
{
if ( i == CONST.CENTER_CELL_INDEX )
{
continue;
}
if ( ( user_card_bitmap [ i ] &
template [ i ] ) != template [ i ] )
{
equal = false;
break;
}
}
if ( equal )
{
GV.found_template = new List < byte > ( );
for ( int i = 0; ( i < template.Count ); i++ )
{
GV.found_template.Add ( template [ i ] );
}
break;
}
}
if ( !equal )
{
display_in_message_RTB (
"NOT A BINGO - DOES NOT MATCH PATTERN" );
return ( false );
}
return ( true );
}
The test
( ( user_card_bitmap & template ) == template )
has a number of outcomes:
- Success - The card is a winner
- NOT A BINGO - DOES NOT MATCH PATTERN
- NOT A BINGO - NOT CALLED ON LAST CALLED
This process is partly depicted in the following figure. Here assume the player identified the Bingo card as "2066011".
3.7. Confirming Stars
When a player shouts "Stars", Play_Bingo must determine if the player's game sheet contains starred numbers that have been called. The software that performs this test is contained in the class Confirm_Stars in the namespace Play_Bingo. Within this section of this article, all referenced code can be found in that class.
To determine if a Bingo card is a winner, the caller must provide the group_face of the top Bingo card on the sheet. For example, in the following figure
the top Bingo card on the sheet has the group_face number of "12017". When that number is entered by the caller, there are three immediate results:
- NOT CALLED IN FIRST THREE NUMBERS
- UNRECOGNIZED CARD COLOR
- FACE NUMBER NOT MULTIPLE OF 3
The first is unrecoverable; the other two may be caused by a player or caller error in reporting the top Bingo card group_face. If the value is accepted, cards_PAN is refreshed. If the three Bingo cards have three stars called, the following will be displayed.
If the three Bingo cards do not have the three stars called, the following will be displayed.
When Resume is clicked, the Bingo game resumes.
4. Executing Play_Bingo
Play_Bingo is an interrupt-driven WinForm application. Its state diagram is depicted in the following state diagram.
The rounded rectangles are buttons; the squared rectangles are states.
Upon starting (Start Program), Play_Bingo must first determine what Bingo card file is to be used.
Next, Play_Bingo must determine which pattern is to be used.
In this case, a double (one horizontal and one vertical) Bingo has been specified (note the green border surrounding the pattern). When the OK button is clicked, the Play_Bingo main screen is displayed.
As the game progresses, the screen updates its information as in the previous screen shot.
When a player calls "Bingo" the caller clicks the Bingo button.
This brings up the first portion of the verification form confirm_bingo.
When the caller enters both the card color and the card number, and clicks Lookup, the following appears.
This screen displays the player's card with all called numbers highlighted in green. When the caller clicks Validate, the following appears.
If there is another "Bingo" called, the caller clears the card number, enters the new card number, clicks Lookup, and follows the same procedure as earlier. If there were no valid "Bingos", the caller clicks Resume and the game continues. If there as a valid "Bingo", the caller clicks New Game and the software opens the Pattern Choice window.
TEST CASE:
At the top of the confirm_bingo.cs file is the statement
If the commenting is removed, a test-case will be instantiated near the end of the lookup method. To have a valid "Bingo", file cards_800000.dat, the pattern vertical-horizontal, the card color LightSkyBlue, and the card number 12017 must be specified.
When a player calls "Stars" the caller clicks the Stars! button.
This brings up the confirm_stars form.bingo. When the caller enters the card number and clicks Lookup, the following appears.
If a different card number is given, the following might appear.
TEST CASE:
At the top of the confirm_stars.cs file is the statement
If the commenting is removed, a test-case will be instantiated near the end of the lookup method. To have a valid "Stars", file cards_800000.dat and the card number 12017 must be specified.
In either case, the caller clicks Resume to return to the Bingo game.
If the timing of the game and/or the color of the pattern marker is not satisfactory, the caller may click Settings to bring up the Settings form.
The red items are NumericUpDown controls that set the value of their respective timings. If the Pattern marker color button is clicked, the KnownColorPicker form is opened.
Although there are no restrictions placed against any color, the user should
not pick LightSkyBlue because the background color of the pattern_PAN is also LightSkyBlue.
Also, colors that are too highly saturated or too dark will distract players from the called_board.
Certain keyboard keys are recognized when focus is in the main form (keyboard keys are not recognized in subordinate forms).
Key | Action |
S | Open settings dialog |
P | Open patterns dialog |
F1 | Toggle instructions visibility |
s | Start the Bingo game |
b | Bingo called |
t | Stars called |
p | Pause the Bingo game |
r | Resume the Bingo game |
i | Reinitialize the Bingo game |
x | Exit the program |
5. Conclusion
Play_Bingo provides a caller assistance in hosting games of Bingo.
6. References
7. Development Environment
The software presented in this article was developed in the following environment:
Microsoft Windows 7 Professional Service Pack 1 |
Microsoft Visual Studio 2008 Professional |
Microsoft .Net Framework Version 3.5 SP1 |
Microsoft Visual C# 2008 |
8. History
Bingo - Part 3 of 3 - Play Bingo | 03/29/2023 | Original Article |