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

How do I finish my Hangman game?

Hi

I'm done with the course "Creating the MVP", but I would love to finish my Hangman game, to make sure I understand everything in the code. I successfully made the console tell the user if the game is lost. But how do I tell the user that they won?

Here is my game.java file code:

public class Game {
  private String mAnswer;
  private String mHits; 
  private String mMisses;
  public static final int MAX_MISSES = 7;

  public Game(String answer) {
    mAnswer = answer;
    mHits = "";
    mMisses = "";
  }

  public boolean applyGuess(char letter) {
    boolean isHit = mAnswer.indexOf(letter) >= 0;
    if(isHit) {
      mHits += letter;
    } else {
      mMisses += letter;
    }
    return isHit;
  }

  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 boolean haveWon() { //This is my failed attempt at showing the user that they won.. :-(
    boolean winner = false;
    if (getCurrentProgress().length() == mAnswer.length()) {
      winner = true;
      System.out.printf("YAAAY, YOU WON!");
    }
    return winner;
  }

}   

and my prompter.java file code:

import java.io.Console;

public class Prompter {

  private Game mGame;

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

  public void play() {
    while (mGame.getRemainingTries() > 0) {
      displayProgress();
      promptForGuess();
    }
    if (mGame.getRemainingTries() == 0) { 
      System.out.printf("YOU LOST! :-(\n");
      System.exit(0);
    }
  }

  public boolean promptForGuess() {
    Console console = System.console();
    String guessAsString = console.readLine("Enter a letter:   ");
    char guess = guessAsString.charAt(0);
    return mGame.applyGuess(guess);
  }

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

Tagging Steve Hunter , since I know you know this! ;-)

4 Answers

Hey Marina,

I know it was stated, but your logic looks fine on this, you're making sure that the length of the guessed word including the hits matches the length of the answer, so that's fine.

I have to agree, that this method is never being called in the play method. You can go about this in the next few ways.

You can add an extra condition to your while statement

while (mGame.getRemainingTires > 0 || !game.hasWon()) 

This will keep the game running and cut it off once the conditions are met for winning. (Your given logic check that the accumulated answer is the length of the word)

The problem with this, is once the conditions are met, your program will just exit, without notifying the user that they won. Your best to add a check with your has won in your code, something like below.

public void play() {
    while (mGame.getRemainingTries() > 0) {
      displayProgress();
      promptForGuess();
      mGame.haveWon();
    }
    if (mGame.getRemainingTries() == 0) { 
      System.out.printf("YOU LOST! :-(\n");
      System.exit(0);
    }
  }

Also, just a suggestion, but it might be good to add another System.exit(0) once you notify the user that they won, so that the program doesn't hang in an awkward state after they won and making the user close it.

Just a suggestion, all in all. Good job, it looks good.

While not actually having done this...what doesn't work? Have you tried putting the win check inside the play method where the lose check is also? It looks like comparing those lengths should work, or you could use mHits but both should accomplish the same thing.

Edit: By putting the win check inside the play method, I mean putting an if statement, calling the haveWon, and based off of the return value, outputting a message or not.

Hi! Thank you both for your answer. I'm quite proud of myself, since you said my logic is fine :-D. Rob Bridges I added the haveWon(); method to the play method like you showed me. But now it just says "YAAY you won" every time it promts me for a guess.. So that's not right.. I want it to work just like the "you lost" logic does - because that works correct! And another thing: if I add a system.exit to the won method, won't it just exit every time it comes across it?

I really hope we can figure this one out! :-)

UPDATE: I thought about how to construct the play method in a way where both won and lost are checked and the system.exit is used. Here is what I came up with. If this is correct, all I need is some functional logic in my haveWon method...

public void play() {
    while (mGame.getRemainingTries() > 0)  {
      displayProgress();
      promptForGuess();
    }
    if (mGame.getRemainingTries() == 0) {
      System.out.printf("YOU LOST! :-(\n");
      System.exit(0);
    } else if (mGame.haveWon() == 0) {
      System.out.printf("YAAAY, YOU WON!");
      System.exit(0);
    }
  }

I tried to change the logic of the haveWon method, but it still doesn't work. It just doesn't do anything once I've guessed my word:

public int haveWon() {
    int number = mAnswer.length() - mHits.length();
    return number;
  }

Hey Marina at work but I'll look at this when I arrive home.

For the shown code, I assume after you updated it :

The game is not ended upon winning because you're not checking if someone has won until after getRemainingTries = 0.

Another way of saying this is that you aren't exiting the while loop until someone has already lost, so you'll want to put your haveWon check inside the while loop.

Edit : I noticed putting this check in the while loop is what Rob had in his post earlier as well

Hey Maria,

I loaded up your code in my IDE and worked through it, The first thing I noticed is that we're comparing mGame.haveWon() to a int value, normally this wouldn't compile, but because in java both 0 and 1 can be converted to an boolean value (0 being false, so every time it's true that the player has not won yet it will think that the code compiles and runs it, an awkard bug, and one I didn't notice when first looking at this)

I fixed that that and it put it in the same loop that you can, so I had to check to make sure that the logic was good, and I adjusted the code a bit, instead of making sure that the same amount of hits are the same as the length of the answer, (it looks like it was only count two hits in letters that had multiple repeats, I changed the logic check to below

public boolean haveWon() { //This is my failed attempt at showing the user that they won.. :-(
        boolean winner = false;
        if (getCurrentProgress().equals(mAnswer)) {
            winner = true;
            System.out.printf("YAAAY, YOU WON!");
            System.exit(0);
        }
        return winner;
    }

So that instead what this is doing is checking to make sure that when comparing the string that is returned from your get current progress has to match the mAnswer exactly.

Your code was good, and it would work for most time, but I think some words were tripping it up. After I toyed around with that method I just called the play method like this

public  void play() {
        while (mGame.getRemainingTries() > 0) {
            displayProgress();
            promptForGuess();
            mGame.haveWon();
        }
        if (mGame.getRemainingTries() == 0) {
            System.out.printf("YOU LOST! :-(\n");
            System.exit(0);
        }
    }

Which seems to work okay and passes the few test cases I give it, I think the only thing that needed to be changed was the logic, which looked good to begin with, but probably just led to bugs after multiple use. When we're comparing any type of strings together == can give false postives, and .equals is a much more reliable method.

Thanks, let me know if I didn't explain this well enough and what parts are a still a bit murky, and I'll see if I can give it a better second chance.

Still, a very good job at a first project.

Hi again

Just an update: I continued the course, and of course Craig had a great solution, which didn't really occur to me:

public boolean isSolved() {
    return getCurrentProgress().indexOf('-') == -1;
  }
  public void play() {
    while (mGame.getRemainingTries() > 0 && !mGame.isSolved())  {
      displayProgress();
      promptForGuess();
    }
    if (mGame.isSolved()) {
      System.out.printf("YAAAY, You won!!");
    } else {
      System.out.printf("You LOST :-(.\n The answer was: %s", mGame.getAnswer());
    }
  }