Scanner(System.in).nextLine() blocking my game - java

I'm currently making a simple 2D RPG game in Java.
I got the render & tick methods done, the game is working fine.
Now I want to implement a console where the user can type some commands and interact with the map.
The problem is when I start the game, it is just freezing. The freeze is caused by Scanner(System.in).nextLine(). Here's my parser class :
import java.util.Scanner;
public class Parser
{
private CommandWords aValidCommands;
private Scanner aReader;
public Parser()
{
this.aValidCommands = new CommandWords();
this.aReader = new Scanner( System.in );
} // Parser()
public Command getCommand()
{
String vInputLine;
String vWord1 = null;
String vWord2 = null;
System.out.print( "> " );
vInputLine = this.aReader.nextLine();
Scanner vTokenizer = new Scanner( vInputLine );
if ( vTokenizer.hasNext() ) {
vWord1 = vTokenizer.next();
if ( vTokenizer.hasNext() ) {
vWord2 = vTokenizer.next();
}
}
if ( this.aValidCommands.isCommand( vWord1 ) ) {
return new Command( vWord1, vWord2 );
}
else {
return new Command( null, null );
}
} // getCommand()
} // Parser
and my tick function (which is called 60 times/sec)
Parser aParser = new Parser();
Command command = aParser.getCommand();
The game just freezes when it reaches the line "vInputLine = this.aReader.nextLine(); ". I have no idea why.
Also the parser class is working fine, I already made a console-based RPG using this class. I just don't know why it freezes when I try to implement it in my 2D game.
Any help would be appreciated.

Scanner.nextLine() is a blocking call. This means it will make the current thread wait until it returns a value. If you want to receive input through your scanner, aswell as possibly do other things at the same time, youll need another thread.
class Test {
private static Scanner scanner;
private static Thread inputThread = new Thread() {
public void run() {
scanner = new Scanner(System.in);
while(true) {
//scanner.nextLine();
}
}
};
public static void main(String[] args) {
inputThread.start();
//handle everything else on main thread
}
}
Because your scanner is receiving input on one thread, and possibly handling thr input on the other, you should start thinking of ways of passing values from thread-0 (the new thread) to the main thread (which calls the main method).
There are many ways of doing this, the most basic probably being adding input data to a list right when it comes in, then retreive it from the list on your other thread. But keep in mind, when using multiple threads, you need to worrry about memory inconsistancy. If both objects are trying to access the same object (in this case, the list containing the data), things might not calculate as expected. This is where synchronization come in: http://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html

It happens so because it actually does not finishes the line.
For example:
Code:
Scanner scan = new Scanner(System.in);
int a, b;
String name;
System.out.println("Enter two numbers");
a = scan.nextInt();
b = scan.nextInt();
System.out.println("Sum of " +a+ " and " +b+ " is " +(a+b));
System.out.println("Please enter your name");
name = scan.nextLine();
System.out.println(""+name);
Output :
Enter two numbers
1
2
Sum of 1 and 2 is 3
Please enter your name -> And it freezes here.
It happens as nextLine is still in waiting as this code (System.out.println(""+name);) just prints and does not finishes the line.

Related

Arraylist User input

I would greatly appreciate some help with my java code. I am using ArrayLists to store the users favorite type of vehicles. So they will input vehicles until they type "Exit" to get out of the loop. It will then print the array list. Right now, it is only reading every other input. Depending on how many inputs there are, the user might have to type "Exit" twice before it prints the results out. Any help would be greatly appreciated, thank you!
package bacaCCh6Sec8;
import java.util.ArrayList;
import java.util.Scanner;
public class BacaCCh6Sec8 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
ArrayList<String> vehicles = new ArrayList<>();
boolean done = false;
final String EXIT = "Exit";
System.out.printf("Enter your favorite vehicles.\n");
System.out.printf("Type Exit after you have input all your vehicles.\n");
do {
String input = in.next();
if (!input.equals(EXIT)) {
vehicles.add(in.next());
} else {
done = true;
} // end If
} while (!done); // End Do While
System.out.printf("Your favorite vehicles are %s.\n" , vehicles);
} // End Main
} // End Class
the user might have to type "Exit" twice before it prints the results
out
the issue is that you're calling next() method twice hence the user must enter a value twice. the solution is to simply use the value you've got from the first next() method rather than discarding it.
String input = in.next();
if (!input.equals(EXIT)) {
vehicles.add(input); // <--- we're using the input variable
} else {
done = true;
} // end If
Each call of .next() actually reads the input. So if you call .next() twice, it'll read two lines. To rectify change vehicles.add(in.next()); to vehicles.add(input);
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
ArrayList<String> vehicles = new ArrayList<>();
boolean done = false;
final String EXIT = "Exit";
System.out.printf("Enter your favorite vehicles.\n");
System.out.printf("Type Exit after you have input all your vehicles.\n");
do {
String word = in.next();
if(word.equalsIgnoreCase("exit")) break;
vehicles.add(word);
} while (!done); // End Do While
System.out.printf("Your favorite vehicles are %s.\n" , vehicles);
}
}
Well not my best code but it helped
Enter your favorite vehicles.
Type Exit after you have input all your vehicles.
hola
mundo
exit
Your favorite vehicles are [hola, mundo].

Scanner HasNextLine always returns false

I'm facing this weird problem with Scanner.hasNextLine().
I'm not used with the Scanner class but I'm used to use Scanner.hasNextLine() as a condition for a loop to get continuously user's input but in this part of code it always returns false !
public static void main(String[] args) throws IOException {
String s = "";
Scanner ssc = new Scanner(System.in);
Client cli = new Client();
cli.HLO();
Thread t = new Thread(new ThreadMessage(cli));//Thread that asks user for input using Scanner and closing it then
t.start();
boolean b = ssc.hasNextLine();
while (true) {
b = ssc.hasNextLine();
System.out.println(b);
if (b) {
s = ssc.nextLine();
System.out.println("you wrote" + s);
cli.dp.setData(s.getBytes());
cli.ds.send(cli.dp);
}
}
}
and as is an input I only have a loop of lines with the word false
Does anybody have an idea why it behaves so?
EDIT: Seems that the errors comes froms HLO function that uses another Scanner I removed it and it words properly now.
Try to use the .hasNext() method instead of using the .hasNextLine() method.
You are having problems because the .hasNextLine() method returns true if there is another line in the input of this scanner. But the .hasNext() method returns true if this scanner has another token in its input.
Refer : http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
In my case I have multiple Scanner(System.in) instances in a code which is touched by several people.
If one of those instances call "close", it will closed for all and the file is not reopened.
After the call to close hasNextLine() always will return false.

How can I create and infinite loop and exit it with a command?

I was wondering if I could make it so a loop can end with typing in a command like end or -1. What I have now is
while ( gradeCounter <= 10 ) // loop 10 times
I would like to know how to have it loop infinitely till I end it.
Simply create a while loop and a condition to break it
while(true){
String inputString = //Get user input here
if(inputString.equals("Your Termination Text"))
break;
}
If you want to know how to get console input here is one method
Java: How to get input from System.console()
Edit per comments below
double grades = 0;
int entries = 0;
while(true){
String inputString = //Get user input here
if(inputString.equals("Your Termination Text"))
break;
else{
grades += Double.parseDouble(inputString);
entries++;
}
}
double averageGrade = grades / entries;
Please keep in mind that this does not account for text that is not a number and also not your termination text. From the question it sounds like a low level CIS class and I don't think this will be an issue. If it is however you need to learn how to do try catch and some more input validation.
While(true) {} creates an infinite loop. A break command inside the loop breaks out of it. You'll have to detect whatever sort of event will occur inside the loop to determine if you should break.
I don't know what you're doing on a larger scale, but it could be a better idea to use Threads which don't loop infinitely and suck up processing power.
Yes, it is possible. Just make sure, there is a different thread that can handle some kind of input...
public class MyBreakableInfiniteLoop
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
new Thread(r).start();
System.out.println("Press Enter to stop thread");
new Scanner(System.in).readLine();
r.stop = true;
}
public static class MyRunnable extends Runnable {
public volatile boolean stop = false;
public void run() {
while(!stop) {
//do nothing, preferably in a meaningful way
}
}
}
}
(aLso, I didn't take into count kill -9 as "input that breaks the infinite loop"...)

JOptionPane and Scanner input issue

I'm writing a program where at one point, I need to print a String on a window using JOptionPane. The code for the line looks something like this:
JOptionPane.showMessageDialog(null, "Name: " + a.getName());
The getName function refers to the object a that i created that has a method that returns a String. However, when my code reaches this point, the program appears to enter some kind of infinite loop as the window never pops up and when using debug, it appears never-ending.
The main thing is, when I use getName, I am allowing the user the set this name with a different function earlier in the main driver.
getName() is basically one line, return name;
The code for my setName() function is basically:
Scanner a = new Scanner(System.in);
System.out.print("Pick a name: ");
name = in.nextLine();
a.close();
Name is a private variable in the class. The close() isn't necessary but I tried it to see if it had any effect.
What I did notice is that, if I use the above code, the window never pops up, and I get stuck in an infinite loop. However, if I simply change the name = line to anything, such as:
name = "foo";
The code runs smoothly, the window pops up, and I do not get stuck in a loop. Even if I do not input a name when the program prompts me to, resulting in a null String, the window still doesn't pop up. Can anyone help and advise me on why this is happening? Thanks.
Using Scanner operations creates a block in the WaitDispatchSuport class used by JOptionPane which checks non-dispatch threads are free from blocking IO. Calling Scanner.close() will not un-block the thread.
One solution is to call showMessageDialog from the EDT :
Scanner a = new Scanner(System.in);
System.out.print("Pick a name: ");
final String name = a.nextLine();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JOptionPane.showMessageDialog(null, "Name: " + name);
}
});
This code snippet can help you
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
final String s = scanner.nextLine();
SwingUtilities.invokeLater(() -> {
JDialog dialog = new JDialog();
dialog.setAlwaysOnTop(true);
JOptionPane.showMessageDialog(dialog, s);
});
}

arraylist isn't printing out correctly in a separate method for loop? wrapper class or loops to blame?

for my project, i have an arraylist for the user to input whatever names they want in one method as long as it isn't stop. then in a separate method, the values i just inputted have to be called out again, so i can input more information for each name.
example:
enter names:
name: bob
name: joe
name: Stop
this triggers another method to prompt more info:
bob:
enter age:
enter address:
joe:
enter age:
enter address:
However, right now, the arraylist isn't printing out correctly, and i'm getting repeats of certain names, while other names don't show up in the second method. Also, the loop in the second method doesn't end. i enter in info for the names i entered, but i keep getting prompted with "name:" and no actual arraylist value. I suspect something is wrong with my loops, but i don't quite know how to fix it? I also thought that maybe the problem has something to do with how i'm using a wrapper to put in values into the arraylist, but i don'tknow how to fix that.
in the second method, I've tried swapping the countervariable to keep track of the order in the Array List with a separate counter in the second method, but it doesn't seem to make a difference. In the first method, i've tried swapping the loop with different a boolean while loop, with a straight up while (!input.equals("Stop")), a for loop counter inside of the previous two options, if loops, and some combination of the above.
here is my code
Scanner console = new Scanner(System.in);
private ArrayList<Directory> nameList; //i have to use object oriented programming to store values in the Directory Class
public int i;
first method:
private void addName()
{
Scanner LocalInput = new Scanner(System.in);
Directory buffer = null;
String ID = null;
System.out.println("Enter Station Designations Below, Enter Stop to quit");
boolean breaker = false;
while(breaker ==false)
{
System.out.print("Name: ");
ID = (LocalInput.nextLine());
if(ID.equals("Stop"))
breaker = true;
else
buffer = new Directory(ID);
nameList.add(buffer);
}
}
second method:
private void getInfo()
{
Scanner LocalInput = new Scanner(System.in);
Directory buffer;
buffer = nameList.get(i);
double age; String address;
System.out.println("Enter Temperatures below...");
System.out.println("" + nameList.get(i));
for (i = 0; i < nameList.size(); i++)
{
System.out.println("Name: " + buffer.GetID()); //there's a getter and setter in the Directory class
System.out.println( "Age:\t");
age = LocalInput.nextDouble();
System.out.print( "Address:\t");
address = LocalInput.nextLine();
buffer= new Directory(age, address);
nameList.add(buffer);
}
}
Critique of first method
I haven't looked closely yet, but I strongly suspect this is the problem:
if(ID.equals("Stop"))
breaker = true;
else
buffer = new Directory(ID);
nameList.add(buffer);
You appear to be expecting the last statement only to be executing when ID is not equal to "Stop", but actually it's always going to execute. Unlike (say) Python, whitespace is irrelevant in Java. If you statements to be considered as a block, you need braces:
if(ID.equals("Stop"))
breaker = true;
else {
buffer = new Directory(ID);
nameList.add(buffer);
}
Personally I would put braces around both parts:
if (ID.equals("Stop")) {
breaker = true;
} else {
buffer = new Directory(ID);
nameList.add(buffer);
}
... and quite possibly get rid of the somewhat-irrelevant buffer variable:
if (ID.equals("Stop")) {
breaker = true;
} else {
nameList.add(new Directory(ID));
}
I'd also get rid of the breaker variable, and limit the scope of ID (changing its name, too, to comply with normal conventions) with a result of:
while (true) {
System.out.print("Name: ");
string id = LocalInput.nextLine();
if (id.equals("Stop")) {
break;
}
nameList.add(new Directory(ID));
}
Critique of second method
This is really odd at the moment. It's not at all clear where the i variable is declared, or why you only fetch buffer once, or why you're just adding to the existing list rather than mutating the existing object. I suspect you really want:
for (Directory entry : nameList) {
System.out.println("Name: " + entry.GetID());
System.out.println( "Age:\t");
double age = LocalInput.nextDouble();
entry.setAge(age);
System.out.print( "Address:\t");
String address = LocalInput.nextLine();
entry.setAddress(address);
}
Note that your current loop will always continue until i equals nameList.size() - but you're always increasing the size in the loop, so you'll never terminate.
private void getInfo()
{
Scanner LocalInput = new Scanner(System.in);
double age; String address;
for (Directory name : nameList) {
System.out.println("Name: " + name .GetID());
System.out.println( "Age:\t");
double age = LocalInput.nextDouble();
name.setAge(age);
System.out.print( "Address:\t");
String address = LocalInput.nextLine();
name.setAddress(address);
}
}
get method should be like this
and Add must be -
private void addName()
{
Scanner LocalInput = new Scanner(System.in);
Directory buffer = null;
String ID = null;
System.out.println("Enter Station Designations Below, Enter Stop to quit");
boolean breaker = false;
while(breaker ==false)
{
System.out.print("Name: ");
ID = (LocalInput.nextLine());
if(ID.equals("Stop"))
breaker = true;
else {
buffer = new Directory(ID);
nameList.add(buffer);
}
}
}
Consider using the break keyword, then you don't need the breakerflag and the else branch:
while(true)
{
System.out.print("Name: ");
ID = (LocalInput.nextLine());
if(ID.equals("Stop"))
break;
buffer = new Directory(ID);
nameList.add(buffer);
}
Sorry was already posted...

Categories