A YahtzeeGame instance is pretty simple: it encapsulates some configuration information (the number of dice, the maximum value on the die faces, and the number of rolls allowed in a round) along with a list of categories. There is no other state information required, since each category object keeps track of the score for that category. The method for returning the total game score just needs to iterate over the scoring categories to add things up.
One feature that may not be obvious is the method createNewHand(). This method constructs and returns a new Hand object that is based on the attributes of that particular game instance. This way, a client does not have to separately keep track of the number of dice, maximum value, or number of rolls; that information is only stored in the game object. See the UI for sample usage.
(Note that the class GameFactory is already implemented. However, you can add to it as you wish for testing and experimentation.)
This class has some static methods for creating various games. You can take a look to see how the game constructor is used and how the categories are added to a YahtzeeGame object. This class is used in the sample UI.
Note that in the sample code, all the calls to the constructors of the Category implementations are commented out. That’s because this code won’t compile until you actually have implementations of the classes that are named there that are subtypes of Category. As you complete the implementations, you can start uncommenting the constructor calls to try them out (and uncomment the import statements too).
The sample code is an Eclipse project that you can import. See the instructions given for homework 2 if you don’t remember how to import a project.
There are “complete” skeletons present for Hand and YahtzeeGame classes in package hw3. (The Hand class has the toString method implemented for you already.) You will also find partial skeletons for the 8 required concrete subtypes of Category. Each of these classes has a descriptive javadoc comment and a stub for the required constructor. You will need to add either an implements or extends clause to each of these class declarations to make it a subtype of Category, and add whatever implementation code is necessary for your design, as discussed in the above section “Scoring Categories”.
There is a sample user interface TextUIMain provided in the default (top-level) package of the sample code. This code will not run until you have implemented the YahtzeeGame and Hand classes, and you will not be able to play a game until you have started implementing the necessary categories. As you implement and test the categories, you can uncomment the corresponding constructors (and add appropriate import statements) in the GameFactory.
This is a text-based UI using clunky console I/O. It is not as slick as a graphical UI, but has the advantage that the code is entirely comprehensible, so you can read it to see how the other classes in the application are used. A typical screenshot of a game in progress is shown below.
The dashed lines in the second column indicate the categories called “Sixes” and “Three of a kind” are already filled, and the rightmost columns show the score and the list of dice for the hand that was used to fill the category. The “You rolled…” shows the current state of our hand. Since the parentheses are nonempty, this is not the first roll in this round. We must have previously chosen to “keep” the 2, 3, and 4 from the previous roll, and we just rolled a 1 and a 6. The second column in the list shows us what potential score we would get in each category for this roll as it stands (e.g. 30 points if we use it to fill the “Small Straight” category, or 16 points if we use it for the “Chance” category). One of our options might be to “keep” the 1 and reroll the 6 in the hope of getting a 5 (that would be a large straight).
Potential scores for this roll: 0) 1 Aces 1) 2 Twos 2) 3 Threes 3) 4 Fours 4) 0 Fives 5) --- Sixes 12 (1 2 3 6 6) 6) --- 3 of a kind 15 (2 2 2 4 5) 7) 0 4 of a kind 8) 0 Fill House 9) 30 Small Straight 10) 0 Large Straight 11) 0 Yahtzee 12) 16 Chance ----- SCORE: 27 You rolled 1 6 (2 3 4) Press ENTER to roll available dice, or: a) keep all b) select dice to keep c) select dice to free Your choice:
You can edit the UI main method to 1) choose a seed for the random number generator, in case you want the dice results to be reproducible while you are developing the code, and 2) to get a different game from the GameFactory. To try a different game from those constructed in the GameFactory, add another static method to GameFactory. (The “factory” keeps the UI from having any direct dependence on any of the specific category classes, so it will continue to work correctly even if you add new or different categories.)
As always, you should try to work incrementally and write tests for your code as you develop it. Please do not put your test code in the hw3 package.
Do not rely on the UI code for testing! Trying to test your code using a UI is generally slow and unreliable. In particular, when we grade your work we are NOT going to run either of UIs, we are going to test that each method works according to its specification.
We will provide a basic SpecChecker, but it will not perform any functional tests of your code. At this point in the course, you are expected to be able to read the specfications, ask questions when things require clarification, and write your own unit tests.
Since the test code is not a required part of this assignment and does not need to be turned in, you are welcome to post your test code on Piazza for others to check, use and discuss.
The SpecChecker will verify the class names and packages, the public method names and return types, and the types of the parameters. If your class structure conforms to the spec, you should see a message similar to this in the console output:
x out of x tests pass.
Note that spec conformance can only be checked for the ten required classes listed at the beginning of this document that are known to the specchecker. Remember that your instance variables should always be declared private, and if you want to add any additional “helper” methods that are not specified, they must be declared private as well.
This SpecChecker will also offer to create a zip file for you. Note that it will look for the 10 required classes, and it will also zip up all other java files in your hw3 directory. Thus the archive should include any additional classes you added to your inheritance hierarchy, and should NOT include extraneous or unnecessary files such as your unit tests.
- The YahtzeeGame class is very straightforward and doesn’t really depend on anything else you’re implementing. It should refer only to the interface Category.
- Hand can also be developed and tested independently. You might start with the constructor that takes an int array, so you can specify starting values, and just implement the method getAll(). Your first attempt may not be sufficient for implementing all the other methods of Hand, but having this much will enable you to start on the scoring categories.
- Although the scoring categories depend on Hand, they can be individually developed and tested with just a simplified, partial implementation of Hand. Within a given category class implementation, the only method of Hand you will need is getAll().
- For the scoring categories, you might start with something like CountOccurrences. Add the clause implements Category and create stubs for the required methods. Write a couple of simple test case and start to implement the methods. (You may later move some of this code into an abstract superclass, but this is a good place to begin.)
- As noted above, you can develop and test all the categories with just that minimal implementation of Hand. Of, course, at some point you’ll need to finish the rest of the Hand methods. As usual, start with some test cases and think about the expected behavior. Start with getAvailableDice(), getFixedDice(), and keep().
- Note that the roll() method of Hand takes a Random as an argument. For testing, you can specify a Random with a known seed to make your test results reproducible.
- Once you have YahtzeeGame, Hand, and CountOccurrences, you can uncomment the constructor in the createReallyTinyGame() method of the GameFactory. Then, you can run the UI and play the Really Tiny Game! Likewise, as you complete and test each of the scoring categories, uncomment the relevant constructor from one of the games in GameFactory and try it out.