Noah C Noah C - 6 months ago 8
Java Question

My Hangman Code Isn't Registering Incorrect Guesses Immediately, is Printing Double Sets of Underscores, and more

I'm having three primary issues with my code to replicate a Hangman game:

The "fill-in" portion is randomly printed twice, correct guesses are randomly logged as incorrect

enter image description here




and incorrect guesses are not always counted

enter image description here
This is the code for the Main Class:

public class Main
{

public static void main(String[] args)
{
Hangman manHang = new Hangman();
}

}

The Hangman class:

import java.util.Random;


public class Hangman
{
Random r;
GetData get;
String[] Bank = {"consider","minute","accord","evident","practice","intend","concern","commit","issue","approach","establish","utter","conduct","engage","obtain","scarce","policy","straight","stock","apparent","property","fancy","concept","court","appoint","ambiguous","arbitrary","alliteration","arrogant","benevolent","belligerent","boycott","cynical","connotation","cessation","contemporary","craving","grandiose","gratuitous","guile","harbinger","impetuous","incandescent","indigent","inexorable","injunction","insipid","insurgent","languish","magnate","abjure","abrogate","abstemious", "acumen", "antebellum","auspicious","belie","bellicose","bowdlerize","chicanery","chromosome","churlish","circumlocution","circumnavigate","deciduous","deleterious","diffident","enervate","enfranchise","epiphany","equinox","evanescent","expurgate","facetious", "fallacious"};
String word;//Stores the random word used
boolean finished = false;
int incGuessCount = 0;
boolean[] lettersFound;//Used to mark which letters have been found
String guessedLetter=" ";//Used to store guesses
boolean playerHasWon = false;

public Hangman()
{
r = new Random();
get = new GetData();
word=Bank[r.nextInt(Bank.length)]; //Selects a random word and assigns word the value
lettersFound = new boolean[word.length()]; //Creates a boolean array the length of the word
int incGuessCount = 0;

while(incGuessCount<5 && playerHasWon == false)
{
drawGallows(); //Show the Gallows depending on how many incorrect guesses there are
displayWord();
getGuess();
checkGuess();
//checkVictory();

}

if (incGuessCount>=5)
{
System.out.print('\u000C');//Clears the screen
fiveWrong();//Displays full Hangman
System.out.println("You have lost! The word was "+word);
}
}

public void getGuess()
{
System.out.println("\u000C");
System.out.println(" ");
System.out.println("What letter do you guess?");
System.out.println("You have "+(5-incGuessCount)+" guesses left.");
System.out.print("Enter guess:");
guessedLetter = get.aWord();//Uses scanners to take in the guesses
}


public boolean displayWord()
{
boolean goodGuess = false;//Assumes guess is bad automatically
char letter = guessedLetter.charAt(0);

for(int i = 0;i<word.length();i++)//Goes through all the letters to check guess's status
if (lettersFound[i]==true)//Checks if a letter was already revealed at that position
{
System.out.print(word.charAt(i)+" ");
}

else if (word.charAt(i)==letter)//Prints the correctly guessed letter at the position
{
System.out.print(word.charAt(i)+" ");
lettersFound[i] = true;
goodGuess = true;
}
else//Fills in non-applicable spaces with an underscore
System.out.print("_ ");


return goodGuess;
}

public void checkGuess()
{
if(!displayWord() && incGuessCount==5)
fiveWrong();
else if(!displayWord() && incGuessCount<5)
{
incGuessCount++;
drawGallows();
getGuess();
displayWord();
}

else
{
drawGallows();
getGuess();
displayWord();
}
}

public void defaultMan()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | ");
System.out.println(" |_________ ");
System.out.println(" ");
}

public void oneWrong()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | \\ ");
System.out.println(" |_________ ");
System.out.println(" ");
}

public void twoWrong()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | / \\ ");
System.out.println(" |_________ ");
System.out.println(" ");
}

public void threeWrong()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | /| ");
System.out.println(" | / \\ ");
System.out.println(" |_________ ");
System.out.println(" ");
}

public void fourWrong()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | /|\\ ");
System.out.println(" | / \\ ");
System.out.println(" |_________ ");
System.out.println(" ");
}

public void fiveWrong()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | ( ) ");
System.out.println(" | /|\\ ");
System.out.println(" | / \\ ");
System.out.println(" |_________ ");
System.out.println(" ");
System.out.println("You have lost! The word was "+word+".");
System.out.println("Rerun the program to try again.");
finished=true;
}

public void drawGallows()
{
if(incGuessCount==0)
{
defaultMan();
}

if(incGuessCount==1)
{
oneWrong();
}

if(incGuessCount==2)
{
twoWrong();
}

if(incGuessCount==3)
{
threeWrong();
}

if(incGuessCount==4)
{
fourWrong();
}

if(incGuessCount==5)
{
fiveWrong();

}

}
}

And the GetData class:

import java.util.Scanner;

public class GetData
{
private Scanner input;

public GetData()//Produces a scanner to take in input
{ input = new Scanner(System.in); }

public String aWord()//Gets the input as a guess/string
{ return input.next(); }

public int aNumber()//Gets the input as a number
{ return input.nextInt(); }

}


Apologies for poor organization, I'm new to coding. I've dug through my code for hours with help from multiple people but we just can't figure out where my logic fails, and it obviously does in at least several areas. Any help is appreciated, even if it's just pointing out more minor flawed logic or useless variables. Thank you.

Update: Thanks so much to those who contributed, those answers helped me to fix all the bugs with the program. I now just have one more problem with my win detection. I have created a variable gameOver which stores true when the user has exceeded his number of incorrect guesses and I also had it increment whenever a letter is printed as opposed to an underscore. I then created two if statements:

if(corLetters == word.length())
gameOver = true;

if (incGuessCount<5 && gameOver)
{
System.out.println("\u000c");
System.out.println("Congratulations!");
System.out.println("You have won!");
System.out.println("Rerun the program to try again.");
}


But the game doesn't register the win. Again, thanks so much for all your help and if you have any suggestions to fix or improve my win detection it would be much appreciated :)

This is my new Hangman Class after having my issues resolved in this thread:

import java.util.Random;


public class Hangman
{
Random r;
GetData get;
String[] Bank = {"consider","minute","accord","evident","practice","intend","concern","commit","issue","approach","establish","utter","conduct","engage","obtain","scarce","policy","straight","stock","apparent","property","fancy","concept","court","appoint","ambiguous","arbitrary","alliteration","arrogant","benevolent","belligerent","boycott","cynical","connotation","cessation","contemporary","craving","grandiose","gratuitous","guile","harbinger","impetuous","incandescent","indigent","inexorable","injunction","insipid","insurgent","languish","magnate","abjure","abrogate","abstemious", "acumen", "antebellum","auspicious","belie","bellicose","bowdlerize","chicanery","chromosome","churlish","circumlocution","circumnavigate","deciduous","deleterious","diffident","enervate","enfranchise","epiphany","equinox","evanescent","expurgate","facetious", "fallacious"};
String word;//Stores the random word used
boolean finished = false;
int incGuessCount = 0;
int corLetters = 0;
boolean[] lettersFound;//Used to mark which letters have been found
String guessedLetter=" ";//Used to store guesses
boolean gameOver = false;


public Hangman()
{
r = new Random();
get = new GetData();
word=Bank[r.nextInt(Bank.length)]; //Selects a random word and assigns word the value
lettersFound = new boolean[word.length()]; //Creates a boolean array the length of the word


do
{
drawGallows(); //Show the Gallows depending on how many incorrect guesses there are
displayWord();
getGuess();
checkGuess();

}
while(incGuessCount<5 && gameOver == false);

if (incGuessCount>=5)
{

fiveWrong();//Displays full Hangman

}

if(corLetters == word.length())
gameOver = true;

if (incGuessCount<5 && gameOver)
{
System.out.println("\u000c");
System.out.println("Congratulations!");
System.out.println("You have won!");
System.out.println("Rerun the program to try again.");
}


}

public void getGuess()
{
System.out.println("\u000C");
System.out.println(" ");
System.out.println("What letter do you guess?");
System.out.println("You have "+(5-incGuessCount)+" guesses left.");
System.out.print("Enter guess:");
guessedLetter = get.aWord();//Uses scanners to take in the guesses
}


public boolean displayWord()
{
boolean goodGuess = false;//Assumes guess is bad automatically
char letter = guessedLetter.charAt(0);

for(int i = 0;i<word.length();i++)//Goes through all the letters to check guess's status
if (lettersFound[i]==true)//Checks if a letter was already revealed at that position
{
System.out.print(word.charAt(i)+" ");
corLetters++;
}

else if (word.charAt(i)==letter)//Prints the correctly guessed letter at the position
{
System.out.print(word.charAt(i)+" ");
lettersFound[i] = true;
goodGuess = true;
corLetters++;
}
else//Fills in non-applicable spaces with an underscore
System.out.print("_ ");


return goodGuess;
}

public void checkGuess() {
boolean disW = displayWord();

if (!disW && incGuessCount == 5)
fiveWrong();
else if (!disW && incGuessCount < 5) {
incGuessCount++;

}
}


public void defaultMan()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | ");
System.out.println(" |_________ ");
System.out.println(" ");
}

public void oneWrong()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | \\ ");
System.out.println(" |_________ ");
System.out.println(" ");
}

public void twoWrong()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | / \\ ");
System.out.println(" |_________ ");
System.out.println(" ");
}

public void threeWrong()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | /| ");
System.out.println(" | / \\ ");
System.out.println(" |_________ ");
System.out.println(" ");
}

public void fourWrong()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | | ");
System.out.println(" | /|\\ ");
System.out.println(" | / \\ ");
System.out.println(" |_________ ");
System.out.println(" ");
}

public void fiveWrong()
{
System.out.println('\u000C');
System.out.println(" ________");
System.out.println(" | | ");
System.out.println(" | ( ) ");
System.out.println(" | /|\\ ");
System.out.println(" | / \\ ");
System.out.println(" |_________ ");
System.out.println(" ");
System.out.println("You have lost! The word was "+word+".");
System.out.println("Rerun the program to try again.");
gameOver=true;
}

public void drawGallows()
{
if(incGuessCount==0)
{
defaultMan();
}

if(incGuessCount==1)
{
oneWrong();
}

if(incGuessCount==2)
{
twoWrong();
}

if(incGuessCount==3)
{
threeWrong();
}

if(incGuessCount==4)
{
fourWrong();
}

if(incGuessCount==5)
{
fiveWrong();

}

}
}

Answer

The reason the "fill-in" portion can be printed twice is because you are using to print the word and to determine if the character is correct. By this I mean when you have this inside checkGuess():

if(!displayWord() && incGuessCount==5)
             fiveWrong();
else if(!displayWord() && incGuessCount<5)

You are calling displayWord() (which prints the word and returns true if the guess is good) in the decision part of the if statement. This causes the word to be printed inside your checkGuess() method. This could be fixed by making a checkWord() such as:

public boolean checkWord()            
{
    boolean goodGuess = false;//Assumes guess is bad automatically
    char letter = guessedLetter.charAt(0);
    for(int i = 0;i<word.length();i++){//Goes through all the letters to check guess's status
        if (word.charAt(i)==letter)
        {
            lettersFound[i] = true;
            goodGuess = true;
        }
    }

    return goodGuess;           
} 

This would then be used in the decision part of the if statement.

The second thing that is causing the diagram to not be updated timely is that you are doing too much in the checkGuess(). You are asking them for new guesses when that really should be handled by the main while{}. The edited version could look like this:

public void checkGuess()
{
    if(!checkWord() && incGuessCount==5)
        fiveWrong();
    else if(!checkWord() && incGuessCount<5)
    {
        incGuessCount++;
    }
} 

Also, in your constructor you make another counter which makes the loop fail to end after the player loses (because local variables of the same name are used before global variables) see the following code:

 r = new Random();
 get = new GetData();
 word=Bank[r.nextInt(Bank.length)];
 lettersFound = new boolean[word.length()];
 int incGuessCount = 0; // <<< This shouldn't be here

The only thing left is to make win detection and I think you're well on your way!

Edit:

For your win detection, I like the way you decided to count the number of characters the user has guessed correctly. The only problems are that in your displayWord() you add to the number of correct letters each time the word is printed, rather than only when you add a new correct character. This change would make:

if (lettersFound[i]==true)//Checks if a letter was already revealed at that position
{
    System.out.print(word.charAt(i)+" ");
    corLetters++;
}
else if (word.charAt(i)==letter)//Prints the correctly guessed letter at the position
{
    System.out.print(word.charAt(i)+" ");
    lettersFound[i] = true;
    goodGuess = true;
    corLetters++;
}

into this:

if (lettersFound[i]==true)//Checks if a letter was already revealed at that position
{
    System.out.print(word.charAt(i)+" ");
    //Deleted line here
}
else if (word.charAt(i)==letter)//Prints the correctly guessed letter at the position
{
    System.out.print(word.charAt(i)+" ");
    lettersFound[i] = true;
    goodGuess = true;
    corLetters++;
}

The other problem is that you only check if the game is over from a user win outside the main do while. This can be fixed by moving the if statement into the checkGuess(). Such as:

public void checkGuess() {
    boolean disW = displayWord();

    if (!disW && incGuessCount == 5)
        fiveWrong();
    else if (!disW && incGuessCount < 5) {
        incGuessCount++;

    }

    if (corLetters == word.length()){
        gameOver = true;
    }
}