1

山がなくなるまで、2 人のプレイヤーが 1 から 3 のマッチを次々と拾うという単純なゲームを作成するタスクがありました。コンピューターがマッチのランダムな値を選択するためにそれを行うことができましたが、さらに進んで人間がゲームをプレイできるようにしたいと考えています。ここに私がすでに持っているものがあります: http://paste.pocoo.org/show/201761/

クラス Player はコンピュータ プレーヤーであり、PlayerMan は人間である必要があります。問題は、PlayerMan のスレッドが一致の適切な値が与えられるまで待機する必要があることですが、この方法で機能させることはできません。ロジックは次のとおりです。スレッドは、一致がゼロになるまで実行されます。プレイヤー番号が正しい場合、関数 pickMatches() が呼び出されます。テーブルの一致数が減少した後、スレッドは待機し、別のスレッドに通知する必要があります。wait() と notify() を使用する必要があることはわかっていますが、正しく配置できません。Class Shared は、現在のプレーヤーの値と、マッチの数を保持します。

public void suspendThread() {
    suspended = true;
}

public void resumeThread() {
    suspended = false;
}

@Override
public void run(){
    int matches=1;
    int which = 0;
    int tmp=0;
    Shared data = this.selectData();
    String name = this.returnName();
    int number = this.getNumber();

    while(data.getMatches() != 0){

        while(!suspended){

            try{             
                which = data.getCurrent();

                if(number == which){

                    matches = pickMatches();

                    tmp = data.getMatches() - matches;
                    data.setMatches(tmp, number);

                    if(data.getMatches() == 0){
                        System.out.println("                          "+
                            name+" takes "+matches+" matches.");
                        System.out.println("Winner is player: "+name);
                        stop();
                    }

                    System.out.println("                          "+
                            name+" takes "+matches+" matches.");

                    if(number != 0){
                        data.setCurrent(0);
                    }
                    else{
                        data.setCurrent(1);
                    }
                }
                this.suspendThread();
                notifyAll();
                wait();

            }catch(InterruptedException exc) {}    
        }
    }
}

@Override
synchronized public int pickMatches(){
    Scanner scanner = new Scanner(System.in);
    int n = 0;
    Shared data = this.selectData();

    System.out.println("Choose amount of matches (from 1 to 3): ");

        if(data.getMatches() == 1){
            System.out.println("There's only 1 match left !");
            while(n != 1){
                n = scanner.nextInt();
            }
        }
        else{
            do{
                n = scanner.nextInt();
            }
            while(n <= 1 && n >= 3);
        }
    return n;
}

}

4

3 に答える 3

1

スレッド間の通信をセットアップして実行を同期する必要があることに気付いた場合、指定された一連のイベント (交代でゲームをプレイするなど) が発生するようになっている場合は、必要以上のスレッドが存在する可能性があることを示しています。

この場合、Player クラスのさまざまな拡張機能で takeTurn() メソッドを実行する単一のスレッドを検討すると、作業が楽になる可能性があります。Player を .takeTurn() を義務付ける抽象基本クラスにしてから、HumanPlayer クラスと MachinePlayer クラスに、そのメソッド内の各タイプのプレーヤーにとって意味のあるコードをカプセル化させることができます。これにより、多数の wait() および notify() と比較して、より多くのプレーヤーへの拡張が比較的簡単になります。

于 2010-04-14T23:28:06.307 に答える
1

わかりましたので、wait()などなしでなんとかできました。

http://paste.pocoo.org/show/201966/

于 2010-04-14T23:01:57.350 に答える
1

ええと、最初に言っておきますが、あなたはこれを必要以上に難しくしていると思います。私だったら、「GameMaster」クラスを作成します。このクラスの仕事は、ループして各プレイヤーに順番が来たときに通知することです。プレイヤー クラスにはループはなく、takeTurn メソッドだけです。このようにして、プレイヤー クラスから待機/通知動作を削除できます。

あなたが持っているデザインを維持したい場合でも、待機/通知を取り除き、Semaphoreを使用します。適切な使用法についてはドキュメントを確認してください。ただし、要点は、サスペンド/再開メソッドを削除し、ループの上部で acquire() 呼び出しを行い、下部で解放することです。コンストラクターで公平性が true に設定されていることを確認してください。そうすれば、セマフォ ロックを 2 回続けて取得することで、プレーヤーが 2 回続けてターンを取得することを心配する必要がなくなります。

于 2010-04-14T14:01:13.000 に答える