CS110
Project 3
Betty
O’Neil
Finding
a good strategy for DiceJack
DiceJack: like Blackjack, but using
dice (simpler)
Provided
files: Project3.zip
At the start of a game, the players and the dealer throw two dice.
The best
possible result is sum of 12. This is called a natural 12, and the player
holding this automatically wins unless the dealer also has a natural 12. If a
player and the dealer each have a 12, the result is a draw. If the dealer has a
12, all players not holding a 12 lose.
After
the original two dice have been thrown, the game goes on with each player
taking action in turn, as follows.
The
player can keep his score as it is (stand) or throw a die again (hit), one at a
time, until either the player judges that the score is good enough to go up
against the dealer's holding and stands, or until it goes over 12, in which
case the player immediately loses (busts).
After all the players have taken their
turn, the dealer takes a turn and throws if the dealer score is under 8, and
throws a single die again and again until the score is 8 or more. The dealer
can bust, in which case any unbusted player wins. If
not, the dealer’s final score is compared to each player’s score (unless the
player has already won or lost), and higher scores win, and equal scores tie.
Is there a simple strategy to win at
this game? That is what we want to find out in this project.
Plan: set up a group of players, each of
which plays with a different strategy: Clearly it is not good to stand on
5 or less, since even an added 6 won't bust. Thus we start from strategy
6. Similarly, it's not good to hit on a 12, so the highest strategy uses
11.
Player 0 stands on 6 or more.
Player 1 stands on 7 or more.
Player 2 stands on 8 or more. (This player should be even with the dealer)
Player 3 stands on 9 or more.
Player 4 stands on 10 or more.
Player 5 stands on 11 or more.
The dealer, also a Player, stands on 8 or more.
We play the game over and over, and see which strategy is best against the house. We can record how many games are won by player 4, player 5, etc.
You will write the central Player class,
with the help of TestPlayer, a provided test program
for Player. A certain Player has two
dice to play with, and a certain stand value as listed above. A player must be
able to throw the dice on command in the first round of play (the startGame action), and throw one die over and over in the
second round of play, until the score reaches the stand value (the takeTurn action). At any time, the Player must be able to
provide its current score (the getCurrentValue
action), as well as its stand value (the getStandValue
action).
At the end of the first round of play,
the dealer throws dice, and if the dealer gets a natural 12, the game is over,
with all non-dealer Players immediately losing unless they also have a natural
12, in which case they tie. The house
(represented by class GameManager, and separately by TestPlayer) determines this outcome and tells the Player by
calling win() or tie(). The Player then adds one to nWins or nTies to tally this
game.
At the end of the first round of play,
the dealer throws dice, and if the dealer gets less than 12, the game continues
in its second round. Each Player does the takeTurn
action, and then the dealer does takeTurn too. The house determines whether each player
wins, loses or ties, by calling win(),
lose(), or tie() of Player. The Player then adds one to nWins,
nTies, or nLosses to tally
this game.
When the game is done and tallied,
Player is then ready to play another game, using the same stand value. After many games, we have statistics on wins,
losses, and ties for each strategy. All a Player has to do is provide the
number of wins, losses, and ties to another software entity for display. That is done by getWins(), getLosses(), and getTies(). As is normal for Java object deep in an
application, Player does no direct output to the user, except for
debugging/error reporting.
In the FindBest
application, the GameManager runs the whole sequence
of games, using a Player for each strategy, and later prints out the results of
all the games.
The TestPlayer
program uses a single Player object, putting it through its paces. It makes
sense to concentrate on TestPlayer first, and when
you think Player is working, go on to GameManager and
FindBest.
Since Player throws dice, it is a
challenge to write a TestPlayer program. How can you
check that the outcome is correct if you don’t know what the dice will do? The
answer is use a “mock Die”, a die that works like a Die, but has known
outcomes. Our MockDie
class has roll() and getFaceValue()
methods that always return the same number, the one we specify in the
constructor: MockDie(3) creates a die that rolls 3
every time, for example.
But how can we fool Player into using a MockDie instead of a Die in TestPlayer?
The answer is to use the power of interfaces.
We define the Rollable interface that requires
roll() and getFaceValue(),
so that Die IS-A Rollable and also MockDie IS-A Rollable. We make Player use Rollable
instead of Die as the working type.
Player will be happy, since it only wants to call roll()
on the objects anyway. Then we use real
Die’s in FindBest and MockDie’s
in TestPlayer.
We will provide Player with its “dice” at construction time. Note that it is important that Player does
NOT itself construct the dice. If it
did, then it would have the same kind of dice in all cases, but we want it to
have mock dice in the testing case.
Step 1. Implement Player.java and test it with TestPlayer.
Here is the class diagram for TestPlayer: You program Player.java. The other Java
sources, TestPlayer.java, Rollable.java, and MockDie.java, are provided. As soon as you have a compilable
version of Player, one that can create a Player and do “startGame”,
run TestPlayer with it and see the reported problems,
if any. Then add further functionality.
The diamond and connector to Rollable shows that aggregation is going on. This means that the two Die/MockDie objects are just parts of Player, probably not
important in themselves. The dashed line and triangle mean that MockDie implements Rollable.
Your job here is to write Player.java from scratch, based on the
UML above and the discussion above of what a Player needs to do. Test it by
running TestPlayer. Include Javadoc comments
in your Player class code with @author and @version for the class and with @param and @return for each method. In the
comments for each method, include a brief description of the functions or
decisions that your code performs.
Step
2.
Create Javadoc for Player in Player.html
Run “javadoc Player.java” on the
command line to create a webpage describing Player in Player.html. Alternatively,
you can use DrJava Tools>Javadoc>Preview
Javadoc for Current Class, and then save the result
to your Project3 directory as Player.html.
Step 3. Get the FindBest application working
and find out the best strategy.
Once you get TestPlayer
working by implementing Player, turn to finishing up GameManager
and FindBest. Here is the UML class diagram for the
whole application:
Here GameManager aggregates Players, i.e.,
GameManager HAS-A group of Players as parts of it, to do its work. GameManager
acts as the house as each game runs. A caller can run games by calling
playGames after creating a GameManager, and then print out statistics by
calling printWins, etc. GameManager is started for you. Just fill in the code
indicated by comments. Then the whole application will be working.
Report (memo.txt)
For this project and all projects in
this course, the memo.txt file that you upload to the turn-in system MUST BE A
PLAIN TEXT FILE - NOT A WORD (.DOC or .RTF) FILE. On a Windows PC, I recommend that you use
Notepad to create this file. On a MAC,
you must use a suitable editor or DrJava to create a plain text file.
Write a report that answers the
following questions:
1. Was it helpful to have
the provided TestPlayer class while writing the code in your Player
class? How?
2.
What is your conclusion from this experiment, i.e., what is the best
strategy to play this game? Can you
expect to win against the house if you follow this strategy?
3.
We used an ArrayList<Player> for the players held in GameManager.
Could we use an array of Player instead?
If so, what line of code would you write to create the array? If not, why not?
4.
Explain in your own words how the interface Rollable allowed us to use
two different “Die” classes with Player.java.
Turning in your Assignment:
Use the secure file transfer program to
upload your Project3 folder containing your files (listed below) to your UNIX
file directory: “account/cs110/Project3” where “account” is your account
ID.
You must upload the files to our UNIX system before the posted
deadline.
You will get no credit for late submissions. Plan your time carefully so that you have
enough time to upload your files. If you
have not finished, upload your files on time anyway - even if the program does
not work correctly yet. That way you are
eligible for part credit on the assignment.
If you upload your files more than once, only the most recent copy will
be saved.
Files for Project3 Delivery:
·
All .java files discussed
above: Player.java, FindBest.java, GameManager.java, TestPlayer.java, Die.java,
MockDie.java, Rollable.java, Histogram.java (only the first two have code
you’ve added)
·
memo.txt
·
Player.html: Javadoc for
Player.java