我正在开发一个客户端/服务器井字游戏,该游戏由一个服务器和一个由两个线程组成的客户端组成。整个程序包括一个 TicTacToeServer 类、TicTacToeService 类和 TicTacToeClientPanel(即 GUI 和客户端放在一起)。
我面临的主要问题是客户端类本身。我启动了 GUI/客户端的两个窗口(用于两个不同的玩家),并且能够在第一个玩家上放置一个标记 (X)。之后,线程似乎停止了,我无法继续玩游戏。
如果我试图让客户端 1(玩家 1)的线程进入睡眠状态,它会在给定的分配中休眠,但客户端 2(玩家 2)的线程永远不会开始。
有什么方法可以在这两个线程之间交替并通过我的程序,这取决于轮到哪个玩家?
import java.awt.*; //Color and GridLayout
import java.awt.event.*;
import java.io.*; //DataInputStream & DataOutputStream
import java.net.Socket;
import java.util.Scanner;
import javax.swing.*; //JPanel & JPanel
import javax.swing.border.LineBorder;
/**
* This is the Main Panel for the TicTacToe Client.
* It uses a displayBoard of Cell objects to display the TicTacToe board
* @author Professor Myers
*
*/
public class TicTacToeClientPanel extends JPanel implements Runnable {
//instance variables and constants
private Cell displayBoard[][] = new Cell[3][3];
private Scanner fromServer;
private PrintWriter out;
private Boolean myTurn, waiting, inputReady;
private Thread thread;
private char mySymbol;
private int rowSelected, columnSelected;
private JLabel statusLabel, playerInfo;
public static final int PLAYER1 = 1, PLAYER2 = 2;
public TicTacToeClientPanel()
{
//give initial values to instance variables
mySymbol = ' ';
myTurn = false;
JPanel sub1 = new JPanel();
playerInfo = new JLabel("");
statusLabel = new JLabel("");
sub1.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
//initialize Cells in board array and add to display
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 3; x++)
{
displayBoard[y][x] = new Cell(x+1, y+1);
c.gridx = y;
c.gridy = x;
c.fill = GridBagConstraints.BOTH;
sub1.add(displayBoard[y][x], c);
}
}
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(new JPanel().add(playerInfo));
add(sub1);
add(new JPanel().add(statusLabel));
connectToServer();
}
private void connectToServer()
{
try
{
//create socket
//set up Scanner and PrintWriter
Socket s = new Socket("localhost", 8880);
InputStream instream = s.getInputStream();
OutputStream outstream = s.getOutputStream();
fromServer = new Scanner(instream);
out = new PrintWriter(outstream);
}
catch (Exception e)
{
System.err.println(e);
}
//start the thread
thread = new Thread(this);
thread.start();
}
public void run()
{
int otherPRow, otherPColumn;
try {
int player = Integer.parseInt(fromServer.nextLine()); //Begin the game
int message = 0;
//set up symbol
//keep track of who's turn it is
//Display the player number and symbol (JLabel)
//Display the status of the player (who's turn is it)
if (player == PLAYER1) {
mySymbol = 'X';
playerInfo.setText("Player 1 with symbol \'X\'");
statusLabel.setText("My turn");
myTurn = true; //player1 goes first
message = Integer.parseInt(fromServer.nextLine());
}
else if (player == PLAYER2) {
mySymbol = 'O';
playerInfo.setText("Player 2 with symbol \'O\'");
statusLabel.setText("Waiting for Player 1 to move");
//what to do with waiting?
myTurn = false;
while (!myTurn) {
if (fromServer.hasNextLine()) {
System.out.println("ITS HAPPENING");
myTurn = true;
thread.setPriority(thread.MAX_PRIORITY);
}
}
}
while(message != 1 && message != 2 && message != 3) //CHANGE TO GAME NOT OVER
{
if(player == PLAYER1)
{
//wait for user to select a cell - sleep for awhile
//"write" the row and column to server
//"read" from the server - perform the appropriate action
//this code is only reached if server passes 5 or 4 to the first player
if (myTurn) {
waiting = true;
while(waiting) {
Thread.sleep(1000);
} //thread sleeps until something is clicked
}
//if this cell value is not empty (WRITE)
if (displayBoard[rowSelected-1][columnSelected-1].getSymbol() != ' ') {
System.out.println("Success");
out.println(rowSelected + '\n' + columnSelected);
out.flush();
statusLabel.setText("Waiting for Player 2 to move");
}
waiting = true;
while (waiting)
Thread.currentThread().sleep(1000);
//READ from server
message = Integer.parseInt(fromServer.nextLine());
if (message == 1) {
statusLabel.setText("I Won! (X)");
return;
}
else if (message == 2) {
//update from player 2's turn
otherPRow = Integer.parseInt(fromServer.nextLine());
otherPColumn = Integer.parseInt(fromServer.nextLine());
displayBoard[otherPRow-1][otherPColumn-1].setSymbol('O');
statusLabel.setText("Player 2 has won (O)");
return;
}
else if (message == 3) {
//update from player 2's turn
otherPRow = Integer.parseInt(fromServer.nextLine());
otherPColumn = Integer.parseInt(fromServer.nextLine());
displayBoard[otherPRow-1][otherPColumn-1].setSymbol('O');
statusLabel.setText("Game is over, no winner");
return;
}
else if (message == 4) { //traverses back to beginning of loop
otherPRow = Integer.parseInt(fromServer.nextLine());
otherPColumn = Integer.parseInt(fromServer.nextLine()); //What kind does it send? normal or +1?
displayBoard[otherPRow-1][otherPColumn-1].setSymbol('O');
statusLabel.setText("My turn");
myTurn = true;
}
}
else if(player == PLAYER2)
{
//"read" from the server - perform the appropriate action
//wait for the user to select a cell - sleep for a while
//"write" the row and column to server
myTurn = true;
statusLabel.setText("My turn");
message = Integer.parseInt(fromServer.nextLine());
System.out.println(message);
//player1 has won or game is full
if (message == 1 || message == 3) {
otherPRow = Integer.parseInt(fromServer.nextLine());
otherPColumn = Integer.parseInt(fromServer.nextLine());
displayBoard[otherPRow-1][otherPColumn-1].setSymbol('X');
if (message == 1) {
statusLabel.setText("Player 1 (X) won");
return;
}
else {
statusLabel.setText("Game is over, no winner");
return;
}
}
else if (message == 2) { //player2 has won
statusLabel.setText("I won! (O)");
return;
}
else if (message == 4) {
otherPRow = Integer.parseInt(fromServer.nextLine());
otherPColumn = Integer.parseInt(fromServer.nextLine());
displayBoard[otherPRow-1][otherPColumn-1].setSymbol('X');
//SLEEP for user input
statusLabel.setText("My turn");
myTurn = true;
waiting = true;
while (waiting) {
Thread.sleep(1000);
}
//WRITE to server
char s = displayBoard[rowSelected-1][columnSelected-1].getSymbol();
if (s != ' ' && s != 'X' && waiting == false) {
out.println(rowSelected + '\n' + columnSelected);
out.flush();
}
statusLabel.setText("Waiting for Player 1 to move");
if (!myTurn)
Thread.currentThread().sleep(10000);
}
}
}
}
catch (Exception e)
{
}
}
public class Cell extends JPanel
{
int row;
int column;
private char symbol;
public Cell(int r, int c)
{
row = r;
column = c;
symbol = ' ';
setBorder(new LineBorder(Color.black,1));
setPreferredSize(new Dimension(100,150));
addMouseListener(new ClickListener());
}
public void setSymbol(char c)
{
symbol = c;
repaint();
}
public char getSymbol()
{
return symbol;
}
protected void paintComponent (Graphics g)
{
super.paintComponent(g);
if(symbol == 'X')
{
g.drawLine(10, 10, getWidth()-10, getHeight()-10);
g.drawLine(getWidth()-10, 10, 10, getHeight()-10);
}
else if(symbol == 'O')
{
g.drawOval(10, 10, getWidth()-10, getHeight()-20);
}
}
private class ClickListener extends MouseAdapter
{
public void mouseClicked(MouseEvent e)
{
System.out.println("Clicked: " + row + " " + column);
if(symbol == ' ' && myTurn)
{
setSymbol(mySymbol);
myTurn = false;
rowSelected = row;
columnSelected = column;
statusLabel.setText("Waiting for the other player to move");
waiting = false;
}
}
}
}
public static void main (String[] args)
{
JFrame frame = new JFrame();
frame.setBounds(0, 0, 1000, 1200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TicTacToeClientPanel ttt = new TicTacToeClientPanel();
frame.getContentPane().add(ttt);
frame.pack();
frame.setVisible(true);
}
}