50% found this document useful (2 votes)
456 views9 pages

Tic Tac Toe Java

This document describes a two-player tic-tac-toe game that can be played over a network between a client and server. The server code handles pairing up two clients and managing the game state and turns. It communicates with the clients using a text-based protocol. The client code displays the tic-tac-toe board graphically and handles user input and network communication to make moves.

Uploaded by

Nayada Sky
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
50% found this document useful (2 votes)
456 views9 pages

Tic Tac Toe Java

This document describes a two-player tic-tac-toe game that can be played over a network between a client and server. The server code handles pairing up two clients and managing the game state and turns. It communicates with the clients using a text-based protocol. The client code displays the tic-tac-toe board graphically and handles user input and network communication to make moves.

Uploaded by

Nayada Sky
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 9

A Two-Player Networked Tic-Tac-Toe Game

The server

TicTacToeServer.java

package edu.lmu.cs.networking;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
* A server for a network multi-player tic tac toe game. Modified and
* extended from the class presented in Deitel and Deitel "Java How to
* Program" book. I made a bunch of enhancements and rewrote large
sections
* of the code. The main change is instead of passing *data* between the
* client and server, I made a TTTP (tic tac toe protocol) which is
totally
* plain text, so you can test the game with Telnet (always a good idea.)
* The strings that are sent in TTTP are:
*
* Client -> Server Server -> Client
* ---------------- ----------------
* MOVE <n> (0 <= n <= 8) WELCOME <char> (char in {X, O})
* QUIT VALID_MOVE
* OTHER_PLAYER_MOVED <n>
* VICTORY
* DEFEAT
* TIE
* MESSAGE <text>
*
* A second change is that it allows an unlimited number of pairs of
* players to play.
*/
public class TicTacToeServer {

/**
* Runs the application. Pairs up clients that connect.
*/
public static void main(String[] args) throws Exception {
ServerSocket listener = new ServerSocket(8901);
System.out.println("Tic Tac Toe Server is Running");
try {
while (true) {
Game game = new Game();
Game.Player playerX = game.new Player(listener.accept(),
'X');
Game.Player playerO = game.new Player(listener.accept(),
'O');
playerX.setOpponent(playerO);
playerO.setOpponent(playerX);
game.currentPlayer = playerX;
playerX.start();
playerO.start();
}
} finally {
listener.close();
}
}
}

/**
* A two-player game.
*/
class Game {

/**
* A board has nine squares. Each square is either unowned or
* it is owned by a player. So we use a simple array of player
* references. If null, the corresponding square is unowned,
* otherwise the array cell stores a reference to the player that
* owns it.
*/
private Player[] board = {
null, null, null,
null, null, null,
null, null, null};

/**
* The current player.
*/
Player currentPlayer;

/**
* Returns whether the current state of the board is such that one
* of the players is a winner.
*/
public boolean hasWinner() {
return
(board[0] != null && board[0] == board[1] && board[0] ==
board[2])
||(board[3] != null && board[3] == board[4] && board[3] ==
board[5])
||(board[6] != null && board[6] == board[7] && board[6] ==
board[8])
||(board[0] != null && board[0] == board[3] && board[0] ==
board[6])
||(board[1] != null && board[1] == board[4] && board[1] ==
board[7])
||(board[2] != null && board[2] == board[5] && board[2] ==
board[8])
||(board[0] != null && board[0] == board[4] && board[0] ==
board[8])
||(board[2] != null && board[2] == board[4] && board[2] ==
board[6]);
}
/**
* Returns whether there are no more empty squares.
*/
public boolean boardFilledUp() {
for (int i = 0; i < board.length; i++) {
if (board[i] == null) {
return false;
}
}
return true;
}

/**
* Called by the player threads when a player tries to make a
* move. This method checks to see if the move is legal: that
* is, the player requesting the move must be the current player
* and the square in which she is trying to move must not already
* be occupied. If the move is legal the game state is updated
* (the square is set and the next player becomes current) and
* the other player is notified of the move so it can update its
* client.
*/
public synchronized boolean legalMove(int location, Player player) {
if (player == currentPlayer && board[location] == null) {
board[location] = currentPlayer;
currentPlayer = currentPlayer.opponent;
currentPlayer.otherPlayerMoved(location);
return true;
}
return false;
}

/**
* The class for the helper threads in this multithreaded server
* application. A Player is identified by a character mark
* which is either 'X' or 'O'. For communication with the
* client the player has a socket with its input and output
* streams. Since only text is being communicated we use a
* reader and a writer.
*/
class Player extends Thread {
char mark;
Player opponent;
Socket socket;
BufferedReader input;
PrintWriter output;

/**
* Constructs a handler thread for a given socket and mark
* initializes the stream fields, displays the first two
* welcoming messages.
*/
public Player(Socket socket, char mark) {
this.socket = socket;
this.mark = mark;
try {
input = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
output = new PrintWriter(socket.getOutputStream(), true);
output.println("WELCOME " + mark);
output.println("MESSAGE Waiting for opponent to
connect");
} catch (IOException e) {
System.out.println("Player died: " + e);
}
}

/**
* Accepts notification of who the opponent is.
*/
public void setOpponent(Player opponent) {
this.opponent = opponent;
}

/**
* Handles the otherPlayerMoved message.
*/
public void otherPlayerMoved(int location) {
output.println("OPPONENT_MOVED " + location);
output.println(
hasWinner() ? "DEFEAT" : boardFilledUp() ? "TIE" : "");
}

/**
* The run method of this thread.
*/
public void run() {
try {
// The thread is only started after everyone connects.
output.println("MESSAGE All players connected");

// Tell the first player that it is her turn.


if (mark == 'X') {
output.println("MESSAGE Your move");
}

// Repeatedly get commands from the client and process


them.
while (true) {
String command = input.readLine();
if (command.startsWith("MOVE")) {
int location =
Integer.parseInt(command.substring(5));
if (legalMove(location, this)) {
output.println("VALID_MOVE");
output.println(hasWinner() ? "VICTORY"
: boardFilledUp() ? "TIE"
: "");
} else {
output.println("MESSAGE ?");
}
} else if (command.startsWith("QUIT")) {
return;
}
}
} catch (IOException e) {
System.out.println("Player died: " + e);
} finally {
try {socket.close();} catch (IOException e) {}
}
}
}
}
The client

TicTacToeClient.java

package edu.lmu.cs.networking;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

/**
* A client for the TicTacToe game, modified and extended from the
* class presented in Deitel and Deitel "Java How to Program" book.
* I made a bunch of enhancements and rewrote large sections of the
* code. In particular I created the TTTP (Tic Tac Toe Protocol)
* which is entirely text based. Here are the strings that are sent:
*
* Client -> Server Server -> Client
* ---------------- ----------------
* MOVE <n> (0 <= n <= 8) WELCOME <char> (char in {X, O})
* QUIT VALID_MOVE
* OTHER_PLAYER_MOVED <n>
* VICTORY
* DEFEAT
* TIE
* MESSAGE <text>
*
*/
public class TicTacToeClient {

private JFrame frame = new JFrame("Tic Tac Toe");


private JLabel messageLabel = new JLabel("");
private ImageIcon icon;
private ImageIcon opponentIcon;

private Square[] board = new Square[9];


private Square currentSquare;

private static int PORT = 8901;


private Socket socket;
private BufferedReader in;
private PrintWriter out;

/**
* Constructs the client by connecting to a server, laying out the
* GUI and registering GUI listeners.
*/
public TicTacToeClient(String serverAddress) throws Exception {

// Setup networking
socket = new Socket(serverAddress, PORT);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);

// Layout GUI
messageLabel.setBackground(Color.lightGray);
frame.getContentPane().add(messageLabel, "South");

JPanel boardPanel = new JPanel();


boardPanel.setBackground(Color.black);
boardPanel.setLayout(new GridLayout(3, 3, 2, 2));
for (int i = 0; i < board.length; i++) {
final int j = i;
board[i] = new Square();
board[i].addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
currentSquare = board[j];
out.println("MOVE " + j);}});
boardPanel.add(board[i]);
}
frame.getContentPane().add(boardPanel, "Center");
}

/**
* The main thread of the client will listen for messages
* from the server. The first message will be a "WELCOME"
* message in which we receive our mark. Then we go into a
* loop listening for "VALID_MOVE", "OPPONENT_MOVED", "VICTORY",
* "DEFEAT", "TIE", "OPPONENT_QUIT or "MESSAGE" messages,
* and handling each message appropriately. The "VICTORY",
* "DEFEAT" and "TIE" ask the user whether or not to play
* another game. If the answer is no, the loop is exited and
* the server is sent a "QUIT" message. If an OPPONENT_QUIT
* message is recevied then the loop will exit and the server
* will be sent a "QUIT" message also.
*/
public void play() throws Exception {
String response;
try {
response = in.readLine();
if (response.startsWith("WELCOME")) {
char mark = response.charAt(8);
icon = new ImageIcon(mark == 'X' ? "x.gif" : "o.gif");
opponentIcon = new ImageIcon(mark == 'X' ? "o.gif" :
"x.gif");
frame.setTitle("Tic Tac Toe - Player " + mark);
}
while (true) {
response = in.readLine();
if (response.startsWith("VALID_MOVE")) {
messageLabel.setText("Valid move, please wait");
currentSquare.setIcon(icon);
currentSquare.repaint();
} else if (response.startsWith("OPPONENT_MOVED")) {
int loc = Integer.parseInt(response.substring(15));
board[loc].setIcon(opponentIcon);
board[loc].repaint();
messageLabel.setText("Opponent moved, your turn");
} else if (response.startsWith("VICTORY")) {
messageLabel.setText("You win");
break;
} else if (response.startsWith("DEFEAT")) {
messageLabel.setText("You lose");
break;
} else if (response.startsWith("TIE")) {
messageLabel.setText("You tied");
break;
} else if (response.startsWith("MESSAGE")) {
messageLabel.setText(response.substring(8));
}
}
out.println("QUIT");
}
finally {
socket.close();
}
}

private boolean wantsToPlayAgain() {


int response = JOptionPane.showConfirmDialog(frame,
"Want to play again?",
"Tic Tac Toe is Fun Fun Fun",
JOptionPane.YES_NO_OPTION);
frame.dispose();
return response == JOptionPane.YES_OPTION;
}

/**
* Graphical square in the client window. Each square is
* a white panel containing. A client calls setIcon() to fill
* it with an Icon, presumably an X or O.
*/
static class Square extends JPanel {
JLabel label = new JLabel((Icon)null);

public Square() {
setBackground(Color.white);
add(label);
}

public void setIcon(Icon icon) {


label.setIcon(icon);
}
}

/**
* Runs the client as an application.
*/
public static void main(String[] args) throws Exception {
while (true) {
String serverAddress = (args.length == 0) ? "localhost" :
args[1];
TicTacToeClient client = new TicTacToeClient(serverAddress);
client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.frame.setSize(240, 160);
client.frame.setVisible(true);
client.frame.setResizable(false);
client.play();
if (!client.wantsToPlayAgain()) {
break;
}
}
}
}

You might also like