Here is the output from my version of the program.
Dee Parks CS 1440 Summer 2013
Sunday, July 28, 2013
Saturday, July 27, 2013
Last Program -- The Menagerie
This program is MUCH easier than many of the programs of the summer. There will be a lot of classes involved (and one interface), but each of them is simple as pie. Here is my best attempt at a UML diagram of all but the driver class:
The methods called roam, eat, vocalize, and play simply print to the output with System.out.println.
My Menagerie class didn't contain anything but a main. It created an ArrayList (although an array would work fine) and then created a Dog, a Cat, a Wolf, and a Tiger. It added each of those to the ArrayList. Then it traversed the list and, for each animal, it printed the animal's name and age using the toString, then called roam, eat, vocalize, and play (calling play only if the animal was a pet).
That's it! Write if you have questions.
The methods called roam, eat, vocalize, and play simply print to the output with System.out.println.
My Menagerie class didn't contain anything but a main. It created an ArrayList (although an array would work fine) and then created a Dog, a Cat, a Wolf, and a Tiger. It added each of those to the ArrayList. Then it traversed the list and, for each animal, it printed the animal's name and age using the toString, then called roam, eat, vocalize, and play (calling play only if the animal was a pet).
That's it! Write if you have questions.
Wednesday, July 17, 2013
Finished
I would suggest that you read my Yahtzee postings in reverse order.
I finished writing the Yahtzee program. I ended up with these classes: Die, DiceTray, Scorer, Player, Game, and Yahtzee. Here is a link to a UML diagram that summarizes the structure of my code:
http://www.cs.appstate.edu/~dap/classes/1440/yahtzee.jpg
The takeTurn method in the Player class does the following:
The constructor of the Game class gets passed the number of players. It makes an array of Player objects of that size and then runs a loop that same number of times. Each time through the loop it asks for a player's name, allocates a new Player object, sets its name, and adds it to the array of Players.
The play method in the Game class does the following:
I finished writing the Yahtzee program. I ended up with these classes: Die, DiceTray, Scorer, Player, Game, and Yahtzee. Here is a link to a UML diagram that summarizes the structure of my code:
http://www.cs.appstate.edu/~dap/classes/1440/yahtzee.jpg
The takeTurn method in the Player class does the following:
- Say whose turn it is.
- Print the Scorer object.
- Roll the dice.
- Print the DiceTray object.
- Ask the user which dice to reroll.
- for two more times:
- Read the user's answer to the reroll question.
- Make the boolean array to pass to the roll method.
- Pass the array to the roll method.
- Print the Scorer object.
- Print the DiceTray object.
- If it's the first of two rerolls, ask the user again which ones to reroll.
- Ask the user how to score the roll.
- Get the answer.
- Call the tally method.
My Yahtzee class is very simple:
import java.util.Scanner;
public class Yahtzee
{
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
System.out.print("How many players? ");
int numPlayers = keyboard.nextInt();
Game g = new Game(numPlayers);
g.play();
}
}
The constructor of the Game class gets passed the number of players. It makes an array of Player objects of that size and then runs a loop that same number of times. Each time through the loop it asks for a player's name, allocates a new Player object, sets its name, and adds it to the array of Players.
The play method in the Game class does the following:
- Run a loop 13 times. Each time through that loop, run another loop that goes through the array of players calling the takeTurn method on each one.
- Find the largest score by going through the array of players and calling the getScore method on each one.
- Declare the winner.
More about Scorer
The first thing I did in my Scorer class was create an enumerated data type for all the categories of scoring. I made it public, but I'm thinking that it could be private. I'll hold off on changing it. Here it is:
public enum Category { ONES, TWOS, THREES, FOURS, FIVES, SIXES,
TKIND, FKIND, HOUSE, LOW, HIGH, YAHTZEE, CHANCE }
This came in very handy in several ways. In my tally method, which is where all the mess of tallying up a score was done, I had a big switch statement. I passed a DiceTray and a Category to the tally method and I switched on the Category. Inside the switch my cases were things like:
switch (cat)
{
case ONES:
...
case TWOS:
...
etc.
Another way that the enumerated type came in handy is that the ordinal values of the various categories could be used as indexes into arrays. I had a boolean array that I called taken where I kept track of whether or not a given category had been used yet. I could say something like this:
case TKIND:
if (!taken[Category.TKIND.ordinal()])
{
...
Now let's talk about how the scoring was done. First let's talk about scoring the ones through sixes, all of which require the same algorithm. I made a helper (private) method called scoreUpper to avoid having a lot of duplication in the first six cases. I called this method from the tally method like this, where t was the DiceTray that got passed to tally:
switch(cat)
{
case ONES:
scoreUpper(t, Category.ONES);
break;
case TWOS:
scoreUpper(t, Category.TWOS);
break;
case THREES:
scoreUpper(t, Category.THREES);
break;
case FOURS:
scoreUpper(t, Category.FOURS);
break;
case FIVES:
scoreUpper(t, Category.FIVES);
break;
case SIXES:
scoreUpper(t, Category.SIXES);
break;
If a player chooses to score a DiceTray as one of these upper values, you have to add up the occurrences of that value in the tray. For example, if your dice values are 3, 4, 5, 3, 3 and the player says to score it as Threes, then the value of that round will be the sum of three 3's or 9. Here is how the algorithm for scoreUpper works:
Doing that count is easy:
So my Scorer class is finished now. I am going to work on Player and then put it all together somehow. I expect I'm going to have a Yahtzee class that will contain the main. I'll write more when I get finished.
public enum Category { ONES, TWOS, THREES, FOURS, FIVES, SIXES,
TKIND, FKIND, HOUSE, LOW, HIGH, YAHTZEE, CHANCE }
This came in very handy in several ways. In my tally method, which is where all the mess of tallying up a score was done, I had a big switch statement. I passed a DiceTray and a Category to the tally method and I switched on the Category. Inside the switch my cases were things like:
switch (cat)
{
case ONES:
...
case TWOS:
...
etc.
Another way that the enumerated type came in handy is that the ordinal values of the various categories could be used as indexes into arrays. I had a boolean array that I called taken where I kept track of whether or not a given category had been used yet. I could say something like this:
case TKIND:
if (!taken[Category.TKIND.ordinal()])
{
...
Now let's talk about how the scoring was done. First let's talk about scoring the ones through sixes, all of which require the same algorithm. I made a helper (private) method called scoreUpper to avoid having a lot of duplication in the first six cases. I called this method from the tally method like this, where t was the DiceTray that got passed to tally:
switch(cat)
{
case ONES:
scoreUpper(t, Category.ONES);
break;
case TWOS:
scoreUpper(t, Category.TWOS);
break;
case THREES:
scoreUpper(t, Category.THREES);
break;
case FOURS:
scoreUpper(t, Category.FOURS);
break;
case FIVES:
scoreUpper(t, Category.FIVES);
break;
case SIXES:
scoreUpper(t, Category.SIXES);
break;
If a player chooses to score a DiceTray as one of these upper values, you have to add up the occurrences of that value in the tray. For example, if your dice values are 3, 4, 5, 3, 3 and the player says to score it as Threes, then the value of that round will be the sum of three 3's or 9. Here is how the algorithm for scoreUpper works:
- Set a local variable, value, to 0.
- If the category has not been taken already,
- walk through the dice tray (t) and
if the value of a die is of the category being used (cat), then add it to value. Here is how I did that. Keep in mind that the ordinal value of ONES is zero, but when I'm counting ones I want to add up 1's. The ordinal value of the first six categories is one less than the face value of that category. So I have to add 1 to the ordinal value.
for (int i = 0; i < 5; i++) if (t.getValue(i) == cat.ordinal()+1) value += cat.ordinal()+1; - Put that value into the scores array at the location of the category being used. (scores[cat.ordinal()] = value)
- Set the location in the taken array (the one that corresponds to the category) to true.
- Add the value onto the subtotal field.
- If the subtotal is 63 or more and the bonus has not yet been taken, then set the bonus to 35.
- Add value and bonus to total.
I didn't make any other helper methods. I just handled the other cases right in the tally method.
I found it useful to have a local integer array in the tally method that I called count. I made it be of size 7 but I never used the 0 cell. I used cells 1 through 6 to correspond to the values of dice. I started all the cells of count at 0. I used this count array in almost every case. The first thing I did in almost every one of my cases was to go through the dice tray and add 1 to the count of each possible dice value. If the dice in the tray were 3, 4, 1, 4, 5, then after I looked through the tray my count array would have the values in the table below (the top row shows the indexes of the cells of the array and the bottom row shows the values in the array). There is 1 one, no twos, 1 three, 2 fours, 1 five, and no sixes. I don't use the 0 cell.
I found it useful to have a local integer array in the tally method that I called count. I made it be of size 7 but I never used the 0 cell. I used cells 1 through 6 to correspond to the values of dice. I started all the cells of count at 0. I used this count array in almost every case. The first thing I did in almost every one of my cases was to go through the dice tray and add 1 to the count of each possible dice value. If the dice in the tray were 3, 4, 1, 4, 5, then after I looked through the tray my count array would have the values in the table below (the top row shows the indexes of the cells of the array and the bottom row shows the values in the array). There is 1 one, no twos, 1 three, 2 fours, 1 five, and no sixes. I don't use the 0 cell.
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
| 0 | 1 | 0 | 1 | 2 | 1 | 0 |
Doing that count is easy:
for (int i = 0; i < 5; ++i)
count[t.getValue(i)]++;
One you have the counts of the various dice, you can check to see if one of the counts is 3 (good for three of a kind) or 4 (good for four of a kind) or 5 (yahtzee!) For a full house you can check to see if one count is 2 and another is 3.
So my Scorer class is finished now. I am going to work on Player and then put it all together somehow. I expect I'm going to have a Yahtzee class that will contain the main. I'll write more when I get finished.
Player and Scorer
So the next thing I'm going to do is create a Player class. A player needs a name, a DiceTray, and a Scorer. I'm thinking of a Scorer as some sort of automated scoring gizmo. Maybe I'd better deal with the Scorer class before the Player class.
The Scorer is going to have to keep a total, a subtotal of the upper categories (the ones through the sixes), and a bonus. Those will all be ints. It's also going to have to keep track of which of the categories have been used and which have not been used. I'll use an array of booleans for that.
Here is a screen shot of my C++ version while it's running:
I like having those values by each of the categories so you can see how many points you got for something. So my Scorer is also going to have to keep an array of individual values. I'll keep them in the order they're listed in that screen shot. Both the boolean array that's keeping track of which categories have been used and the points array will be in that order.
My Scorer class constructor is going to create the two arrays (of size 13) set all the values to 0's, including the ints where I'm keeping tracks of totals. I know Java sets things to 0 by default but it's better to make it explicit. I might need a reset method that will set everything back to 0, so I'll make that. I'll probably need getters for my int fields. I'll definitely need a toString method that will print out a score sheet that looks like the above. And I think it makes sense to have a tally method to which you pass a DiceTray and a category. The tally method will examine the DiceTray to see how many points can be awarded for that category, given the current values of the dice in the tray, and will update the fields accordingly.
I'll implement the Scorer and then make another posting.
The Scorer is going to have to keep a total, a subtotal of the upper categories (the ones through the sixes), and a bonus. Those will all be ints. It's also going to have to keep track of which of the categories have been used and which have not been used. I'll use an array of booleans for that.
Here is a screen shot of my C++ version while it's running:
I like having those values by each of the categories so you can see how many points you got for something. So my Scorer is also going to have to keep an array of individual values. I'll keep them in the order they're listed in that screen shot. Both the boolean array that's keeping track of which categories have been used and the points array will be in that order.
My Scorer class constructor is going to create the two arrays (of size 13) set all the values to 0's, including the ints where I'm keeping tracks of totals. I know Java sets things to 0 by default but it's better to make it explicit. I might need a reset method that will set everything back to 0, so I'll make that. I'll probably need getters for my int fields. I'll definitely need a toString method that will print out a score sheet that looks like the above. And I think it makes sense to have a tally method to which you pass a DiceTray and a category. The tally method will examine the DiceTray to see how many points can be awarded for that category, given the current values of the dice in the tray, and will update the fields accordingly.
I'll implement the Scorer and then make another posting.
Starting Yahtzee
Thinking about each of you and how you should approach this project, first you really have to understand how to play the game of Yahtzee. I would suggest that you play the game online if you don't understand how it works. There is a version here: http://www.yahtzeeonline.org/ Click Roll each time you want to roll -- you get up to three rolls per round. Once you are out of rolls or have a combination that you can use, click on one of the boxes at the top that represent the scoring categories and hit Enter. To keep a die at its current value so that rerolling doesn't change it, click Hold by that die.
We won't be implementing a pretty GUI (graphical user interface) for the game, but anybody who knows how to do that can go right on and do it. If you watch this week's webinar you can see how a version I wrote in C++ a few years back runs in a console window. In C++ I could clear the screen before I printed the "board" so it appears that the stuff on screen isn't scrolling. We can't do that in Java so you can just let your output scroll.
I'm going to begin with the tray of dice. First I'll make a class called Die that represents just one die. I'm going to make a constructor for a Die that sets it to a random value between 1 and 6, a roll method that does the same thing, and a getValue method that returns the value of the die. Once I have this Die class, I'll make the DiceTray class. The field in that class will be an array of five Die. In the constructor of the DiceTray class, I'll create the array and then I'll walk through the array and create the Die objects. Like this:
public DiceTray()
{
tray = new Die[5];
for (int i = 0; i < 5; i++)
{
tray[i] = new Die();
}
}
So now I have a tray of dice. I need to be able to tell the tray that I want to roll only certain dice in the tray. I could make a roll method to which I would pass the index of the die to be rolled and that would work fine. But I think I'm going to handle this differently. I think I'm going to pass an array of five boolean values to the roll method so it can walk through the boolean array and use the values in that array to decide whether or not to roll the corresponding Die. This choice might make it a little harder to write the code that deals with playing the game because when the user says which dice need to be re-rolled, the code will have to create the array of booleans. But I'll worry about that later. For right now, here is my roll method in the DiceTray class:
public void roll(boolean[] rollMe)
{
for (int i = 0; i < 5; i++)
{
if (rollMe[i])
{
tray[i].roll();
}
}
}
I need to be able to get the values of the individual dice, so I'm going to pass an index to a getValue method and have that method call the getValue method in the Die class (on the die that corresponds to that index of the tray) and return the value of that die.
Finally, I need the DiceTray to be able to print itself so I need a toString method. I'm going to do what I did in my C++ program and not try to print the dots on the dice. Instead I'm going to print a number surrounded by lines. Like this:
_____ _____ _____ _____ _____
| 3 | | 1 | | 3 | | 4 | | 2 |
----- ----- ----- ----- -----
Finally I'll make a main in the DiceTray class that I'll use to test things with. Here is my idea for a main:
public static void main(String[] args)
{
DiceTray t = new DiceTray();
System.out.println(t);
boolean[] rollers = {true, true, false, false, true};
t.roll(rollers);
System.out.println(t);
}
That's the plan for right now. I'll do that and then come back to the blog.
We won't be implementing a pretty GUI (graphical user interface) for the game, but anybody who knows how to do that can go right on and do it. If you watch this week's webinar you can see how a version I wrote in C++ a few years back runs in a console window. In C++ I could clear the screen before I printed the "board" so it appears that the stuff on screen isn't scrolling. We can't do that in Java so you can just let your output scroll.
I'm going to begin with the tray of dice. First I'll make a class called Die that represents just one die. I'm going to make a constructor for a Die that sets it to a random value between 1 and 6, a roll method that does the same thing, and a getValue method that returns the value of the die. Once I have this Die class, I'll make the DiceTray class. The field in that class will be an array of five Die. In the constructor of the DiceTray class, I'll create the array and then I'll walk through the array and create the Die objects. Like this:
public DiceTray()
{
tray = new Die[5];
for (int i = 0; i < 5; i++)
{
tray[i] = new Die();
}
}
So now I have a tray of dice. I need to be able to tell the tray that I want to roll only certain dice in the tray. I could make a roll method to which I would pass the index of the die to be rolled and that would work fine. But I think I'm going to handle this differently. I think I'm going to pass an array of five boolean values to the roll method so it can walk through the boolean array and use the values in that array to decide whether or not to roll the corresponding Die. This choice might make it a little harder to write the code that deals with playing the game because when the user says which dice need to be re-rolled, the code will have to create the array of booleans. But I'll worry about that later. For right now, here is my roll method in the DiceTray class:
public void roll(boolean[] rollMe)
{
for (int i = 0; i < 5; i++)
{
if (rollMe[i])
{
tray[i].roll();
}
}
}
I need to be able to get the values of the individual dice, so I'm going to pass an index to a getValue method and have that method call the getValue method in the Die class (on the die that corresponds to that index of the tray) and return the value of that die.
Finally, I need the DiceTray to be able to print itself so I need a toString method. I'm going to do what I did in my C++ program and not try to print the dots on the dice. Instead I'm going to print a number surrounded by lines. Like this:
_____ _____ _____ _____ _____
| 3 | | 1 | | 3 | | 4 | | 2 |
----- ----- ----- ----- -----
Finally I'll make a main in the DiceTray class that I'll use to test things with. Here is my idea for a main:
public static void main(String[] args)
{
DiceTray t = new DiceTray();
System.out.println(t);
boolean[] rollers = {true, true, false, false, true};
t.roll(rollers);
System.out.println(t);
}
That's the plan for right now. I'll do that and then come back to the blog.
Thursday, July 4, 2013
Finished the program
This is a time-consuming program to write. Those are the fun ones, though, because they make you feel good when they work.
I ended up adding some methods to my Ticket class so that I could get some of the information off a ticket when I was producing the report. I ended up with the two constructors, getClient, getAgent, getProblem, getTicketID, toString, and equals as methods in the Ticket class.
In the TechSupportSystem class I ended up with the following:
The time stuff is a little confusing. Here is an example.
Say that the client is a Basic level client and his request came in 50 minutes ago. We have promised to fix problems for Basic clients in 60 minutes so we only have 10 minutes left. Say that we assign the ticket to Brandon who averages 10 minutes per machine. In that case we can project that the request is on time. But if we assign the ticket to Dee who averages 20 minutes per machine, then we can project that we are 10 minutes behind schedule.
When you are assigning tickets to agents, you will always have one agent who handles PCs, one who handles Macs, and one who can handle anything. Just match the client's system to the specialty of the agents. Assign PCs to the PC agent, Macs to the Mac agent, and all others to the agent who can handle anything.
Keep working. To make the wisest use of your time, write the easy classes first and then work on Ticket and TechSupportSystem. I found it useful to have the text files open in TextPad along with the Java files I was working on. I also compiled and tested as I worked. Saving compilation and testing until the end is just asking to be frustrated beyond words.
I ended up adding some methods to my Ticket class so that I could get some of the information off a ticket when I was producing the report. I ended up with the two constructors, getClient, getAgent, getProblem, getTicketID, toString, and equals as methods in the Ticket class.
In the TechSupportSystem class I ended up with the following:
- the constructor
- getDate
- getFileNames
- readTickets
- readOneTicket
- readAgents
- readOneAgent
- main
The time stuff is a little confusing. Here is an example.
Say that the client is a Basic level client and his request came in 50 minutes ago. We have promised to fix problems for Basic clients in 60 minutes so we only have 10 minutes left. Say that we assign the ticket to Brandon who averages 10 minutes per machine. In that case we can project that the request is on time. But if we assign the ticket to Dee who averages 20 minutes per machine, then we can project that we are 10 minutes behind schedule.
When you are assigning tickets to agents, you will always have one agent who handles PCs, one who handles Macs, and one who can handle anything. Just match the client's system to the specialty of the agents. Assign PCs to the PC agent, Macs to the Mac agent, and all others to the agent who can handle anything.
Keep working. To make the wisest use of your time, write the easy classes first and then work on Ticket and TechSupportSystem. I found it useful to have the text files open in TextPad along with the Java files I was working on. I also compiled and tested as I worked. Saving compilation and testing until the end is just asking to be frustrated beyond words.
Subscribe to:
Posts (Atom)


