CSCI 161 Homework Assignment 7 - Graphical Hangman
Due Fri Nov 02 at 11:59pm
Introduction
Over the past few weeks, we've managed to make a pretty spiffy Hangman program. We can play multiple games of Hangman, and we can even make the game evil so that the player (almost) always loses. For the assignment, we're going to add a nice graphical user interface (or "GUI") to the game, so that it draws a pretty picture as we're playing. We're also going to package the whole game into a single file, so that you can easily show it to your family and friends! This homework will give you a chance to practice using the Canvas object and writing programs that can be run without BlueJ.
The Assignment
You will be continuing to extend your Hangman game, adding a graphical interface that shows the gallows and draws a picture. You will also package the whole game into a .jar
file.
As always, be sure to download and unzip a FIXED copy of the the Homework 7 project. so that you can submit your project once completed. This project also contains some extra classes you can use in programming your game (the same WordList class from before, a Canvas like you used in lab, and a HangmanButtons class that gives you some buttons you can use to control your game).
Note: Once again, you will need to copy your HangmanGame class from the last assignment into this one! Make a new HangmanGame class in the Homework 7 project, but copy and paste the code from Homework 6 into it. You should use your evil hangman program (which, remember, can be either good or evil). Make sure that you can run this class and it works just like the last homework. If you didn't finish that homework, you can use the solution to Homework 5 (linked from the last assignment), though you will be missing the evil functionality.
Remember to read all the way through the instructions carefully! I reserve the right to not answer questions that are already answered in the assignment ;p
-
Read the assignment
Read all the way through the assignment carefully. Make sure you understand the big picture and what each step will accomplish. Then when you get to each step, focus on just that step, testing until you have it right!
-
Make new constructor and field for HangmanGame
The Hangman game is going to need to a Canvas to draw on, so give it one. You'll need to make a new variable of the Canvas type to hold the Canvas object. Should this be a local variable or a field? Are multiple methods going to need to access it?
- Declare and instantiate the variable. If it is a field, you'll need to make sure to initialize it in all of your constructors.
- You should also make a new constructor (a third one!) that takes in a single parameter a new Canvas object on which we can draw. This way the user can specify a different canvas for us to use if they want.
- You can test that this works by seeing if making a new HangmanGame (using BlueJ) and seeing if the blank canvas shows up
-
Make the
drawGallows()
methodStart by drawing the gallows, which should always show up when the game is being played. Make a new method that just draws the gallows on your canvas.
- If you're like me, you'll probably need to experiment with line lengths and coordinates in order to make something that looks good.
- Test this method to make sure your gallows appear and look the way you want!
-
Make the
drawCurrentGuess()
methodNext add in the "current guess"--the word with guessed letters revealed (i.e., the underscores). Make a new method that just draws the guess on your canvas.
- Note that we should already be able to convert the current guess to a String using the only-sorta-aptly-named currentGuessString() method.
- This method is a little bit harder to test--you should be able to call it and see the underscores, but how do you make sure letters are showing up? One thing you can do is first call checkGuess() a few times to "guess" letters and add them to your word, and then call this method to see if they show up correctly.
-
Make the
drawHangedMan()
methodNow add in the hangedman--that is, the stick figure that is drawn as the user misses letters. Make a new method that just draws the figure on your canvas.
- This method is going to have some logic in it! You'll need to draw pieces of the hangedman based on how many wrong guesses the player made (or equivalently, how many lives they have left). First you draw the head, then the body, then one arm, then the other, then one leg, then the other.
- Note that this method should draw the entire figure based on the number of lives--so if I currently have made 2 wrong guesses, it draws the head and the body.
- You can test this method by locally setting the number of lives, then calling this method from BlueJ (in other words, make it so the method sets the appropriate nubmer of lives for testing). Just make surethat you delete that local assignment before you continue!
-
Make the
redrawCanvas()
methodFinally, make a method that will perform all of the above actions and "draw" your current hangman game.
- This method should erase the current canvas, draw the gallows, draw the current guess, then draw the hangedman.
- This method is easy to test!
-
Call the
redrawCanvas()
method from your codeNow that you've giving your game the ability to be drawn on the Canvas, add this functionality to your playGame() method! Modify your playGame() method so it draws the output to the Canvas in addition to printing to the console.
- Basically, where-ever you print your guess to the console (such as at the start of your game loop), you'll want to add in a call to redrawCanvas().
- You'll also want to add a call to JOptionPane.showMessageDialog() whenever you report to the user that they missed a letter, or used an already guessed letter, etc.
- Note that we add in the GUI interactions in addition to printing to the console so that the game can still be played without the GUI. Flexibility is king!
- Test that this works--you should be able to smoothly play a game of Hangman without looking at the console (or without looking at the Canvas!)
-
Make the
HangmanGUI
classFor this program, you'll need to create a new class called
HangmanGUI
to create the different parts of the GUI. We do this in a separate class in order to support better encapsulation, cohesion, and coupling (see Chapter 6). This class is very simple: see the documentation below.- The class should have three things in it: a
Canvas
to draw on, aHangmanGame
object that is the game we'll play, and aHangmanButtons
object to create the control buttons. Check the parameters for the constructors of each of these objects--in what order do you need to create the objects so that you can pass a previously defined variable to the constructor? THINK! - Note that the buttons SHOULD work, since they just execute the
playGame()
and toggleEvil() methods of your HangmanGame. That is, you should be able to click on these buttons and get the exact same effect you had by right-clicking on the object in BlueJ and selecting the relevant method. - Test your HangmanGUI class--making a new GUI object should give you a set of working buttons.
- The class should have three things in it: a
-
Refactor the
Canvas
object into theHangmanGUI
classThis is almost complicated, read these instructions carefully!
Now that you know that everything works, you'll want to pull the Canvas object OUT of the HangmanGame class, and instead use the Canvas object that you defined in your HangmanGUI class. You can pass a reference to this Canvas object using the appropriate constructor of the HangmanGame class. In other words, your HangmanGame will use the Canvas supplied by the GUI, instead of making its own.
- This produces cleaner, more maintainable code (it means that we can change the Canvas, a GUI element, without needing to change the HangmanGame code). And we can play HangmanGame without the GUI if we want!
-
Additionally, you should make it so that the
redrawCanvas()
method only gets called if the HangmanGame has a canvas. If the HangmanGame wasn't given a Canvas object, then that field should be null. You can check if the HangmanGame has a canvas using:if(canvasField == null)
-
Test and clean-up your code
Make sure the game plays how you want it to, shows the right messages, etc. You want this to look good, so you can show it off to your friends and family! Remember, this is an entire program that you wrote from scratch!
-
Make the
HangmanGUITester
classIt's good programming style to make our program that we can run ("execute") outside of BlueJ have a single class that actually does that running. We generally name these ___Tester, where ___ is the name of the class we would instantiate in BlueJ to start things. In this case: the
HangmanGUI
. So make a newHangmanGUITester
class.- This class will be disgustingly simple. It will contain a single method:
public static void main(String[] args)
(see Appendix E in the book). - Your main method will have a single line of code: creating a new HangmanGUI object. Thus calling the static
main
method--which will be called when you start the program--will create the HangmanGUI object, just like if you had selected it from BlueJ.
- This class will be disgustingly simple. It will contain a single method:
-
Fill in documentation (if you haven't already!)
Be sure to document all your code clearly using Javadoc comments and tags for each class. In addition, be sure to include inline comments explaining how your code works--particularly if you have a complicated sequence of if statements. NOTE: Private methods will not show up in BlueJ's Javadoc window, but you should still include Javadoc style comments for these. After you are done testing, feel free to make any of your helper methods private instead of public (this is better design).
-
Create an executable
jar
fileNow that your program is all written and works (it does work, right?), you can export it as an executable file that someone can double-click and run, just like any other program.
- In the BlueJ menu, select
Project > Create Jar File...
. Your "main class" will be the HangmanGUITester. You should be sure to include the source files and BlueJ Project Files in your jar, so that the word list gets included! - Make sure you save the new jar file in the same folder as the rest of your project (so that you can submit it!). You should name this file
Hangman.jar
. - You can test that this file works by double-clicking it--it should run your hangman game!
- In the BlueJ menu, select
- Test that everything works, and then submit!
Extensions
The same extensions from previous homeworks apply to this homework; if you haven't done them yet, you can do them now!Remember to save a working copy of your code before trying any extensions, just in case something breaks!
- Make it so your game also displays any currently guessed letters on the Canvas. Bonus points if you list them in alphabetical order!
- Make the guess display in a more interesting (but still readable!) font. See the java.awt.Font class.
-
Support a greater number of guesses--such as by drawing in a face of the hangedman. This is particularly appropriate for Evil Mode.
- Bonus: allow the user so specify the number of guesses (perhaps picking from an "easy" "medium" or "hard" option), and then have your game react appropriately.
- Draw something other than a stick figure being hanged--perhaps a robot?
Submitting
As always, before submitting, test each of your methods and classes thoroughly. Make sure your game works exactly as expected! When you're convinced it's ready to go, submit the project through BlueJ just like you did in the previous Assignments (selecting Hwk7 of course).
Submitter will look for the HangmanGame.java
, HangmanGUI.java
, HangmanGUITester.java
, and Hangman.jar
files (whew!).
Grading
This assignment will be graded on the following criteria:
- Your program can play both normal and evil hangman [10%]
- Your program displays a canvas, with the gallows, word, and figure drawn on it [25%]
- Your canvas is updated as the user plays the game [15%]
- You have a separate HangmanGUI and HangmanGUITester classes to organize your code [10%]
- Your program can be run from an executable jar file [20%]
- Your code is carefully documented, with proper Javadoc methods [10%]
- Your code uses good style. This means that variables are given descriptive names, local variables aren't specified in the fields, methods are properly refactored, redundant code is expunged, etc. If you have any questions about good style, don't hesitate to ask! [10%]
Documentation
Class HangmanGame
java.lang.Object HangmanGame
-
public class HangmanGame
A class to play a game of Hangman. And possibly... an EVIL game of Hangman!
- Version:
- Oct 2012
- Author:
- Joel Ross
- Creates a new HangmanGame object--basicaly a wordlist that can be used to start a new game.
- Creates a new HangmanGame that is either evil or normal
- Parameters:
-
isEvil
- whether or not the HangmanGame should be evil
- Creates a new HangmanGame (not evil) that is displayed on the given canvas.
- Parameters:
-
newCanvas
- the Canvas on which to draw the game.
- Creates a new HangmanGame object, with the wordlist containing only the given debugWord. This enables testing of the game using a known word.
- Parameters:
-
debugWord
- The single word in the wordlist, used for testing and debugging
- A helper method (that could be private) that checks to see if a given letter is present in the target word.
If so, all instances of that letter in the target word are revealed.
- Parameters:
-
letter
- the letter being guessed - Returns:
- whether or not the letter was found in the word
- A helper method (that could be private) that checks to see if a given letter is present in the target word, but cheats! If so, all instances of that letter in the target word are revealed.
This method cheats by picking a new word from the list of possibleWords when necessary,
or trims down the size of possibleWords if the letter is correct
- Parameters:
-
letter
- the letter being guessed - Returns:
- whether or not the letter was found in the word
- A helper method (that could be private) that returns a String representation of the current guess state.
For example: "g _ e _ _" for the word "guess" if the letters 'g' and 'e' have been guessed.
- Returns:
- A String displaying the current guess of the word. Has the form "g _ e _ _ ".
- A helper method (that could be private) that draws the current guess on the game's Canvas.
- A helper method (that could be private) that draws the gallows on the game's Canvas.
- A helper method (that could be private) that draws the hangedman on the game's Canvas.
How much of the man is drawn depends on the number of lives left.
- A helper method (that could be private) that finds the list of possible words that match the current revealed word.
Finds words that match every revealed character, and whose unrevealed letters have not previously been guessed.
- Returns:
- the list of possible words that match the revealed word
- A helper method (that could be private) which gets a list of possible words that don't include the given letter.
This method does not check that the possible words match the revealed characters; it assumes that the existing list of possible words match the current revealed word.
- Parameters:
-
letter
- the letter we want to exclude - Returns:
- the list of possible words that exclude the letter
- A helper method (that could be private) that prompts the user to provide a guessed letter. This method converts any guesses into a single, lower-case character.
- Returns:
- a single, lower-case char that the player guessed
- A method that plays a complete game of Hangman. Method ends when the game has been either won or lost.
- A helper method that clears and redraws the Canvas based on the current state of the game.
- A helper method (that could be private) which re-initializes variables for the start of a new game.
Resets the word to guess, the current letters guessed, the number of lives, etc.
- Toggles whether the game is evil or not. If was evil, becomes not evil. If was not evil, becomes evil.
Constructor Summary | |
---|---|
HangmanGame()
Creates a new HangmanGame object--basicaly a wordlist that can be used to start a new game. |
|
HangmanGame(boolean isEvil)
Creates a new HangmanGame that is either evil or normal |
|
HangmanGame(Canvas newCanvas)
Creates a new HangmanGame (not evil) that is displayed on the given canvas. |
|
HangmanGame(String debugWord)
Creates a new HangmanGame object, with the wordlist containing only the given debugWord. |
Method Summary | |
---|---|
boolean |
checkGuess(char letter)
A helper method (that could be private) that checks to see if a given letter is present in the target word. |
boolean |
checkGuessEvil(char letter)
A helper method (that could be private) that checks to see if a given letter is present in the target word, but cheats! If so, all instances of that letter in the target word are revealed. |
String |
currentGuessString()
A helper method (that could be private) that returns a String representation of the current guess state. |
void |
drawCurrentGuess()
A helper method (that could be private) that draws the current guess on the game's Canvas. |
void |
drawGallows()
A helper method (that could be private) that draws the gallows on the game's Canvas. |
void |
drawHangedMan()
A helper method (that could be private) that draws the hangedman on the game's Canvas. |
ArrayList<String> |
findPossibleMatchingWords()
A helper method (that could be private) that finds the list of possible words that match the current revealed word. |
ArrayList<String> |
findPossibleWithoutLetter(char letter)
A helper method (that could be private) which gets a list of possible words that don't include the given letter. |
char |
getGuess()
A helper method (that could be private) that prompts the user to provide a guessed letter. |
void |
playGame()
A method that plays a complete game of Hangman. |
void |
redrawCanvas()
A helper method that clears and redraws the Canvas based on the current state of the game. |
void |
setupGame()
A helper method (that could be private) which re-initializes variables for the start of a new game. |
void |
toggleEvil()
Toggles whether the game is evil or not. |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructor Detail |
---|
HangmanGame
public HangmanGame()
HangmanGame
public HangmanGame(boolean isEvil)
HangmanGame
public HangmanGame(Canvas newCanvas)
HangmanGame
public HangmanGame(String debugWord)
Method Detail |
---|
checkGuess
public boolean checkGuess(char letter)
checkGuessEvil
public boolean checkGuessEvil(char letter)
currentGuessString
public String currentGuessString()
drawCurrentGuess
public void drawCurrentGuess()
drawGallows
public void drawGallows()
drawHangedMan
public void drawHangedMan()
findPossibleMatchingWords
public ArrayList<String> findPossibleMatchingWords()
findPossibleWithoutLetter
public ArrayList<String> findPossibleWithoutLetter(char letter)
getGuess
public char getGuess()
playGame
public void playGame()
redrawCanvas
public void redrawCanvas()
setupGame
public void setupGame()
toggleEvil
public void toggleEvil()
Class HangmanGUI
java.lang.Object HangmanGUI
-
public class HangmanGUI
A GUI for the Hangman Game
Constructor Summary HangmanGUI()
Creates a new HangmanGUI object.Method Summary Methods inherited from class java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
Constructor Detail HangmanGUI
public HangmanGUI()
- Creates a new HangmanGUI object.
Class HangmanGUITester
java.lang.Object HangmanGUITester
-
public class HangmanGUITester
A Tester for the HangmanGUI.
Constructor Summary HangmanGUITester()
Method Summary static void
main(String[] args)
Main methodMethods inherited from class java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
Constructor Detail HangmanGUITester
public HangmanGUITester()
- Main method
Method Detail |
---|
main
public static void main(String[] args)