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 Java Objects (Retired) Delivering the MVP Determining if It Is Solved

Dorka Tamas
Dorka Tamas
5,085 Points

The game is not running, it passes immediately to congratulations...

For some reason it doesnt run as it should be. I think I followed, I cannot find the problem. Here is my code. Thanks for the help!!

prompter.java: import java.io.Console;

public class Prompter { private Game mGame; //do we need to store?

public Prompter(Game game) {
    mGame = game;
}

public void play() {
    while (mGame.getRemainingTries() > 0 && !mGame.isSolved()) {
        displayProgress();
        promptForGuess();
    }
    if (mGame.isSolved()) {
        System.out.printf("Congratulations, you won with %d tries remaining\n",
                                                mGame.getRemainingTries());
    } else {
        System.out.printf("Sorry, the word was %s.  :(\n",
                                             mGame.getAnswer());
    }
}

public boolean promptForGuess() {
 Console console  = System.console();
 boolean isHit = false;
 boolean isValidGuess = false;
 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());
    }
 }   
 return isHit;
}

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

}

Hangman.java: public class Hangman {

public static void main(String[] args) {
    // Enter amazing code here:
        Game game = new Game("treehouse");
        Prompter prompter = new Prompter(game);
        prompter.play();
}

}

Game.java: public class Game { public static final int MAX_MISSES = 7; private String mAnswer; //What is a member variable? private String mHits; private String mMisses;

public 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(letter + " has already been guessed.");
    }
    return letter;
}

public boolean applyGuess(String letters) {
    if (letters.length() == 0) {
        throw new IllegalArgumentException("No letter found.");
        }
        return applyGuess(letters.charAt(0));
}

public Game(String answer) { //is this a constructor? - for forcing, dont understand why it is like this
    mAnswer = answer;
    mHits = "";
    mMisses = "";
}

public boolean applyGuess(char letter) {
    letter = validateGuess(letter);
    boolean isHit = mAnswer.indexOf(letter) >= 0;
    if (isHit) {
        mHits += letter;
    } else {
        mMisses += letter;
    }
    return isHit; //is this a must?
}

public String getCurrentProgress() { //?
    String progress = "";
    for (char letter :  mAnswer.toCharArray()) {
        char display = '_';
        if (mHits.indexOf(letter) >= 0) {
            display = letter;
        }
        progress += display;
    }
    return progress;
}

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

public String getAnswer() {
    return mAnswer;
}

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

}

4 Answers

You never get started because of the && (AND) in the 2nd line of code below:

public void play() {
    while (mGame.getRemainingTries() > 0 && !mGame.isSolved()) {
    . . . 

You have written isSolved() so that it is true at the beginning of the game. So !mGame.isSolved() is false, and since false rules with && the whole condition is false, and the game never starts.

If you change && to || (OR) the game will start, and play. Alternatively, you could check to see why isSolved() is true at the beginning of the game.

You have another bug, however:

You have 7 tries left to try to solve: _________
Enter a letter:  h
You have 7 tries left to try to solve: ____h____
Enter a letter:  t
You have 7 tries left to try to solve: t___h____
Enter a letter:  r
You have 7 tries left to try to solve: tr__h____
Enter a letter:  e
You have 7 tries left to try to solve: treeh___e

You aren't decrementing the number of hits the user has. So one has to miss 7 times to end the game.

I forgot to answer some of your questions.

   public Game(String answer) { //is this a constructor? - for forcing, dont understand why it is like this
       mAnswer = answer;
       mHits = "";
       mMisses = "";
   }

Yes, it is a constructor. It has the same name as the class. It takes one parameter: answer. So when you create a Game object, you have to provide an answer, as you do here:

Game game = new Game("treehouse");

in the Hangman class.

public class Game { 
   public static final int MAX_MISSES = 7; 
   private String mAnswer; //What is a member variable? 
   private String mHits; 
   private String mMisses;

Member variables, also called instance variables, belong the objects created from the class. So each game has its own set. Static variables or constants, also called class variables or class constants, belong to the class, and are shared by each class object. So the Game object game you create in Hangman has its own copies of mAnswer, mHits, and mMisses, but shares the class's MAX_MISSES constant.

   public boolean applyGuess(char letter) {
       letter = validateGuess(letter);
       boolean isHit = mAnswer.indexOf(letter) >= 0;
       if (isHit) {
           mHits += letter;
       } else {
           mMisses += letter;
       }
       return isHit; //is this a must?
   }

Yes, since the method's return type is not void, it must have a return statement, and since the return type is boolean, it must return a boolean.

   public class Prompter { 
   private Game mGame; //do we need to store?

Since the constructor for Prompter requires a game:

   public Prompter(Game game) {
       mGame = game;
   }

Yes, you do need to store it when you create the Prompter object. Otherwise you would have no game to play when you get to this line of code:

   public void play() {
       while (mGame.getRemainingTries() > 0 || !mGame.isSolved()) {

As you need to call the getRemainingTries() and isSolved() methods on that game (mGame).

Dorka Tamas
Dorka Tamas
5,085 Points

Thanks for your help! However, I changed the && to || but it still does not run. :-( Also, I realised that I have this bug now with the remaining tries, but I do not know how to fix it.

Isaac Koenig
Isaac Koenig
2,191 Points

The code works with the && statement: (while (mGame.getRemainingTries() > 0 && !mGame.isSolved()) as it was shown in the video.

The main problem I saw in your code is a similar mistake to the one I made and it made the game finish right away like it did for you. In this block of code that you have: public String getCurrentProgress() { //? String progress = ""; for (char letter : mAnswer.toCharArray()) { char display = '_'; if (mHits.indexOf(letter) >= 0) { display = letter; } progress += display; } return progress; }

You made the char display '_'. This should be '-'. Later on when you put this code into Game.java: public boolean isSolved() { return getCurrentProgress().indexOf('-') == -1; }

It confuses it because those two symbols are different and ends the game right away. If you make both of those '-', thet problem should be solved. It worked for me at least. Hope this helps