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 {
private boolean myTurn = false;
private char myToken = ' ';
private char otherToken = ' ';
private Cell[][] cell = new Cell[3][3];
private JLabel jlblTitle = new JLabel();
private JLabel jlblStatus = new JLabel();
private int rowSelected;
private int columnSelected;
private DataInputStream fromServer;
private DataOutputStream toServer;
private boolean continueToPlay = true;
private boolean waiting = true;
private boolean isStandAlone = false;
private String host = "localhost";
public void init() {
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));
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));
add(jlblTitle, BorderLayout.NORTH);
add(p, BorderLayout.CENTER);
add(jlblStatus, BorderLayout.SOUTH);
connectToServer();
}
private void connectToServer() {
try {
Socket socket;
if (isStandAlone)
socket = new Socket(host, 8000);
else
socket = new Socket(getCodeBase().getHost(), 8000);
fromServer = new DataInputStream(socket.getInputStream());
toServer = new DataOutputStream(socket.getOutputStream());
}
catch (Exception ex) {
System.err.println(ex);
}
Thread thread = new Thread(this);
thread.start();
}
public void run() {
try {
int player = fromServer.readInt();
if (player == PLAYER1) {
myToken = 'X';
otherToken = 'O';
jlblTitle.setText("Player 1 with token 'X'");
jlblStatus.setText("Waiting for player 2 to join");
fromServer.readInt();
jlblStatus.setText("Player 2 has joined. I start first");
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");
}
while (continueToPlay) {
if (player == PLAYER1) {
waitForPlayerAction();
sendMove();
receiveInfoFromServer();
}
else if (player == PLAYER2) {
receiveInfoFromServer();
waitForPlayerAction();
sendMove();
}
}
}
catch (Exception ex) {
}
}
private void waitForPlayerAction() throws InterruptedException {
while (waiting) {
Thread.sleep(100);
}
waiting = true;
}
private void sendMove() throws IOException {
toServer.writeInt(rowSelected);
toServer.writeInt(columnSelected);
}
private void receiveInfoFromServer() throws IOException {
int status = fromServer.readInt();
if (status == PLAYER1_WON) {
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) {
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) {
continueToPlay = false;
jlblStatus.setText("Game is over, no winner!");
if (myToken == 'O') {
receiveMove();
}
}
else {
receiveMove();
jlblStatus.setText("My turn");
myTurn = true;
}
}
private void receiveMove() throws IOException {
int row = fromServer.readInt();
int column = fromServer.readInt();
cell[row][column].setToken(otherToken);
}
public class Cell extends JPanel {
private int row;
private int column;
private char token = ' ';
public Cell(int row, int column) {
this.row = row;
this.column = column;
setBorder(new LineBorder(Color.black, 1));
addMouseListener(new ClickListener());
}
public char getToken() {
return token;
}
public void setToken(char c) {
token = c;
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (token == 'X') {
g.drawLine(10, 10, getWidth() - 10, getHeight() - 10);
g.drawLine(getWidth() - 10, 10, 10, getHeight() - 10);
}
else if (token == 'O') {
g.drawOval(10, 10, getWidth() - 20, getHeight() - 20);
}
}
private class ClickListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
if ((token == ' ') && myTurn) {
setToken(myToken);
myTurn = false;
rowSelected = row;
columnSelected = column;
jlblStatus.setText("Waiting for the other player to move");
waiting = false;
}
}
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Tic Tac Toe Client");
TicTacToeClient applet = new TicTacToeClient();
applet.isStandAlone = true;
if (args.length == 1) applet.host = args[0];
frame.getContentPane().add(applet, BorderLayout.CENTER);
applet.init();
applet.start();
frame.setSize(320, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}