You are on page 1of 30

Mehran Sahami Handout #33

CS 106A November 5, 2007


Debugging
Thanks to Eric Roberts and Nick Parlante for portions of this handout.

Much of your time as a computer programmer will likely be spent debugging. This
phenomena is best described by a quotation from one of the first computer pioneers,
Maurice Wilkes:

easv to get programs right as we had thought. We had to discover debugging. I
can remember the exact instant when I realized that a large part of mv life from
then on was going to be spent in finding mistakes in mv own programs.
Maurice Wilkes, 1949

In order to be better prepared to undertake the more complex future debugging that you
will be doing, we aim to give you here both a sense of the philosophy of debugging as
well as to teach you how to use some of the practical tips that make testing and debugging
easier.

The philosophy of debugging
Debugging is one of the most creative and intellectually challenging aspects of
programming. It can also be one of the most frustrating. To a large extent, the problems
that people face debugging programs are not so much technical as they are psychological.
To become successful debuggers, you must learn to think in a different way. There is no
(given below) will probably help. What you need is insight, creativity, logic, and
determination. I've heard that Diet Coke

As computer scientists, it is important to remember that the programming process leads
you through a series of tasks and roles:
7DVN 5ROH
Design Architect
Coding Engineer
Testing Vandal
Debugging Detective

These roles require you to adopt distinct strategies and goals, and it is often difficult to
shift your perspective from one to another. Although debugging can often be very
difficult, it can be done. It will at times take all of the skill and creativity at your disposal,
e task.

Debugging is an important skill that you will use every day if you continue in Computer
Science or any related field. Even though it is the final task of those listed above, it is
certainly not the least important. You should always plan ahead and allow sufficient time
for testing and debugging, as it is required if you expect to produce quality software. In
addition, you should make a concentrated effort to develop these skills now, as they will
be even more important as programs become more complicated later in the quarter.

http://technicalsupportindia.blogspot.com/
id279093 pdfMachine by Broadgun Software - a great PDF writer! - a great PDF creator! - http://www.pdfmachine.com http://www.broadgun.com
2

The 11 Truths of Debugging
1. Intuition and hunches are great you just have to test them out. When a hunch and a fact
collide, the fact wins. That's life in the city.
2.
weird behavior. Everyone is capable producing extremely simple and obvious errors from
time to time. Look at code critically ies of simple
statements assuming that they are too simple to be wrong.
3. The clue to what is wrong in your code is in the values of your variables and the flow of
control. Try to see what the facts are pointing to. The computer is not trying to mislead
you. Work from the facts.
4. Be systematic and persistent. . The bug is not moving around in your code,
trying to trick or evade you. It is just sitting in one place, doing the wrong thing in the same
way every time.
5. If you code was working a min what was the last thing you
changed? This incredibly reliable rule of thumb is the reason your section leader told you
to test your code as you go rather than all at once.
6. Do not change your code haphazardly trying to track down a bug. This is sort of like a
scientist who changes more than one variable in an experiment at a time. It makes the
observed behavior much more difficult to interpret, and you tend to introduce new bugs.
7. If you find some wrong code that does not seem to be related to the bug you were tracking,
fix the wrong code anyway. Many times the wrong code was related to or obscured the bug
in a way you had not imagined.
8. You should be able to explain in Sherlock Holmes style the series of facts, tests, and
deduct
then you should be able to give an argument to a critical third party detailing why each one
of your functions cannot contain the bug. One of these arguments will contain a flaw since
one of your functions does in fact contain a bug. Trying to construct the arguments may
help you to see the flaw.
9.
when your instinct is that the function is innocent. Only when the facts have proven
without question that the function is not the source of the problem should you assume it to
be correct.
10. Although you need to be systematic, there is still an enormous amount of room for beliefs,
hunches, guesses, etc. Use your intuition about where the bug probably is to direct the
order that you check things in your systematic search. Check the functions you suspect the
most first. Good instincts will come with experience.
11. Debugging depends on an objective and reasoned approach. It depends on overall
perspective and understanding of the workings of your code. Debugging code is more
mentally demanding than writing code. The longer you try to track down a bug without
success, the less perspective you tend to have. Realize when you have lost the perspective
on your code to debug. Take a break. Get some sleep. You cannot debug when you are not
seeing things clearly. Many times a programmer can spend hours late at night hunting for a
bug only to finally give up at 4:00A.M. The next day, they find the bug in 10 minutes. What
allowed them to find the bug the next day so quickly? Maybe they just needed some sleep
and time for perspective. Or maybe their subconscious figured it out while they were asleep.

Nick Parlante, Stanford University

http://technicalsupportindia.blogspot.com/
3

Using an online debugger
Because debugging is a difficult but nonetheless critical task, it is important to learn the
tricks of the trade. The most important of these tricks is to get the computer to show you
, after all, is there in front
you can have it show you its work as it goes. Modern programming environments like
Eclipse come equipped with a debugger, which is a special facility for monitoring a
program as it runs. By using the Eclipse debugger, for example, you can step through the
operation of your program and watch it work. Using the debugger helps you build up a
good sense of what your program is doing, and often points the way to the mistake.

To illustrate the operation of the Eclipse debugger in as concrete a way as possible, let's
look at how we might us the debugger to find bugs in the Roulette.java program
shown in Figure 2 below. As the bug icons indicate, the program is buggy. As a
programmer, it is your job to figure out why. The remainder of this handout describes the
techniques you might use to look for bugs with the help of the Eclipse debugger.
http://technicalsupportindia.blogspot.com/
4


Figure 2. Buggy program intended to play a simplified form of roulette

/*
* File: Roulette.java
* -------------------
* This program simulates a small part of the casino game of
* roulette.
*/

import acm.program.*;
import acm.util.*;

public class Roulette extends ConsoleProgram {

/** Amount of cash with which the player starts */
private static final int STARTING_MONEY = 100;

/** Amount wagered in each game */
private static final int WAGER_AMOUNT = 10;


/** Runs the program */
public void run() {
giveInstructions();
playRoulette();
}



/**
* Plays roulette until the user runs out of money.
*/
private void playRoulette() {
int money = STARTING_MONEY;
while (money > 0) {
println("You now have $" + money + ".");
String bet = readLine("Enter betting category: ");
int outcome = spinRouletteWheel();
if (isWinningCategory(outcome, bet)) {
println("That number is " + bet + " so you win.");
money += WAGER_AMOUNT;
} else {
println("That number is not " + bet + " so you lose.");
money -= WAGER_AMOUNT;
}
}
println("You ran out of money.");
}


















http://technicalsupportindia.blogspot.com/
5
Figure 2. Buggy program intended to play a simplified form of roulette (continued)


/**
* Simulates the spinning of the roulette wheel. The method
* returns the number of the slot into which the ball fell.
*/
private int spinRouletteWheel() {
println("The ball lands in " + rgen.nextInt(0, 36) + ".");
return rgen.nextInt(0, 36);
}

/*
* Returns true if the outcome matches the category specified
* by bet. If the player chooses an illegal betting
* category, this function always returns false.
*/
private boolean isWinningCategory(int outcome, String bet) {


if (bet == "odd") {
return outcome % 2 == 1;
} else if (bet == "even") {
return (outcome % 2 == 0);
} else if (bet == "low") {
return (1 <= outcome && outcome <= 18);
} else if (bet == "high") {
return (19 <= outcome && outcome <= 36);
} else {
return (false);
}
}



/**
* Welcomes the player to the game and gives instructions on
* the rules of roulette.
*/
private void giveInstructions() {
println("Welcome to the roulette table!");
println("Roulette is played with a large wheel divided into");
println("compartments numbered from 0 to 36. Each player");
println("places bets on a playing field marked with the");
println("numbers and various categories. In this game,");
println("the only legal bets are the following categories:");
println("odd, even, low, or high. Note that 0 is not in any");
println("category. After the bet is placed, the wheel is");
println("spun, and a marble is dropped inside, which bounces");
println("around until it lands in a compartment. If the");
println("compartment matches the betting category you chose,");
println("you win back your wager plus an equal amount. If");
println("not, you lose your wager.");
}

/* Private instance variables */

private RandomGenerator rgen = new RandomGenerator();
}



http://technicalsupportindia.blogspot.com/
6
Assessing the symptoms
Before you start using the debugger, it is always valuable to run the program to get a
sense of what the problems might be. If you run the Roulette program, you might see
the following sample run:

that 20 s happily taken your wager.
Something is definitely wrong.

For programs that use random numbers, it is important to debug the program in a
deterministic environment. For this reason, it is useful to set the random number
generator to a particular seed before proceeding. You can do that by adding the following
line to the run method:

rgen.setSeed(1);

That way your program will work the same way each time, so that you can always get
back to the same situation. With this new statement, the output (leaving out the
instructions this time) looks like this:

http://technicalsupportindia.blogspot.com/
7
The Eclipse debugger
One of the easiest ways to figure out what the program is doing is to use the Eclipse
debugger to help with that process. When you run a project under Eclipse, you can use
the debugger to set breakpoints in your code, which will enable you to stop it at
interesting places, step through the program one step at a time, examine variables, and do
other useful things.

Debugging, however, is a creative enterprise, and there is no magic technique that tells
you what to do. You need to use your intuition, guided by the data that you have. In the
Roulette program, your intuition is likely to suggest that the problem is in the method
isWinningCategory, given that the sample runs suggest on the basis of what is still a
pretty small sample that the computer is never allowing the user to win. Thus, you
might scroll the editor window down to isWinningCategory and set a breakpoint on
the first line, so that the program will stop there. To do so, double-click in the just barely
gray margin (which will surely show up as white on the photocopies), at which point a
small circle appears indicating that there is now a breakpoint on that line, as shown:


connected, which you can do by clicking on the bug icon ( ) that appears to the left of
the green triangle on the Eclipse tool bar. Your program will then start running, display
all of the instructions, and then again ask you to select a category. Suppose that you again
enter "even" and watch as the program again tells you that the wheel has landed in
number 27 (given that it is now behaving deterministically). At that point, the program
calls isWinningCategory, where it stops at the breakpoint as shown below. (Note that
you may first see a dialog box which says "This kind of launch is configured to open the
Stanford Debugger perspective when it suspends. Do you want to open this perspective
now?" If you do see this dialog, go ahead and click "Yes".)


The arrow and the background highlight mark the line of code you are about to execute.
http://technicalsupportindia.blogspot.com/
8
program. If you scroll this window down a couple of lines, you see the following:



The bottom lines tell you where you are in the execution. You are currently at line 61 of
isWinningCategory, which was called from line 35 of playRoulette, which was in
turn called from line 13 of run. Each of these constitutes a stack frame, as described in
the text.

current values of variables in the current stack frame, which looks like this:



In this frame, the local variables are simply the parameters to isWinningCategory. We
chose the category "even", which appears as the value of the variable bet, and the
variable outcome has the value 15.

But wait a minute, the outcome as shown on the console indicates that the ball landed in
27. Why does this frame show it as 15? Clearly the computer is doing something wrong.

In point of fact, that diagnosis tempting as it sometimes is for all of us is almost
certainly incorrect. The computer is almost certainly doing exactly what you told it to do.
The problem is that the programmer has done something wrong. The task now is to find
out what that is. The problem is obviously earlier in the program than intuition might
suggest, so it is necessary to go back and insert an earlier breakpoint.

http://technicalsupportindia.blogspot.com/
9
You can now go back and stop the Roulette program, either by clicking in its close box
or by clicking on the red square in the Debug window. In the editor window, you can
double-click on the first line of spinRouletteWheel to see wh
you debug the program again, it will soon stop in the following state:

Think about what you know. The spinRouletteWheel method prints out one outcome,
but somewhere later on that value seems to be different. Armed with that understanding
of the problem, look at the code for spinRouletteWheel:
private int spinRouletteWheel() {
println("The ball lands in " + rgen.nextInt(0, 36) + ".");
return rgen.nextInt(0, 36);
}

Very soon, the problem will jump out at you. The println method generates a random
number in the range 0 to 36, but the return statement goes on and generates a new one.
There is nothing to guarantee that the value spinRouletteWheel prints and the value it
returns will be the same. You need to rewrite the method as follows:
private int spinRouletteWheel() {
int spin = rgen.nextInt(0, 36);
println("The ball lands in " + spin + ".");
return spin;
}

t the debugger.
Unfortunately, the output looks exactly as it did before. You still lose every time:

Back to the drawing board.
http://technicalsupportindia.blogspot.com/
10
Finding the critical clues
As always in debugging, your primary goal is to figure out what your program is doing
rather than why is it not doing what you wanted. To do so, you need to gather as much
k
and look for more clues.

You still have the breakpoints in place, so try debugging the program and letting it run to
the breakpoint in isWinningCategory. To save time, however, it is probably worth
changing your wager given that you know that the first
category "odd" rather than "even", since that will allow you to follow through what
happens when you have picked the correct category.

When you arrive at the breakpoint, things look a little better. The variables window now
looks like this:



The value of outcome shows correctly as 27, and we are betting on "odd". Things should
therefore be good for the player, but something is still going wrong.

The most useful tools at this point are the various controls that appear along the top of the
Debug window, of which the following are the most important:


Resume. Continues the program from where it last stopped, either because
of hitting a breakpoint or because the user clicked Suspend.

Suspend. Stops the program as if it had hit a breakpoint.

Terminate. Exits from the program entirely.

Step Into. Executes one statement of the program and then stops again. If
that statement includes a method call, the program will stop at the first line
of that method. As noted below, this option is not as useful as Step Over.

Step Over. Executes one statement of the program at this level and then
stops again. Any method calls in the statement are executed through to
completion unless they contain explicit breakpoints.

Step Return. Continues to execute this method until it returns, after which
the debugger stops in the caller.
http://technicalsupportindia.blogspot.com/
11
The three stepping options are extremely useful, but you need to take some care in
choosing which one to use. In most cases, Step Over is the right option to use.
Intuitively, it has the effect of continuing to the next step at this level, allowing you to
stay at the same conceptual level of abstraction. If the current statements calls one of
your own methods, Step Into may be exactly what you want, because that will allow you
to debug that subsidiary method if necessary. The danger with Step Into arises when the
current statement contains calls to library methods such as println. In such cases, Step
Into will try to step through the code for those methods, which can be extremely
confusing.

The source window in the debugger now shows the following situation:



Here, the program is stopped at a line that includes n
which of Step Into or Step Over
probably best to go with Step Over unless there is a reason not to.

What you would like to have happen at this point is for the program to determine that bet
is in fact equal to "odd" and continue on to the return statement on the next line. But it
Step Over, you end up in the following position:



http://technicalsupportindia.blogspot.com/
12
Avoiding value rigidity
If you go look at the code for isWinningCategory, many of you will see the problem
immediately. On the other hand, others might stare right at the bug and not see anything.
In this case, the way in which the difficulty of seeing the bug manifests itself has to do
with thinking too literally about the express
you want them to mean as opposed to what they in fact do mean. Here, the problem lies
in the if tests, starting with the first:

if (bet == "odd")

bet is equal to the string "odd"
else could it mean? The answer is that Java interprets the == operator for objects in a
bet is the
same object as the constant string "odd". bet was read in from the user, this
condition will never be true.

The fix in this case is to replace the instances of the == operator with calls to equals or,
better yet, equalsIgnoreCase. Now the isWinningCategory method looks like this:

private boolean isWinningCategory(int outcome, String bet) {
if (bet.equalsIgnoreCase("odd")) {
return outcome % 2 == 1;
} else if (bet.equalsIgnoreCase("even")) {
return (outcome % 2 == 0);
} else if (bet.equalsIgnoreCase("low")) {
return (1 <= outcome && outcome <= 18);
} else if (bet.equalsIgnoreCase("high")) {
return (19 <= outcome && outcome <= 36);
} else {
return (false);
}
}

Seeing the process through
One of the most common failures in the debugging process is inadequate testing. After
making the corrections described in the preceding sections, you could run this program
for some time before you discovered anything amiss. There is, however, one additional
problem. The instructions generated by the program go out of their way to remind you
that the number 0 is not considered part of any category. The current implementation of
isWinningCategory correctly determines that 0 is neither high or low, but does allow it
to count as even. This error if it were allowed to stand would give the player a better-
than-50/50 chance of winning by betting on "even", which would undoubtedly be of
some concern to the owners of the casino. To avoid the problem, the implementation of
isWinningCategory must specifically disallow 0 when it tests for even numbers. Thus,
the code should look as shown on the next page.

http://technicalsupportindia.blogspot.com/
13
private boolean isWinningCategory(int outcome, String bet) {
if (bet.equalsIgnoreCase("odd")) {
return outcome % 2 == 1;
} else if (bet.equalsIgnoreCase("even")) {
return (outcome % 2 == 0 && outcome != 0);
} else if (bet.equalsIgnoreCase("low")) {
return (1 <= outcome && outcome <= 18);
} else if (bet.equalsIgnoreCase("high")) {
return (19 <= outcome && outcome <= 36);
} else {
return (false);
}
}

There is no strategy that can guarantee that your program is ever bug free. Testing helps,
when you design, write, test, and debug your programs, you will reduce the number of
bugs, but you will be unlikely to eliminate them entirely.

Getting back to the regular Editor perspective
Once you have completed using the debugger and want to return to using Eclipse in the
regular "Editor" perspective (the one that you've been using most of the time), you can
simply go to the "Stanford" menu and pick the "Switch to Editor" selection.
http://technicalsupportindia.blogspot.com/
Mehran Sahami Handout #35
CS 106A November 5, 2007
Assignment #5 Yahtzee!
Due: 3:15pm on Wednesday, November 14th
Based on a handout written by Eric Roberts and Julie Zelenski.

Note: Yahtzee is the trademarked name of a game produced by Hasbro. We refer to this
game for educational purposes only. Okay, we also like to have fun playing the game.
But then again, something can be both "educational" and "fun" (hopefully, like CS106A),
so we shouldn't run into any problems there. Thanks for listening. We now return to our
previously scheduled assignment.

Arrays, arrays, everywhere...
Now that you have have arrays at your disposal, your ability to write interesting programs
takes a dramatic leap forward. To solidify your understanding, Assignment #5 uses
arrays in a variety of contexts to implement a popular multiplayer dice game. There are
arrays for the dice, arrays for the dice to reroll, arrays for the player names, arrays for a
(that is, a 2-dimensional array) to handle the
the
concept of arrays.

The goal
Your task is to create a computer version of the game Yahtzee . Some of you may have
dice and one to four players. A round of the game consists of each player taking a turn.
On each turn, a player rolls the five dice with the hope of getting them into a
the dice again. If the second roll is still unsuccessful, the player may roll any or all of the
dice once more. By the end of the third roll, however, the player must assign the final
dice configuration to one of the thirteen categories on the scorecard. If the dice
configuration meets the criteria for that category, the player receives the appropriate score
for that category; otherwise the score for that category is 0. Since there are thirteen
categories and each category is used exactly once, a game consists of thirteen rounds.
After the thirteenth round, all players will have received scores for all categories. The
player with the total highest score is declared the winner.

http://technicalsupportindia.blogspot.com/
2
Dice categories
The thirteen categories of dice configurations and their scores are:

1. Ones. Any dice configuration is valid for this category. The score is equal to the

2 6. Twos, Threes, Fours, Fives, and Sixes. (same as above but for different values).
Any dice configuration is valid for these categories. The score is equal to the sum

7. Three of a Kind. At least three of the dice must show the same value. The score is
equal to the sum of all of the values showing on the dice.
8. Four of a Kind. At least four of the dice must show the same value. The score is
equal to the sum of all of the values showing on the dice.
9. Full House. The dice must show three of one value and two of another value. The
score is 25 points.
10. Small Straight. The dice must contain at least four consecutive values, such as the
sequence 2-3-4-5. The score is 30 points.
11. Large Straight. The dice must contain five consecutive values, such as the
sequence 1-2-3-4-5. The score is 40 points.
12. Yahtzee! All of the dice must show the same value.. The score is 50 points.
13. Chance. Any dice configuration is valid for this category. The score is equal to the
sum of all of the values showing on the dice.

Running the applet
On the "Assignments" page on the CS106A web site, you will find a demo applet that you
methods to implement the graphics and mouse interaction have been written for you.
This section describes the way the program works as a whole.

When the program begins, it displays a welcome message and asks the user to enter the
number of players. It then asks the user to enter the names of the players, one at a time.
Suppose that there are two players Eric and Julie locked in a cutthroat, head-to-head,
winner-take-all showdown. After you use the pop-up dialog boxes to enter the names
Eric and Julie, the applet displays the starting Yahtzee scorecard and dice in the
graphics window, as shown in Figure 1 on the next page.

http://technicalsupportindia.blogspot.com/
3
Figure 1 (After configuring a new two-player game with players "Eric" and "Julie")



The Yahtzee scoreboard
that make up the game are divided into two sections. The upper section contains the
categories Ones, Twos, Threes, and so forth. At the end of the game, the values in these
categories are added to generated the value in the entry labeled Upper Score. Moreover,
63 or more, that player is
awarded a 35-point bonus on the next line. The scores in the lower section of the
scorecard are also added together to generate the entry labeled Lower Score. The total
score for each player is then computed by adding together the upper score, the bonus (if
any), and the lower score.


Playing a sample game
The game shown in Figure 1 is now ready to begin. Eric is first, so his name is
highlighted in the scorecard, which also displays the following message:

Eric's turn. Click "Roll Dice" button to roll the dice.

When Eric clicks the Roll Dice button, the dice are randomly rolled, resulting in a display
that looks like the diagram shown in Figure 2 at the top of the next page.
http://technicalsupportindia.blogspot.com/
4



At first gl
has a chance for the Yahtzee category, Eric wants to reroll the 3 and the 4. To indicate
this choice, all Eric has to do is click on these two dice. Doing so highlights these dice as
follows:

Figure 3 (Eric has selected the 3 and 4 and is ready to reroll)


To reroll the selected dice, all the player has to do is click on the Roll again button. Until
this button is clicked, the player can select or deselect any particular die by clicking on it.
For example, if Eric decided instead to try for some kind of straight, he could deselect the
3 and the 4 by clicking on them and then selecting new dice presumably two of the
by clicking on these.

Always overconfident, Eric decides to go for the Yahtzee and rerolls just the 3 and 4.
http://technicalsupportindia.blogspot.com/
5
up with the three

Three of a Kind)


Yahtzee, he did come up with a reasonably decent
Three of a Kind. When asked to choose a category, Eric clicks Three of a Kind, and a
score of 24 points will be recorded in the column.

ulie has better karma than Eric, but we won't talk about that right
now. Anyway, Figure 5 shows the configuration of the dice at the end of her three rolls:
Full
House, which is worth 25 points and gives her the early lead.

urn, as she is choosing her category)


http://technicalsupportindia.blogspot.com/
6
a large straight. He rolls the single die again and gets . . . a 2! He made it! Of course,
Roll again button ZLWKRXW
VHOHFWLQJ DQ\ PRUH GLFH and then selects the Large Straight category to end his turn, as
shown in Figure 6.

Figure 6 (Eric getting ready to take the lead with his large straight)


rays for another 3!
She rolls the single die and gets . . . a 1. Dejectedly, she uses the result for Threes; which
earns 12 points for her efforts. Eric goes into the third round with the commanding lead
shown in Figure 7.

Figure 7 (State of the scorecard at the beginning of the third round)


http://technicalsupportindia.blogspot.com/
7
The game continues in a similar fashion. On each turn, players must

1. Click on the Roll Dice button to set up the initial roll of all five dice.
2. Select a set of dice and then click the Roll again button to reroll the selected dice.
3. Repeat step 2 to generate the final dice configuration after the third roll.
4. Click on a category to store the score in the appropriate box.

configuration of the dice, because there are no appropriate categories left. In such cases,
the player simply scores 0 in the selected box.

-forward to Round #13 the final round where we find the tide has turned:

Figure 8 (At the beginning of the final round


Eric is in trouble. Julie has already gotten her Yahtzee, and Eric desperately needs his. He
and 4. Now he gets a 5, 6, and 3. He rolls these same dice yet another time. Nothing
much comes of it just a 2, 4, and 6. Eric is forced to use this motley collection in the
Yahtzee category, which gets him a big, fat 0 (since it does not satisfy the criteria for an
actual Yahtzee). Too bad Eric sometimes that's just how life turns out.

Sixes. She is already headed for victory, but she plows
Sixes.

Since the game is now over, the upper and lower scores are computed and if applicable,
score of 273 to 192 (shown on the next page)!

http://technicalsupportindia.blogspot.com/
8
Figure 9 (At the end of the game)



What is provided in the starter project
The starter project provides the following:

A Yahtzee.java file that you need to expand to play the game. The initialization
code, however, is already provided.
A YahtzeeConstants.java file that defines several constants used in the game. The
contents of this file appear in Figure 10 on the next page. Some of these are simple
conveniences, such as defining the number of dice to be the named constant N_DICE.
The most important entries, for you to understand are the category constants at the end
of the file. These constants form an enumeration that allows you to refer to constants
on the score sheet. These constants are available to the Yahtzee class because it
declares itself as implementing the YahtzeeConstants interface.
A precompiled class called YahtzeeDisplay that manages all the graphics and event
3 and 4, so
more detail in the section that follows.
A precompiled class called YahtzeeMagicStub that exports a method checkCategory
that will allow you to get your program working a little sooner. You have to write this
method on your own before you submit your assignment, but having a working
implementation available means that you can test your scoring methods without having
to work out the details of this method as well.

http://technicalsupportindia.blogspot.com/
9
Figure 10. The YahtzeeConstants interface

/*
* File: YahtzeeConstants.java
* ---------------------------
* This file declares several constants that are shared by the
* different modules in the Yahtzee game.
*/

public interface YahtzeeConstants {

/** The width of the application window */
public static final int APPLICATION_WIDTH = 600;

/** The height of the application window */
public static final int APPLICATION_HEIGHT = 350;

/** The number of dice in the game */
public static final int N_DICE = 5;

/** The maximum number of players */
public static final int MAX_PLAYERS = 4;

/** The total number of categories */
public static final int N_CATEGORIES = 17;

/** The number of categories in which the player can score */
public static final int N_SCORING_CATEGORIES = 13;

/* The constants that specify categories on the scoresheet */
public static final int ONES = 1;
public static final int TWOS = 2;
public static final int THREES = 3;
public static final int FOURS = 4;
public static final int FIVES = 5;
public static final int SIXES = 6;
public static final int UPPER_SCORE = 7;
public static final int UPPER_BONUS = 8;
public static final int THREE_OF_A_KIND = 9;
public static final int FOUR_OF_A_KIND = 10;
public static final int FULL_HOUSE = 11;
public static final int SMALL_STRAIGHT = 12;
public static final int LARGE_STRAIGHT = 13;
public static final int YAHTZEE = 14;
public static final int CHANCE = 15;
public static final int LOWER_SCORE = 16;
public static final int TOTAL = 17;

}

http://technicalsupportindia.blogspot.com/
10

The YahtzeeDisplay class
As noted in the preceding section, the starter project contains a precompiled class called
YahtzeeDisplay that manages the drawing and event-handling. This section of the
handout offers a brief overview of the methods, which should be enough to get you
started. The assignments area of the CS 106A web site contains a javadoc file for
YahtzeeDisplay that displays the full story, the important parts of which are reproduced
as Figure 11 on the next two pages.

There is a constructor method YahtzeeDisplay that creates the initial display. It takes
as parameters the GCanvas for the Yahtzee program and an array containing the names
of each player. The call to this method is included in the Yahtzee.java starter file

The waitForPlayerToClickRoll
turn. It waits for the player to click the Roll Dice button indicating they are ready to take
their chances.
The displayDice method draws the dice on the board. It takes an array of N_DICE
values. You call this method to draw the random dice results you generated on each
roll or reroll.
The waitForPlayerToSelectDice method allows the player to click on the dice to
select and deselect which ones should be rerolled. You call this method on the second
an
The isDieSelected method allows you to check whether the player has chosen to
reroll a particular die. You call this method after waitForPlayerToSelectDice
returns to determine which dice you need to reroll and which you can leave alone.
The waitForPlayerToSelectCategory method allows the player to click on the
when they need to choose the category to assign the current dice configuration. The
method returns the number of a category, as defined in YahtzeeConstants.
The updateScorecard method updates a score entry on the scorecard. You call this
port the latest score. It takes a player
number, a category, and a value, and updates the scorecard to display that value in the
proper row and column.
The printMessage method allows you to display a message at the bottom of the
graphics window. This method works exactly like println and allows you to include
values in exactly the same way. For example, if you want to display the message
Eric's turn.
with the name Eric replaced by the contents of the string variable name, you could use
the following call to printMessage:
display.printMessage(name + "'s turn.");
As this last example illustrates, any calls to the methods in the YahtzeeDisplay class
must include the variable display as the receiver. You are asking the display to print
a message and therefore must use the receiver-based style of method call.
http://technicalsupportindia.blogspot.com/
11
Figure 11. Entries in the YahtzeeDisplay class
public YahtzeeDisplay(GCanvas gc, String[] playerNames)
Creates a new YahtzeeDisplay object that adds its objects to the GCanvas specified by gc. The
playerNames parameter is an array consisting of the names of the players.

Usage: YahtzeeDisplay display = new YahtzeeDisplay(gc, playerNames);
Parameters: gc The GCanvas on which the board is displayed
playerNames An array containing the names of the players, indexed from 0.
public void waitForPlayerToClickRoll(int player)
Waits for the player to click the "Roll Dice" button to start the first dice roll. You will call this method
once at the beginning of each player's turn. The parameter is the index number of the player, which
ranges from 1 to nPlayers, where nPlayers is the number of players in the game. The method
highlights the player's name in the scorecard, erases any dice displayed from previous rolls, draws the
"Roll Dice" button, and then waits for the player to click the button. This method returns when the
button is pressed. At that point, it is your job to randomly roll the dice and call the displayDice
method.

Usage: display.waitForPlayerToClickRoll(player);
Parameter: player The index of the player, ranging from 1 to nPlayers
public void displayDice(int[] dice)
Draws the pictures of the dice on the screen. You pass one parameter, a zero-based integer array with
N_DICE entries, that contains the values to draw on the dice. Each value in the array must be a valid
die roll between 1 and 6; if not, displayDice will throw an ErrorException. You will need to call
this method after each roll or reroll of the dice to display the new random values.

Usage: display.displayDice(dice);
Parameter: dice An array of dice values, whose indices range from 0 to N_DICE - 1
public void waitForPlayerToSelectDice()
Allows the player to select which dice to reroll by clicking on the dice with the mouse. You will call
this method twice each player turn, giving them two additional chances to improve their roll. This
method draws the "Roll Again" button, and waits for the player to click on the dice to select and
deselect which ones they would like to reroll. The method returns only after the player has made a
selection and clicks the "Roll Again" button. Once the method returns, you can use the
isDieSelected method to determine whether the die should be rerolled.

Usage: display.waitForPlayerToSelectDice();
public boolean isDieSelected(int index)
Checks to see whether the die specified by index is selected. You call this method before each reroll to
determine whether this die needs to be updated.

Usage: if (display.isDieSelected(index)) . . .
Parameter: index The index number of the die, which ranges from 0 to N_DICE - 1
Returns: true if the die is selected, and false otherwise
public int waitForPlayerToSelectCategory()
Allows the user to select a category in which to place the score for this roll. You will call this method
once each turn after the player finishes rolling the dice. As its name suggests, the method waits for the
player to click on one of the categories and returns the index of the category, which will be one of the
constants defined in YahtzeeConstants. Note that this method does not check to see whether the
category is valid for the dice values or whether this category has already been used by this player.
Thus, you will need to include some error-checking in your program to test the result of
waitForPlayerToSelectCategory before you try to update the scorecard.

Usage: int category = display.waitForPlayerToSelectCategory();
Returns: The category number selected by the player
http://technicalsupportindia.blogspot.com/
12
Figure 11. Entries in the YahtzeeDisplay class (continued)
public void updateScorecard(int category, int player, int score)
Updates a value on the Yahtzee scorecard. You must call this method once each turn after the player
has finished rolling and has chosen the category in which to score the result. The parameters to the
method are the index of the category (which will be one of the constants defined in
YahtzeeConstants), the player number, and the score to be displayed in that cell of the scorecard.

Usage: display.updateScorecard(category, player, score);
Parameters: category The category number to update
player The player number (between 1 and nPlayers)
score The score to display in that box
public void printMessage(String message)
Prints a message on the bottom of the Yahtzee scorepad. The old message is cleared whenever any
YahtzeeDisplay method is called.

Usage: int category = display.waitForPlayerToSelectCategory();
Parameter: message The message string to display


Another point to which you should pay attention is that the methods in the
YahtzeeDisplay class take player numbers that run from 1 to the number of players, and
not from 0 to the number of players minus one. The latter is what you need for array
selection, but the former makes more sense to humans, who are unaccustomed to thinking
about a player 0. You might want to l g
design, although it should be rather straightforward to deal with.

Some strategies to consider
As always, we recommend first spending time thinking about the program before you
jump in and start coding. Consider what types of variables will be needed to store the
various information. How will you arrange the data and how will you pass it around in
the program? Sketching out a decomposition tree will be helpful here. Take time to
identify the parameters going into each method and the return value coming out. Also
consider how you plan to use the library routines in your solution. Be sure to read the
javadoc for YahtzeeDisplay (available from the "Assignments" page of the CS106A
web site) very carefully so that you thoroughly understand how the methods behave and
the kinds of parameters they require.

One of the most interesting (and challenging) array tasks you will be faced with is
determining whether a dice configuration meets the requirements for a given category,
and is therefore valid. For example, Three of a Kind requires a dice configuration in
which at least three of the dice show the same value, Small Straight requires at least four
of the dice values to be consecutive, and so forth. If a player assigns an invalid dice
configuration to a category, they receive 0 points for it.

To make it easier for you to get your program working, we have provided a method called
YahtzeeMagicStub.checkCategory, which tests to see whether an array of dice values
matches a particular category. If you call this method with the array of dice and the index
checkCategory returns true if the values of the dice
http://technicalsupportindia.blogspot.com/
13
stored in the array are valid for the category and false otherwise. Note some categories
(namely, Chance and Ones, Twos, etc.) accept any dice configuration; for these categories
checkCategory always returns true. The javadoc describing the class
YahtzeeMagicStub is available from the "Assignments" page of the CS106A web site,
but for your convenience, we note that the static method
YahtzeeMagicStub.checkCategory can be called as follows (assuming we have an
array of ints named dice that we want to check to see if it matches the Full House
category):

boolean p = YahtzeeMagicStub.checkCategory(dice, FULL_HOUSE);

In the early stages of your development, you can use our checkCategory method to help
you get up and running. Ultimately, however, you need to write this method yourself. As
you develop your own
You could, for example, write a method that tests the validity of, say, Three of a Kind, but
uses the implementation from YahtzeeMagicStub for everything else. When that works,
you could move on to take care of Four of a Kind, and then Yahtzee and Full House.
Once you have your own methods for checking the validity of these categories, move on
to tackling Small Straight and Large Straight.

For full credit, you should not use YahtzeeMagicStub.checkCategory anywhere in the
final version of your program. If you find determining the validity of a certain category
or categories too difficult, you may use our method, but you will lose points for each
category whose validity you do not check with your own implementation.

In a similar vein, look for other intermediate milestones you can aim for instead of
heading straight for the final goal and letting it overwhelm you. For example, it is easier
to get a single-player game working than a multi-player game. If there is only one player,
you can work with a single array of scores. After you can reliably play a single-person
array will be needed.

You also migh
are running in cheat mode, you can prompt the user to specify the values by typing them
in instead of choosing the dice randomly. Implementing this feature will make it easier
for you to check the various situations that can come up during the game, rather than
waiting and hoping for them to come up randomly at some point during your testing.

Hints and other random details
a great deal difference between determining the validity for Three of a
Kind, Four of a Kind, Yahtzee, and Full House.
a great deal of difference between determining the validity for Small
Straight and Large Straight.
Any dice configuration is valid for Ones, Twos, Threes, Fours, Fives, Sixes, and
Chance.

receives a score of 0.
http://technicalsupportindia.blogspot.com/
14
You should print text messages along the way to inform the players what to do next
(whose turn it is, when the player should roll, when to select dice for rerolling, when to
choose a category, who the winner is, etc.). You can use the demo applet provided on
the CS106A as a guide to the sorts of messages you should give the players.
Be sure to check for errors when the player selects the category to assign a dice
configuration. The user cannot re-use any previous category. Print a message if you
cannot honor their choice and have them select another.

anything on a subsequent roll, that player should click the Roll again button ZLWKRXW
VHOHFWLQJDQ\GLFH.
At the end
if their upper score is 63 or over), upper score, lower score, and final total.
Be sure to mark all methods as private unless you explicitly plan for them to be used
outside the module. The grading criteria that we will use for the assignment will
include a deduction along these lines.

Extensions
Since the standard assignment is pretty much a full implementation of the Yahtzee game,
vity stop you
occurred to us:
Add a high score feature. Save the top ten highest scores and names to a file and make
it persistent between runs of the program. Read the file when you start and print out the
hall of fame. If a player gets a score that preempts one of the early high scores,
congratulate them and update the file before you quit so it is recorded for next time.
Incorporate the bonus scores for multiple Yahtzees in a game. As long as you have not
entered a 0 in the Yahtzee box, the rules of the game give you a bonus chip worth 100
points for each additional Yahtzee you roll during the same game.
In this variant, each
player manages three simultaneous scorecard columns, as if they were playing for three
players at once. The player can assign a roll to any one of their three columns. All
entries are scored normally with respect to categories and validity, but the values in the
score consists of the sum of all three columns. This would make for a three-
dimensional array (an array of players who have any array of columns which are an
array of score entries) pretty tricky! Game play continues for 3*13 rounds, until all
players have filled in all entries in all three columns. The player with the highest total
score is the winner.

As always, you should only tackle extensions after you have completed and thoroughly
tested all the basic requirements. If you do create an extended version, please hand in
both a basic and an extended version to make it easier for us to verify the base
funct
include in one version. Be sure to describe in your comments where we should look for
your fun additions!
http://technicalsupportindia.blogspot.com/
Mehran Sahami Handout #34
CS 106A November 5, 2007
Section Handout #6: More Arrays and HashMaps
Portions of this handout by Eric Roberts

1. Image processing (Chapter 11, exercise 12, page 458)
Write a method flipHorizontal that works similarly to the flipVertical method
presented in the chapter except that it reverses the picture in the horizontal dimension.
Thus, if you had a GImage containing the image on the left ( 7KH
0LONPDLG c. 1659), calling flipHorizontal on that image would return a new GImage
as shown on the right:





2. Name Counts
Write a program that asks the user for a list of names (one per line) until the user enters a
blank line (i.e., just hits return when asked for a name). At that point the program should
print out KRZPDQ\WLPHV each name in the list was entered. You may find that using a
HashMap to keep track of the information entered by user may greatly simplify this
problem. A sample run of this program is shown below.


http://technicalsupportindia.blogspot.com/
Mehran Sahami Handout #34A
CS 106A November 7, 2007
Solutions to Section #6

1. Image processing


private GImage flipHorizontal(GImage image) {
int[][] array = image.getPixelArray();
int width = array[0].length;
int height = array.length;
for (int row = 0; row < height; row++) {
for (int p1 = 0; p1 < width / 2; p1++) {
int p2 = width - p1 - 1;
int temp = array[row][p1];
array[row][p1] = array[row][p2];
array[row][p2] = temp;
}
}
return new GImage(array);
}





Solution for Problem #2 Name Counts on back of page.
http://technicalsupportindia.blogspot.com/
2
2. Name Counts
/*
* File: CountNames.java
* ---------------------
* This program shows an example of using a HashMap. It reads a
* list of names from the user and list out how many times each name
* appeared in the list.
*/

import acm.program.*;
import java.util.*;

public class CountNames extends ConsoleProgram {

public void run() {
HashMap<String,Integer> nameMap = new HashMap<String,Integer>();

readNames(nameMap);
printMap(nameMap);
}


/*
* Reads a list of names from the user, storing names and how many
* times each appeared in the map that is passed in as a parameter.
*/
private void readNames(Map<String,Integer> map) {
while (true) {
String name = readLine("Enter name: ");
if (name.equals("")) break;

// See if that name previously appeared in the map. Update
// count if it did, or create a new count if it didn't.
Integer count = map.get(name);
if (count == null) {
count = new Integer(1);
} else {
count = new Integer(count + 1);
}

map.put(name, count);
}
}


/*
* Prints out list of entries (and associated counts) from the map
* that is passed in as a parameter.
*/
private void printMap(Map<String,Integer> map) {
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
int count = map.get(key);
println("Entry [" + key + "] has count " + count);
}
}

}
http://technicalsupportindia.blogspot.com/

You might also like