0

五目並べをするアプリを準備中です。

見栄えの良い GUI を作成しましたが、今はコア エンジンと戦っています。

GameEngine移動するための同期メソッドを持つクラスがあります。IClient「プレーヤー」であるインターフェイスを実装するクラスもあります。最初に行うことは、(五目板を表す)で「と」と言ったときにPlayerClient、に接続されてBoardPanel動くものを実装することです。コンピューター プレーヤーも実装できるように、アプリケーションをオープンにしたいと考えています。それがとても複雑な理由です。MouseListenerBoardPanel

だから...問題:私GameEngineのクラスは次のようになります:

public class GameEngine {
    private IClient blackPlayer;
    private IClient whitePlayer;
    private GameState gameState;

    ...

    public void play() {
        blackPlayer.run();
        whitePlayer.run();
    }

    public synchronized void move(Move move) throws IllegalMoveException {
        gameState.move(move);
        if (move.isBlackMove()){
            whitePlayer.notify();
        }else{
            blackPlayer.notify();
        }
    }

    public synchronized void waitForYourTurn(boolean color){
        try {
            while (gameState.isBlackToMove()!=color) {
                wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

私の Client クラスには run() メソッドがあります:

@Override
    public void run() {
        while (gameState.getWinner() == 0) {
            move = null;
            boolean moved = false;
            while (!moved) {
                gameEngine.waitForYourTurn(black);
                try {
                    //waitForPickedMove();
                    gameEngine.move(move);
                    moved = true;
                } catch (IllegalMoveException e) {
                    e.printStackTrace();
                }
            }
        }
    }

「//waitForPickedMove()」と書いた場所で、クライアントはユーザーがボード上の適切な場所をクリックするのを待つ必要があります。だから...私のBoardクラスにはMouseListenerがあります:

private class MoveMouseListener implements MouseListener {
        @Override
        public synchronized void mouseReleased(MouseEvent e) {
            if (gameState == null) {
                return;
            }

            if (currentMove != null) {
                movePicked();
                repaint();
            }
        }
    }

currentMove はもちろん、ユーザーがボードをクリックして選択した移動です。movePicked() は次のようになります。

private synchronized void movePicked() {
    if (gameState.isBlackToMove() && blackClient != null) {
        blackClient.notify();
        clearCurrentMove();
    }
    if (!gameState.isBlackToMove() && whiteClient != null) {
        whiteClient.notify();
        clearCurrentMove();
    }
}

いろいろなところに入れてみましたwait()。制御を逆にしてクラスに入れようとしたBoardので、Client クラスのメソッド (setCurrentMove(Move move)) を呼び出しました。残念ながら、私が望むものに到達することはできません。私はいつもIllegalMonitorStateExceptionGUIブロックを取得します。

私の問題を十分に説明したことを願っています。どんな助けにも感謝します。

編集:

public class MockComputerClient implements IClient {
    private GameState gameState;
    private GameEngine gameEngine;
    private boolean black;
    private ExecutorService executorService;
    private boolean myTurn = false;
    private int i = 3;

    public MockComputerClient(GameEngine gameEngine, GameState gameState,
            boolean black) {
        this.gameEngine = gameEngine;
        this.gameState = gameState;
        this.black = black;
        executorService = new ExecutorService();
        executorService.run();
    }

    @Override
    public void enemyMoved() {
        myTurn = true;
        executorService.notify();
    }

    private class ExecutorService implements Runnable {

        @Override
        public void run() {
            while (gameState.getWinner() == 0) {
                try {
                    while (!myTurn) {
                        wait();
                    }
                    // Hardcoded Moves
                    gameEngine.move(new Move(black, 3, i++));
                    myTurn = false;
                } catch (InterruptedException | IllegalMoveException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

sth を同期する必要があることは確かですが、何を行うべきかはよくわかりません。

編集2:

@Override
    public void enemyMoved() {
        myTurn = true;
        executorService.move();
    }

    private class ExecutorService implements Runnable {

        @Override
        public void run() {
            while (gameState.getWinner() == 0) {
                System.out.println("Calculating: j= " + j);
                if (j == 3)
                    j = 4;
                else
                    j = 3;

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }

        public void move() {
            while (myTurn) {
                try {
                    gameEngine.move(new Move(black, j, i++));
                    myTurn = false;
                } catch (IllegalMoveException e) {
                    e.printStackTrace();
                }
            }
        }

    }
4

3 に答える 3

4

ゲーム エンジンが常にスレッドを占有して、何もすることがないときにスレッドをブロックする必要はありません。これをリアクティブに再設計する必要があります。イベントが発生すると、イベント ハンドラが実行されているスレッドでコードが実行されます。その後、メカニズムは必要ありませんwaitnotify

Player の実装が呼び出し元のスレッドを占有することなく時間をかけられるようにしたい場合は、非同期性を念頭に置いて API を設計してください。IClient「他のプレイヤーが移動した」ことを表すメソッドがあり、プレイヤーの動きがすぐには返されません。はIClient、ゲーム エンジンのメソッドをその移動とともに呼び出すことが期待されます。

于 2012-12-07T08:40:54.057 に答える
0

それが何であるかを正確に伝えるのは難しい: たくさんのピース. ただし、ここで説明されているように、通知呼び出しを同期する必要があるようです。

http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#notify ()

于 2012-12-07T08:36:57.147 に答える
0

こんにちは、sleep() と notify() をお勧めします。不明な時間のためにスレッドを停止したい場合は、スリープさせ、再び必要なときにnotify()を与えます。

于 2012-12-07T08:40:42.637 に答える