package chapter18; /** * Title: Chapter 18, "Networking" * Description: Examples for Chapter 18 * Copyright: Copyright (c) 2000 * Company: Armstrong Atlantic State University * @author Y. Daniel Liang * @version 1.0 */ // TicTacToeClient.java: Play the TicTacToe game import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.LineBorder; import java.io.*; import java.net.*; public class TicTacToeClient extends JApplet implements Runnable, TicTacToeConstants { // Indicate whether the player has the turn private boolean myTurn = false; // Indicate the token for the player private char myToken = ' '; // Indicate the token for the other player private char otherToken = ' '; // Create and initialize cells private Cell[][] cell = new Cell[3][3]; // Create and initialize a title label private JLabel jlblTitle = new JLabel(); // Create and initialize a status label private JLabel jlblStatus = new JLabel(); // Indicate selected row and column by the current move private int rowSelected; private int columnSelected; // Input and output streams from/to server private DataInputStream isFromServer; private DataOutputStream osToServer; // Continue to play? private boolean continueToPlay = true; // Wait for the player to mark a cell private boolean waiting = true; /**Initialize UI*/ public void init() { // Panel p to hold cells JPanel p = new JPanel(); p.setLayout(new GridLayout(3, 3, 0, 0)); for (int i=0; i<3; i++) for (int j=0; j<3; j++) p.add(cell[i][j] = new Cell(i, j)); // Set properties for labels and borders for labels and panel p.setBorder(new LineBorder(Color.black, 1)); jlblTitle.setHorizontalAlignment(JLabel.CENTER); jlblTitle.setFont(new Font("SansSerif", Font.BOLD, 16)); jlblTitle.setBorder(new LineBorder(Color.black, 1)); jlblStatus.setBorder(new LineBorder(Color.black, 1)); // Place the panel and the labels to the applet this.getContentPane().add(jlblTitle, BorderLayout.NORTH); this.getContentPane().add(p, BorderLayout.CENTER); this.getContentPane().add(jlblStatus, BorderLayout.SOUTH); // Connect to the server connectToServer(); } private void connectToServer() { try { // Create a socket to connect to the server Socket connectToServer = new Socket("localhost", 8000); // Create an input stream to receive data from the server isFromServer = new DataInputStream( connectToServer.getInputStream()); // Create an output stream to send data to the server osToServer = new DataOutputStream(connectToServer.getOutputStream()); } catch (Exception ex) { System.err.println(ex); } // Control the game on a separate thread Thread thread = new Thread(this); thread.start(); } /**This main method enables the applet to run as an application*/ public static void main(String[] args) { // Create a frame JFrame frame = new JFrame("Tic Tac Toe Client"); // Create an instance of the applet TicTacToeClient applet = new TicTacToeClient(); // Add the applet instance to the frame frame.getContentPane().add(applet, BorderLayout.CENTER); // Invoke init() and start() applet.init(); applet.start(); // Display the frame frame.setSize(320, 300); // frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } public void run() { try { // Get notification from the server int player = isFromServer.readInt(); // Am I player 1 or 2? if (player == PLAYER1) { myToken = 'X'; otherToken = 'O'; jlblTitle.setText("Player 1 with token 'X'"); jlblStatus.setText("Waiting for player 2 to join"); // Receive startup notification from the server isFromServer.readInt(); // Whatever read is ignored // The other player has joined jlblStatus.setText("Player 2 has joined. I start first"); // It is my turn myTurn = true; } else if (player == PLAYER2) { myToken = 'O'; otherToken = 'X'; jlblTitle.setText("Player 2 with token 'O'"); jlblStatus.setText("Waiting for player 1 to move"); } // Continue to play while (continueToPlay) { if (player == PLAYER1) { waitForPlayerAction(); // Wait for player 1 to move sendMove(); // Send the move to the server receiveInfoFromServer(); // Receive info from the server } else if (player == PLAYER2) { receiveInfoFromServer(); // Receive info from the server waitForPlayerAction(); // Wait for player 2 to move sendMove(); // Send player 2's move to the server } } } catch (Exception ex) { } } /**Wait for the player to mark a cell*/ private void waitForPlayerAction() throws InterruptedException { while (waiting) { Thread.sleep(100); } waiting = true; } /**Send this player's move to the server*/ private void sendMove() throws IOException { osToServer.writeInt(rowSelected); // Send the selected row osToServer.writeInt(columnSelected); // Send the selected column } /**Receive info from the server*/ private void receiveInfoFromServer() throws IOException { // Receive game status int status = isFromServer.readInt(); if (status == PLAYER1_WON) { // Player 1 won, stop playing continueToPlay = false; if (myToken == 'X') { jlblStatus.setText("I won! (X)"); } else if (myToken == 'O') { jlblStatus.setText("Player 1 (X) has won!"); receiveMove(); } } else if (status == PLAYER2_WON) { // Player 2 won, stop playing continueToPlay = false; if (myToken == 'O') { jlblStatus.setText("I won! (O)"); } else if (myToken == 'X') { jlblStatus.setText("Player 2 (O) has won!"); receiveMove(); } } else if (status == DRAW) { // No winner, game is over continueToPlay = false; jlblStatus.setText("Game is over, no winner!"); // if (myToken == 'O') { receiveMove(); } } else { receiveMove(); jlblStatus.setText("My turn"); myTurn = true; // It is my turn } } private void receiveMove() throws IOException { // Get the other player's move int row = isFromServer.readInt(); int column = isFromServer.readInt(); cell[row][column].setToken(otherToken); } // An inner class for a cell public class Cell extends JPanel implements MouseListener { // Indicate the row and column of this cell in the board private int row; private int column; // Token used for this cell private char token = ' '; public Cell(int row, int column) { this.row = row; this.column = column; setBorder(new LineBorder(Color.black, 1)); // Set cell's border addMouseListener(this); // Register listener } /**Return token*/ public char getToken() { return token; } /**Set a new token*/ public void setToken(char c) { token = c; repaint(); } /**Paint the cell*/ public void paintComponent(Graphics g) { super.paintComponent(g); if (token == 'X') { g.drawLine(10, 10, getSize().width-10, getSize().height-10); g.drawLine(getSize().width-10, 10, 10, getSize().height-10); } else if (token == 'O') { g.drawOval(10, 10, getSize().width-20, getSize().height-20); } } /**Handle mouse click on a cell*/ public void mouseClicked(MouseEvent e) { // If cell is not occupied and the player has the turn if ((token == ' ') && myTurn) { setToken(myToken); // Set the player's token in the cell myTurn = false; rowSelected = row; columnSelected = column; jlblStatus.setText("Waiting for the other player to move"); waiting = false; // Just completed a successful move } } public void mousePressed(MouseEvent e) { // TODO: implement this java.awt.event.MouseListener method; } public void mouseReleased(MouseEvent e) { // TODO: implement this java.awt.event.MouseListener method; } public void mouseEntered(MouseEvent e) { // TODO: implement this java.awt.event.MouseListener method; } public void mouseExited(MouseEvent e) { // TODO: implement this java.awt.event.MouseListener method; } } }