I am creating a hangman game. Everything works fine, I have code ready to be used for failing the game and giving -1 to the guesses. Though when adding it to the else statement it gets duplicate equal to the length of the word and it also gives a guess—even though its right? I don't see what's wrong in the code? I believe it's my code when guessing wrong which is not placed right though I see no other way?
This is the code:
private class check implements ActionListener {
public void actionPerformed(ActionEvent ae) {
try {
// Grabs the letter from the guessField and converts it into a char
// which can be used to compare against the word.
guess = guessField.getText();
guessField.setText("");
char guess2 = guess.charAt(0);
// --------------------
// Here is the guessing logic but it's currently
// not working and you can not win since i haven't written code for
// it yet. it's not selecting all the letters. for Example if
// choosing A in a word such as Banana it only selects the first
// a--------------------------- //
String displaySecret = wordField.getText();
if (displaySecret.equals("")) {/* case for fist execution */
displaySecret = "";
for (int i = 0; i < random.length(); i++)
displaySecret += "_ ";
}
String newDisplaySecret = "";
for (int v = 0; v < random.length(); v++) {
if (guess2 == random.charAt(v)) {
newDisplaySecret += random.charAt(v); // newly guessed
// character
} else {
newDisplaySecret += displaySecret.charAt(v); // old state
guesses--;
statusLabel.setText("Guesses left: " + guesses);
missField.setText(missField.getText() + guess);
if (guesses <= 0) {
JOptionPane.showMessageDialog(null,
"Game over! The word was: " + random);
guessField.setEditable(false);
wordField.setText("");
missField.setText("");
guesses = 7;
statusLabel.setText("Guesses left: " + guesses);
}
}
}
displaySecret = new String(newDisplaySecret);
wordField.setText(displaySecret);
if (displaySecret.equals(random)) {
JOptionPane.showMessageDialog(null, "You Won! The Word was: "
+ random);
guesses = 7;
statusLabel.setText("Guesses left: " + guesses);
wordField.setText("");
missField.setText("");
guessField.setEditable(false);
}
} catch (Exception e) {
System.out.println(e);
}
}
}
If randomis your Word, you iterate over each Character of it and then check whether each single character matches the guess you get for each character that doesn't match the guess a -1.
For Example: The Word is Bananaramaand you guess a nyour first and second matches will go to the else clause. then one time the if clause goes again, then the else and so on.
You have to
iterate over all characters, check whether they match or not
if a match occurs, replace the char and increase the counter
check if the counter of correct characters equals 0
if so, decrease the guesses
Some other tips: you should use .toLower() on your input and word string before comparsion to allow insensitivity for case
Some sample code:
int charsGuessedCorrectly;
for ( int i = 0; i < random.length( ); i++ )
{
if ( random.charAt( i ) == guess )
{
charsGuessedCorrectly++;
newDisplaySecret += random.charAt(v); // newly guessed
// character
}
}
if ( charsGuessedCorrectly == 0 )
{
newDisplaySecret += displaySecret.charAt(v); // old state
guesses--;
statusLabel.setText("Guesses left: " + guesses);
missField.setText(missField.getText() + guess);
if (guesses <= 0) {
JOptionPane.showMessageDialog(null,
"Game over! The word was: " + random);
guessField.setEditable(false);
wordField.setText("");
missField.setText("");
guesses = 7;
statusLabel.setText("Guesses left: " + guesses);
}
Here is what you need to check your word and generate "newDisplaySecret":
for (int v = 0; v < random.length(); v++) {
if (guess2 == random.charAt(v)) {
newDisplaySecret += random.charAt(v); // newly guessed
// character
} else {
newDisplaySecret += displaySecret.charAt(v);
}
Here is how you can determine whether the player guessed right or wrong:
if(newDisplaySecret.equals(displaySecret)){
guesses --;
}
This needs to be placed after your check word code. Your code seems to decrement guesses for each letter in the word random.
Update display:
displaySecret = new String(newDisplaySecret);
wordField.setText(displaySecret);
Now that you know what the current state of affairs is for this move you can decide if the person has won or lost or just needs to continue playing:
if(guesses <= 0){
/*place here instructions for loosing scenario*/
}else{
if(displaySecret.equals(random)) {
/*place here instructions for winning scenario*/
}
/*simply do nothing the game is neither lost or won*/
}
Hope this helps
Related
I am currently trying to right a rough draft code block for an object oriented hangman assignment I have to tackle. I know that similar questions have been asked but I didn't find a solution for the specific way i'm attempting to write this (which quite possibly is actual shite).
The way the code is intended to work is as follows.
Word_to_guess pulls a word from the array wordBank[] which contains 19 different fruits and 1 pickle (this is just to entertain my professor).
Then, the following While loop checks if "noSuccess" has been falsified, while it remains true the loop asks for character input from the user as a guess.
then the nested for loop iterates through the length of word_to_guess to check if Characters at index i match character c which has been set to userGuess.charAt(0) (in case the user enters more than 1 letter restricting their guess to the first letter in the string they might enter).
now this is where I'm having my issues. I don't know how to use the .replace method to fill in spots with specific characters and store newWord for each iteration of the for loop and have it print a progress report to the user as they guess so that they can keep track of their guesses. I had attempted to use the following statement
newWord = newWord.replace(newWord.CharAt(i), c) but this did not work and caused a compiling error stating that the index could not be found. Which i didn't understand and still don't.
the final if statement checks if noSuccess has been falsified which is defined by booleancheck.contentEquals(word_to_guess)
booleancheck is defined by newWord without any spaces between characters.
If anyone can lend me a hand in sorting out that portion of the code or any other parts that look iffy I'd greatly appreciate it.
Thank you so much!
Alex
word_to_guess = wordBank[num];
boolean noSuccess = true;
while(noSuccess)
{
System.out.println("Enter your guess: ");
System.out.println("letters used - " + lettersUsed);
userGuess = keyboard.nextLine();
c = userGuess.charAt(0);
for(int i = 0; i < word_to_guess.length(); i++)
{
if(word_to_guess.charAt(i) == c)
{
if(newWord.charAt(i) == ' ')
{
newWord = newWord.replace(' ', c);
}
else if(newWord.charAt(i) == '_')
{
newWord = newWord.replace('_', c);
}
}
else
newWord = newWord.replace(' ', '_');
}
System.out.println(newWord);
counter ++;
lettersUsed = lettersUsed + c;
System.out.println("letters used - " + lettersUsed);
String booleanCheck = newWord.replaceAll("\\s+","");
if(booleanCheck.contentEquals(word_to_guess ) && counter > 1)
{
noSuccess = false;
System.out.println("Great job, you guessed the right letters!");
}
Update #1:
I came up with the following code:
for(int i = 0; i < word_to_guess.length(); i++)
{
if(word_to_guess.charAt(i) == c)
{
strProg.setCharAt(i, c);
}
else
{
strProg.setCharAt(i, '_');
}
newWord = strProg.toString();
}
but i'm not sure what I'm doing wrong with the .toString() method because each iteration replaces the previous progress with "_" instead of being additive.
Update: #2
Edit to the previous update, I read that using StringBuilder in this instance is better than StringBuffer. I also discovered that the append and insert methods are available to the StringBuilder object.
This string object is located outside of the while loop the for loop is in.
String newWord = String.join("", Collections.nCopies(word_to_guess.length(),
" "));
this is inside the while loop.
StringBuilder strProg = new StringBuilder(newWord);
for(int i = 0; i < word_to_guess.length(); i++)
{
if(word_to_guess.charAt(i) == c)
{
strProg.insert(i, c);
}
else if(word_to_guess.charAt(i) != c && newWord.charAt(i) == '_')
{
strProg.delete(i, i);
}
else
{
strProg.insert(i, '_');
}
}
the .insert method is resulting in a much longer string. I don't know what to do now.
//The bugs was on replace method: I used a naive way to fix it
//Maybe you need also to check your initialization ...
public void hangman(){
String word_to_guess = "pickle";//wordBank[num];
boolean noSuccess = true;
//start: initializations
char c;
String lettersUsed = "";
String userGuess;
Scanner keyboard = new Scanner(System.in);
int counter=0;
//end: initializations
String newWord = word_to_guess.replaceAll("(?s).", " ");
while(noSuccess)
{
System.out.println("Enter your guess: ");
System.out.println("letters used: " + lettersUsed);
userGuess = keyboard.nextLine();
//sanity check: To ignore empty entry
if(userGuess.isEmpty())
continue;
c = userGuess.charAt(0);
for(int i = 0; i < word_to_guess.length(); i++)
{
if(word_to_guess.charAt(i) == c)
{
if(newWord.charAt(i) == ' ')
{
newWord = newWord.substring(0,i) + c + newWord.substring(i+1); //newWord = newWord.replace(' ', c);
}
else if(newWord.charAt(i) == '_')
{
newWord = newWord.substring(0,i) + c + newWord.substring(i+1);//newWord.replace('_', c);
}
}
else
newWord = newWord.replace(' ', '_');
}
System.out.println("New Word: "+newWord);
counter ++;
lettersUsed = lettersUsed + c;
System.out.println("letters used: " + lettersUsed);
String booleanCheck = newWord.replaceAll("\\s+","");
System.out.println("Check: "+booleanCheck);
if(booleanCheck.contentEquals(word_to_guess ) && counter > 1)
{
noSuccess = false;
System.out.println("Great job, you guessed the right letters!");
}
}
}
I'm creating a little mini game of Hangman. The user has 10 chances to guess, but only 5 lives.
The app works, but will continue after the 5th life, even though, I was hoping it would throw the player out of that loop.
The instantiable class (Hangman.java) is working without problems.
The secret word is "julie" as described in the instantiable class.
My App class:
import javax.swing.JOptionPane;
public class HangmanApp {
public static void main(String args[]) {
String input, secret, result, playAgain;
char guess;
int i, j, k, lives;
Hangman myHangman = new Hangman();
do{
JOptionPane.showMessageDialog(null, "Hello, welcome to Hangman! You have 10 chances but only 5 lives! Best of luck");
lives = 5;
for (j = 10; j > 0; j--) {
while (lives >= 0){
input = JOptionPane.showInputDialog(null, "Please enter a letter");
guess = input.charAt(0);
//process
myHangman.setGuess(guess);
myHangman.compute();
result = myHangman.getResult();
if ((input.charAt(0) == 'j') || (input.charAt(0) == 'u') || (input.charAt(0) == 'l') || (input.charAt(0) == 'i') || (input.charAt(0) == 'e')) {
JOptionPane.showMessageDialog(null, "That letter is in the word! Current correct letters: " + result + ".");
} else {
lives--;
JOptionPane.showMessageDialog(null, "Sorry, that letter is not there. Current correct letters: " + result + ".");
}
//output
//JOptionPane.showMessageDialog(null, "Current correct letters: " + result);
};
lives = -1;
}
result = myHangman.getResult();
secret = myHangman.getSecret();
if (secret.equals(result)) {
JOptionPane.showMessageDialog(null, "Congratulations, you got it!! The word was " + secret + ".");
} else {
JOptionPane.showMessageDialog(null, "Sorry, you didn't get it, better look next time! The word was " + secret + ".");
}
playAgain = JOptionPane.showInputDialog("Do you want to play again? yes/no");
}while (playAgain.equals("yes"));
}
}
Try the following change:
while (lives > 0){
you start at 5 and then go down to 4 3 2 1 AND 0. with the change this will stop at 0
// don't need two nested cycles, you can do it in a single one
// The cycle exits if any one of the conditions fail
// max attempts exhausted or all the lives are lost
// -------------------v v------------------------
for (j = 10, lives=5; j > 0 && lives > 0 ; j--) {
// -------------------------------------^
// j - the number of attempt is decremented for each trial,
// no matter if successful or not
//... the rest of cycle logic, which will decrement the lives
// only in cases of unsuccessful attempts
}
[EDIT]
It seems like moving this piece of code somewhere else would solve my issue, but I can't see to figure out where..
if (numLeaving < MIN_PEOPLE || numEntering < MIN_PEOPLE || totalPeople < MIN_PEOPLE) {
JOptionPane.showMessageDialog(null,"Invalid data");
}
Could someone explain why my 'total people' still gets updated when I enter an invalid value such as a negative number? Also, why would the total people get printed anyway if the user enters invalid input?
final int MAX_PEOPLE = 65;
final int MIN_PEOPLE = 0;
int totalPeople = 0;
int numLeaving = 0;
int numEntering = 0;
boolean invalid = true;
while (invalid) {
String question = JOptionPane.showInputDialog("leaving or entering?");
try {
// Decrease the total if people are leaving
if (question.equalsIgnoreCase("leaving")) {
numLeaving = Integer.parseInt(JOptionPane.showInputDialog("number leaving:"));
totalPeople -= numLeaving;
}
// Increase the total if people are entering
else if (question.equalsIgnoreCase("entering")) {
numEntering = Integer.parseInt(JOptionPane.showInputDialog("number entering:"));
totalPeople += numEntering;
}
else {
JOptionPane.showMessageDialog(null,"'leaving' or 'entering' only");
}
// Prints out current total before capacity is exceeded
if (totalPeople > MAX_PEOPLE) {
invalid = false;
totalPeople = totalPeople - numEntering;
JOptionPane.showMessageDialog(null,"Capacity exceeded\n" + "Total people = " + totalPeople);
}
else {
JOptionPane.showMessageDialog(null,"Total people = " + totalPeople);
}
}
catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null,"numbers only");
}
}
The reason 'totalPeople' is still being updated is because you are not checking if it is a valid input in the beginning your loop. If I were you I would add the following code in the beginning of your while loop:
if(totalPeople < 0){
invalid = false;
break;
}
Also I find it a bit misleading naming a boolean in the negative. Having a boolean named 'invalid' being true would make one question, "Does the true stand for valid or invalid?"
I would name the boolean as 'valid' instead.
Your program doesn't say anywhere that a negative number is invalid input. -= and += operators will just work fine for negative ints.
[Edit]
Suppose you select "leaving" and provide numLeaving =-65 tehn total people will be 0-(-65) = 65. You will enter the if block of below code and not the else blocks which checks for negative inputs.
if (totalPeople > MAX_PEOPLE) {
invalid = false;
totalPeople = totalPeople - numEntering;
JOptionPane.showMessageDialog(null,"Capacity exceeded\n" + "Total people = " + totalPeople);
}
else if (numLeaving < MIN_PEOPLE || numEntering < MIN_PEOPLE || totalPeople < MIN_PEOPLE) {
JOptionPane.showMessageDialog(null,"Invalid data");
}
else {
JOptionPane.showMessageDialog(null,"Total people = " + totalPeople);
}
I'm new to this site. I've decided to create a console base hangmaan game and I've been doing ok up till now. My current problem has me stuck.
I'm trying to make it so that if the user has input a letter and it has been marked as correct or incorrect. The program should then not let the user input that same letter again in later iterations of the while loop.
The comments should give you a better idea of what I'm talking about.
Can anyone please help me?
package hangMan2;
import java.io.IOException;
import java.util.Scanner;
public class mainClss {
public static void main(String[] args) {
int point = 0;
int numberOfLetterInWord;
// prompt user for input and store input into String word
System.out.println("Enter a word in lower case from the dictionary: ");
Scanner inputWord = new Scanner(System.in);
String word = inputWord.next();
// letters remaining in word equals the length of the word at the start
int lettersRemainingInWord = word.length();
for (int i = 0; i < 30; i++) {
System.out.println("\b");
}
// while points are above 7 (7 is when man is hung) and there's more
// than one letter remaining do all the following:
while (point > -7 && lettersRemainingInWord >= 1) {
//prompts user to input letter guess and stores in letter
System.out.print("\nEnter a letter for this " + word.length()
+ " letter word: ");
Scanner inputLetter = new Scanner(System.in);
String letter = inputLetter.next();
if (word.contains(letter)) {
System.out.println("Correct!");
point += 1;
System.out.println("Score: " + point);
lettersRemainingInWord -= 1;
//I need code here to remove the current letter from being able to be used again
if (lettersRemainingInWord > 0) {
continue;
}
else {
System.out.println("\nYou win!!!");
System.out.println("The word was: " + word);
break;
}
}
else {
System.out.println("Incorrect\n");
point -= 1;
System.out.println("Score: " + point);
//I need code here to remove the current letter from being able to be used again
if (lettersRemainingInWord > 0) {
continue;
}
else {
System.out.println("Game over! You lose!");
System.out.println("Score: " + point);
System.out.println("The word was: " + word);
break;
}
}
}
if (point <= -7) {
System.out.println("Game over! You lose!");
System.out.println("Score: " + point);
System.out.println("The word was: " + word);
}
}
}
You could test whether the letter is in a Set. If not, accept it and add it to the set. If so, then reject it.
Set<String> usedLetters = new HashSet<String>();
boolean isUsedLetter(String letter) {
if (usedLetters.contains(letter)) {
return true;
} else {
usedLetters.add(letter);
return false;
}
}
You can use an ArrayList to hold the characters that have already been typed and then check the list to see if the character is in there.
List<Character> used = new ArrayList<Character>();
char let = //letter that they inputted
if(used.contains(let)) {
//do something
}
else {
used.add(let);
}
When I run this code, which is a menu with many different options. it consists of many loops. Some of which I have yet to make. But my issue arises when I have the user select "t" or the coin toss simulator. The loop begins but once the user enters the amount of coin flips say 4, it says 2.0 heads and 2.0 tails means 50.0% were heads
Type code letter for your choice: COIN TOSS SIMULATOR
Enter 0 to quit. How many tosses?
It shouldn't say type the letter for your choice: COIN TOSS SIMULATOR, enter 0 to quit. how many tosses?
Also when I enter 0 it says You have entered an invalid option. 't' is not a valid option. I want to Bring back the main menu!!!! what is going on????
public class toolBox {
public static void main(String[] args) {
Scanner myScanner = new Scanner(System.in);
boolean properInput = false;
int usersInput;
while (!properInput) {
System.out.println("Enter seed value:");
if (myScanner.hasNextInt()) {
usersInput = myScanner.nextInt();
properInput = true;
Random randomSeed = new Random(usersInput);
String randomNumberList = "";
for (int i = 0; i < 10; i++) {
randomNumberList += randomSeed.nextInt(80) + " ";
}
} else
{
String helloWorld = myScanner.next();
System.out.println("You have not entered an integer. '" + helloWorld + "' is not an integer");
}
}
outer:
System.out.println("===== CS302 TOOL BOX =====\nT > COIN TOSS SIMULATOR\nG > GRADE ESTIMATOR\nC > COLOR CHALLENGE\nQ > QUIT");
{
Scanner anotherScanner = new Scanner(System.in);
boolean usersSelection = false;
String c;
outer:
while (!usersSelection) {
{
System.out.print("" + "Type code letter for your choice: ");
}
if (anotherScanner.hasNext("q|Q")) {
c = anotherScanner.next();
usersSelection = true;
System.out.println("" + "" + "Good-Bye");
break;
}
if (anotherScanner.hasNext("t|T")) {
{
System.out.println("" + "COIN TOSS SIMULATOR" + "");
}
System.out.println("Enter 0 to quit. How many tosses?");
Random rand = new Random();
boolean headsOrTails;
float headsCount = 0;
float tailsCount = 0;
Scanner scanMan = new Scanner(System.in);
int numero = scanMan.nextInt();
if (numero == 0) {
break outer;
}
for (int j = 0; j < numero; j++) {
headsOrTails = rand.nextBoolean();
if (headsOrTails == true) {
headsCount++;
} else {
tailsCount++;
}
}
System.out.println(headsCount + " heads and " + tailsCount + " tails means "
+ (headsCount / (headsCount + tailsCount) * 100 + "% were heads"));
}
}
if (anotherScanner.hasNext("g|G")) // if the user were to enter either case of g, the
// program will register both and initialize the
// grade estimator.
{
c = anotherScanner.next();
usersSelection = true;
}
if (anotherScanner.hasNext("c|C"))
{
c = anotherScanner.next();
usersSelection = true;
System.out.println("Welcome to the Color Challenge!");
}
else {
String zoom = anotherScanner.next();
System.out.println("You have entered an invalid option. '" + zoom + "' is not a valid option.");
}
}
}
}
Your question is not clear, but your title suggests to me you think there is an inner and outer loop.
You don't have an inner and an outer loop.
Your indentation was really messy, but when I cleaned it up and then deleted a lot of extra lines of code, the structure of the code became clear.
Notice the following:
1) You have two loops, one on top switched on !properInput, the lower one switched on !usersSelection. There is also a for loop, but it doesn't do anything related to the code flow you are asking about.
2) You have two identical labels, one outside an anonymous block of code (see my comment in the code below), and another inside the anonymous block. In this case it doesn't affect your question, but it is definitely a problem.
My guess is that your break outer line isn't working because you are breaking out of the lower while loop.
I suggest you try fragmenting your code into functions to make the structure clearer.
while (!properInput) {
}
outer:
System.out.println("===== CS302 TOOL BOX =====\nT > COIN TOSS SIMULATOR\nG > GRADE ESTIMATOR\nC > COLOR CHALLENGE\nQ > QUIT");
{ /* begin anonymous code block */
outer:
while (!usersSelection) {
if (anotherScanner.hasNext("q|Q")) {
System.out.println("" + "" + "Good-Bye");
break;
}
if (anotherScanner.hasNext("t|T")) {
System.out.println("Enter 0 to quit. How many tosses?");
if (numero == 0) {
break outer;
}
for (int j = 0; j < numero; j++) {
}
}
}
}