Modify TictacToe server/client example from deitel "How To Program"

We've been given example code from the deitel & deitel book how to program and have to carry out the following alterations:

a) Modify the TicTacToeServer class to test for a win, loss or draw on each move in the game. Send a message to each client applet that indicates the result of the game when the game is over.

b) Modify the TicTacToeClient class to display a button that when clicked allows the client to play another game. The button should be enabled only when a game completes. Note that both class TicTacToeClient and class TicTacToeServer must be modified to reset the board and all state information. Also, the other TicTacToeClient should be notified that a new game is about to begin so its board and state can be reset.

c) Modify the TicTacToeClient class to provide a button that allows a client to terminate the program at any time. When the user clicks the button, the server and the other client should be notified. The server should then wait for a connection from another client so a new game can begin.

d) Modify the TicTacToeClient class and the TicTacToeServer class so the winner of a game can choose game piece X or O for the next game. Remember: X always goes first.

So far I have only been able to do part a) of the exercise im having a lot of difficulty with part b) which allows the client to play a new game.The code ive done so far is listed below if anyone can help i would be forever greatful. Thanks.

// Fig. 18.8: TicTacToeServer.java

// This class maintains a game of Tic-Tac-Toe for two client applets.

import java.awt.*;

import java.net.*;

import java.io.*;

import javax.swing.*;

public class TicTacToeServer extends JFrame {

private char[] board;

private JTextArea outputArea;

private Player[] players;

private ServerSocket server;

private int currentPlayer;

private final int PLAYER_X = 0, PLAYER_O = 1;

private final char X_MARK = 'X', O_MARK = 'O';

int moves=0;

// set up tic-tac-toe server and GUI that displays messages

public TicTacToeServer()

{

super( "Tic-Tac-Toe Server" );

board = new char[ 9 ];

for (int i = 0; i<9; i++){

board = ' ';

}

players = new Player[ 2 ];

currentPlayer = PLAYER_X;

// set up ServerSocket

try {

server = new ServerSocket( 12345, 2 );

}

// process problems creating ServerSocket

catch( IOException ioException ) {

ioException.printStackTrace();

System.exit( 1 );

}

// set up JTextArea to display messages during execution

outputArea = new JTextArea();

getContentPane().add( outputArea, BorderLayout.CENTER );

outputArea.setText( "Server awaiting connections\n" );

setSize( 300, 300 );

setVisible( true );

} // end TicTacToeServer constructor

// wait for two connections so game can be played

public void execute()

{

// wait for each client to connect

for ( int i = 0; i < players.length; i++ ) {

// wait for connection, create Player, start thread

try {

players[ i ] = new Player( server.accept(), i );

players[ i ].start();

}

// process problems receiving connection from client

catch( IOException ioException ) {

ioException.printStackTrace();

System.exit( 1 );

}

}

// Player X is suspended until Player O connects.

// Resume player X now.

synchronized ( players[ PLAYER_X ] ) {

players[ PLAYER_X ].setSuspended( false );

players[ PLAYER_X ].notify();

}

} // end method execute

// utility method called from other threads to manipulate

// outputArea in the event-dispatch thread

private void displayMessage( final String messageToDisplay )

{

// display message from event-dispatch thread of execution

SwingUtilities.invokeLater(

new Runnable() { // inner class to ensure GUI updates properly

public void run() // updates outputArea

{

outputArea.append( messageToDisplay );

outputArea.setCaretPosition(

outputArea.getText().length() );

}

} // end inner class

); // end call to SwingUtilities.invokeLater

}

// Determine if a move is valid. This method is synchronized because

// only one move can be made at a time.

public synchronized boolean validateAndMove( int location, int player )

{

boolean moveDone = false;

// while not current player, must wait for turn

while ( player != currentPlayer ) {

// wait for turn

try {

wait();

}

// catch wait interruptions

catch( InterruptedException interruptedException ) {

interruptedException.printStackTrace();

}

}

// if location not occupied, make move

if ( !isOccupied( location ) ) {

// set move in board array

board[ location ] = currentPlayer == PLAYER_X ? X_MARK : O_MARK;

// change current player

currentPlayer = ( currentPlayer + 1 ) % 2;

// let new current player know that move occurred

players[ currentPlayer ].otherPlayerMoved( location );

notify(); // tell waiting player to continue

// tell player that made move that the move was valid

return true;

}

// tell player that made move that the move was not valid

else

return false;

} // end method validateAndMove

// determine whether location is occupied

public boolean isOccupied( int location )

{

if ( board[ location ] == X_MARK || board [ location ] == O_MARK )

return true;

else

return false;

}

void gameOverCheck() {

boolean over = false;

// Check rows

for (int start=0; start < 9; start += 3)

over = over || ((board[start] != ' ') &&

(board[start] == board[start+1]) &&

(board[start] == board[start+2]));

// Check columns

for (int start=0; start < 3; start++)

over = over || ((board[start] != ' ') &&

(board[start] == board[start+3]) &&

(board[start] == board[start+6]));

// Check diagonals

over = over || ((board[0] != ' ') &&

(board[0] == board[4]) && (board[0] == board[8]));

over = over || ((board[2] != ' ') &&

(board[2] == board[4]) && (board[2] == board[6]));

if (over || (moves>=9))

for ( int i = 0; i < players.length; i++ )

players.gameOver(over ? (currentPlayer+1)%2 : -1 );

}

public static void main( String args[] )

{

TicTacToeServer application = new TicTacToeServer();

application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

application.execute();

}

// private inner class Player manages each Player as a thread

private class Player extends Thread {

private Socket connection;

private DataInputStream input;

private DataOutputStream output;

private int playerNumber;

private char mark;

protected boolean suspended = true;

boolean done = false;

// set up Player thread

public Player( Socket socket, int number )

{

playerNumber = number;

// specify player's mark

mark = ( playerNumber == PLAYER_X ? X_MARK : O_MARK );

connection = socket;

// obtain streams from Socket

try {

input = new DataInputStream( connection.getInputStream() );

output = new DataOutputStream( connection.getOutputStream() );

}

// process problems getting streams

catch( IOException ioException ) {

ioException.printStackTrace();

System.exit( 1 );

}

} // end Player constructor

// send message that other player moved

public void otherPlayerMoved( int location )

{

// send message indicating move

try {

output.writeUTF( "Opponent moved" );

output.writeInt( location );

}

// process problems sending message

catch ( IOException ioException ) {

ioException.printStackTrace();

}

}

void gameOver(int winner) {

try {

output.writeUTF( "Game Over. " +

(( winner == -1 ) ? "No winner." :

( "Winner is " + ( winner == 0 ? 'X' : 'O' ) + "." ) ) );

done=true;

output.writeUTF("Game Over");

} catch( IOException e ) {

e.printStackTrace(); System.exit( 1 );

}

}

public void run()

{

// send client message indicating its mark (X or O),

// process messages from client

try {

displayMessage( "Player " + ( playerNumber ==

PLAYER_X ? X_MARK : O_MARK ) + " connected\n" );

output.writeChar( mark ); // send player's mark

// send message indicating connection

output.writeUTF( "Player " + ( playerNumber == PLAYER_X ?

"X connected\n" : "O connected, please wait\n" ) );

// if player X, wait for another player to arrive

if ( mark == X_MARK ) {

output.writeUTF( "Waiting for another player" );

// wait for player O

try {

synchronized( this ) {

while ( suspended )

wait();

}

}

// process interruptions while waiting

catch ( InterruptedException exception ) {

exception.printStackTrace();

}

// send message that other player connected and

// player X can make a move

output.writeUTF( "Other player connected. Your move." );

}

while ( ! done ) {

// get move location from client

int location = input.readInt();

// check for valid move

if ( validateAndMove( location, playerNumber ) ) {

displayMessage( "\nlocation: " + location );

output.writeUTF( "Valid move." );

gameOverCheck();

}

else

output.writeUTF( "Invalid move, try again" );

}

// close connection to client

} // end try

// process problems communicating with client

catch( IOException ioException ) {

ioException.printStackTrace();

System.exit( 1 );

}

}

// end method run

// set whether or not thread is suspended

public void setSuspended( boolean status )

{

suspended = status;

}

} // end class Player

} // end class TicTacToeServer

*****************************************************************************

// Fig. 18.9: TicTacToeClient.java

// Client that let a user play Tic-Tac-Toe with another across a network.

import java.awt.*;

import java.awt.event.*;

import java.net.*;

import java.io.*;

import javax.swing.*;

public class TicTacToeClient extends JApplet implements Runnable, ActionListener {

private JButton Button;

private JTextField idField;

private JTextArea displayArea;

private JPanel boardPanel, panel2;

private Square board[][], currentSquare;

private Socket connection;

private DataInputStream input;

private DataOutputStream output;

private char myMark;

private boolean myTurn;

private final char X_MARK = 'X', O_MARK = 'O';

boolean done=false;

Container container;

// Set up user-interface and board

public void init()

{

container = getContentPane();

// set up JTextArea to display messages to user

displayArea = new JTextArea( 4, 30 );

displayArea.setEditable( false );

container.add( new JScrollPane( displayArea ), BorderLayout.SOUTH );

// set up panel for squares in board

boardPanel = new JPanel();

boardPanel.setLayout( new GridLayout( 3, 3, 0, 0 ) );

// create board

board = new Square[ 3 ][ 3 ];

// When creating a Square, the location argument to the constructor

// is a value from 0 to 8 indicating the position of the Square on

// the board. Values 0, 1, and 2 are the first row, values 3, 4,

// and 5 are the second row. Values 6, 7, and 8 are the third row.

for ( int row = 0; row < board.length; row++ ) {

for ( int column = 0; column < board[ row ].length; column++ ) {

// create Square

board[ row ][ column ] = new Square( ' ', row * 3 + column );

boardPanel.add( board[ row ][ column ] );

}

}

// textfield to display player's mark

idField = new JTextField();

idField.setEditable( false );

container.add( idField, BorderLayout.NORTH );

Button = new JButton("New Game");

container.add(Button, BorderLayout.BEFORE_FIRST_LINE);

// set up panel to contain boardPanel (for layout purposes)

panel2 = new JPanel();

panel2.add( boardPanel, BorderLayout.CENTER );

container.add( panel2, BorderLayout.CENTER );

} // end method init

// Make connection to server and get associated streams.

// Start separate thread to allow this applet to

// continually update its output in textarea display.

public void start()

{

// connect to server, get streams and start outputThread

try {

// make connection

connection = new Socket( getCodeBase().getHost(), 12345 );

// get streams

input = new DataInputStream( connection.getInputStream() );

output = new DataOutputStream( connection.getOutputStream() );

}

// catch problems setting up connection and streams

catch ( IOException ioException ) {

ioException.printStackTrace();

}

// create and start output thread

Thread outputThread = new Thread( this );

outputThread.start();

} // end method start

// control thread that allows continuous update of displayArea

public void run()

{

// get player's mark (X or O)

try {

myMark = input.readChar();

// display player ID in event-dispatch thread

SwingUtilities.invokeLater(

new Runnable() {

public void run()

{

idField.setText( "You are player \"" + myMark + "\"" );

}

}

);

myTurn = ( myMark == X_MARK ? true : false );

// receive messages sent to client and output them

while ( !done) {

processMessage( input.readUTF() );

}

} // end try

// process problems communicating with server

catch ( IOException ioException ) {

ioException.printStackTrace();

}

} // end method run

// process messages received by client

private void processMessage( String message )

{

// valid move occurred

if ( message.equals( "Valid move." ) ) {

displayMessage( "Valid move, please wait.\n" );

setMark( currentSquare, myMark );

}

// invalid move occurred

else if ( message.equals( "Invalid move, try again" ) ) {

displayMessage( message + "\n" );

myTurn = true;

}

// opponent moved

else if ( message.equals( "Opponent moved" ) ) {

// get move location and update board

try {

int location = input.readInt();

int row = location / 3;

int column = location % 3;

setMark( board[ row ][ column ],

( myMark == X_MARK ? O_MARK : X_MARK ) );

displayMessage( "Opponent moved. Your turn.\n" );

myTurn = true;

} // end try

// process problems communicating with server

catch ( IOException ioException ) {

ioException.printStackTrace();

}

} // end else if

else if ( message.equals("Game Over") ){

displayMessage("**** sake" );

}

// simply display message

else

displayMessage( message + "\n" );

} // end method processMessage

// utility method called from other threads to manipulate

// outputArea in the event-dispatch thread

private void displayMessage( final String messageToDisplay )

{

// display message from event-dispatch thread of execution

SwingUtilities.invokeLater(

new Runnable() { // inner class to ensure GUI updates properly

public void run() // updates displayArea

{

displayArea.append( messageToDisplay );

displayArea.setCaretPosition(

displayArea.getText().length() );

}

} // end inner class

); // end call to SwingUtilities.invokeLater

}

// utility method to set mark on board in event-dispatch thread

private void setMark( final Square squareToMark, final char mark )

{

SwingUtilities.invokeLater(

new Runnable() {

public void run()

{

squareToMark.setMark( mark );

}

}

);

}

// send message to server indicating clicked square

public void sendClickedSquare( int location )

{

if ( myTurn ) {

// send location to server

try {

output.writeInt( location );

myTurn = false;

}

// process problems communicating with server

catch ( IOException ioException ) {

ioException.printStackTrace();

}

}

}

// set current Square

public void setCurrentSquare( Square square )

{

currentSquare = square;

}

public void actionPerformed(ActionEvent e) {

// I need code here

}

// private inner class for the squares on the board

private class Square extends JPanel {

private char mark;

private int location;

public Square( char squareMark, int squareLocation )

{

mark = squareMark;

location = squareLocation;

addMouseListener(

new MouseAdapter() {

public void mouseReleased( MouseEvent e )

{

setCurrentSquare( Square.this );

sendClickedSquare( getSquareLocation() );

}

}

);

} // end Square constructor

// return preferred size of Square

public Dimension getPreferredSize()

{

return new Dimension( 30, 30 );

}

// return minimum size of Square

public Dimension getMinimumSize()

{

return getPreferredSize();

}

// set mark for Square

public void setMark( char newMark )

{

mark = newMark;

repaint();

}

// return Square location

public int getSquareLocation()

{

return location;

}

// draw Square

public void paintComponent( Graphics g )

{

super.paintComponent( g );

g.drawRect( 0, 0, 29, 29 );

g.drawString( String.valueOf( mark ), 11, 20 );

}

} // end inner-class Square

} // end class TicTacToeClient

[18742 byte] By [JavaDistress] at [2007-11-26 12:17:43]
# 1
1. Use code tags2. Make sure your examples are short enough to read.3. Please ask specific questions.
zadok at 2007-7-7 14:55:37 > top of Java-index,Archived Forums,Socket Programming...