CS 161 Homework 7 - Hangman
Due Fri Apr 10 Sun Apr 12 at 11:59pm
Overview
For this assignment, you will be making a simple version of the word game Hangman, This game will be played in the terminal window. In this game, the computer picks a random word from a pre-supplied list. The player then guesses a letter that they think may appear in the word. The computer checks whether the letter appears in the word and either reveals all instances of it (if it exists) or takes away one of the player's lives. The computer then displays the progress that the player has made towards guessing the word. The game continues until either all of the letters have been guessed (and the player wins) or all of the player's lives are used up (and the player loses). In either case, the computer should announce this event and the game should end.
An example exchange is below. Read this carefully--your program should be able to produce very similar output! (This is one of the ways I will test your code).
Welcome to Hangman! The word is: _ _ _ _ _ Guess a letter: a The word is: _ _ a _ _ Guess a letter: e Computer: I'm sorry, the word has no 'e'. You have 4 lives left. The word is: _ _ a _ _ Guess a letter: s The word is: _ _ a s s Guess a letter: e Computer: You already guessed 'e'! You have 4 lives left. Guess a letter: l The word is: _ l a s s Guess a letter: c Congratulations, the word is 'class'! You figured out the word with 4 lives remaining.
If the player loses, they should see (as an example):
No more lives remaining. The word was 'class'.
Note that the player can see the size of the word before they start guessing (e.g., each letter is shown as an
'_'
(underscore). The player is also able to guess a previously guessed letter without penalty.
This assignment should be completed individually. You are welcome to ask for help (either from me or from your classmates), but remember the Gilligan's Island rule!
Objectives
- To practice working with
array
s andArrayList
s - To practice using loops and conditionals do to simple searching
-
To practice designing and implementing programs
- Determining the variables and methods needed
- Using pseudocode to plan out complex algorithms
- To practice breaking up code into appropriate helper methods to support testing and readability
Necessary Files
You will need a copy of the Hwk7.zip file. The BlueJ project in this file contains two classes:
-
WordFile
is a class that represents a file full of words. You instantiate a newWordFile
object in order to load the file, and then you can call thegetWordArrayList()
method to get aArrayList<String>
that contains all the words in the file. You can see further details about this class by looking at it's Java Documentation (select Documentation in the upper-right corner of the class window in BlueJ). You do not need to modify this class. If there are any questions, let me know!- Notice that this class is very similar to the
TwitterDataFile
class from Lab H!
- Notice that this class is very similar to the
-
HangmanGame
this is the class that will contain your entire Hangman Game. Your task is to complete the implementation of this class. I have included the public interface of the class---that is, what public methods need to exist so that other classes can use it. Specifically, the class has two constructors and aplayGame()
method. Be sure and look at the Javadoc comments for details about the functionality of these methods! -
HangmanGameTester
A simple tester class for theHangmanGame
, demonstrating how to use the methods of the public interface.
The project also contains two word lists: wordsSmall.txt
(the default) and wordsHuge.txt
(a bigger list). Note that you'll need to get the size
of the word list that you're using; do not "hard-code" the value!
And last but certainly not least, the zip file also contains the README.txt that you will need to fill out and turn in along with your assignment.
Remember to extract the files from the zip folder before proceeding!
Implementation Notes
This assignment will be different from the last few assignments in that your task is less clearly defined. The description at the top (and the grading rubric below) gives a list of details and requirements for the program. However, it is up to you to determine what methods you will need to make and how those methods will interact.
- You will need to design the program so it has good coupling and cohesion--that is, each method should do one and only one thing, methods should be independent from each other, and you should avoid code duplication.
I'll provide some hints below to help you think through how to make this program. Be sure and read through all of the assignment carefully. Think about what variables you will need, what your functions should do, etc.
- I highly recommend first writing out method signatures and pseudocode to lay out your program and see how it will fit together, and then start filling code.
- When writing a method, be sure and write out a method comment that explains what the method should do, and then make sure that the method you are writing matches the comment.
- Finally, write one method at a time and test the method thoroughly--once you are sure that method works, you can move on to the next.
This will be more difficult than previous assignments, but I know you are all up to the task! There are lots of hints in the program description to help you on your way. And of course if you get stuck or need or just want to talk things over, please let me know and I'm happy to help :)
Assignment Details
As with any class you create, you should start by thinking about and declaring the instance variables. What attributes will your program have?
-
For example, your HangmanGame will likely need to keep track of the word-to-guess (e.g.,
"class"
in the above example), and the word-so-far (e.g.,"cl_ss"
---the underscores underscores represent letters that have not been guessed yet). You'll need to keep track of a growing list (that's a hint) of letters that have already been guessed, so that you don't deduct points for reguessing. You'll also need to keep track of the player's lives in some way. Finally, you'll want to keep track of the list of possible words to pick from, so that you can pick a new word every game!- Remember that you can always add more instance variables later, but we want to try and keep variables as local as possible! So if you can have a method return a value rather than save it as an instance variable, that is much better style!
-
Helpful hint:
Normally you'd use a String to keep track of a word. However, for this program we're interested in the individual characters of a word. You could use methods like
word.substring(0,1)
(to fetch the first letter of the String for example). However, because Strings are immutable, it is really awkward to change an individual letter in a String, such as converting a'_'
to an'a'
.-
Instead, I recommend you represent both the word-to-guess and the word-so-far as arrays of chars,
char[]
. An array will let you access and change each letter using an index (so you can get and change the 3rd letter). You can easily convert a String into achar[]
by using thetoCharArray()
method of the String object.-
Don't forget to initialize and fill your arrays! E.g., you might put underscores
(
'_'
) in your word-so-far to start.
-
Don't forget to initialize and fill your arrays! E.g., you might put underscores
(
-
Instead, I recommend you represent both the word-to-guess and the word-so-far as arrays of chars,
After you've determined your instance variables, you will want to initialize them in your constructors. The constructor signatures have been provided for you, but you will need to fill these in!
-
Remember: the goal of constructors is to set up your instance variables. This may involve calling other methods or using other control structures (conditionals, loops, etc) to create the values for the instance variables.
- Remember that you can pick a a random word from an
array
or anArrayList
by selecting a random index using a random number generator--the same way you selected Colors for the BouncingBall lab.
- Remember that you can pick a a random word from an
-
The first constructor takes no parameters, and is your "normal" constructor. Note that this constructor will need to fetch the list of possible words to guess from a new
WordFile
object. I recommend you work with the"wordsSmall.txt"
file, but you can use the larger file if you wish. -
The second constructor takes a
String[]
as a parameter that will provide the list of words for all games played. This constructor should be used for testing and grading--a smaller word list will make it easy to see if your program is working. In fact, I recommend testing your program with a provided word list of 1 or 2 words! (See the provided HangmanGameTester for an example).
Now that you've set up your HangmanGame
object, you'll want to start adding methods to represent each piece of functionality your program will need. Below is a list of "internal" functionality that your program will likely need to have, along with further hints and details:
-
Whenever the player selects to play a new game (calls the
playGame()
method described below), you'll want a way to easily reset the game (e.g., reset the number of lives left, the letters guessed, etc). This would involve resetting the word-to-guess (picking a new random word from the list!) and the word-so-far, the number of lives, and emptying out the list of letters guessed.- You can just call such a helper method from your constructors, allowing you to avoid duplicating code!
-
You'll be printing out the word-so-far quite a lot, and it would be nice to be able to see the letters with spaces between them:
"cl___"
is hard to read (how many letters go after thecl
?), but"c l _ _ _"
is easy to understand. This it might be nice to have a method that can convert achar[]
into a formatted String, which you can easily print out!- You can do this by looping through the entries in your array and adding each letter to the end of a String you are building (an 'output' String).
- You may want to convert different
char[]
into Strings, and you may want to use those Strings for things other than printing. Creating a method such that it takes in achar[]
as a parameter and then returns the generated String version will let you easily reuse code you've already written--you can just call your method! This makes it easy to avoid code duplication.
-
Your program will need to be able to determine if a particular letter (e.g., the letter that was guessed) is inside the word-to-guess. Again, you should implement this functionality in such a way that you can re-use it if needed, such as by making a helper method that returns whether or not the word-to-guess contains a given letter.
- This will involve a simple linear search: loop through each character in the word-to-guess, and see if that character is the same as the given letter. If so, then the word-to-guess contains the letter. If you get through the whole word without finding anything, then the word-to-guess does not contain the letter.
-
Your program will also need to be able to replace a letter in the word-so-far (for when the user correctly finds a letter).
-
You will need to go through the word-so-far and replace each
'_'
with the guessed letter only if the letter in the word-to-guess at that index of the'_'
is the one that you're trying to replace. -
Note that you can do this with a single loop, but you'll need to consider both the word-so-far (to see if there is an
'_'
to replace) and the word-to-guess (to see if the'_'
is one that should be replaced).
-
You will need to go through the word-so-far and replace each
-
It will probably be helpful if your program can count the letters left to guess--that is, count how many
'_'
are in the word-so-far. You can call this method later and, if the number is 0, then that means the player has finished guessing the word!
Once you have this internal functionality implemented as "helper" methods, you can use those helpers to write the method(s) that will let a user play your game!
-
This functionality will be run from the program's
playGame()
method--that is, when someone callsplayGame()
, the game starts. You should thus be able to run your program by instantiating a newHangmanGame
object, and then calling it'splayGame()
method.- All user interaction (printing, using the Scanner, etc) will go in this method!
-
Your game should play like this (note this is not pseudocode, just instructions broken up into steps for readability):
- You should show the user the word-so-far (with spaces between letters), and then prompt the user for a guess.
-
Read in their guess using a Scanner (I recommend using
nextLine()
to actually fetch the input; you can convert their response into a character by using the.charAt()
method of String class to get thechar
at the first index---e.g., the first character of the String). - You'll want to check if they already guessed the letter---if so let them know (and if not, add that letter to the list of guessed letters). This will involve searching the list of guessed letters... though you might check if there is an existing method (e.g., in ArrayList) that you can use.
- Then you should check if the guessed letter is in the word-to-guess. If so, then replace that letter in the word-so-far; if not, tell the user they got the letter wrong and lose a life.
- You'll need to check whether they are out of lives (and if so, tell them they lost), or if they have guessed all the letters (and if so, tell them they won!)
- If the game isn't over yet, go back to step 1 (e.g., using a loop).
- Remember to reset the game state at the very start of the
playGame()
method so that the user can play multiple games!
-
This is a complex algorithm! There are lots of different conditions as well as a loop to repeatedly ask for letters. You should write out the code structure in pseudocode first. Once you have that, you can start replacing each piece of pseudocode with the appropriate Java code.
- You should expect to call the helper methods you've written earlier in the assignment; this should help keep your clean and readable. Again, think carefully about what each method does and what it returns, and make sure you do something with a returned variables!
-
Although not required, you might decide to "factor out" some helper methods from your
playGame()
code. For example, maybe you pull out the code that asks a player for a guess (into aaskForGuess()
method which returns thechar
they guessed, for example)
Testing
Be sure and text your code thoroughly. Use the "testing" constructor with a single word in your list will let you not need to guess at the computer's chosen word. Use copious System.out.println() calls to print out what is going on in your program (but be sure to remove/comment them out when you are done!)
- Again, your program should be able to produce similar output to the example at the top of the page! That is, I should be able to type in those letters and get similar output. (I say similar because you are allowed to change the text of the messages somewhat, though please keep your program polite).
Documentation
Include lots of inline comments that explain your code, both to help me and to help you keep your place. Documentation is worth quite a bit in this assignment.
In addition, every one of your methods (including all of your helper methods) should have a full Javadoc comment (complete with @param and @return tags). Hint: Fill in these comments along with the skeleton (the method signatures of all your classes) and your pseudocode when you first start--that way you will know what each method is supposed to do!
- Be sure and double-check the formatting of the Javadoc comments (see pages 89-92 in the text).
Development Schedule
This is a big assignment--as large as any we've done before (in part because it's a bit less structured). However, there are no new concepts here: just methods, arrays, and control statements. Try to add one piece of functionality per day, testing as you go. Work for an hour or so; if you get stuck you can put it down and come back later (this is often enough), or ask me for help. Develop iteratively---you should build a small piece, test that it works, and then move on to the next bit.
Below is a suggested order of steps, as well as good deadlines for getting each step working (if you haven't figure something out by the listed date, definitely ask for help!!):
- Wed 04/01: Read through the assignment; create (and initialize!) instance variables and constructors. This is also a good time to add in method signatures and documentation!
- Fri 04/03: Be able to print out a String version of the word-so-far, and check if a letter is inside a word
- Mon 04/06: Be able to replace a letter in the word-so-far, and count the number of letters left to guess
- Thu 04/09: Use the Scanner to ask the player for letters one after another replacing the letter in the word-so-far.
- Fri 04/10: Check if the user finished the game or are out of lives (and so the game ends), and if they guessed a previously-guessed letter.
Scheduling Note: This homework is due the day after the second midterm (similar to the schedule for Hwk 4). This means you'll also likely want to block out time for studying--though this homework does draw on most of the topics that will be on the midterm. Plan accordingly; if you start early, you can get this done well before the midterm.
Extensions
There is other functionality you might consider adding. They might be fun (or at leas good practice), and you can earn up to 5% extra credit for completing them. Only start on these once you have finished the rest of the assignment and you are sure that works. Be sure to save a copy of your working code in case you don't finish these!
-
Make sure that the letter the user guesses is actually a letter (e.g., by using the
Character.isLetter()
method). If the user gives invalid input, keep asking them to try again until they get it right (hint: this will require a loop, and breaking this functionality into a helper method keeps things clean)! Similarly, you might make sure your program correctly works with upper-case and lower-case letters. -
Modify the program to print out a graphical representation of the hangedman! E.g.:
__O__ | / \
The hangedman should gain body parts as the game continues.
Submitting Your Assignment
- Double-check that your program is complete and works correctly. If your program doesn't compile, I can't give you credit for it!
- Make sure that your code is commented. Give lots of inline comments, and include a JavaDoc method comment for each method in your program.
-
You will also need to fill out the README.txt file. You can open this file in BlueJ by double-clicking on the white paper icon in the upper left corner of the class window. You should place the answer to each question below the question box, replacing the "<Replace this with your response!>". Remember to save your changes (select "Class > Save" from the menu).
- The README as a few more questions that normal, be sure and fill it out completely!
-
You should compress the entire Hwk7 folder into a single zip file (like you did for Lab A), and then submit it to the Hwk7 Submission page on Moodle.
- Be sure an upload the ENTIRE project folder--that is what includes all your work!
- This assignment is due at midnight on
Fri, Apr 10Sun, Apr 12.
Grading
This assignment will be graded out of 28 points.
- HangmanGame (18pt)
- [1pt] Your program has and uses appropriate instance variables
- [2pt] Your program fully supports both constructors
- [1pt] Each game uses a random word from the provided list
- [1pt] A game can be played via the
playGame()
method - [1pt] The word-so-far is shown with spaces between the letters
- [1pt] The player inputs letter guesses via the Scanner
- [3pt] Your program recognizes correct letters and replaces them in the word-so-far
- [1pt] Your program replaces all instances of a correct letter in the word-so-far
- [2pt] Your program recognizes incorrect letters, which cause a player to lose a life
- [3pt] Your program recognizes previously-guessed letters (and displays appropriate output)
- [1pt] Players do not lose a life for guessing a previously-guessed letter
- [2pt] A game ends when the player guesses all the letters o when the player loses all their lives
- [1pt] A HangmanGame object can be played a second time, with a new word and everything
- Style & Documentation (10pt)
- [2pt] You use appropriate data types for the word-so-far and letters already guessed
- [2pt] Your program avoids code duplication by using helper methods
- [1pt] Helper methods have appropriate method signatures (private, with useful params and return values)
- [1pt] Your program shows good cohesion in its methods
- [2pt] You have included a full JavaDoc comment (with
@param
and@return
tags) for each method, including constructors - [1pt] You include inline comments to explain the why of your code (especially the
playGame()
method) - [1pt] You have completed the included README.txt file