I'm making a game which plays until the user enters quit in the command line.
The user can enter different commands like get and go, with the get command the user can say what to get like, get baseball bat. What I do in my code is split the command.
everything is working fine but I have found a bug which I can't solve. If I enter "get" and press space and then ctrl+z it gets in a while loop which never ends.
It only happens with ctrl+z (1 time with ctrl c but after that 1 time not anymore)
private void run()
{
while (! quitCommand)
{
String input = null;
try
{
input = null;
System.out.println("Input "+ input);
System.out.println("Give a command.");
BufferedReader is = new BufferedReader(new InputStreamReader(System.in));
input = is.readLine();
handleCommand(input);
// As long as the command isn’t to quit:
// get the next input line and handle it. (With handleCommand.)
}
catch (Exception e)
{
System.out.println("Something went wrong we are sorry try again.");
e.printStackTrace();
}
}
}
/**
* #param userInput (This is the entire input string from the user.)
*
* (Tell others to) Perform the task which belongs to the given
* command.
*/
private void handleCommand(String userInput)
{
// Split the user input string.
if (userInput != null) // user input can not be empty
{
String[] delenTekst = userInput.split(" ");
// The first word is a command. The rest is extra information
String command = delenTekst[0];
String extra = "";
for (int i = 1; i < delenTekst.length; i ++)
{
if (i == 1)
{
extra = extra + delenTekst[i];
}
else
{
extra = extra +" " + delenTekst[i];
}
}
switch (command)
{
// Check if the command is to travel between rooms. If so, handle
case "go"
:
this.checkRoomTravel(extra);
break;
// If there isn't any room travel, then check all other command
case "get"
:
System.out.println("Looking for " +extra );
this.handleGetCommand(extra);
break;
case "quit"
:
quitCommand = true;
break;
default
:
System.out.println("Command is not known try help for information");
break;
}
}
else
{
userInput = "help";
}
}
I'm new to java so it can be something really simple.
On the top of my script I have a private boolean quitCommand = false; which is to check if the user entered quit.
Ctrl+Z closes the Console and therefore your readLine() returns null as pretended to indicate that end of file was reached. So all you need to do, is to check for null returned by readLine() and handle this as you handle the "quit".
I've changed your code (just to test my thesis) and also stream lined a few things, e.g. you dont need to recreate a BufferedReader every time you read a line.
private boolean quitCommand = false;
private void runIt() {
BufferedReader is = new BufferedReader(new InputStreamReader(System.in));
String input = null;
while(!quitCommand) {
try {
System.out.print("Give a command: ");
input = is.readLine();
// As long as the command isn’t to quit:
if(input == null || "quit".equals(input.trim())) quitCommand = true;
if(quitCommand) break;
// get the next input line and handle it. (With handleCommand.)
String[] words = input.trim().split("\\s+");
// ** This is the original handleCommand line **
System.out.println(input + ":" + Arrays.toString(words));
}
catch (Exception e) {
System.out.println("Something went wrong we are sorry try again.");
e.printStackTrace();
}
}
}
BTW: To split the input into words I'd use the regular expression as shown in my code. This works also if the user enters tabs or multiple spaces.
On DOS/Windows Ctrl+Z means end of input. This causes readLine() to return null no matter how many times you call it. This is likely to cause your code to fail as you don't appear to check for it. I suspect you are getting a NullPointerException which you are pretending didn't happen and trying again, endlessly.
Related
I'm asking for user input, but I want it to follow the enter: prompt and be on the same line.
My code produces this as a result input from 'ok'
ok
enter: ok
ok
I would like the user input to start after enter: - hoping for this as a result...
enter: ok
ok
Here's my code:
private static Scanner u = new Scanner(System.in);
try{
while(u.hasNext() && !u.equals("exit")) {
System.out.printf("enter: ");
usrInput = u.next();
System.out.printf(usrInput + "\n");
System.out.println(findClosestMatch(usrInput.toLowerCase()));
}
} catch(NullPointerException e) {
System.out.println("Error - NullPointerException");
}
u.hasNext() is blocking on input before the prompt. It's unnecessary, since calling u.next() afterwards will block anyway. And you're comparing the actual Scanner object to "exit", which will never be true. Try this:
while (true) {
System.out.print("enter: ");
if (!u.hasNext() || (usrInput = u.next()).equals("exit")) {
break;
}
System.out.println(usrInput);
System.out.println(findClosestMatch(usrInput.toLowerCase()));
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I was just experimenting with java (NetBeans) and I though up a quick text based adventure game. I'm trying to get it to check for your username and password in two text files "users.txt" and "passwords.txt" and i was following a guide on Cave of Programming
Here are the imports
import java.io.*;
import javax.swing.JFrame;
This is where the errors are,
private void loginActionPerformed(java.awt.event.ActionEvent evt) {
String usernametxt = "users.txt";
String passwordtxt = "passwords.txt";
String user = null;
String pass = null;
try {
// file reader for username \\
FileReader fileReader = new FileReader(usernametxt);
// file reader for password \\
FileReader fr = new FileReader(passwordtxt);
// buffered reader for username \\
BufferedReader bufferedReader = new BufferedReader(fileReader);
// buffered reader for password \\
BufferedReader br = new BufferedReader(fr);
// check for if user doesn't equal null \\
while((user = bufferedReader.readLine()) != null){
// if username equals first line of username.txt \\
if (username.getText().equalsIgnoreCase(user)){
// check for if pass doesn't equal null \\
while((pass = br.readLine()) != null){
// if password equals first line of passwords.txt \\
if (password.getPassword().equals(pass)){
// if password = pass than it will exit \\
System.exit(1);
}
// else continue \\
else{
continue;
}
}
}
}
bufferedReader.close();
br.close();
}
catch(FileNotFoundException ex){
System.out.println("Unable to open file ");
}
catch(IOException ex){
System.out.println("Error reading file");
}
}
Here are the text files
users.txt
matthew
passwords.txt
matt
Full code available here
http://textuploader.com/57urs
Newest Code Here
http://textuploader.com/577qk
feel free to ask me questions here.
Thank you for the help in advance!
Newest Code
private void loginActionPerformed(java.awt.event.ActionEvent evt) {
String usernames = username.getText();
String passwords = password.toString();
boolean signedin = false;
String usernametxt = "users.txt";
String passwordtxt = "passwords.txt";
String user = null;
String pass = null;
try {
FileReader fr1 = new FileReader(usernametxt);
FileReader fr2 = new FileReader(passwordtxt);
BufferedReader br1 = new BufferedReader(fr1);
BufferedReader br2 = new BufferedReader(fr2);
System.out.println("Username: "+br1.readLine());
System.out.println("Password: "+br2.readLine());
// While loops not running (not a if statement error \
while ((user = br1.readLine()) != null){
// checks if username is not equal to usernames.txt \\
if (user.equalsIgnoreCase(usernames)){
System.out.println("while loop running, username (right)");
break;
}
else{
System.out.println("while loop running, username (wrong)");
}
}
br1.close();
while ((pass = br2.readLine())!= null){
if (pass.equalsIgnoreCase(passwords)){
signedin = true;
System.out.println("While loop running, password (right)");
break;
}
else{
System.out.println("While loop running, password (wrong)
}
}
br2.close();
// Commented out the if statements because i dont want to to close while testing \
// if (signedin){
// System.out.println("SIGNEDIN = TRUE");
// new error1().setVisible(true);
// this.dispose();
// }
// if (!signedin){
// System.out.println("SIGNEDIN = FALSE");
// System.exit(1);
// }
}
catch(FileNotFoundException ex){
System.out.println("Unable to open file ");
}
catch(IOException ex){
System.out.println("Error reading file");
}
}
New Problem
The while loops do not run, this is confirmed when it doesn't print "While loop running, User/Pass", This is not a if/then statement error as I have added the else statement to print if the username is right or wrong. Please help, Thanks Matthew.
If i understood it correctly:
Two files:
users.txt holds the usernames.
passwords.txt holds the passwords.
We want:
Keep reading the user file until the file ends or we've found our user.
Read the corresponding line on the password file and check if the password matches.
Checking the code, while((user = bufferedReader.readLine()) != null) does the first part nicely. We DO want to keep reading the entire file trying to find our user, right?
but the nested while seems a bit fishy. We only need to check a SINGLE password for a given user, right? RIGHT?
Digging a bit deeper into your code, we see:
if (password.getPassword().equals(pass)) {
// if password = pass than it will exit
System.exit(1);
} // plus Lots of code...
Hey! I don't think System.exit does what you're looking for!
System.exit will exit the program, going back to DOS or whatever the cool kids are using these days. The integer it returns is called an error code, and can be used to feed info back to the terminal/shell that started our program.
The keyword you're most likely looking for is break: that will exit a given loop pronto, no questions asked.
Let's do some break/continue mashups! Suppose we "Win at life" if the password is indeed correct:
boolean winAtLife = false;
while((user = bufferedReader.readLine()) != null){
String candidatePassword = br.readLine();
if (candidatePassword == null) {
// So the password file is shorter than the userfile?
// We probably want to log or alert the poor DevOp guys.
// throwing an exception seems like the right thing to do here!
break;
}
if (!user.equalsIgnoreCase(username.getText())) {
// These are not the droid we're looking for, Better luck next line!
continue;
// Also notice that, since we KNOW that user can't be null,
// we're using the force to save ourselves from dreaded NullPointerExceptions!
}
if (!candidatePassword.equals(password.getPassword())) {
// Hmmm, wrong password, I guess?
// Not sure what do do next, but we DO NOT need to keep looping
// since we've found our droid/user/whatever.
// So let's break and save some EC2 Cycles.
break;
}
// If we ever reach here, we got ourselves a winner!
pass = candidatePassword
winAtLife = true;
}
EDIT: Ok... So I've heard that:
The cool kids use Scanner nowadays.
Auto-closing resources is good for our health.
Something about separation of concerns and mixing domain-code with the UI. In code samples. Whatever.
So here we go, take two, now as a method:
public boolean checkCredentials(String username, String password) throws IOException {
// these two are begging to be constants or inlined.
final String usernametxt = "users.txt";
final String passwordtxt = "passwords.txt";
if (username == null || password == null) {
// You probably don't want this in production code.
// Exceptions are your best friends when something unexpected occurs.
return false;
}
try (final Reader fileReader = new FileReader(usernametxt);
final Reader passwordReader = new FileReader(passwordtxt)) {
Scanner userScanner = new Scanner(fileReader);
Scanner passwordScanner = new Scanner(passwordReader);
while(userScanner.hasNext()) {
final String user = userScanner.next();
if (!passwordScanner.hasNext()) {
// So the password file is shorter than the userfile?
// We probably want to log or alert the poor DevOp guys.
// throwing an exception seems like the right thing to do here!
return false;
}
final String candidatePassword = passwordScanner.next();
if (!user.equalsIgnoreCase(username)) {
// This is not the droid we're looking for
// Also notice that, since we KNOW that user can't be null,
// we're using the force to save ourselves
// from dreaded NullPointerExceptions!
continue;
}
if (!candidatePassword.equals(password)) {
// Hmmm, wrong password, I guess?
// Not sure what do do next, but we DO NOT need to keep looping
// So let's return early and save some EC2 Cycles.
return false;
}
// If we ever reach here, we got ourselves a winner!
return true;
}
} // yay for autocloseable
return false;
}
} else if (selectionKey == 2) {
System.out.println("Please enter the item name");
if (s.nextLine() != "") {
item = s.nextLine();
}
try {
ZybezChecker zb = new ZybezChecker(item);
zb.getAveragePrice();
System.out.println(zb.toString());
} catch(Exception e) {
System.out.println("Something went wrong. Perhaps an invalid item name?");
}
That's my code atm. How do I return back to the if statement and continue the loop after it catches?
You could embed it in a loop like,
for (;;) { // <-- start an infinite loop
System.out.println("Please enter the item name");
if (s.nextLine() != "") {
item = s.nextLine();
}
try {
ZybezChecker zb = new ZybezChecker(item);
zb.getAveragePrice();
System.out.println(zb.toString());
break; // <-- terminate the infinite loop.
} catch(Exception e) {
System.out.println("Something went wrong. Perhaps an "
+ "invalid item name?");
e.printStackTrace(); // <-- tell them what went wrong.
}
}
I think (if I understand your question and code correctly) that what you want is a loop containing the s.nextLine(). Note that I am assuming several things here:
s is a Scanner or something equivalent that reads input from the user
an exception is thrown if the user enters invalid input
you want to keep asking the user for input until they enter something valid
If this is the case, then you should create a loop like this:
while (true) {
System.out.println("Please enter the item name");
if (s.nextLine() != "") {
item = s.nextLine();
}
try {
ZybezChecker zb = new ZybezChecker(item);
zb.getAveragePrice();
System.out.println(zb.toString());
break;
} catch(Exception e) {
System.out.println("Something went wrong. Perhaps an invalid item name?");
}
}
Also, why are you calling nextLine() twice? When you call it the first time, it will read a line from the scanner. When you call it again, it will not return the same line; it will instead wait for a new line. This means the user has to enter some random string, then enter the actual value. Finally, you should NEVER use == or != on Strings. Since they are reference types, you are essentially checking if they occupy the same location in memory, rather than if they are equal. Use s.nextLine().equals("") instead.
So if a user puts in a postfix value like say 453-* , my method EvalPostFix() does the work, but when the user inputs something invalid like 43*+ or any invalid string want the program to repromt the user for input dont know how to implement with try catch..
'
String in;
while(true){
System.out.println("Please enter the numbers first followed by the operators, make sure to have one less operator than of numbers");
try {
in = getString();
int result = EvalPostFix(in);
System.out.println(result);
} catch (IOException e) {
// TODO Auto-generated catch block
String s = "Not a valid postfix string";
e.toString();
in = getString();
}
}
'
Looking at your code I think you just need to get rid of the in = getString(); in the catch block and add an break at the end of the try block.
I don't recommend using a while(true) or an IOException for what you are doing though, but that should get your code working.
Use a flag:
boolean flag = false;
while(!flag)
{
//make the loop break, if no exception caught
flag = true;
try{
}
catch{
//make the loop repeat
flag = false;
}
}
this should repeat the prompt every time you catch an exception. you can also use this to validate input.
how the flag is oriented depends on your preference. I like to flag true when an error occured ;)
this will also break your while loop, as soon as you get a valid input.
Something like this is can be used to get an input of desired specifications
public static void userMove() {
System.out.println("Where would you like to move? (R, L, U, D)\n");
Scanner input = new Scanner(System.in) ;
while (true){
String userInput = input.next() ;
if(userInput.length()>1){
System.out.println("Please input a valid direction");
}else{
break ;
}
}
}
I developed the following application in which I needed to masking the PIN and terminate the program after the user has entered the wrong PIN thrice. However, the program terminates only if i close the stopThread at the beginning (I commented it in the code below), however the password masking does not occur for all the three channces when I do so. But, when I close the stopThread just before displaying the login successful screen, the program does not terminate. I need to use ctrl+c to end the program.
Any help is greatly appreciated.
boolean stopThread = false;
boolean hideInput = false;
boolean shortMomentGone = false;
public static double userBal=0.0D;
public void run(){
try{
sleep(500);
} catch(InterruptedException e){
}
shortMomentGone = true;
while(!stopThread){
if(hideInput){
System.out.print("\b*");
}
try{
sleep(1);
} catch(InterruptedException e){
}
}
}
public static final int NB_OF_TRIES = 3;
public void validatePin(){
BankAccount getAll=new BankAccount();
String pin="";
getAll.Login();
Login hideThread =new Login();
hideThread.start();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try{
do{
} while(hideThread.shortMomentGone == false );
// Now the hide thread should begin to overwrite any input with "*"
hideThread.hideInput = true; // Read the PIN
System.out.println("\nPIN:");
boolean pinMatch = false;
int i = 0;
while(!pinMatch && i < NB_OF_TRIES) {
hideThread.hideInput = true;
pin = in.readLine();
i++;
//hideThread.stopThread = true; //Program terminates after third attempt
//PIN masking is stopped, if uncommented
System.out.print("\b \b");
if(pin.equals(" ")){
System.out.println("Please do not leave unnecessary spaces!");
getAll.Login();
}else if(pin.equals("")){
System.out.println("Please do not press the enter key without entering the PIN!");
getAll.Login();
}
FileInputStream fileinputstream = new FileInputStream(".\\AccountInfo.txt");
DataInputStream datainputstream = new DataInputStream(fileinputstream);
BufferedReader bufferedreader1 = new BufferedReader(new InputStreamReader(datainputstream));
do
{
String s1;
if((s1 = bufferedreader1.readLine()) == null)
{
break;
}
if(s1.trim().charAt(0) != '#')
{
String as[] = s1.split(" ");
if(pin.equals(as[0]))
{
System.out.println("You have login!");
String s2 = as[2];
userBal = Double.parseDouble(s2);
getAll.balance = userBal;
hideThread.stopThread = true;
getAll.MainMenu();
System.exit(0);
}else if(pin != as[0]){
System.out.println("Invalid PIN!");
getAll.Login();
System.out.println("\n NOTE :- You are only allowed to enter the PIN THREE times. The number of tries remaining before your card is blacklisted are "+i + "\n Please re-enter your PIN");
}
}
} while(true);
datainputstream.close();
}//End of While Loop
}catch(Exception exception)
{
System.err.println((new StringBuilder()).append("Error: ").append(exception.getMessage()).toString());
}//End of try-catch block
}
There's a readPassword() method in java.io.Console, use that. Why do you need a separate thread at all? That makes everything way too complicated.
Regarding your question why this does not close: Java may optimize while(isTrue){} to something like if(isTrue) { while(true) { } } if you don't set isTrue volatile or synchronize the access to isTrue (getter/setter). This optimizations is called hoisting and explained in Effective Java SE, item 66.
Here is an article which explains exactly your problem: echoing * instead of blanks.
http://java.sun.com/developer/technicalArticles/Security/pwordmask/
They are going the complicated way, too but it works. I would prefer blanks over asterisks since that is the easier way to go. Not echoing * is *nix standard afaik.
Actually after I analysed it a but more i realized that the reason the system wont terminate is because it is not kept in the proper place. Therefore, the solution would be to end the program as soon as the while loop is closed and then everything would work fine.
} while(true);
datainputstream.close();
}//End of While Loop
System.exit(0); // After the system is closed the program would terminate after the third attempt
}catch(Exception exception)
{
System.err.println((new StringBuilder()).append("Error: ").append(exception.getMessage()).toString());
}//End of try-catch block