For week two, you wrote a program that put the letters on a grid so that it resembled a Bingo Card. In this lab and follow-up programming project you will implement a working Bingo Game from an existing skeleton.
What is the game of Bingo?
The rules of Bingo are quite simple. A Bingo game consists of a series of rounds. Within each round, a caller repeatedly pulls numbers, in the range from 1 to 75, from a contraption similar to lottery ball holders. He or she puts the number up on a screen, then calls out the number. Players have a certain number of seconds to find the number on their Bingo cards. Each card has a random selection of numbers. The "B column contains random numbers between 1 - 15, the "I" column has numbers between 16 - 30, the "N" column has numbers between 31 - 45 (with a free space in the center), the "G" column has numbers between 46 - 59, and the "O" column has numbers between 60 - 75. When a player finds a matching number on their card, they mark it as found (for example, with a marker or pen). Whoever is the first to fill a complete line of numbers on their card, whether horizontally, vertically, or diagonally, yells "BINGO!" loudly and wins the round. Then everyone clears their cards (or takes new cards), and a new round starts.
The skeleton program provided for this lab creates a graphical user interface for a Bingo Card (without the "BINGO" column headings), fills the card with some numbers, and then chooses 5 random numbers and looks for them on the card. It "marks" each number it finds on the card by changing its color.
The program needs several enhancements to act like a real Bingo game. One problem is that the card should be initialized with a different set of random numbers every time the game is played; instead, this version places the same pre-defined numbers in each column every time. This is one of the improvements you will make in the follow-up programming project. The focus of the lab will be on a more important problem: the "game" currently consists of calling out only 5 random numbers, whereas it should continue to call out random numbers until there is a winning Bingo pattern on the card. (A real game with multiple cards would continue until one of the cards has a winning pattern, but our game has only one card.) There are a variety of patterns that could be considered a winning pattern in Bingo, such as a complete row of marked numbers, a complete column of marked numbers, marked numbers in the four corners, etc. Each of these could be considered a separate strategy for winning.
In this lab you will create an interface for classes that implement different winning strategies, and then create two strategy classes. In the follow-up programming project you will implement additional winning strategies and make several other improvements to the program.
Become familiar with the program.
Play
button.)
BingoGameApp
,
BingoGame
, and BingoCard
classes, and the class documentation for the BingoValueCell
class.
BingoGameApp
: contains the main
method,
which merely creates an instance of the BingoGame
class.
BingoGame
: creates a BingoCard
object
and a BingoGUI
graphical user interface. The game object also provides the code
that is executed when the user clicks on the Play
button.
Find the code that causes the program to choose 5 random numbers and
then stop, which is one of the segments you will be modifying.
By the
end of lab, you will also write code to be executed when the user
clicks on the existing CompleteRowWins
strategy
button or a new CompleteColumnWins
strategy button.
BingoCard
: a BingoCard
object is a
Grid
object with a number of extra methods for
initializing the numbers on a card (you will modify these later as
part of the follow-up programming project), and finding and marking
called numbers.
BingoValueCell
: this class is very similar to the
TextCell
class, but allows programmers to change the color
of the object in the cell after it has been constructed, which
TextCell
does not allow.
BingoGUI
: this graphical user interface is similar
to the GridPlotterGUI
graphical user interface,
in that it provides color choosers and action buttons that allow the
user to direct the behavior of the game.
Create a WinningStrategy
interface.
description
: a method that takes no
parameters and returns a String
with a strategy
description.
isWinner
: a method that takes a
BingoCard
object as a parameter and returns
true
or false
, depending on whether
the strategy detects that the card has a winning Bingo pattern.
WinningStrategy
instance variable in the
BingoGame
class. You won't be able to initialize
it yet, but you can test that the declaration compiles.
BingoGame
class that
invokes both the description
and
isWinner
methods on your new instance variable,
for testing purposes. (Actually, just to test whether code
that invokes these methods would compile.) For example,
your method might
print the strategy instance variable's description, and then
true
or false
depending on whether the
strategy's isWinner
method returns
true
or false
. Since this method is just
for testing purposes, you could call it anything.
Test your temporary method
and the WinningStrategy
interface by compiling your code.
(Stop and Think:
Why is compiling your code enough of a test? What will
happen if you run the program? Run it to confirm your
prediction.)
Implement a WinningStrategy
class.
Create a class that, when you're done, will test to see if any row has
all its values marked.
Give your class a meaningful name and description based on its
eventual behavior. Your class should implement the
WinningStrategy
interface. (Remember, this means it
should say it implements the interface, and it should actually
implement it, i.e., implement all of the methods specified in
the interface. You might find it helpful to copy and paste the method
signatures and javadoc comments from the interface as your starting
point.)
Objects of this class will not have any state, so the
class won't have any instance variables and does not need to have a
constructor either. (When you leave the constructor out, Java
provides a default zero-parameter constructor that just constructs
the object itself.)
Eventually this strategy should test for a row with all values marked
(any row), but for now just have your isWinner
method always return true
. Implement the
description
method to return a string that describes this
strategy.
Make sure to document your class and its methods with
appropriate javadoc comments. Make sure your class compiles.
BingoGame
constructor to initialize your strategy
instance variable to an object of your new class.
Compile and run your program, comparing your expected and actual results.
(Stop and Think:
What do you expect the behavior of the program to be?)
reportStrategies
method to print your new strategy's
description rather than "none."
Compile and run your program, comparing your expected and actual results.
gameOver
method and the loop in onPlayButtonClick
to loop
continuously until there is a winning row on the card.
(Stop and Think:
What modification should you make to the
gameOver
method? Once you have decided on
that, think about what modification you should make to
the onPlayButtonClick
method. )
Compile and run your program, comparing your expected and actual results.
(Stop and Think:
Since your strategy returns true
the
very first time it is called, what do you expect
the behavior of the program to be? Play the game
multiple times to confirm your expectation.)
getCellAt
method in the BingoCard
class
and the isMarked
method in
the BingoValueCell
class useful.
Compile and run your program, playing multiple games to make sure that your
program acts as you expect. (You may wish to adjust the speed of
the program, since it may often take between 30 and 130 called
numbers before the game is won.)
WinWithMarkedRow
with whatever name you
gave your class. This method will cause any two objects of this
strategy class to be treated as equal.
(This method will be useful in the future.)
public boolean equals(Object obj) { if ( obj instanceof WinWithMarkedRow ) return true; return false; }
Implement a second WinningStrategy
class.
WinningStrategy
interface. (Once you have created a new, generic class, you can
copy and paste the contents of your first strategy class into it.)
This strategy should test for a column with all values marked (any
column). Give your class a meaningful name and description, and
update the equals
method to test for the correct class type.
Make sure to document your class and its methods with
appropriate javadoc comments. Make sure your class compiles.
BingoGame
constructor to initialize your strategy
instance variable to an object of your new class.
Compile and run your program, playing multiple times to verify that a
win consists of a completely marked column rather than a completely
marked row.
Support wins based on multiple strategies.
ArrayList
of registered or chosen strategies.
(Stop and Think:
Why is it important to use the
WinningStrategy
interface
when creating your list rather than one of your strategy
classes?)
Construct the list in the BingoGame
constructor and,
for now, initialize it to contain an object of each of your
strategy classes. Modify the reportStrategies
method
to report on all strategies in the list (however many there may be).
Modify the gameOver
method to return true
when any strategy in the list identifies a win.
toggle
method in the
BingoGame
class. If you didn't name
your strategy list registeredStrategies
, modify
the method to use your instance variable name.
Modify the OnCompleteRowWinsButtonClick
method to
call the toggle method, passing it a newly-constructed object of
your row-wins strategy class. (The reason you added the
equals
implementation provided above to your strategy
classes is so that the ArrayList
remove
method will recognize a newly-constructed strategy object passed
to toggle
as a parameter as equivalent to an existing
strategy object of the same type in the list, if there is one.)
Finally, modify the BingoGame
constructor so that it constructs an empty list, without adding any
strategy objects to it. Users will now choose which strategy or
strategies to use by clicking on the appropriate button.
CompleteRowWins
button before the Play
button.
Verify that the program acts as you expect it to.
onCompleteColumnWinsButtonClick
method to the
BingoGame
class, calling the toggle
method
with a newly-constructed object of the appropriate class. Compile
and run your program. If you named your new method correctly, you
should see a new button created automatically on the graphical user
interface. Play the game multiple times, changing which strategies
you use each time. (Note that each time you click on a
strategy-choosing button it either adds that strategy or removes it
from the list of strategies to use.) Make sure that you test it
several times using just the row-winning strategy, several times
using the column-winning strategy, and several times using both
strategies. See the picture below for an example of sample output
from the various System.out.println
statements in the
program.
(Stop and Think:
What would you expect to happen if you play the game
with no registered winning strategies? Test it once
to see what happens.)
onPlayButtonClick
method (just before the call to
reportStrategies
) that adds both of your basic
strategies to the list if it is empty. Test your program without
registering any strategies and confirm that it runs with both
strategies in effect. Submit your modifications.