CS 124, Fall 2017
Lab 12: Hangman GUI

For the remaining labs in this course, you will work on a GUI Hangman game, or possibly on some other final project that you design yourself. Some ideas for alternative projects include: a program that does more with Midi, including things like letting the user play a tune on the keyboard and save the result to a file; a more ambitious sprite game, implementing a number of the ideas for extra features given at the end of the sprite lab; and a drawing program based on the sample program that we looked at in class, but with more features. You might come up with your own idea. If you are thinking of doing anything other than Hangman, you should discuss your plans with me before starting the program.

As with the previous lab, you have the option of working with a partner on this program. If you work with a partner, you should be sure that the program that you write is ambitions. For Hangman, for example, you could add features such as a menu of alternative word lists, a "cheat" button that would give the user a free letter, and Midi sound effects.

The rest of this web page deals only with Hangman. You should create a new class named Hangman. You will be writing this class from scratch. Later, you will need to copy a list of words for the game into your project.

The completed program is due at 3:00 PM on the last day of class, Friday, December 8. You will turn in one file named Hangman.java. If you are working on the project with a partner, you should turn in only one copy, and you should make sure that both names appear in the comment at the top of the program. You will also be able to submit other files, such as alternative lists of words, if they are needed by your program. (If you are not doing Hangman, you can submit all of your files as "extra files," and ignore the requirement for a file named Hangman.java.)

About Hangman

Hangman is a simple word-guessing game. A GUI version was demonstrated in class. The program selects a word for the user to guess. Initially, each letter in the word is shown as an empty space. The user guesses letters. When the user guesses a letter that appears in the word, that letter is filled in; it is filled in at every space where it occurs in the word, not just one space. When the user guesses a letter that is not in the word, a part of a "hanged man" is drawn. If the hanged man is completed before the user finds all the letters in the word, the user loses. The picture at the right shows an example. The hanged man here is complete. In my version of the game, I start with the scaffold already drawn, and the user gets 7 incorrect guesses. For the first incorrect guess, I draw the man's head; for the second, the neck; and then the left arm, right arm, body, left leg, and right leg.

About Layout, Etc.

You will have to create a user interface for Hangman (or whatever program you write). The game will require 26 buttons, one for each letter of the alphabet, as well as a display panel where you can draw the hanged man. You will also need other components or a menu bar or both. We have been talking about techniques for GUI programming in class. You will probably want to review some of the techniques from the sample program, RectPanel.java, and maybe even copy some code from that program. (That program is based on an unused lab, which you could also look at.) Here are a few more ideas you can use in this program...

You will need to "lay out" all the program's GUI components in a main panel. You can read about layout in Section 6.6. To hold the 26 alphabet buttons, you will want to put them into a JPanel on which you are using a GridLayout. In a GridLayout, components appear in equal-sized rectangles arranged into rows and columns. To create a panel and install a GridLayout for it, you can say:

JPanel panel = new JPanel();
panel.setLayout( new GridLayout( r, c ) );

where r is the number of rows and c is the number of columns. You can then use the panel.add method to add the buttons to the panel. For example, depending on the overall design of your window, you might arrange 26 buttons into a 2-by-13, or a 3-by-9, or a 9-by-3 grid:

The 3-by-9 and 9-by-3 grids have an empty spot. You are not required to fill the grid completely. Once you have the panel that holds the buttons, you need to add it to your main panel. Presumably, the main panel will use a BorderLayout, like the one in RectPanel.java, with a Display panel in the center and several other components along some of the edges. However, for the sake of appearances, it's nice to have a constrasting color between and around the components in a BorderLayout. A BorderLayout can specify a gap between components; the background color of the panel will show through the gaps. To get color around the outside of the panel, you can add a "border." Here's an example of setting this up in the constructor of the main panel:

setLayout( new BorderLayout(3,3) ); // Allow 3-pixel gap between components.
Color darkred = new Color(100,0,0);
setBackground( darkred ); // Color shows between components in the BorderLayout.
setBorder(BorderFactory.createLineBorder( darkred, 3 )); // Shows around edges.

In addition to layout, you will need to use a few other facts about components. You will at least need to know how to enable and disable buttons. You can read about basic properties of components in the first part of Section 6.5, and you can learn more about buttons in Subsection 6.5.1. You might want to use a JLabel or two to display information to the user. Read about JLabel in Subsection 6.5.2. (As an alternative to using labels, you can also simply draw a message string in the display panel using the method g.drawString; that's what I did in my version.) You will probably want to use bigger fonts than the default for some of your components. You can review basic use of fonts in Subsection 6.2.3.

Finally, you might want to use some of the capabilities of Graphics2D in your drawing. Graphics2D provides extra capabilities that are not available through a standard Graphics object. In fact, the Graphics object in paintComponent is a Graphics2D, and you can type-cast it to get access to the extra methods from Graphics2D. I found it useful to use a wider stroke for drawing lines and to turn on "antialiasing," which can make lines and ovals look smoother. To do that, add the following lines to the beginning of the paintComponent method in your Display class:

Graphics2D g2 = (Graphics2D)g;
g2.setStroke(new BasicStroke(3));  // draw 3-pixel-wide lines.

The Assignment for Lab 12

The assignment for this week is to create the GUI for your program and test that it is working correctly. Next week, you will implement the actual logic of the game. You should also add a main() routine to the Hangman class to create the window for the game. (Again, see RectPanel.java for an example.)

This program does need comments! You should fully document Hangman.java with appropriate comments.

For your Hangman game, you are required to have 26 buttons representing the letters of the alphabet. The user will select a letter by clicking one of the buttons. Furthermore, you must disable the button when the user clicks it, so that they can't choose the same letter again. After the user finishes with one word, the user must be able to begin a new game with a new word. At that time, all the letter buttons will have to be enabled again. This means that you will need to keep references to the 26 alphabet buttons — you should store them in an array of type JButton[]. You are required to draw the hanged man, step-by-step, as the user makes incorrect guesses. You are required to display information to the user about the progress of the game, such as a message saying that the user's letter does or does not occur in the word. You should show all the the guessed letters in the word, with some indication of the blank spaces that have not yet been guessed.

The program will need at least one menu item or button for starting a new game. If you use a menu item, you will have to create a menu bar for the program. If you use a button, you will need another JPanel to hold the button. You can add more commands such as "exit" and "give up".

For this week: You should set up the user interface, with all the panels, buttons, etc., that you anticipate using. You should create an ActionListener to respond to buttons and possibly menu commands. For now, the actionPerformed() method can just print a message to show that the button is functional. You will want to make sure that you can draw the hanged man for all stages of the game. Remember that what you draw at any given time will depend on the number of incorrect guesses, which should be stored in an instance variable; the paintComponent() method in your Display class should use the test the value of that variable to decide what parts of the hanged man to draw.

At this point, it would also be a good idea to implement some way to display the word to the user. You can test it by displaying some (made up) word. You could wait until next week to work on this, but you should at least save space for displaying the word. For representing the word in your program, I suggest storing the characters of the word in an array of type char[], or more likely in two such arrays, one for the complete word, and one holding the letters that have been guessed, with underscore characters in the spaces of letters that have not yet been guessed. You should also think about what other information you want to display to the user about the progress of the game and where it will be displayed.

Next week, you will add a list of words to the game, and you will fully implement the actual game. You should be sure to show up next week with a working and tested GUI.

Note: you can also check out Part 2 and Part 3 of this project.