While Loop Error Is Repeating My User Input Prompt - java

My goal in this project is to be able to ask a user if they want to add a mechanic and bay number to their respective ArrayLists. My code works fine, but there is one annoying problem. When the while loop that starts all of the code over again runs, the prompt for if they would like to edit the schedule prints twice, once without allowing a user response. I realise there is a lot of code to read but I will print it all here, and the bug that I get every time. It would mean a lot if someone could take the time to tell me what I need to fix.
Code:
// Import packages and create main function
import java.util.Scanner;
import java.util.ArrayList;
public class schedule{
public static void main(String []args){
// Creates scanner and ArrayLists
Scanner scanner = new Scanner(System.in);
ArrayList<Integer> mechanics = new ArrayList<Integer>();
ArrayList<Integer> bays = new ArrayList<Integer>();
boolean edit = true;
while(edit == true){
edit = editSchedule(scanner);
// Runs AddorRemove or ends program based on user's previous choice
if(edit == true){
if(AddorRemove(scanner) == true){
add(scanner, mechanics, bays);
}
else{
remove(scanner, mechanics, bays);
}
}
else{
System.out.println("Have a nice day!");
}
}
}
// Asks user if they want to edit the schedule
public static boolean editSchedule(Scanner scanner){
String answer = "b";
while(!(answer.equals("y")) || answer.equals("n")){
System.out.print("Would you like to edit the schedule? (y/n): ");
answer = scanner.nextLine();
if(answer.equals("y") || answer.equals("n")){
break;
}
else{
System.out.println("Invalid response.");
}
}
if(answer.equals("y")){
return true;
}
else{
return false;
}
}
// Asks user if they want to add or remove an element
public static boolean AddorRemove(Scanner scanner){
String aor = "b";
while(!(aor.equals("a")) || aor.equals("r")){
System.out.print("Do you want to add or remove a mechanic and bay? (a/r): ");
aor = scanner.nextLine();
if(aor.equals("a") || aor.equals("r")){
break;
}
}
if(aor.equals("a")){
return true;
}
else{
return false;
}
}
// Checks to see that elements are not present already and adds element to the mechanic and bay ArrayLists
public static void add(Scanner scanner, ArrayList<Integer> mechanics, ArrayList<Integer> bays){
System.out.print("Enter the mechanic's ID number: ");
int mechanic = scanner.nextInt();
System.out.print("Enter the bay number: ");
int bay = scanner.nextInt();
boolean shouldAdd = true;
for(int i=0; i<=mechanics.size()-1; i++){
if(mechanic == mechanics.get(i)){
System.out.println("Mechanic " + mechanic + " is already booked.");
shouldAdd = false;
}
}
for(int j=0; j<=bays.size()-1; j++){
if(bay == bays.get(j)){
System.out.println("Bay " + bay + " is already booked.");
shouldAdd = false;
}
}
if(shouldAdd == true){
mechanics.add(mechanic);
bays.add(bay);
System.out.println("Mechanic " + mechanic + " booked for bay " + bay + ".");
}
else{
System.out.println("Could not book mechanic " + mechanic + " in bay " + bay + ".");
}
}
// Removes an element from the mechanic and bay ArrayLists
public static void remove(Scanner scanner, ArrayList<Integer> mechanics, ArrayList<Integer> bays){
System.out.println("remove");
}
}
That is the code so far. Don't worry about the remove function, as I haven't added anything to it yet. Mainly focus on the main function and the editSchedule function, which is where something goes wrong. I will now paste the problem I am having with the output.
Would you like to edit the schedule? (y/n): y
Do you want to add or remove a mechanic and bay? (a/r): a
Enter the mechanic's ID number: 1
Enter the bay number: 3
Mechanic 1 booked for bay 3.
Would you like to edit the schedule? (y/n): Invalid response.
Would you like to edit the schedule? (y/n):
All I want to know is what is making the code repeat the phrase "Would you like to edit the schedule? (y/n):" and then adding "Invalid response." If any of you need clarification or further explanation, please let me know. Thanks!

When you use scanner.nextInt() it doesn't complete the line. See this test as an illustration:
#Test
public void testScanner() {
Scanner scanner = new Scanner("1\n2\n3\n4\n");
System.out.println("nextLine: [" + scanner.nextLine() + "]");
System.out.println("nextInt: [" + scanner.nextInt() + "]");
System.out.println("nextLine: [" + scanner.nextLine() + "]");
System.out.println("nextLine: [" + scanner.nextLine() + "]");
}
It produces:
nextLine: [1]
nextInt: [2]
nextLine: []
nextLine: [3]
So after the add() method returns, you have a line ending that the scanner will read as a blank line. That gives you the Invalid response message.

Related

Repeat a loop already satisfied in java

I'm looking to repeat a "game" if it is already satisfied in my case where user has to guess the random number. I can't understand where to to get back to the main game unless i have to create another "do - while" loop inside it and retype the game again in the section where it says: System.out.println("you have tried: " + count + " times. Would you like to play again? y/n"). Is there a way to just bring back to the actual guess loop rather than create another one?
Hopefully makes sense.
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;
public class pass {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String pass = "password123";
String input;
int guess;
int count;
count = 0;
int num;
do {
System.out.print("Enter your password: ");
input = scanner.next();
} while (!input.equals(pass));
System.out.println("Correct! Now play the guess game! Guess a number between 1 - 10.");
do {
num = ThreadLocalRandom.current().nextInt(1,10);
guess = scanner.nextInt();
count++;
if (guess == num) {
System.out.println(" Well done!");
**System.out.println("you have tried: " + count + " times. Would you like to play again? y/n");**
}
else if (guess < num) {
System.out.println("your number is smaller than the number given");
}
else {
System.out.println("your guess is too high");
}
} while (guess != num);
}
}
The simplest solution would be to move the entire "guess loop" into a separate method. Then in the case when you want it to repeat, just call the method recursively.
If you want to reuse code you can make functions (or methods here, because we are inside a class). They can be used to encapsulate code and call it from anywhere to use it.
You can define a methods like that:
public static void methodName() {
// code go here
}
Then, you can call it from anywhere like that :
pass.methodName(); // It will execute the code inside methodName()
In reality, this is a lot more complex than that, you can give methods values and return others, change the scope of it to make it internal only or reachable by other classes. But I presume that you are a beginner so I keep it simple. I strongly recommend you to make a quick research about Object Oriented Programmation!
For your code, you can put the game's while loop in a method and call it at the beginning and each time the player wants to restart the game. Good luck with your game!
I manage to do this way. It seems working but one thing is letting me down at the very last when I key in "n" or other key than "y". Exception in thread "main" java.util.InputMismatchException. Is there a more softer way to finish it?
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;
public class pass {
public static void randomnum(){
Scanner scanner = new Scanner(System.in);
int guess;
int count;
count = 0;
int num;
do {
num = ThreadLocalRandom.current().nextInt(1,10);
guess = scanner.nextInt();
count++;
if (guess == num) {
System.out.println(" Well done!");
System.out.println("you have tried: " + count + " times.");
String answer;
do{
System.out.println("Do you want to play again? y/n");
answer = scanner.next();
if (answer.equals("y")) {
System.out.println("let's play again");
randomnum();
System.out.println("Correct! Now play the guess game! Guess a number between 1 - 10.");
}
else {
System.out.println("you are logout!");
break;
}
}while (answer.equals("Y"));
randomnum();
}
else if (guess < num) {
System.out.println("your number is smaller than the number given");
}
else {
System.out.println("your guess is too high");
}
} while (guess != num);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String pass = "password123";
String input;
do {
System.out.print("Enter your password: ");
input = scanner.next();
} while (!input.equals(pass));
System.out.println("Correct! Now play the guess game! Guess a number between 1 - 10.");
randomnum();
}
}

How to avoid having to declare a new scanner inside do while loop

I have created a program that allows a user to keep guessing numbers until they either guess the correct number or enter end. I have used a do-while loop to do this. When I create a new scanner inside the loop body it works as expected. However if I create it outside the loop body, it works fine if the input is integers or the first input is end However if the input end follows integer inputs it doesn't
pick up the nextLine() until the next loop. Is there a way to do this without having to creat a new scanner object each time.
private static void guessingGame() {
Scanner sc = new Scanner(System.in);
int answer = 7;
String input = "";
int number = 0;
do {
//Scanner sc = new Scanner(System.in);
System.out.print("Guess a number between 1 and 10 or end to finish ");
System.out.println("input at start is: " + input);
boolean b = sc.hasNextInt();
if(b) {
number = sc.nextInt();
System.out.println("number is: " + number); //for testing code
}else {
input = sc.nextLine();
System.out.println("input is: " + input); //for testing code
}
if (number == answer) {
System.out.println("Correct Guess");
break;
}else {
if(input.equals("end")) System.out.println("Hope you enjoyed the game");
else System.out.println("Incorrect Guess, try again ");
}
System.out.println("input before while is: " + input); //for testing code
}while(number != answer && !(input.equals("end")));
}
Example output for when end follow an integer input:enter code here
number is: 3
Incorrect Guess, try again
input before while is:
Guess a number between 1 and 10 or end to finish input at start is:
end
input is:
Incorrect Guess, try again
input before while is:
Guess a number between 1 and 10 or end to finish input at start is:
input is: end
Hope you enjoyed the game
input before while is: end
you can solve this by using a while loop .
See the following code.
private static void guessingGame() {
Scanner sc = new Scanner(System.in);
int answer = 7;
String input = "";
int number = 0;
while(!input.equals("end")) {
//Scanner sc = new Scanner(System.in);
System.out.print("Guess a number between 1 and 10 or end to finish ");
System.out.println("input at start is: " + input);
boolean b = sc.hasNextInt();
if(b) {
number = sc.nextInt();
System.out.println("number is: " + number); //for testing code
}else {
input = sc.next(); //Edited here . Changed nextLine() to next().
System.out.println("input is: " + input); //for testing code
}
if (number == answer) {
System.out.println("Correct Guess");
break;
}else {
if(input.equals("end")) System.out.println("Hope you enjoyed the game");
else System.out.println("Incorrect Guess, try again ");
}
System.out.println("input before while is: " + input); //for testing code
}
}
In here , at first , input will always be empty String . On while loop, it gets assigned to your String input i.e, end . Till it encounters end , your loop will be running.
Edited
Change input=sc.nextLine(); to input=sc.next(); . This is because , your scanner waits for next Line and doesn't consider "end" as input string .

Is there any way to pass a mutator method as an argument to another method?

I'm creating a text based game, I have a class made for the main character so you can set the characters name, etc. What I'm trying to figure out is, is there any way to pass a mutator (character.setname(input)) as an argument to another method. When I try to do it I'm told that I can't use a void type as an argument to a method. When I was writing out the code for the user to enter their name, and everything else it was repetitive with the error checking so I wanted to create my own method I could call that would error check for me. A couple sentences use the setname method to reset the name if it was entered incorrectly but I can't directly use setname in the error checking method because it's going to be using the same method to check other inputs of data.
Is there any way around this?
Here is the code as requested: I indeed may be overcomplicating the problem, I'm pretty new to java so I'm still learning.
The following code is the code I use to check if the user entered something correctly, it accepts an array which contains all the possible correct answers the user can type in, I've tried to design it in a way that I can error check anything with it, not just "yes" or "no" statements, getVariable is the accessor method, and setVariable is the one I'm trying to get to work, I'm trying to pass the mutator as well so I can reset the error
public void confirmEntry(String question, String[] options, String getVariable, setVariable) throws InterruptedException
{
boolean correctEntry = false;
System.out.print("Is this correct? ");
for(int i = 0; i < options.length - 1; i++)
{
System.out.print(options[i] + ", ");
}
System.out.print("or ");
System.out.print(options[options.length - 1] + ": ");
input = in.nextLine();
for(int i = 0; i < options.length; i++)
{
if(input.equals(options[i]))
{
correctEntry = true;
System.out.println(correctEntry);
}
}
System.out.println(correctEntry);
while(correctEntry == false)
{
Thread.sleep(2000);
System.out.print("You must enter ");
for(int i = 0; i < options.length - 1; i++)
{
System.out.print("\"" + options[i] + "\", ");
}
System.out.print("or ");
System.out.print("\"" + options[options.length - 1] + "\" to continue: ");
Thread.sleep(2000);
System.out.println();
System.out.println("You chose " + getVariable);
Thread.sleep(2000);
System.out.print("Is this correct? ");
for(int i = 0; i < options.length - 1; i++)
{
System.out.print(options[i] + ", ");
}
System.out.print(" or ");
System.out.print(options[options.length - 1] + ": ");
input = in.nextLine();
for(int i = 0; i < options.length; i++)
{
if(input.equals(options[i]))
{
correctEntry = true;
}
}
}
}
The following code is what is currently in the method where you enter information about the character. I'm trying to move more of the code into the error checking method so that each time I ask the user a question, name, age, etc. I just simply need to call the method.
public void characterCreation() throws Exception
{
//create an instance of the class player (your character creation)
Player character = new Player();
//Initial Introduction to the game
System.out.println("Welcome to Stranded!");
Thread.sleep(2000);
System.out.println("Tell us a little about yourself!");
Thread.sleep(2000);
//______________________________________________________________________________________________________________
//SET YOUR CHARACTER'S NAME
String[] yesNo = {"yes", "no"}; //array to feed into confirmEntry method
System.out.print("Enter your character's name: ");
input = in.nextLine(); //asks for input of the name
character.setName(input); //sets name in the player class
System.out.println("You chose " + character.getName()
+ " for your character's name");
Thread.sleep(2000);
confirmEntry("Enter your character's name: ", yesNo, character.getName(), character.setName(input));
while(input.equals("no"))
{
Thread.sleep(2000);
System.out.print("Enter your character's name: "); //prompt to enter name again
input = in.nextLine();
character.setName(input); //sets name in player class
Thread.sleep(2000);
System.out.println("You chose " + character.getName()
+ " for your character's name"); //confirms what user entered for name
Thread.sleep(2000);
confirmEntry("Enter your character's name: ", yesNo, character.getName(), character.setName(input));
}
I'm trying to move more code after the SET CHARACTER NAME comment into the confirmEntry method, however the rest of the code involved with the character's name uses the mutator to set the name. That's the problem. I wanted to try to get as much code into confirmEntry as possible so whenever I ask the user to enter something about their character I basically just have to call the method.
If you are using java 8 you can create your method with a method reference param :
public void functionName(Consumer<String> setter){setter.
accept(string);}
and to call your method you can use : functionName(character::setname);
you can see : http://www.informit.com/articles/article.aspx?p=2171751&seqNum=3
What is an entry? It appears to be some value that the user has entered.
class Entry{
String value;
public Entry(String value){
this.value = value;
}
public boolean confirm(String input){
return value.equals(input);
}
}
How about you store all of your entries.
Map<String, Entry> entries = new HashMap<>();
String message = "Enter your character's name: ";
System.out.println(message);
String input = in.nextLine();
entries.put(message, new Entry(input));
Now when you want to confirm.
public void confirmEntries(){
for(String message: entries.keySet()){
System.out.println(message);
System.out.println(entries.get(message) + "yes/no?");
//get some input and update the value. etc.
}
}
Another way to do it would be to create a Runnables.
List<Runnable> entryRunnables = new ArrayList<>();
Then anytime you want to add an action.
Runnable r = ()->{
System.out.println("Enter your players name, yes/no");
String input = in.readLine();
//check input and do stuff.
}
entryRunnables.add(r);
Now to check entries. (stream method)
entryRunnables.forEach(Runnable::run);
Or
for(Runnable r: entryRunnables){
r.run();
}

How to keep the program running if the user entered Y?

Here is my code:
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner Keyboard = new Scanner(System.in);
{
System.out.println("What is the answer to the following problem?");
Generator randomNum = new Generator();
int first = randomNum.num1();
int second = randomNum.num2();
int result = first + second;
System.out.println(first + " + " + second + " =");
int total = Keyboard.nextInt();
if (result != total) {
System.out.println("Sorry, wrong answer. The correct answer is " + result);
System.out.print("DO you to continue y/n: ");
} else {
System.out.println("That is correct!");
System.out.print("DO you to continue y/n: ");
}
}
}
}
I'm trying to keep the program to continue but if the user enters y and closes if he enters n.
I know that I should use a while loop but don't know where should I start the loop.
You can use a loop for example :
Scanner scan = new Scanner(System.in);
String condition;
do {
//...Your code
condition = scan.nextLine();
} while (condition.equalsIgnoreCase("Y"));
That is a good attempt. Just add a simple while loop and facilitate user input after you ask if they want to continue or not:
import java.util.*;
class Main
{
public static void main(String [] args)
{
//The boolean variable will store if program needs to continue.
boolean cont = true;
Scanner Keyboard = new Scanner(System.in);
// The while loop will keep the program running unless the boolean
// variable is changed to false.
while (cont) {
//Code
if (result != total) {
System.out.println("Sorry, wrong answer. The correct answer is " + result);
System.out.print("DO you to continue y/n: ");
// This gets the user input after the question posed above.
String choice = Keyboard.next();
// This sets the boolean variable to false so that program
// ends
if(choice.equalsIgnoreCase("n")){
cont = false;
}
} else {
System.out.println("That is correct!");
System.out.print("DO you to continue y/n: ");
// This gets the user input after the question posed above.
String choice = Keyboard.next();
// This sets the boolean variable to false so that program
// ends
if(choice.equalsIgnoreCase("n")){
cont = false;
}
}
}
}
}
You may also read up on other kinds to loop and try implementing this code in other ways: Control Flow Statements.

Trouble getting my while loop to work

I'm currently working on this assignment for a class and I'm having a hard time getting my while loop to work. Can anyone assist me on figuring out why I can't get the user to enter y or n to either restart the loop or terminate it? Thank you so much!
import java.util.Scanner;
import java.text.NumberFormat;
public class EvenQuizzes {
public static void main (String[] args) {
String another="y";
double percent;
int answers;
int score = 0;
Scanner scan = new Scanner(System.in);
NumberFormat fmt = NumberFormat.getPercentInstance();
// Asks the user to input the amount of questions on the quiz
System.out.print("How many questions are on the quiz? ");
final int QUESTIONS = scan.nextInt();
System.out.println(); // spacer
int[] key = new int [QUESTIONS];
// Asks the user to enter the key
for (int i=0; i<key.length; i++){
System.out.print("Enter the correct answer for question "+ (i+1) +": ");
key[i] = scan.nextInt();
}
System.out.println(); // spacer
while (another.equalsIgnoreCase("y")) {
// Asks the user to enter their answers
for (int i=0; i<key.length; i++) {
System.out.print("Student's answer for question " + (i+1) + ": " );
answers = scan.nextInt();
if (answers == key[i])
score++;
}
// Grades the amount of questions right and gives the percentage
percent = (double)score/QUESTIONS;
System.out.println();
System.out.println("Your number of correct answers is: " + score);
System.out.println("Your quiz percentage: " + fmt.format(percent));
System.out.println();
System.out.println("Grade another quiz? (y/n)");
another = scan.nextLine();
}
}
}
So instead of this
for (int i=0; i<key.length; i++) {
System.out.print("Student's answer for question " + (i+1) + ": " );
answers = scan.nextInt();
if (answers == key[i])
score++;
}
you should try this
for (int i=0; i<key.length; i++) {
System.out.print("Student's answer for question " + (i+1) + ": " );
answers = scan.nextInt();
if (answers == key[i])
score++;
}
scan.nextLine();
At the end of your while loop, try adding this print statement:
System.out.println("Next line is >>>" + another + "<<<");
That should make it clear what you are getting from the scan.nextLine() call. It won't fix your problem, but it will make the issue obvious.
It has to do with that your scan is reading integers before getting the y/n from the user.
In this transition, the scan is reading a newline character instead of y. As a result, the another is a newline char and hence fails the while-loop condition.
To overcome this, the shortcut method is what #3kings had mentioned.
Another method is scan all inputs as string (nextLine) and then for the quiz part, parse for integer. It may seems a lot of work but you get to use parseInt and try/catch exception.

Categories