2

私は、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);
}

}

4

1 に答える 1

1

私はすぐにあなたのコードを見ました。1 つのヒント: 待機中の変数は揮発性ではありません。したがって、次のループが終了するという保証はありません。

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

マウス クリックの待機中は false に設定されます。それは別のスレッドで発生します。変数の待機は揮発性ではないため、JVM は上記のループを次のように最適化できます。

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

待機を揮発性にしてみてください。これにより、この変数への各書き込みが強制的に他のスレッドから見えるようになります。変数が揮発性でない場合、各スレッドはこの変数の独自のローカル コピーを保持できます。

于 2012-12-14T16:26:23.333 に答える