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

  1. 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!

  2. 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
  3. Make the drawGallows() method

    Start 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!
  4. Make the drawCurrentGuess() method

    Next 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.
  5. Make the drawHangedMan() method

    Now 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!
  6. Make the redrawCanvas() method

    Finally, 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!
  7. Call the redrawCanvas() method from your code

    Now 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!)
  8. Make the HangmanGUI class

    For 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, a HangmanGame object that is the game we'll play, and a HangmanButtons 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.
  9. Refactor the Canvas object into the HangmanGUI class

    This 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)
  10. 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!

  11. Make the HangmanGUITester class

    It'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 new HangmanGUITester 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.
  12. 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).

  13. Create an executable jar file

    Now 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!
  14. 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!

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:

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

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()
Creates a new HangmanGame object--basicaly a wordlist that can be used to start a new game.


HangmanGame

public HangmanGame(boolean isEvil)
Creates a new HangmanGame that is either evil or normal

Parameters:
isEvil - whether or not the HangmanGame should be evil

HangmanGame

public HangmanGame(Canvas newCanvas)
Creates a new HangmanGame (not evil) that is displayed on the given canvas.

Parameters:
newCanvas - the Canvas on which to draw the game.

HangmanGame

public HangmanGame(String debugWord)
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
Method Detail

checkGuess

public 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. 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

checkGuessEvil

public 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. 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

currentGuessString

public String currentGuessString()
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 _ _ ".

drawCurrentGuess

public void drawCurrentGuess()
A helper method (that could be private) that draws the current guess on the game's Canvas.


drawGallows

public void drawGallows()
A helper method (that could be private) that draws the gallows on the game's Canvas.


drawHangedMan

public void drawHangedMan()
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.


findPossibleMatchingWords

public ArrayList<String> findPossibleMatchingWords()
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

findPossibleWithoutLetter

public 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. 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

getGuess

public char getGuess()
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

playGame

public void playGame()
A method that plays a complete game of Hangman. Method ends when the game has been either won or lost.


redrawCanvas

public void redrawCanvas()
A helper method that clears and redraws the Canvas based on the current state of the game.


setupGame

public void setupGame()
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.


toggleEvil

public void toggleEvil()
Toggles whether the game is evil or not. If was evil, becomes not evil. If was not evil, becomes evil.


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 method
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

HangmanGUITester

public HangmanGUITester()
Method Detail

main

public static void main(String[] args)
Main method