私は、1 つのサーバーで構成されるクライアント/サーバー Tic-Tac-Toe ゲームと、2 つのスレッドで構成されるクライアントに取り組んでいます。プログラム全体には、TicTacToeServer クラス、TicTacToeService クラス、および TicTacToeClientPanel (GUI とクライアントを組み合わせたもの) が含まれています。
私が直面している主な問題は、クライアント クラス自体にあります。GUI/クライアントの 2 つのウィンドウ (2 人の異なるプレイヤー用) を起動し、最初のプレイヤーに 1 つのマーカー (X) を配置できます。この後、スレッドが停止したように見え、ゲームを続行できなくなります。
クライアント 1 (プレーヤー 1) のスレッドをスリープ状態にしようとすると、指定された割り当てのためにスリープしますが、クライアント 2 (プレーヤー 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);
}
}