Advertisement

Loop infinitely but wait before next loop

Started by December 06, 2014 05:39 PM
4 comments, last by rip-off 10 years, 1 month ago

Socket s = new Socket("localhost", SBAP_PORT);
		InputStream instream = s.getInputStream();
		OutputStream outstream = s.getOutputStream();
		Scanner in = new Scanner(instream);
		PrintWriter out = new PrintWriter(outstream); 

		ArrayList<String> wordList = new ArrayList<String>();
		// Creates a scanner to read input from the keyboard
		Scanner input = new Scanner(System.in);
		// instantiates a string for use with the input from the user
		String command = "";

		// While connected is true, then prompt the user to send words to the server
			
	
			System.out.println("Type in a word to send to the server.");
			// Sends the word to the server from the TextField
			System.out.print("Sending: " + component.text() + "\n");
			out.println(component.text());
			out.flush();
			// gets the Response from the server
			response = in.nextLine();
			if(!response.equals("Word does not exist"))
			{

					wordList.add(response);
				System.out.println("Receiving: " + response + "\n");
				
			}
			for(String str: wordList)
			{
				System.out.println(wordCount);
				wordCount++;
			}

Everything underneith //While connected is true...

Is what I want to have loop infinitely, however, I want it to loop back through, and wait for the user to input again before continuing.

As it is now, if I have a while{ ... } loop around all that, it keeps adding the response to the wordList ArrayList, and since it continues to repeat that, wordCount continues to increase also.

I'm still currently trying to think of a way to get this loop to halt and wait before continuing. Google searches for making a loop wait kept bringing up threading and using wait() and notify() on threads... and this is not a threading issue, lol.

Thank you for your time.

I'm afraid I don't understand. Can you explain your program, but in terms of the user's goal and intentions, instead of programming terms like "loop" and "input".

Advertisement

Yes. The program is a networked 3+ player game. I'm currently only working on one client, and that is a special client.

Before I get into that, the overall game is basically a 'word attack' Where words will fall from the top of the frame to the bottom of the players screens, and they have to correctly type the word in. They get points for doing so, and the words fall at different speeds depending on the size of the word, with smaller words falling faster than larger words. There is an overall time limit , and if none of the players lose all 3 of their lives (working on just 2 players fighting eachother for now), and they don't reach whatever point limit I create for winning, then lives get converted to points and the winner is determined on overall points.

The special client has a frame that will allow him/her to see the other players screens, and then a blank text field. This user controlls what words fall down the screen. Anything they type into that text field, is sent to a process that determines if that word is in the dictionary, and then it removes any upper case characters, replaces them so the entire word is lower case, and sends that word back from the server to the client(s).

I'm trying to get it so that when this special client submits a word, if it is a word that passed the screening of if it is or is not in the dictionary, then it is added to a list. This list will be used later. Right now, this list continues to get populated with the same word. So if your word was 'what'

You'd get a list like

what

what

what

what

what... etc.

Right now, I want it to take that, and make it so if you submit what, you get

what

*waits for next word*

Ok, I understand a little better now, but there are still some details missing.

How does the user interact with this special client? Your code includes a reference to "component.text()", and you mention a "frame", but there are also console print statements, and a reference to System.in. If you have a GUI, how does the user interact with it? Is there a button to submit the word?

Then, the server. Have you tested it using something like "telnet", to ensure the server you didn't show isn't the source of the problematic behaviour?

How I built this so far was I started, before I added gui elements, I had it at a simple console input is then sent to server, and then the server responds. I know the problem is in the code I linked. The "component.text()" is a reference to a JTextField. The class that holds the code I showed you, has two inner classes. Everything works except what I've mentioned about the input is stuck in an infinite loop. The code I linked is working code for A SINGLE interation. If I surround


while(connected)
{
			System.out.println("Type in a word to send to the server.");
			// Sends the word to the server from the TextField
			System.out.print("Sending: " + component.text() + "\n");
			out.println(component.text());
			out.flush();
			// gets the Response from the server
			response = in.nextLine();
			if(!response.equals("Word does not exist"))
			{

					wordList.add(response);
				System.out.println("Receiving: " + response + "\n");
				
			}
			for(String str: wordList)
			{
				System.out.println(wordCount);
				wordCount++;
			}
}
		

the stuff I WANT to do with a while statement, it keeps adding the last input to the ArrayList and keeps increasing wordCount endlessly. Basically.

For pseudo code.

I want to continue to listen for input from the user

Check it against the dictionary

if it's a real word, send it back from the server to the client

add that word to an ArrayList

increase the wordCount (really just there to determine if I've finally got it working so it will only add one word to the ArrayList for that input)

Repeat this process for the duration the game is running.

In the event that I am wrong about everything else working in my code, I will supply the entire 3 classes I am working with.

The Client (That controlls the words used):


import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class ControllerClient 
{
	static boolean connected = true;
	public static String response = "test";
	public static ClientComponent component;
	public static int wordCount = 0;
	public static String wordCountString = "";
	public static void main(String[] args) throws IOException
	{
		component = new ClientComponent();
		final int SBAP_PORT = 8888;
		//Creates a frame
		JFrame frame = new JFrame();
		frame.setSize(1080,720);
		frame.add(component);
		frame.setVisible(true);


		//creates a socket
		// with a input and output stream
		Socket s = new Socket("localhost", SBAP_PORT);
		InputStream instream = s.getInputStream();
		OutputStream outstream = s.getOutputStream();
		Scanner in = new Scanner(instream);
		PrintWriter out = new PrintWriter(outstream); 

		ArrayList<String> wordList = new ArrayList<String>();
		// Creates a scanner to read input from the keyboard
		Scanner input = new Scanner(System.in);
		// instantiates a string for use with the input from the user
		String command = "";

		// While connected is true, then prompt the user to send words to the server
			
	
			System.out.println("Type in a word to send to the server.");
			// Sends the word to the server from the TextField
			System.out.print("Sending: " + component.text() + "\n");
			out.println(component.text());
			out.flush();
			// gets the Response from the server
			response = in.nextLine();
			if(!response.equals("Word does not exist"))
			{

					wordList.add(response);
				System.out.println("Receiving: " + response + "\n");
				
			}
			for(String str: wordList)
			{
				System.out.println(wordCount);
				wordCount++;
			}
		

		s.close();

	}
}

class ClientComponent extends JComponent
{

	private Object setLayout;
	public JTextField controllerInput;
	public TextFieldKeyListener textListener;

	public ClientComponent()
	{

		// creates the TextField and sets it's bounds
		controllerInput = new JTextField();
		this.setLayout = null;
		textListener = new TextFieldKeyListener(this);
		controllerInput.setBounds(50, 480, 1000, 30);
		controllerInput.setText("Type here");
		this.add(controllerInput);
		controllerInput.setVisible(true);
		controllerInput.addKeyListener(textListener);

	}
	// draw method
	public void paintComponent(Graphics g)
	{
		Graphics2D g2 = (Graphics2D) g;
		g2.setFont(new Font("TimesRoman", Font.PLAIN, 15));
		g2.drawString(String.valueOf(ControllerClient.wordCount), 10, 10);
		g2.drawString(ControllerClient.response, 320, 30);
		//text();

	}

	public void update()
	{
		Graphics g = getGraphics();
		controllerInput.setText("");
		controllerInput.hasFocus();
		//paint(g);
		repaint();


	}
	public String text()
	{
		return textListener.getTextField();
	}


}

class TextFieldKeyListener implements KeyListener
{
	public String text;
	public ClientComponent gamePanel;
	public TextFieldKeyListener(ClientComponent gamePanel)
	{
		this.gamePanel = gamePanel;
	}
	@Override
	/**
	 * Gets the key press event for the text field
	 */
	public void keyPressed(KeyEvent event) 
	{
		// makes sure that the key is the enter key before actually working
		if(event.getKeyCode() == KeyEvent.VK_ENTER)
		{
			JTextField textField = (JTextField) event.getSource();
			text = textField.getText();

			gamePanel.update();
		}
		// if it's not, do nothing
		else
		{	
		}
	}
	@Override
	public void keyReleased(KeyEvent arg0) 
	{
	}
	@Override
	public void keyTyped(KeyEvent arg0) 
	{
	}
	//returns the text in the textfield
	public String getTextField()
	{
		return text;
	}

}


The Service (Runnable Thread):


import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;



public class ControllerService implements Runnable
{
	private Socket s;
	private Scanner in;
	private PrintWriter out;
	private File aFile = new File("Dictionary.txt");

	public ControllerService(Socket aSocket)
	{
		s = aSocket;
	}

	public void run()
	{
		
			System.out.println("Has reached run method of ControllerService");      
			try
			{
				try
				{
					in = new Scanner(s.getInputStream());
					out = new PrintWriter(s.getOutputStream());
					while(true)
					{
					doService(); 
					}
				}
				finally
				{
					s.close();
				}
			}
			catch (IOException exception)
			{
				exception.printStackTrace();
			}
		
	}



	public void doService() throws IOException
	{      

		System.out.println("Has reached doService method of ControllerService");

		String command = in.next();
		command = command.toLowerCase();
		executeCommand(command);

	}


	public void executeCommand(String command) throws FileNotFoundException
	{
		System.out.println("In the executeCommand method");

		Scanner scanFile = new Scanner(new File("Dictionary.txt"));
		int val = 0;
		//While the value is not 2
		while(val != 2)
		{
			// Prints out a line to tell me it has reached the first loop of the method
			System.out.println("In the executeCommand first loop of the method");
			// while the Dictionary file has another line
			while(scanFile.hasNextLine())           
			{
				// Prints out to tell me it has reached the inner loop
				System.out.println("In the executeCommand second loop of the method");
				// Creates a string that is the word on that line of the dictionary file
				String line = scanFile.nextLine();
				// if line.indexOf command doesn't return -1(which is false, meaning
				// that it wasn't that word
				//Then it returned 1, which means it WAS that word
				if(line.indexOf(command) != -1)
				{
					// sends the word back to the client
					// and breaks out of the loop
					out.print(command +"\n");
					out.flush();
					val= 2;
					break;
				}
				// the value stays 1 if the above is not true
				else
				{
					val = 1;
				} 
			}
			// if the value is 1 after the loop, the the word does not exist in the file
			if(val == 1)
				out.print("Word does not exist\n");
			out.flush();
			val=2;
		}
	}
}

The Server:


import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class GameServer 
{
	 public static void main(String[] args) throws IOException
	 {  
		 final int C_PORT = 8888;
		 
	      ServerSocket controller = new ServerSocket(C_PORT);
	      System.out.println("Waiting for clients...");
	      
	      Socket controllerPlayer = controller.accept();
	      System.out.println("Clients connected....");
	      ControllerService cService = new ControllerService(controllerPlayer);
	      Thread cPlayer = new Thread(cService);
	      int val = 1;
	     
	      cPlayer.start();
	      
	      
	 }
}

There are a few solutions. A very simple solution is to maintain a list of words that have been submitted, and wait until the word doesn't match before submitting it. Note that this will spin a thread and just waste CPU time. In addition, I don't think this is thread safe. You'd need to spend more time with the documentation that I did, but I doubt that your current thread communication is safe.

An alternative is to use a thread-safe mechanism to communicate with the background thread. For example, the TextFieldKeyListener could place the current text into a thread-safe blocking queue. The background thread will attempt to pop an element from this queue, which will cause it to block until the primary thread is ready.

Another option might be to use the SwingWorker or an Executor, so you don't have to manage the background thread yourself. If you were to add more background tasks in future, this is probably a better solution.

This topic is closed to new replies.

Advertisement