2

我正在开发一个客户端/服务器井字游戏,该游戏由一个服务器和一个由两个线程组成的客户端组成。整个程序包括一个 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);
}

}

4

1 回答 1

1

我迅速查看了您的代码。一个提示:变量等待不是易失的。因此,不能保证以下循环将永远结束:

   waiting = true;
   while(waiting) {
       Thread.sleep(1000);
   }   //thread sleeps until something is clicked 

鼠标点击等待设置为假。这发生在不同的线程中。因为变量 waiting 不是 volatile 的,所以允许 JVM 将上述循环优化为:

while (true) {
   Thread.sleep(1000);
}

尝试让等待变得不稳定。这会强制对该变量的每次写入都对其他线程可见。如果变量不是易失性的,那么每个线程都可以保留它自己的该变量的本地副本。

于 2012-12-14T16:26:23.333 回答