CS 124, Spring 2017
Lab 12: Hangman GUI
For the next two weeks, you will work on a GUI Hangman game. 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 find something extra to do in the program, such as a menu of alternative word lists or a "cheat" button that would give the user a free letter.
You should create a new class named Hangman. You will be writing this class from scratch. Later, you will copy a folder into your project to implement the list of words for the program.
The completed program is due at 3:00 PM on the last day of class, Monday, May 1 (changed from original due date on April 28). 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.
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 design 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. You will need to "lay out" all these components in a main panel. Many of the techniques that you need were covered in the GUI Tutorial, Lab 10. Note in particular that Lab 10 shows how to use a display panel for drawing and a subpanel for holding some buttons, all in a main panel that uses a BorderLayout. You should review Lab 10 and possibly even reuse some of the code from it. We will also talk about layout in class, and you can read about it in Section 6.7. But here are a few things you might use in this program.
To hold the 26 alphabet buttons, you will probably 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. 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 Lab 10, 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 might need a few new 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.6, and you can learn more about buttons in Subsection 6.6.1. You might want to use a JLabel or two to display information to the user. Read about JLabel in Subsection 6.6.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.3.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. g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
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.
For Lab 10, I asked you to put the main() routine for the program into a separate class. However, for this program, you can add the main() routine to the Hangman class itself, to keep everything in one file.
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 alphabet buttons in an array. 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. And you are required to have extra buttons and/or menu items to provide some features beyond the minimum requirements.
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, it can just print a message to show that the button is functional. You might want to implement the disabling of the alphabet buttons when they are clicked, and you might want to start writing a newGame method that will, among other things, re-enable all the alphabet buttons and select a new word. 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; your paintComponent method should test the test the value of that variable to decide what part of the hanged man to draw.
You should also implement some way to display the word to the user, and you should test it by displaying some (fake) word; the basic options are to show the word in a JLabel or to draw the characters of the word in the display's paintComponent method. You should also think about what other information you want to display to the user about the progress of the game.
Although you are not required to do so at this time, you can get started on selecting words for the game by including the folder named words from /classes/cs124. (You should copy the entire words folder into your src folder, and add the directive import words.WordList; to the top of your program.) The folder includes a class named WordList that represents a list of words read from a resource file. It also includes the resource file, named wordlist.txt. To use the class, you need to create a variable of type WordList. The construtor of the object specifies the path to the resource file. That is, you should create an object of type WordList with
wordlist = new WordList("words/wordlist.txt");
Then, in your program, when you want to get a randomly selected word from the list, you should call wordlist.getRandomWord(). See the comments in WordList.java for more information. The file wordlist.txt contains 438 words. All of the words are between 5 and 11 characters in length. They are a random selection from a much longer list, which is in the file /classes/cs124/wordlist-full.txt; you can add that file to the words folder in Eclipse if you want to use it in your program. You might want to provide your own lists of words. You might even provide several alternative lists of words for the user to choose from.