CSCI 161 Homework Assignment 6 - Evil Hangman
Due Fri Oct 26 at 11:59pm
Introduction
For this assignment, you will be modifying your Hangman game from the last homework and giving it the ability to become... well... evil. To do this, you'll practice with searching and sorting, using all sorts of collections, and extending your previous code.
The Assignment
You will be making an evil version of Hangman--that is, a single-player game of Hangman where the computer cheats. This game will work just like regular hangman, except that if the player guesses the correct letter, the computer changes to a different word. A flowchart describing one way the game works can be found here.
The output from the game should be the same as the previous version--however, it will be incredibly challenging for a player to actually guess the word in time!! Your HangmanGame program will be able to support both versions of Hangman: normal, and evil!
As always, be sure to download and unzip a copy of the the Homework 6 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).
NOTE: You will need to copy your HangmanGame class from the last assignment into this one! Make a new HangmanGame class in the Homework 6 project, but copy and paste the code from Homework 5 into it! Make sure that you can run this class and it works just like the first homework. If you didn't finish that homework, you will need to for this assignment!
- In order to make sure that everyone is able to complete this homework, I have made available a solution to the last homework assignment. You can download this solution and use it as the basis for this assignment. Make sure you read through the solution carefully so you understand how it all works before you start modifying it!
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, fields, and the
toggleEvil()
methodAs always, we'll start with constructors and fields. You'll need to add a new field to represent whether your game is evil or not. Each of your existing constructors will need to initialize this field. Then create a new constructor (see the documentation) that takes in a boolean as a parameter as to whether the game is evil or not. Otherwise, this new constructor should look exactly like your default constructor
-
For this homework, you'll probably want to test it with a shorter list of words to use. You can do this by creating a new file file inside the project folder--for example,
test_words.txt
. Inside this file you can make a small list of words to choose from. Each word should be lower-case and goes on a separate line (with no other punctuation). You can tell your program to use this list instead of the normal list by specifying the filename in the constructor for your WordList object:WordList wl = new WordList("test_words.txt");
- HINT: Your test words don't need to be actual words. A nice test set is:
bead, beid, beod, baed, baid, boed,
which lets you try to guess vowels and see if the proper words are disappearing.
- HINT: Your test words don't need to be actual words. A nice test set is:
- You should also add a
toggleEvil()
method that changes whether the game is evil or not.
-
For this homework, you'll probably want to test it with a shorter list of words to use. You can do this by creating a new file file inside the project folder--for example,
-
Write the method signature for
checkGuessEvil()
So your evil game is going to work pretty much exactly the same way as the non-evil game: it will still ask the player for a guess, etc.. Really, the only difference is in how you check if a guess is correct--rather than saying that it is, you cheat and change the word! So make a new method
checkGuessEvil()
that will be the evil version of your previouscheckGuess()
method. Start by just making the signature--you'll fill the method in during a later step.- Now you'll need to adjust your playGame method so that it uses checkGuessEvil() instead of checkGuess() when you are in evil mode. You'll need to have your program make a decision based on which mode you are in, and then either call checkGuess or call checkGuessEvil(). In either case, the method called will return whether the letter was found and do any replacing if the letter was found. (Note that if you designed your helper methods differently than suggsted, you will need to adapt these instructions).
- Test that this works--your game should continue to play as normal if you are not in evil mode, and the checkGuessEvil() method should be called if you are in evil mode (you can see if the method is called by including a temporary print statement such as "checkGuessEvil was called!"). You can even fill checkGuessEvil() temporarily with the code from checkGuess(), which should cause your game to play normally even when in evil mode.
- Actually, because your word will keep changing, it might be a good idea to print out the current target word at the start of the playGame loop, for debugging purposes (you will of course comment out this println when you turn in your game)!
-
Define and initialize the
possibleWords
variableThe game will cheat by picking a new word whenever the player was about to get a letter right. This means that you'll need to pick a new word from the list. However, you can't just pick any word--the word need to match what you're currently telling the user it looks like. If you tell the user the word looks like "a _ _ _ _", then you can't pick "baseball" as your word! Similarly, if the user has already guessed 'b' and you said the word has no b's, you can't pick "baseball". So you'll want to keep track of what are the possible words you can pick from, so that when you pick a new word you're picking it from a list of valid options.
- You'll need to make a new field to keep track of the possible words. Think about what kind of data structure this field will be. There may be a hint in the documentation. You'll also need to initialize the variable inside the setupGame method (even though it will only be used in evil mode, you can still keep track of it in all modes). Remember that the possible words lists should only contains that are actually possible given the current target word, revealed letters, and previously guessed letters.
- Be careful not to change the main word list! You will need to use that list to play multiple games! Instead, you want to make a new list of words and just add all possible words to that list!
- Remember to test that you've made and initialized this variable correctly by inspecting the HangmanGame object! It may also be helpful to print out this this list of possible words at the start of your playGame loop, for debugging purposes (again, comment out this printing before you turn in your program)!
-
Write the
findPossibleMatchingWords()
methodNext you're going to have to be able to find the list of possible words. no matter what the current state of the game is. Create a method to do this, that returns a new list of possible words. This method will look like a standard searching method. A very basic outline in pseudo-code for this method is below:
for potentialWord in possible words determine if revealed letters of targetWord are at the same spots in potentialWord determine if unrevealed letters of targetWord are not in the alreadyGuessed list if(both of the above are true) add word to list of new possible words return new list of possible words
- You'll need to pick possible words based on 2 criteria: (1) each revealed letter matches the possible word, and (2) any unrevealed letters have not already been guessed.
- HINT: don't actually remove words from the possible words list! Instead, figure out whether a word is possible, then add it to a new list of possible words, and then return that new list (which you can assign to the possible words variable later)
- This method is a bit harder to test, but you can temporary try calling it from your playGame or checkGuessEvil method, print out the results, and make sure it returns the words you'd expect it to at each stage in the game.
-
Write the
findPossibleWithoutLetter()
methodUPDATE: I'm not sure what I was thinking when I wrote the asignment, but you should be able to just re-use the above method instead of writing a new one. Writing another method is fine, but may not be necessary! I'm leaving the below instructions in case anyone needs them.
When a user guesses a correct letter, you're going to want to see if you can tell them that's wrong and pick a different word. That is to say, you're going to want to check to see if there are any other possible words that don't have the guessed letter. Write a method that finds any possible words that don't have a given letter. This method will look very similar to the above method in structure.You'll need to pick possible words based on just one criteria: they do not contain the given letter. You can assume that the words in the possible words list are otherwise valid.Again, don't actually remove words from the possible words list! Instead, build a new list of valid words (words that don't have the letter) and return that.This method is much easier to test than the last: just call it with a given letter, and make sure none of the words it returns has that letter!
-
Write the
checkGuessEvil()
methodOkay, now you should be all ready to fill in your
checkGuessEvil()
method! This method should work similarly to the original checkGuess() method. However, if it finds the guessed letter, it should instead check if there are any other possible wordswords that don't have that letter it can switch to. If there are, it can switch to one of those words and pretend that the letter was never there. If there aren't any words without that letter, then you'll have to reveal it and re-update the list of possible words (since you've now revealed a letter).Note that checkGuessEvil() is going to do the same work as checkGuess(), except that instead of immediately telling the player they got the right answer, we're going to see if we can change the target word so that they actually go it wrong. Some psuedocode is below
go through each letter in the current word and see if the guess is right if the guess is wrong return that they are wrong (no further action required) if the guess is right check to see if there are any possible words (now that another letter has been guessed) if there is another possible word switch to another random possible word return that they are wrong (because the word has changed to make them wrong!) otherwise if there is NOT another possible word go through the underscores and reveal the letter update to see if there are any possible words (now that another letter has been revealed) return that the player got the letter right (and so shouldn't lose a life)
- Remember to use the methods you just wrote and tested!
- You can test this method by playing a HangmanGame, or testing the same way you tested your original checkGuess() method!
-
Check that it works
In the end, I should be able to play an evil game of hangman and lose. A lot. (You may want to increase the number of lives available so I have a fighting chance). I should be able to play multiple evil games, and use the toggleEvil() method to turn evil on and off between games.
-
Clean up your code
Remember to remove any debugging print statements! You don't want to give the game away to the user, do you? ;)
-
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).
Extensions
The same extensions from the last homework apply to this homework; if you haven't done them yet, you can do them now! I particularly recommend doing the graphical print-out, it may come in handy for a future homework! Remember to save a working copy of your code before trying any extensions, just in case something breaks!
- If you're feeling really ambitious, try coming up with a better cheating algorithm. The best cheating algorithm would be one that always leaves as many choices as possible for the player. For example, it might be better to tell the player that there is a single 'e' in the word than to throw out ALL the words that don't have an 'e'. For more details, see the original Evil Hangman assignment by Keith Schwarz.
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 Hwk6 of course).
Submitter will look for the HangmanGame.java
file.
Grading
This assignment will be graded on the following criteria:
- Your program can still play a normal, non-evil game of Hangman [10%]
- Your game can be set to evil mode, and plays evily went told to [10%]
- Your game has a working toggleEvil() method [5%]
- Your game keeps track of possible words it can choose from [10%]
- You can search through the list of possible words for ones that match [10%]
- You can search through the list of possible words for ones that don't contain a certain letter [10%]
- Your game is able to cheat by picking a new, valid word [25%]
- Your code is carefully documented, with proper Javadoc methods [10%]
- Your code uses good style. This means that variables are given descriptive names, tabs and braces are lined up, local variables aren't specified in the fields, 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 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 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 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(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. |
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 |
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(String debugWord)
Method Detail |
---|
checkGuess
public boolean checkGuess(char letter)
checkGuessEvil
public boolean checkGuessEvil(char letter)
currentGuessString
public String currentGuessString()
findPossibleMatchingWords
public ArrayList<String> findPossibleMatchingWords()
findPossibleWithoutLetter
public ArrayList<String> findPossibleWithoutLetter(char letter)
getGuess
public char getGuess()
playGame
public void playGame()
setupGame
public void setupGame()
toggleEvil
public void toggleEvil()