3
\$\begingroup\$

I can't seem to get the formatting right, so here is the pastebin if needed: http://pastebin.com/g6VmdYbM

public class Hangman {
///////////////////////////////////
// Global Variables
///////////////////////////////////

private static String[] correctPhrase = new String[5];
private static String[] currentGuessPhrase = new String[5];
private static char[] currentGuesses = new char[26];
private static int totalWrong = 0;
private static int totalGuesses = 0;
private static int count;
private static char guess;

///////////////////////////////////
// Methods
///////////////////////////////////

public static void makePhrase() {
    //Clear guesses
    for (int x = 0; x < currentGuesses.length; x++){
        currentGuesses[x] = ' ';
    }
    totalWrong = 0;
    totalGuesses = 0;
    //Preset Phrases (Must be 5 words)
    String[] phraseOne = { "this", "is", "a", "sample", "phrase" };
    String[] phraseTwo = { "another", "phrase", "is", "right", "here" };
    String[] phraseThree = { "finally", "this", "is", "the", "last" };
    //Random words for selection
    String[] wordBank = { "a", "ate", "apple", "banana", "bored", "bear",
            "cat", "cow", "carried", "died", "during", "deer", "elephant",
            "flame", "fire", "fruit", "forgave", "forged", "fears", "goat",
            "good", "game", "gave", "greeted", "glory", "ham", "hairy",
            "heaven", "horrible", "I", "illegal", "important", "jammed",
            "juice", "kangaroo", "liar", "loved", "money", "miracles",
            "monday", "named", "never", "noun", "now", "nor", "orange",
            "obligated", "person", "people", "peeled", "quit", "retired",
            "rain", "saved", "sunny", "soaring", "salmon", "sealed",
            "today", "tomorrow", "trained", "the", "umbrella", "up",
            "under", "violent", "violin", "when", "while", "year", "zoo" };
    //Get phrase type
    Scanner in = new Scanner(System.in);
    System.out.println("\n(1) Random Words (2) Presets (3) Custom");
    int phraseType = in.nextInt();
    if (phraseType == 1){
        for (int x = 0; x < 5; x++) {
            correctPhrase[x] = wordBank[(int) Math.round(Math.random() * 61)];
        }
    } else if (phraseType == 2) {
        int phrase = (int) Math.round(Math.random() * 2);
        switch (phrase){
            case 0: correctPhrase = phraseOne.clone();
            case 1: correctPhrase = phraseTwo.clone();
            case 2: correctPhrase = phraseThree.clone();
        }
    } else if (phraseType == 3){
        Scanner in2 = new Scanner(System.in);
        System.out.println("5 Word Phrase: ");
        correctPhrase = in2.nextLine().split("\\s");
    }

    //Create duplicate with underscores
    for (int x = 0; x < correctPhrase.length; x++) {
        currentGuessPhrase[x] = correctPhrase[x].replaceAll(".", "_");
    }
}

public static char getGuess() {
    Scanner in = new Scanner(System.in);
    // Retrieve next guess
    System.out.println("\nGuess:");
    char guessInput = in.next().charAt(0);
    return Character.toLowerCase(guessInput);
}

public static boolean checkGuess(char guess) {
    // Add to guessed chars
    currentGuesses[totalGuesses] = guess;
    totalGuesses++;
    // Count number of occurrences
    count = 0;
    for (int x = 0; x < correctPhrase.length; x++) {
        for (int a = 0; a < correctPhrase[x].length(); a++) {
            if (correctPhrase[x].charAt(a) == guess) {
                count++;
            }
        }
    }
    if (count == 0) {
        return false;
    } else {
        return true;
    }
}

public static void updateGuess(char guess) {
    // Define char array from currentGuess for alerting
    char[][] currentGuessArray = new char[currentGuessPhrase.length][];
    for (int x = 0; x < currentGuessPhrase.length; x++) {
        currentGuessArray[x] = currentGuessPhrase[x].toCharArray();
    }
    //Assign valid values of guess to currentGuessArray
    for (int x = 0; x < correctPhrase.length; x++) {
        for (int a = 0; a < correctPhrase[x].length(); a++) {
            if (correctPhrase[x].charAt(a) == guess) {
                currentGuessArray[x][a] = guess;
            }
        }
    }
    // Convert chars back to string array
    for (int x = 0; x < currentGuessArray.length; x++) {
        currentGuessPhrase[x] = new String(currentGuessArray[x]);
    }
}
public static void drawBoard(){

    // Print previous guesses
    System.out.println("\nGuesses:\n");
    for (int x = 0; x < currentGuesses.length; x++) {
        System.out.print(currentGuesses[x] + " ");
    }
    // Draw hangman
    System.out.print(" \n ");
    if (totalWrong == 0){
        System.out.print("\n______" +
                         "\n|    |" +
                         "\n|     " +
                         "\n|     " +
                         "\n|     " +
                         "\n|     " +
                         "\n|     ");
    } else if (totalWrong == 1){
        System.out.print("\n______" +
                         "\n|    |" +
                         "\n|    O" +
                         "\n|     " +
                         "\n|     " +
                         "\n|     " +
                         "\n|     ");
    } else if (totalWrong == 2){
        System.out.print("\n______" +
                         "\n|    |" +
                         "\n|    O" +
                         "\n|    |" +
                         "\n|     " +
                         "\n|     " +
                         "\n|     ");
    } else if (totalWrong == 3){
        System.out.print("\n______" +
                         "\n|    |" +
                         "\n|    O" +
                         "\n|    |" +
                         "\n|   / " +
                         "\n|     " +
                         "\n|     ");
    } else if (totalWrong == 4){
        System.out.print("\n______" +
                         "\n|    |" +
                         "\n|    O" +
                         "\n|    |" +
                         "\n|   / \\" +
                         "\n|     " +
                         "\n|     ");      
    } else if (totalWrong == 5){
        System.out.print("\n______" +
                         "\n|    |" +
                         "\n|    O" +
                         "\n|    |-" +
                         "\n|   / \\" +
                         "\n|     " +
                         "\n|     ");  
    } else if (totalWrong == 6){
        System.out.print("\n______" +
                         "\n|    |" +
                         "\n|    O" +
                         "\n|   -|-" +
                         "\n|   / \\" +
                         "\n|     " +
                         "\n|     " +
                         "\n\n YOU DIED!");
        //Print correct phrase
        System.out.println("\n");
        for (int x = 0; x < correctPhrase.length; x++){
            System.out.print(correctPhrase[x] + " ");
        }
    }
    //Print guessPhrase
    System.out.println("\n");
    for (int x = 0; x < currentGuessPhrase.length; x++){
        System.out.print(currentGuessPhrase[x] + " ");
    }
}
public static boolean goAgain(){
    //Retreive yes/no
    int dialogButton = JOptionPane.YES_NO_OPTION;
    int dialogResult = JOptionPane.showConfirmDialog(null, "Play again?", "Hangman", dialogButton);
    if (dialogResult == 0 ){
        return true;
    } else {
        return false;
    }
}

///////////////////////////////////
// Main Method
///////////////////////////////////

public static void main(String[] args) {
    boolean goAgain = true;
    boolean isCorrect;
    makePhrase();
    while (goAgain){
        //Print correct for debugging
        /*for (int x = 0; x < correctPhrase.length; x++){
            System.out.print(correctPhrase[x] + " ");
        }
        */
        drawBoard();
        guess = getGuess();
        isCorrect = checkGuess(guess);
        //Update board
        if (isCorrect) {
            updateGuess(guess);
        } else {
            totalWrong++;
        }
        //Determine loss
        if (totalWrong == 6){
            drawBoard();
            goAgain = goAgain();
            if (goAgain){
                makePhrase();
            } else {
                break;
            }
        }
        //Determine win
        if (Arrays.equals(correctPhrase, currentGuessPhrase)){
            System.out.println("\nYOU WIN!" +
                               "\n     O" +
                               "\n    -|-" +
                               "\n    / \\");
            for (int x = 0; x < correctPhrase.length; x++){
                System.out.print(correctPhrase[x] + " ");
            }
            goAgain = goAgain();
            if (goAgain){
                makePhrase();
            }
        }
    }
}
}
\$\endgroup\$
1
  • 5
    \$\begingroup\$ what you mean by efficient? \$\endgroup\$
    – gurghet
    Commented Nov 25, 2013 at 22:52

2 Answers 2

6
\$\begingroup\$

So, going through your code I am struck by a few things....

  • static variables are seldom the 'right' way to do things in Object Oriented languages like Java. Other than for constants, it is a red flag that something is wrong.
  • you have a problem with generating random numbers... e.g. Math.round(Math.random() * 2) will, in fact, generate values of 0, 1, and 2, but it will generate the value '1' twice as many times as it generates the values 0 or 2. The 'right way' for doing random numbers is here on StackOverflow. In this case, you want to create a Random randgen = new Random() instance, and use the nextInt() instance method to get random numbers: randgen.nextInt(range) or, in your 0,1,2 example, you want randgen.nextInt(3);
  • The code correctPhrase[x] = wordBank[(int) Math.round(Math.random() * 61)]; is ugly. The 61 is a 'magic number' and would be best to replace with wordBank.length. The normal mechanism for this line of code is: correctPhrase[x] = wordBank[randgen.nextInt(wordBank.length)]; (using the same randgen instance we created above.
  • you do not convert the 'custom' input phrase to lowercase, which could result in issues, and you should validate that it only has 5 words... otherwise in the next piece of code you could gt an indexout-of-bounds exception when creating the underscore version.
  • getGuess() appears to be fine.
  • checkGuess() is ugly because of the static variables again, and, in fact, the code is essentially a subset of the updateGuess() method. `checkGuess() can be completely removed.... I will describe how, in a moment.
  • the drawBoard() method has lots of code and constant repetition. I would find a way to put a 'blank' board in an array of values (one per line), and then copy that array for each 'totalWrong, but adjust the lines where needed. Then, you can just loop through the lines that are relevant for your 'totalWrong' state (i.e. remove most of the code duplication).
  • the goAgain() method suddenly has GUI components... odd...
  • the main() method appears to be straight-forward enough, but would change a lot if you do what I suggest below:

Suggestion, merge the logic of checkGuess() in to updateGuess():

public static boolean guess(char guess) {
    // Define char array from currentGuess for alerting
    char[][] currentGuessArray = new char[currentGuessPhrase.length][];
    for (int x = 0; x < currentGuessPhrase.length; x++) {
        currentGuessArray[x] = currentGuessPhrase[x].toCharArray();
    }

    boolean goodguess = false;
    //Assign valid values of guess to currentGuessArray
    for (int x = 0; x < correctPhrase.length; x++) {
        for (int a = 0; a < correctPhrase[x].length(); a++) {
            if (correctPhrase[x].charAt(a) == guess) {
                currentGuessArray[x][a] = guess;
                goodguess = true;
            }
        }
    }
    // Convert chars back to string array
    for (int x = 0; x < currentGuessArray.length; x++) {
        currentGuessPhrase[x] = new String(currentGuessArray[x]);
    }
    return goodguess;
}

You can then adapt the main method to:

    if (!guess(guess)) {
        totalWrong++;
    }    

EDIT

Why static fields are ugly .... (and yes, I probably should have been more descriptive about this, but it is a big topic to answer)

Static fields (not final/constant) are used to store program state. This is a bad pattern in OOP because it means your state is not encapsulated. Consider, for the moment, that a 'better' way to solve your problem would be:

public static final void main (String[] args) {
    do {
        String phrase = getPhrase();
        Hangman game = new HangMan(phrase);
        game.play();
    } while (goAgain());
}

Then, you have a Hangman class that encapsulates the state for that instance of the game only:

public class Hangman {
     private final String[] correctPhrase = new String[5];
     private final String[] currentGuessPhrase = new String[5];
     private final char[] currentGuesses = new char[26];
     private int totalWrong = 0;
     private int totalGuesses = 0;

     ... and lots of code to make the game work....

}
\$\endgroup\$
1
  • \$\begingroup\$ static members are neither good nor bad, it depends on how you design your program and what its intended use is. In this particular case, yes, static is the wrong way to go about it. \$\endgroup\$
    – Max
    Commented Nov 26, 2013 at 8:59
2
\$\begingroup\$

This code in makePhrase() should be a switch block:

if (phraseType == 1) {
    ...
} else if (phraseType == 2) {
    ...
} else if (phraseType == 3) {
    ...
}

Within the phraseType == 2 case, your switch is buggy: all cases flow through to correctPhrase = phraseThree.clone().

The cascading if-elses in drawBoard() should also be put into a switch. Better yet, there should be an array with all of the images, then you could index into the array:

private static final String[] IMAGES = {
    // Initial:
    "\n______" +
    "\n|    |" +
    "\n|     " +
    "\n|     " +
    "\n|     " +
    "\n|     " +
    "\n|     ",

    // 1 wrong:
    "\n______" +
    "\n|    |" +
    "\n|    O" +
    "\n|     " +
    "\n|     " +
    "\n|     " +
    "\n|     ",

    // etc.

    // 6 wrong:
    "\n______" +
    "\n|    |" +
    "\n|    O" +
    "\n|   -|-" +
    "\n|   / \\" +
    "\n|     " +
    "\n|     " +
    "\n\n YOU DIED!"
};

Then it's just System.out.print(IMAGES[totalWrong]);.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.