3

So here's yet another hangman question to add to the library here. My entity and boundary classes are all but complete save for a method called revealLetter() that replaces the blanks with the correctly guessed letter. It also counts the number of correctly guessed letters (if any) and returns that integer to the driver to determine if it strikes a miss or hit. revealLetter() will return zero if the user entered a wrong letter, or it will return the number of correct letters to determine a correct letter. My problem is that revealLetter() always returns a zero, despite filling in the correct letter. I have thrown in a few sout's to isolate whats happening, and it appears the counter is set to zero after exiting my for loop. I'm still learning Java, so there is a good chance it is something simple, but it seems complex to me at the moment. Here is the Driver:

package hangman;

import java.util.Scanner;

public class Hangman {

public static int NUMBER_MISSES = 5;

public static void main(String[] args) {

    String guessedLetter;
    WordHider hider = new WordHider();
    Dictionary dictionary = new Dictionary();

    Scanner Keyboard = new Scanner(System.in);
    hider.setHiddenWord(dictionary.getRandomWord());
    System.out.println(hider.getHiddenWord().length());
    System.out.println(hider.getHiddenWord());

    do {
        hider.wordFound();
        System.out.printf(hider.getPartiallyFoundWord() + "   Chances Remaing: %d \nMake a guess: ", NUMBER_MISSES);
        guessedLetter = Keyboard.nextLine();
        hider.revealLetter(guessedLetter.toLowerCase());
        if (hider.revealLetter(guessedLetter)== 0) {
            NUMBER_MISSES--;
            if (NUMBER_MISSES == 4) {
                System.out.println("Swing and a miss!");
            }
            else if (NUMBER_MISSES == 3) {
                System.out.println("Yup. That. Is. A. Miss.");
            }
            else if (NUMBER_MISSES == 2) {
                System.out.println("MISS! They say third time is a charm.");
            }
            else if (NUMBER_MISSES == 1) {
                System.out.println("Ouch. One guess left, think carefully.");
            }              
        } else {
            System.out.println("That's a hit!");
        }
        if (hider.wordFound() == true) {
          NUMBER_MISSES = 0;
        }
    } while (NUMBER_MISSES > 0);

    if ((NUMBER_MISSES == 0) && (hider.wordFound() == false)) {
        System.out.println("Critical Failure. The word was " + hider.getHiddenWord() + " try harder next time and you'll win.");
    } else if ((NUMBER_MISSES == 0) && (hider.wordFound() == true)) {
        System.out.println(hider.getHiddenWord() + "\nBingo! You win!");
    }

}

}

This is the class that stores words from a .txt to an array and generates a random word:

package hangman;

import java.util.Random;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Dictionary {

//Random randomizer = new Random();
private static String randomWord;
String[] dictionary = new String[81452];
private static String FILE_NAME = "dictionarycleaned.txt";

Dictionary() {
    int words = 0;
    Scanner infile = null;
    try {
        infile = new Scanner(new File(FILE_NAME));
        while (infile.hasNext()) {
            dictionary[words] = infile.nextLine();
            words++;

        }
        //System.out.println(dictionary[81451]);
    } catch (FileNotFoundException e) {
        System.err.println("Error opening the file " + FILE_NAME);
        System.exit(1);
    }

}

public String getRandomWord(){
  //randomWord = (dictionary[randomizer.nextInt(dictionary.length)]);  //Are either of these techniques better than the other?
  randomWord = (dictionary[new Random().nextInt(dictionary.length)]);
  return randomWord;    
}

}

And this is the class that contains revealLetter(), it also handles the random word:

package hangman;

public class WordHider {

private static String hiddenWord;
private static String partiallyFoundWord;

WordHider() {

    hiddenWord = "";
    partiallyFoundWord = "";

}

public String getHiddenWord() {
    return hiddenWord;
}

public String getPartiallyFoundWord() {

    return partiallyFoundWord;

}

public void setHiddenWord(String newHiddenWord) {
    int charCount;
    hiddenWord = newHiddenWord;
    for (charCount = 0; charCount < hiddenWord.length(); charCount++) {
        partiallyFoundWord += "*";
    }

}

public int revealLetter(String letter) {
    int correctChars = 0;

    if (letter.length() < 1 || letter.length() > 1) {
        correctChars = 0;
        return correctChars;
    } else {

        String tempString = "";

        for (int i = 0; i < hiddenWord.length(); i++) {
            if ((letter.charAt(0) == hiddenWord.charAt(i)) && (partiallyFoundWord.charAt(i) == '*')) {                   
                correctChars++;
                tempString += Character.toString(hiddenWord.charAt(i));

            } else {
                tempString += partiallyFoundWord.charAt(i);



            }

        }
        partiallyFoundWord = tempString;           
    }

    return correctChars;
}

public boolean wordFound() {
    boolean won = false;
    if (partiallyFoundWord.contains(hiddenWord)) {
        won = true;
    }
    return won;
}

public void hideWord() {
    for (int i = 0; i < hiddenWord.length(); i++) {
        partiallyFoundWord += "*";
    }

}

}

It is also worth noting that I am in a CS college course and there is a strict law on copying code that does not belong to me. So if any kind soul that happens across this, could you explain what I am doing wrong in mostly English. I would still like to figure the code out, I'm just logically stuck. Thanks in advance

LumberSzquatch
  • 1,054
  • 3
  • 23
  • 46
  • 3
    I boldfaced your notice about copying code, so people don't accidentally overlook it and give you a full solution. That being said, have you tried running the code in a debugger such as the one that might be included with an IDE such as Eclipse, Netbeans,' or IntelliJ IDEA? – nanofarad Aug 29 '14 at 16:16
  • 1
    Thanks for that chap! Yeah, I ran the debugger (in Netbeans) specifically on the revelLetter() method call and it appears to go through the for loop and it will correctly add the letters, but I do not know what is happening after that for loop. And if I place an sout statment above the return correctChars, it prints the number of correctly guessed letters (be it 1, 2 or 3) but then it also prints a zero. Which leads me to think there is a second iteration somewhere that is resetting my variable. But I can't seem to isolate the problem. – LumberSzquatch Aug 29 '14 at 16:31
  • I can't spot a specific problem, but I would suggest simplifying the if-condition in `revealLetter` to just `(letter.charAt(0) == hiddenWord.charAt(i))` as revealing an already-revealed letter should be a no-operation. In addition, why are your methods in tha class non-static while `hiddenWord` and `partiallFoundWord` are static? – nanofarad Aug 29 '14 at 16:37
  • I have the compound boolean so that it checks if position (i) is an asterisk, and if it is and the letter guessed is correct it adds that letter to the new string tempString along with the other unfilled blanks. Also I forgot, in the else in my for, correctChars gets set to zero. I'll edit that. As for the static/non-static; I am not sure, as I said I'm still learning, so that's probably just me glancing over things. Does it help for those to be static? – LumberSzquatch Aug 29 '14 at 16:47
  • Static means that it's the same across your application. Non-static means that you're getting a separate value for every instance of your class. If you're using a constructor like `new WordHider()` then generally non-static is the way to go. Refer to [this question and answers](http://stackoverflow.com/questions/3903537/i-want-to-know-the-difference-between-static-method-and-non-static-method) for more details. – nanofarad Aug 29 '14 at 16:50
  • Why thank you kind sir, both your comment and that Q&A were very resourceful. I appreciate your help. – LumberSzquatch Aug 29 '14 at 17:05

1 Answers1

4

In your driver main() you have:

hider.revealLetter(guessedLetter.toLowerCase());
if (hider.revealLetter(guessedLetter)== 0)

That's why you get one successful call then second time round there is nothing to do. There's a few stylistic issues I could highlight, but one big one is:

if (letter.length() < 1 || letter.length() > 1) {
    correctChars = 0;
    return correctChars;
} else {

Why not just letter.length() != 1, and since correctChars is already initialised to zero you don't need to do it again, so the whole "then" part can be dropped and the if becomes letter.length() == 1.

Also:

tempString += Character.toString(hiddenWord.charAt(i));

And:

tempString += partiallyFoundWord.charAt(i);                                   

Both do the same thing, so choose one style or the other.

Ken Y-N
  • 14,644
  • 21
  • 71
  • 114
  • Thank you for the advice, I really appreciate it. That shortened way of saying my if statement does look a hell of a lot better, less clunky. About the if in my main() though. So is that, that statement always receiving a zero as the return value and that's why it never goes to the else? – LumberSzquatch Aug 29 '14 at 16:58
  • Also in regards to the tempString += do you mean the both do the same thing exactly or in that they are two separate stylistic techniques for achieving the same desired outcome? – LumberSzquatch Aug 29 '14 at 17:11
  • The += are two different ways of achieving the same outcome, so choose the shorter form. You could also look at using a `StringBuilder` as there are slight performance benefits and might get you bonus points from your instructor! – Ken Y-N Aug 29 '14 at 17:34
  • I see, thank you for sharing that! I did a quick read up on StringBuilder's use and I can most definitely see its benefits. One last thing from you though good sir, if you'd be so kind. Could you elaborate on what you meant about the statement in my main()? I've been tinkering with it and I'm still a tad stuck. I'm still learning and my critical thinking is still developing, so I'm slightly missing your point. – LumberSzquatch Aug 29 '14 at 17:43
  • Nevermind on that! I re-read your comment and then removed my else out of main and it is nice and peachy now. Thank you for all of your help. – LumberSzquatch Aug 29 '14 at 17:56