Overview

Write, using the Java programming language socket interface, a networked Tic Tac Toe game. The game will be a P2P application, and will use TCP for its transport protocol. The game will use port 50000.

The game will a graphical user interface and feature a chat capability. The user interface will be demonstrated in class to give you an idea of what it is supposed to look like.

Although the game is a P2P application, one of the peers will initially play the role of the server, while the other plays the role of the client. A user starting the application will be asked if they want to be a server or a client. The server will set up a passive socket at port 50000 and wait for a connection request from the client. The client side of the application will then ask its user to enter the IP address or DNS name of the server machine. Once this information is supplied by the user, the client will connect to the server and the game will begin.

Here are the requirements of the game.

  • The server will go first when the game starts
  • The application will keep track of the number of games already played.
  • Each time a game ends, both players will be asked (use a modal dialog box) if they wish to play again. The game will reset and play will proceed if and only if both players reply in the a rmative. If either player (or both) wants to quit, the game will terminate. In the case one player wants to continue while another wants to quit, the player wanting to continue will be noti ed that their partner does not wish to continue, and then the game will terminate.
  • The local player is never allowed to move into an occupied cell.
  • When the local player types a value into the chat message text eld, the program adds the message typed to the local chat history and sends the chat message to the remote side. The remote side appends the message to its chat history.

Game Network Protocol

The game will use the following protocol commands

  • move row col: message sent to remote player when local player has made a move to a given row and column. The row and col are integer values in the range 0, 1, 2.
  • chat message: message sent to remote player. The value message is a string value to be displayed in the chat history component.
  • playagain flag: message sent to remote player when the local player wants to play again (flag is true) or wants to quit flag is false.

The User Interface

The user interface consists of 4 major components:

  • A 3 3 array of a specialized button called a TTTButton. Each TTTButton keeps track of its row and column, as well as whether it is currently occupied by no one, by the local player, or by the remote player.
  • A JTextField used to type in chat messages to send to the other side.
  • A JTextArea used to hold the history of chat messages.
  • A JLabel used for status messages.

Although not strictly a component, there will be javax.swing.Timer that gener-ates timer events every 101 th of a second. The timer event are used to check the incoming network connection for input from the remote side.

Event Listeners

There are to be three event listeners:

  • A listener for the timer reads input when available, interpretes the protocol command, and applies the speci ed actions to the local user interface and to the program state.
  • A listener for the array of TTTButton senses user input on the buttons, applies that input to the local program state, and sends a message of the same to the remote side.
  • A listener for the chat message text eld reads text typed into that text eld, applies it to the chat history component, and sends the message to the remote side.

Design

I am going to sketch out a design to help you get started. First, we note that the three di erent listeners will all need a lot of the same variables and components, meaning we need what are thinly disguised global variables.

To go with these variables, we need a lot of methods to manipulate them. All this stu will be static members of a class called GameGlobals.

enum PlayerId {LOCAL, REMOTE, NONE}; class GameGlobals { // Game state static Boolean isServer; static boolean isLocalPlayerTurn; static boolean localPlayAgain; // Does local player want to play again? static String localPlayerMarker; static String remotePlayerMarker; static int numberCellsFilled; static boolean isGameOver = false; // Games played. Server goes first when numberGamesCompleted is even, // client goes first when numberGamesCompleted is odd. static int numberGamesCompleted = 0; static int numberGamesWon = 0; static int numberGamesLost = 0; // User Interface Components static final TTTButton[][] tttBoard; // The 9 tic tac toe buttons static final JTextArea chatHistoryTextArea; static final JTextField chatMessageTextField; static final JLabel gameStatusLabel; // Used to announce win or loss // Use a static constructor to create the user interface components static { } // This timer is used to periodically check for network input static Timer netInputMonitorTimer; // Does all start of game initializations and starts the // the netInputMonitorTimer. static void init() { } /** * Process a line of input read sent from the remote side * @param input */ static void processInput(String input) { } /** * Process a remote user move to given row and column * @param row * @param col */ static void processRemoteMove(int row, int col) { } /** * Check to see if a player has won. * @param player * @return */ static boolean hasWon(PlayerId player) { return false; } /** * Process a play again message from the remote player * Note: You get this only after the local player has made his or * her decision, which is then stored in GameGlobals.localPlayAgain? * @param flag */ static void processPlayAgainMessage(boolean flag) { } /** * Process a move by the local player * @param row * @param col */ static void processLocalMove(int row, int col) { } } It is also useful to have a class dedicated to network communications. class NetComm { public static ServerSocket serverSocket; public static Socket clientSocket; public static BufferedReader netReader; // Used to read data from socket public static PrintWriter netWriter; // Used to write data to socket /** * Set up network reader and writer streams after client sockets are connected. * @throws IOException */ private static void setUp() throws IOException { } public static void setUpServer() throws IOException { } public static void setUpClient() throws UnknownHostException, IOException { } }

Hints On Setting Up

According to this design, All user interface components will be created in a static block of the GameGlobals class. In your main class, you will need to create a frame, set up the correct layout, and add the already created user interface components to the frame. You can then make the frame visible. Once that is done, you can use a JOptionPane to solicit connection information from the user. Here is the main set up code.

public class TicTacToe { public static void main(String[] args) throws IOException { JFrame frame = new TTTFrame(); // Find out if should be a server or a client String[] possibleValues = { "Tic Tac Toe Server", "Tic Tac Toe Client" }; String selectedValue = (String)JOptionPane.showInputDialog(frame, "Select a Tic Tac Toe Role", "CSC 469/569 Tic Tac Toe", JOptionPane.INFORMATION_MESSAGE, null, possibleValues, possibleValues[0]); System.out.println("You selected " + selectedValue); if (selectedValue.contains("Server")) { NetComm.setUpServer(); } else { NetComm.setUpClient(); } GameGlobals.init(); } } class TTTFrame extends JFrame { public TTTFrame() throws IOException { super("CSC 469 Tic Tac Toe"); JPanel mainPanel = new MainTTTPanel(); this.add(mainPanel); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.pack(); this.setVisible(true); } }

The TTTMainPanel class, not shown, is used to construct the user interface. Once the network connections are in place, the GameGlobals.init() method will initial-ize the game and start the net input monitor timer.

Hints On Continuing Game Play

There are two steps to safely handling game continuation. You will realize that the game is over when you are processing a move by either the local or remote player. Take the following steps in order:

  • If you are processing a local player move, make sure you send a protocol command for the move to the remote side.
  • Use a modal JOPtionPane dialog to ask the user if he or she wants to play again.
  • Use the information obtained from the option pane to set the localPlayAgain ag to indicate the local player's decision, and then send a protocol playagain message to inform the remote player of the local player's decision. All this will take place in the methods for for handling the move by the local or re-mote player. Once that is done, the move handling method can return. Everything else will be handled by the processPlayAgain method. The processPlayAgain method will be called by the network monitor timer listener when a playAgain message arrives. This method will take the following steps in order.
  • Check if the local player wants to play again. If not, exit the program.
  • If you get this far, the local player wants to continue. Check if the remote player wants to continue. If not, use a modal dialog to inform the local player that the other player has quit, and terminate when the dialog box is dismissed. Otherwise, reset the game and go for another round.

Rewrite the Tic Tac Toe assignment so that it uses UDP instead of TCP

The main obstacle to the conversion is the fact that there is no easy way to test a UDP datagram socket to see if data has arrived from the remote side. We will get around this obstacle by creating a separate thread to read network input. This network monitor thread will stay in an in nite loop. During each loop iteration, the thread will issue a blocking call to receive data from the UDP socket. When data arrives, the blocking receive call returns with a newly received DatagramPacket. The thread will extract the message from the DatagramPacket and add the message to a message queue implemented as a Java BlockingQueue object.

In the last assignment, we had a timer listener that monitored the network input stream side of a TCP socket and returned a protocol message when one arrived. We will still have a timer listener. However, this time the timer listener will retrieve messages from the BlockingQueue message queue mentioned above. To determine if there is a message in the queue, the listener can call the isEmpty() method of BlockingQueue.

Note that this change means that we have two threads running concurrently that both need to access the message bu er. The Java BlockingQueue has put() and take() methods to add messages to the bu er, and to remove a message from the bu er. The BlockingQueue is synchronized, meaning that di erent threads can safely call its methods without fear of data corruption.

Here is further information on structuring your code. Your program will need a single UDP Datagram socket. Like before, the server will start running rst and create its socket, with the port number set to 50000. The client will also create its datagram socket, use the connect() method to connect" to the server, and send a protocol message "hello". When the server receives this rst packet, it extracts the client's socket address from the received packet, and uses the connect() method to connect its socket to the client's socket. After this, both sides will be able to send subsequent packets without addressing them.

Once the datagram sockets are connected, the program should create and run the thread for monitoring the datagram sockets for messages from the other side.

Academic Honesty!
It is not our intention to break the school's academic policy. Projects posted are only used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly fill out the form. Please provide a valid email address and we'll get back to you in less than 24 hours. We will be sending an invoice through PayPal upon confirmation. We are a non profit organization however we need an amount to keep this organization running, and to be able to complete our research and development.