Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Java

Jonathan Grieve
MOD
Jonathan Grieve
Treehouse Moderator 91,254 Points

Bug: Program doesn't recognise uppercase letters in guesses, even with toLowerCase()

Hi there.

I have a bug in the Hangman game I've written. If I use an uppercase letter in the guess that I pass in to the program e.g. my name..

clear && javac Hangman.java && java Hangman Jonnie

the game will not recognise that letter.

Of course this will mean you cannot win the game as the word will not be filled in.

I thougth the toLowercase method was meant to stop this?

public class Game {
  //variable declared but not initialised
  private String mAnswer;
  public static final int MAX_MISSES = 7; 

  //initialise hit and miss guess variables. 
  private String mHits;
  private String mMisses;

  //constructor function that takes an answer in form of a string
  public Game(String answer) {
     mAnswer = answer;   
       mHits = "";
     mMisses = "";  
  }

  private char validateGuess(char letter){
   if(! Character.isLetter(letter)) {
      throw new IllegalArgumentException("A letter is required");
   }
   letter = Character.toLowerCase(letter);
   if(mMisses.indexOf(letter) >= 0 || mHits.indexOf(letter) >= 0) {
       throw new IllegalArgumentException("Sorry, " + letter + " has already been guessed. Try another letter"); 
   }
   return letter;
}


  public boolean applyGuess(String letters) {
    if(letters.length() == 0) {
      throw new IllegalArgumentException("Error: We found no letter. Please type a letter");
    }
     char firstLetter = letters.charAt(0);
     return applyGuess(firstLetter);
    }


  //add letters to hit and misses depending on guess
  public boolean applyGuess(char letter) {
     letter = validateGuess(letter);
     boolean isHit = mAnswer.indexOf(letter) >= 0;
     if (isHit) {
        mHits += letter;
        return true;

     }  else {
        mMisses += letter;
        return false;

     }
  }

  //method to display the current progress of the game 
  public String getCurrentProgress() {
    //empty string
    String progress = "";
    //loop through each letter of the answer   
    for (char letter : mAnswer.toCharArray()) {
    //default word display that hides the letter
    char display = '-';

    //if the letter is guessed correctly add that letter to progress
    if(mHits.indexOf(letter) >= 0) {
       //change display to the letter
       display = letter;
    }

    progress += display;

  }
return progress;
}

public int getRemainingTries() {
    return MAX_MISSES - mMisses.length();
  }

public boolean isSolved() {
  return getCurrentProgress().indexOf('-') == -1;
} 

public String getAnswer() {
  return mAnswer;
}


}
//Import package
import java.io.Console;

public class Prompter {

  //private member variable
  private Game mGame;   

  //constructor function
  public Prompter (Game game) { 
      //set member variable equal to what is passed in
      mGame = game;
   }

  public void playTheGame() {
    while(mGame.getRemainingTries() > 0 && !mGame.isSolved()) {
     displayProgress();
     promptForGuess();
    }

    if(mGame.isSolved()) {
      System.out.printf("You won the game with %d tries remaining.\n", mGame.getRemainingTries());
    } else {    
      System.out.printf("Unlucky! The word was %s.  :(\n", mGame.getAnswer());
    }
  }

  //a prompter method for the user to guess new letters  
  public boolean promptForGuess() {

      //store console Object and set up prompter
      Console console = System.console();

      boolean isHit = false;
      boolean isValidGuess = false;

      //while the guess is not valid catch the iae 
      while(! isValidGuess) {
        String guessAsString = console.readLine("Enter a letter: ");

        try {
          isHit = mGame.applyGuess(guessAsString);
          isValidGuess = true;
        } catch (IllegalArgumentException iae) {
         console.printf("%s.  Please try again \n", iae.getMessage());
        }
      }

      //define new guess in a char variable.
      return isHit;

  } 


  public void displayProgress() {
      System.out.printf("You have %d guesses remaining to solve:  %s.\n", 
                          mGame.getRemainingTries(),
                          mGame.getCurrentProgress());
  }


}
public class Hangman {

    public static void main(String[] args) {
        // Enter amazing code here:

        if(args.length == 0) {

             System.out.println("Please enter a word");
             System.exit(0);

           }

           //enter the first element of args array as argument
           Game game = new Game(args[0]);


        //Supply a string to start the game.
        //Game game = new Game("antidisestablishmentarism");

        //The following code calls the prompterForGuess method with a new Prompter object.
        Prompter prompter = new Prompter(game);

        prompter.playTheGame();
        //variable from Prompter object assigned to method.
       /* prompter.displayProgress();
        boolean isHit = prompter.promptForGuess();

        if(isHit) {
             System.out.println("We got a Hit!");
        } else {
             System.out.println("Whoops that was a miss");  
        }
        prompter.displayProgress();*/
    }

}

2 Answers

Jason Anders
MOD
Jason Anders
Treehouse Moderator 145,863 Points

Without me running a check in an IDE, would just changing the assignment of the answer in the constructor to lowercase solve this?

In the Game class, try changing the constructor to:

public Game(String answer) {
     mAnswer = answer.toLowerCase();   
       mHits = "";
     mMisses = "";  
  }
Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,254 Points

Bingo,

Well that was easier than I thought. Works perfectly now. Though I'll be interested to see if that is something I missed from the course.

I'm still a novice in Java and I wish I could say I picked up more than I have. :)

Jason Anders
Jason Anders
Treehouse Moderator 145,863 Points

I thought that too when I first stated Java, but then the "ah-ha" moment happened, and now I'm kind of hooked on it. Lol.

I'm just glad that it was that easy of a fix. :)

Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,254 Points

I'll get there,

I'm seeing a few similarities to C in that it's a compiled language and the way you display variables with your format specifiers. When I finally get this course finished I intend to study the code until I'm comfortable with that's happening. As I said in another thread, the information is in my brain somewhere, I just don't know where it goes :P

Jason Anders
MOD
Jason Anders
Treehouse Moderator 145,863 Points

Hey Jonathan,

Just a quick glance, but a question. You're putting the guesses down to lowercase, but I don't see you putting the inputed answer down to lowercase. So, if you enter "Jonnie" as the answer, the J is uppercased, but all the guesses will be lowercase; therefore, you will never match the uppercase J in the answer.

:dizzy:

Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,254 Points

So I'm going to have to find a way to change the answer on the array rather than the letter variable so all letters will be recognised as lowercase?

Or simply advise users not to use uppercase letters ;)

Jason Anders
Jason Anders
Treehouse Moderator 145,863 Points

Either or...

I would find a way to lowercase the answer input and lowercase the guesses... then everything is lowercase and all should be good. :smiley: (Cuz, we all know how much we can trust users with instructions. Lol.)

Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,254 Points

I just wish I never though to test uppercase J or I'd not have this headache ;)

But yes I'll have a look at lowercasing the input in args. I'm hoping it's just a simple case of replacing some variable values but it may mean a refactor of the whole program. Which is good. I may do this on a new workspace or when I get to running Java in an IDE :)

I will update this thread as and when.