You are on page 1of 19

http://technicalsupportindia.blogspot.

com/

Mehran Sahami CS 106A

Assignment #4 Hangman Due: 3:15pm on Monday, November 5th

Handout #27 October 24, 2007

For this assignment, your mission is to write a program that plays the game of Hangman. As an assignment, Hangman serves two purposes. First, the program is designed to give you some practice writing programs that manipulate strings and files. Second, by extending the program using the graphical tools from Chapter 9, you will have a chance to work with multiple classes in a single application. When it plays Hangman, the computer first selects a secret word at random from a list built into the program. The program then prints out a row of dashes one for each letter in the secret word and asks the user to guess a letter. If the user guesses a letter that is in the word, the word is redisplayed with all instances of that letter shown in the correct positions, along with any letters correctly guessed on previous turns. If the letter does not appear in the word, the user is charged with an incorrect guess. The user keeps guessing letters until either (1) the user has correctly guessed all the letters in the word or (2) the user has made eight incorrect guesses. Two sample runs that illustrate the play of the game are shown in Figure 1 on the next page. When it is played by children, the real fascination (a somewhat morbid fascination, I suppose) from Hangman comes from the fact that incorrect guesses are recorded by drawing an evolving picture of the user being hanged at a scaffold. For each incorrect guess, a new part of a stick-figure body first the head, then the body, then each arm, each leg, and finally each foot is added to the scaffold until the hanging is complete. For example, the three diagrams below show the drawing after the first incorrect guess (just the head), the third (the head, body, and left arm), and the diagram at the tragic end of a losing game:

Based on a handout by Eric Roberts

http://technicalsupportindia.blogspot.com/
2 In order to write the program that plays Hangman, you should design and test your program in three parts. The first part consists of getting the interactive part of the game working without any graphics at all and with a fixed set of secret words. The second part consists of building a separate class that maintains the scaffold diagram. The final part requires you to replace the supplied version of the secret word list with one that reads words from a file. The rest of this handout describes these three parts in more detail.
Figure 1. Two sample runs of the Hangman program (console only)

http://technicalsupportindia.blogspot.com/
3 Part I Playing a console-based game In the first part of this assignment, your job is to write a program that handles the user interaction component of the game everything except the graphical display. To solve the problem, your program must be able to: Choose a random word to use as the secret word. That word is chosen from a word list, as described in the following paragraph. word, which begins as a series of dashes and then updated as correct letters are guessed. Implement the basic control structure and manage the details (ask the user to guess a letter, keep track of the number of guesses remaining, print out the various messages, detect the end of the game, and so forth). The only operation that is beyond your current knowledge is that of representing the list of words from which you can choose a word at random. For the first two parts of the assignment, you will simply m HangmanLexicon that provides a small list of words that will allow you to test your program. (A OH[LFRQ is very much like a dictionary, but does not necessarily include definitions, which makes it a more appropriate name for a class that provides a list of is only a temporary expedient to make it possible to code the rest of the assignment. In Part III, you will replace the from a data file. The strategy of creating a temporary implementation that provides enough functionality to implement the rest of the program is a common technique in programming. Such temporary implementations are usually called stubs. In this assignment, the starter project comes with a stub implementation of the HangmanLexicon class, which appears in Figure 2 on the next page. The class contains two public methods: getWordCount(), which returns the number of words in the lexicon, and getWord(i), which returns the word at index i. Like all indices in Java, the value i runs from 0 to one less than the number of words.

http://technicalsupportindia.blogspot.com/
4
Figure 2. Stub implementation of HangmanLexicon /* * File: HangmanLexicon.java * ------------------------* This file contains a stub implementation of the HangmanLexicon * class that you will reimplement for Part III of the assignment. */ import acm.util.*; public class HangmanLexicon { /** Returns the number of words in the lexicon. */ public int getWordCount() { return 10; } /** Returns the word at the specified index. */ public String getWord(int index) { switch (index) { case 0: return "BUOY"; case 1: return "COMPUTER"; case 2: return "CONNOISSEUR"; case 3: return "DEHYDRATE"; case 4: return "FUZZY"; case 5: return "HUBBUB"; case 6: return "KEYHOLE"; case 7: return "QUAGMIRE"; case 8: return "SLITHER"; case 9: return "ZIRCON"; default: throw new ErrorException("getWord: Illegal index"); } }; }

A game that used this implementation of the HangmanLexicon class would quickly become uninteresting because there are only ten words available. Even so, it will allow you to develop the rest of the program and then come back and improve this part later. Part I is a string manipulation problem using the methods developed in Chapter 8. The sample runs in Figure 1 should be sufficient to illustrate the basic operation of the game, but the following points may help to clarify a few issues: At the beginning of your run method, you need to create a new HangmanLexicon and store it in an instance variable. If you extend the program to allow the user to play multiple games, the creation of the HangmanLexicon should be performed outside the loop that plays the game repeatedly so that this operation is performed once rather than for every game. either lower or upper case, even though all letters in the secret words are written in upper case. If the user guesses something other than a single letter, your program should tell the user that the guess is illegal and accept a new guess.

http://technicalsupportindia.blogspot.com/
5 If the user guesses a correct letter more than once, your program should simply do nothing. Guessing an incorrect letter a second time should be counted as another wrong guess. (In each case, these interpretations are the easiest way to handle the about these cases in detail.) Remember to finish Part I before moving on to Part II. Part II is arguably more fun, but it is essential to develop large programs in manageable stages. Part II Adding graphics For Part II, your task is simply to extend the program you have already written so that it now keeps track of the Hangman graphical display. Although you might want to spice things up in your extensions, the simple version of the final picture for the unfortunate user who has run out of guesses looks like this:

The scaffold and the tiny bit of rope above the head are drawn before the game begins, and then the parts are added in the following order: head, body, left arm, right arm, left leg, right leg, left foot, right foot. Because this picture is simpler than most of the figures you have drawn for section problems, the challenge of this part of the assignment does not lie so much in using the acm.graphics package but rather in implementing the separation of functions between the class that performs the console-based interaction and the class that manages the display. That class is called HangmanCanvas and is included in the starter project in the form of the stub implementation shown in Figure 3 on the next page.

http://technicalsupportindia.blogspot.com/
6
Figure 3. Stub implementation of HangmanCanvas /* * File: HangmanCanvas.java * -----------------------* This file keeps track of the Hangman display. */ import acm.graphics.*; public class HangmanCanvas extends GCanvas { /** Resets the display so that only the scaffold appears */ public void reset() { /* You fill this in */ } /** * Updates the word on the screen to correspond to the current * state of the game. The argument string shows what letters have * been guessed so far; unguessed letters are indicated by hyphens. */ public void displayWord(String word) { /* You fill this in */ } /** * Updates the display to correspond to an incorrect guess by the * user. Calling this method causes the next body part to appear * on the scaffold and adds the letter to the list of incorrect * guesses that appears at the bottom of the window. */ public void noteIncorrectGuess(char letter) { /* You fill this in */ } /* Constants for the simple private static final int private static final int private static final int private static final int private static final int private static final int private static final int private static final int private static final int private static final int private static final int } version of the picture (in pixels) */ SCAFFOLD_HEIGHT = 360; BEAM_LENGTH = 144; ROPE_LENGTH = 18; HEAD_RADIUS = 36; BODY_LENGTH = 144; ARM_OFFSET_FROM_HEAD = 28; UPPER_ARM_LENGTH = 72; LOWER_ARM_LENGTH = 44; HIP_WIDTH = 36; LEG_LENGTH = 108; FOOT_LENGTH = 28;

This stub is somewhat different from the one shown earlier for HangmanLexicon. That stub actually did something, even if it was only a part of what the complete implementation of the class will actually do. This stub declares several named constants methods in the stub implementation of HangmanCanvas reset, displayWord, and noteIncorrectGuess do absolutely nothing. This strategy, however, is also common in programming. The fact that the class exists and exports methods means that you can

http://technicalsupportindia.blogspot.com/
7 call those methods from the console-based Hangman class even before you complete their implementation. The first thing you should do when you begin Part II is to create a new HangmanCanvas in precisely the do-nothing form in which it has been given to you and install it in the program window next to the console. The Hangman class itself is an instance of a ConsoleProgram, which means that the startup code in the ACM libraries has installed an IOConsole in the window that fills the entire space. Your next task is to add a HangmanCanvas to the program window as well. You will learn much more about how to do this kind of operation toward the end of the CS 106A, but the code you need for this part is extremely simple. First, in the instance variables section of the Hangman program, you need to declare an instance variable for the canvas by writing
private HangmanCanvas canvas;

and then add the following init method to your program:


public void init() { canvas = new HangmanCanvas(); add(canvas); }

Note that your Hangman program will have both an init and a run method as a result, and that is perfectly fine. This init method initializes the canvas and adds it to the window prior to the run method being executed; the run method is where the execution of your game will start after the window is initialized. By default, the contents of the program window are given equal amounts of space side by side. Since this is a console program, the console is already installed and will therefore show up in the left column. When you add the HangmanCanvas it will occupy the second column, which means that the console and graphics components of the window will each get half the screen area, as shown in Figure 4 below. Input and output from the Hangman program will continue to appear on the console, and any objects you add to the HangmanCanvas stored in the variable canvas will appear in the area on the right.
Figure 4. Screen shot showing side-by-side console (left) and canvas (right)

http://technicalsupportindia.blogspot.com/
8 You can now go through and add the calls to the methods in HangmanCanvas. Every time you start a game, for example, you will need to call to delete all the body parts from the canvas and redraw the scaffold. Similarly, you will have to call displayWord and noteIncorrectGuess at the appropriate points in your code. As of yet, nothing will actually be displayed on the canvas when you make these calls, but your program should run just the same as it did before, freeing you to concentrate on implementing the methods in HangmanCanvas. Note that you should not add any more public methods to HangmanCanvas (adding private helper methods is fine though). The implementation of HangmanCanvas should be reasonably straightforward. Although the sizes of the scaffold and the various body parts are given to you, their positions are not specified, so you will have to do some arithmetic to calculate the coordinates. The center line of the body should be centered horizontally on the screen, and the scaffold should be displayed a bit higher than the center so that there is room underneath for two labels: a label in a large font showing the secret word as it currently stands and a label in a smaller font showing the incorrect guesses. Figure 5 shows how the screen appears at the end of the tragic session in which the user was unable to guess FUZZY.
Figure 5. The tragic ending of a Hangman game canvas.reset();

http://technicalsupportindia.blogspot.com/
9 Part III Reading the lexicon from a data file Part III of this assignment is by far the easiest and requires considerably less than half a to do it until the lectures next week. So the idea is to start with parts I and II and then fill in this final detail at the end. Your job in this part of the assignment is simply to reimplement the HangmanLexicon class so that instead of selecting from a meager list of ten words, it reads a much larger word list from a file. The steps involved in this part of the assignment are as follows: 1. Open the data file HangmanLexicon.txt using a BufferedReader that will allow you to read it line by line. 2. Read the lines from the file into an ArrayList. 3. Reimplement the getWordCount and getWord methods in HangmanLexicon so that they use the ArrayList from step 2 as the source of the words. The first two steps should be done in a constructor for HangmanLexicon, which you will need to add to the file (see below). The last step is simply a matter of changing the implementation of the methods that are already there. Here is how the HangmanLexicon constructor should be added to the HangmanLexicon class:
public class HangmanLexicon { // This is the HangmanLexicon constructor public HangmanLexicon() { // your initialization code goes here } } // rest of HangmanLexicon class...

Note that nothing in the main program should have to change in response to this change in the implementation of HangmanLexicon. Insulating parts of a program from changes in other parts is a fundamental principle of good software design. Extensions There are many ways to extend Hangman to make it more fun. Here are some ideas: You could spice up the display a little. Stick figures may be fine for elementary school, but they seem a bit tame here. You could animate the pictures. Instead of having the body parts and letters merely appear on the screen, you could have them move in from offscreen, as pictures often do, for example, in PowerPoint slides. Once you get the basic structure working, you could expand the program to play something like Wheel of Fortune, in which the single word is replaced by a common phrase and in which you have to buy vowels. Use your imagination!

http://technicalsupportindia.blogspot.com/

Mehran Sahami CS 106A

Solutions to Practice Midterm

Handout #29 October 24, 2007

Problem 1: Karel the Robot (15 points)


/* File: InnerBorderKarel.java */ import stanford.karel.*;

Portions of this handout by Eric Roberts and Patrick Young

public class InnerBorderKarel extends SuperKarel { public void run() { moveUpRow(); for(int i = 0; i < 4; i++) { handleBorder(); nextPosition(); } } // Assumes Karel starts one avenue before the first beeper to // be placed in this line of the border. Places beepers until // Karel reaches a wall, but does not place a beeper on the last // corner (where Karel is facing the wall). private void handleBorder() { move(); while (frontIsClear()) { // We check for any existing beepers, so we don't put // two beepers on any of the "corners" of the border if (noBeepersPresent()) { putBeeper(); } move(); } } // Moves Karel up one row while keeping the same orientation private void moveUpRow() { turnLeft(); move(); turnRight(); } // Assumes Karel is facing a wall at the end of line of placed // beepers and repositions Karel to be facing in direction of next // line in the border of beepers that needs to be placed private void nextPosition() { turnRight(); move(); turnRight(); move(); turnRight(); }

http://technicalsupportindia.blogspot.com/
2 Problem 2: Simple Java expressions, statements, and methods (15 points) (2a)
5.0 / 4 - 4 / 5 7 < 9 - 5 && 3 % 0 == 3 "B" + 8 + 4

1.25
false "B84"

(2b)

Answer: The 1st number is: 78 The 2nd number is: 73

Problem 3: Simple Java programs (20 points)

/* * File: SecondLargest.java * -----------------------* This program finds the largest and second largest number * in a list entered by the user. */ import acm.program.*; public class SecondLargest extends ConsoleProgram { /* Defines the sentinel used to signal the end of the input */ private static final int SENTINEL = 0; public void run() { println("This program finds the two largest integers in a"); println("list. Enter values, one per line, using a " + SENTINEL + " to"); println("signal the end of the list."); int largest = -1; int secondLargest = -1; while (true) { int input = readInt(" ? "); if (input == SENTINEL) break; if (input > largest) { secondLargest = largest; largest = input; } else if (input > secondLargest) { secondLargest = input; } } println("The largest value is " + largest); println("The second largest is " + secondLargest);

http://technicalsupportindia.blogspot.com/
3 Problem 4: Using the graphics and random number libraries (25 points)
/* * File: SimpleFrogger.java * -----------------------* This program solves the Frogger problem from the practice midterm. */ import import import import acm.graphics.*; acm.program.*; java.awt.*; java.awt.event.*;

/* * This program gets a frog to jump one square in the closest * direction to a mouse click. */ public class SimpleFrogger extends GraphicsProgram { public void run() { frog = new GImage("frog.gif"); fx = (NCOLUMNS / 2 + 0.5) * SQUARE_SIZE; fy = (NROWS - 0.5) * SQUARE_SIZE; add(frog, fx - frog.getWidth() / 2, fy - frog.getHeight() / 2); addMouseListeners(); } /* Responds to a mouse click */ public void mouseClicked(MouseEvent e) { double mx = e.getX(); double my = e.getY(); if (Math.abs(mx - fx) > Math.abs(my - fy)) { if (mx > fx) { moveFrog(SQUARE_SIZE, 0); } else { moveFrog(-SQUARE_SIZE, 0); } } else { if (my > fy) { moveFrog(0, SQUARE_SIZE); } else { moveFrog(0, -SQUARE_SIZE); } } } /* Moves the frog by dx/dy as long as it remains inside the world */ private void moveFrog(double dx, double dy) { if (insideFroggerWorld(fx + dx, fy + dy)) { fx += dx; fy += dy; frog.move(dx, dy); } }

http://technicalsupportindia.blogspot.com/
4
/* Returns true if private boolean return (x >= y >= } /* Private private private private /* Private private private private the point (x, y) is inside the frog's world */ insideFroggerWorld(double x, double y) { 0 && x <= NCOLUMNS * SQUARE_SIZE && 0 && y <= NROWS * SQUARE_SIZE);

constants */ static final int SQUARE_SIZE = 75; static final int NROWS = 4; static final int NCOLUMNS = 7; instance variables */ GImage frog; /* The image of the frog */ double fx; /* The x-coordinate of the frog's center */ double fy; /* The y-coordinate of the frog's center */

/* Sets the graphics window size */ public static final int APPLICATION_WIDTH = NCOLUMNS * SQUARE_SIZE; public static final int APPLICATION_HEIGHT = NROWS * SQUARE_SIZE; }

Problem 5: Strings and characters (15 points)


/* * Removes any doubled letters from a string. */ private String removeDoubledLetters(String str) { String result = ""; for (int i = 0; i < str.length(); i++) { char ch = str.charAt(i); if (i == 0 || ch != str.charAt(i - 1)) { result += ch; } } return result; }

http://technicalsupportindia.blogspot.com/

Mehran Sahami CS106A

Practice Midterm Examination

Handout #28 October 24, 2007

Midterm Time: Tuesday, October 30, 7:00 8:30P.M. Midterm Location: Kresge Auditorium
This handout is intended to give you practice solving problems that are comparable in format and difficulty to those which will appear on the midterm examination next Tuesday. Exam is open book, open notes, closed computer The examination is open-book (specifically the course textbook The Art and Science of Java and the Karel the Robot coursereader) and you may make use of any handouts, course notes/slides, printouts of your programs or other notes you've taken in the class. You may not, however, use a computer of any kind (i.e., you cannot use laptops on the exam). Coverage The midterm exam covers the material presented in class through today (October 24th), which means that you are responsible for the Karel material plus Chapters 1 through 9 of the class textbook The Art and Science of Java, plus the use of mouse listeners from Chapter 10 (sections 10.1-10.4). Data files (which will be covered in class on Friday) are not covered on the exam. General instructions Answer each of the questions included in the exam. Write all of your answers directly on the examination paper, including any work that you wish to be considered for partial credit. Each question is marked with the number of points assigned to that problem. The total number of points is 90. We intend for the number of points to be roughly comparable to the number of minutes you should spend on that problem. In all questions, you may include methods or definitions that have been developed in the course, either by writing the import line for the appropriate package or by giving the name of the method and the handout or chapter number in which that definition appears. Unless otherwise indicated as part of the instructions for a specific problem, comments will not be required on the exam. Uncommented code that gets the job done will be sufficient for full credit on the problem. On the other hand, comments may help you to get partial credit if they help us determine what you were trying to do. Blank pages for solutions omitted in practice exam In an effort to save trees, the blank pages that would be provided in a regular exam for writing your solutions have been omitted from this practice exam. In the real exam, we would certainly provide the blank pages for you to write your solutions.
Portions of this handout by Eric Roberts and Patrick Young

http://technicalsupportindia.blogspot.com/
2 Problem 1: Karel the Robot (15 points) We want to write a Karel program which will create an inside border around the world. Each location that is part of the border should have one (and only one) beeper on it and the border should be inset by one square from the outer walls of the world like this:

In solving this problem, you can count on the following facts about the world: You may assume that the world is at least 3x3 squares. The correct solution for a 3x3 square world is to place a single beeper in the center square. Karel starts off facing East at the corner of 1st Street and 1st Avenue with an infinite number beepers in its beeper bag. final location or heading. You do not need to worry about efficiency. You are limited to the instructions in the Karel booklet the only variables allowed are loop control variables used within the control section of the for loop. Write your solution on the next page (blank page omitted to save trees).

http://technicalsupportindia.blogspot.com/
3 Problem 2: Simple Java expressions, statements, and methods (15 points) (2a)

Compute the value of each of the following Java expressions. If an error occurs during any of these evaluations occurs.
5.0 / 4 - 4 / 5 7 < 9 - 5 && 3 % 0 == 3 "B" + 8 + 4

(2b)

What output is printed by the following program:

/* * File: Problem2b.java * -------------------* This program doesn't do anything useful and exists only to test * your understanding of method calls and parameter passing. */ import acm.program.*; public class Problem2b extends ConsoleProgram { public void run() { int num1 = 2; int num2 = 13; println("The 1st number is: " + Mystery(num1, 6)); println("The 2nd number is: " + Mystery(num2 % 5, 1 + num1 * 2)); } private int Mystery(int num1, int num2) { num1 = Unknown(num1, num2); num2 = Unknown(num2, num1); return(num2); } private int Unknown(int num1, int num2) { int num3 = num1 + num2; num2 += num3 * 2; return(num2); } }

Answer:

http://technicalsupportindia.blogspot.com/
4 Problem 3: Simple Java programs (20 points) In Assignment #2, you wrote a program to find the largest and smallest integers in a list entered by the user. For this problem, write a similar program that instead finds the largest and the second-largest integer. As in the homework problem, you should use 0 as a sentinel to indicate the end of the input list. Thus, a sample run of the program might look like this:

To reduce the number of special cases, you may make the following assumptions: The user must enter at least two values before the sentinel. All input values are positive integers.

If the largest value appears more than once, that value should be listed as both the largest and second-largest value, as shown in the following sample run:

Write your solution on the next page (omitted).

http://technicalsupportindia.blogspot.com/
5 Problem 4: Using the graphics and random number libraries (25 points) In the arcade game Frogger, this is a frog that "hops" along the screen. A full game is beyond the scope of an exam problem, but it is relatively straightforward to write the code that (1) puts an image of the frog on the screen and (2) gets the frog to jump when the user clicks the mouse. Your first task in this problem is to place the frog at the bottom of the graphics window, as shown on the right. The frog itself is the easy part because all you need to do is create a GImage object with the appropriate picture (you can assume the file frog.gif is provided), as follows:
GImage frog = new GImage("frog.gif");

The harder part is getting the image in the appropriate place in the bottom of the window. In Frogger, the frog image cannot be just anywhere on the screen but must instead occupy a position in an imaginary grid such as the one shown on the right. The size of the grid is controlled by three named constants, which have the following values for this grid:
public static final int SQSIZE = 75; public static final int NCOLS = 7; public static final int NROWS = 3;

The SQSIZE constant indicates that each of the squares in the grid is 75 pixels in each dimension and the other two parameters give the width and height of the grid in terms of the number of squares. Remember that the squares shown in the most recent diagram do not actually exist but simply define the legal positions for the frog. In the initial position, the frog must be in the center square along the bottom row. You may assume NCOLS is odd so that there is a center square, and you may also assume that APPLICATION_WIDTH and APPLICATION_HEIGHT have been set so the NCOLS x NNROWS squares fill the window. The second part of the problem is getting the frog to jump when the user clicks the mouse. The goal is to get the frog to jump one square in the direction that moves it closest to the mouse. For example, if you click the mouse at the location shown in the diagram at the right, the frog should move SQSIZE pixels upward so that it occupies the center square in the grid. If the user then clicked the mouse at the left edge of the screen, the frog should jump SQSIZE pixels to the left. The frog, however, should never jump outside the window.

The following restatement of the rule may clarify the intended behavior more explicit. The frog should jump one square position in the direction up, down, left, or right that corresponds most closely to the direction from the center of the frog to the mouse position. Thus, in the diagram, the frog should move up rather than right because the distance to the mouse is larger in the y direction than it is in the x direction. If, however, the new position would lie outside the NCOLS x NROWS grid, the frog should stay where it is. Write your solution on next page (omitted).

http://technicalsupportindia.blogspot.com/
6 Problem 5: Strings and characters (15 points) In the early part of the 20th century, there was considerable interest in both England and the United States in simplifying the rules used for spelling English words, which has always been a difficult proposition. One suggestion advanced as part of this movement was the removal of all doubled letters from words. If this were done, no one would have to remember that the name of

Write a method removeDoubledLetters that takes a string as its argument and returns a new string with all doubled letters in the string replaced by a single letter. For example, if you call
removeDoubledLetters("tresidder")

your method should return the string "tresider". Similarly, if you call
removeDoubledLetters("bookkeeper")

your method should return "bokeper". In writing your solution, you should keep in mind the following: You do not need to write a complete program. All you need is the definition of the method removeDoubledLetters that returns the desired result. about changes in capitalization. You may assume that no letter appears more than twice in a row. (It is likely that your

Write your solution on the next page (omitted).

You might also like