質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.18%

ランダムな組で対戦できるようにしたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,012

ike-0315

score 26

 前提・実現したいこと

初投稿です。
投稿の作法についても、プログラミングの作法についてもまだまだ未熟かと思います。
ご指導よろしくお願いいたします。
Javaでジャンケンプログラムを作っています。
1.プレイヤーは3人
2.対戦は毎回プレイヤーの中からランダムに2名を選び、勝ち負けが出るまで対戦する
3.この1対1対戦をn回繰り返します。
4.結果は
Player1 : Yamada
Player2 : Suzuki
Player3 : Tanaka
Judge   Sato

Results: 20games
1 vs 2 : 5 games
1 vs 3 : 7 games
2 vs 3 : 8 games

Yamada 6 win, 6 lose, 3 draw
Suzuki 5 win, 8 lose, 11 draw
Tanaka 9 win, 6 lose, 8 draw
のように出力します。

 発生している問題・エラーメッセージ

2.のランダムにプレーヤーを対戦させるアイデアが浮かびませんでした。

 該当のソースコード

import javax.xml.transform.Result;

public class Judge {
    private String name;
    private RandomJankenPlayer player1, player2, player3;

    public Judge(String _name) {
        name = _name;
    }
    public void setPlayers(RandomJankenPlayer _player1, RandomJankenPlayer _player2, RandomJankenPlayer _player3) {
        player1 = _player1;// player3人にする
        player2 = _player2;
        player3 = _player3;
    }

    public void play(int n) {
        Hand hand1 = null, hand2 = null, hand3 = null;
        Result result1,result2,result3;

            for (int i = 0; i < n; i++) {
                hand1 = player1.showHand();
                hand2 = player2.showHand();
                hand3 = player3.showHand();

//対戦プレイヤーランダム選択??

                //勝敗判定Judge

                if (hand1 == hand2) {
                    draw1++;
                    draw2++;
                }
                if (hand1 == Hand.ROCK && hand2 == Hand.SCISSORS) {
                    win1++;
                    lose2++;
                    break;
                }
                if (hand1 == Hand.ROCK && hand2 == Hand.PAPER) {
                    lose1++;
                    win2++;
                    break;
                }
                if (hand1 == Hand.SCISSORS && hand2 == Hand.ROCK) {
                    lose1++;
                    win2++;
                    break;
                }
                if (hand1 == Hand.SCISSORS && hand2 == Hand.PAPER) {
                    win1++;
                    lose2++;
                    break;
                }
                if (hand1 == Hand.PAPER && hand2 == Hand.ROCK) {
                    win1++;
                    lose2++;
                    break;
                }
                if (hand1 == Hand.PAPER && hand2 == Hand.SCISSORS) {
                    lose1++;
                    win2++;
                    break;
                }
            }
        }
    //結果表示
        System.out.println("Player1 : " + player1.getName());
        System.out.println("Player2 : " + player2.getName());
        System.out.println("Player3 : " + player3.getName());
        System.out.println("Judge   : " + name);
        System.out.println();
        System.out.println("Results: " + n + " games");
        System.out.println("1 vs 2 : " + a +" games");
        System.out.println("1 vs 3 : " + b +" games");
        System.out.println("2 vs 3 : " + c +" games");
        System.out.println(
                player1.getName() +  win1+ " win,"
                        + " " + lose1 + " lose, " + draw1 + " draw");
        System.out.println(
                player2.getName() + win2 + " win,"
                        + " " + lose2 + " lose, " + draw2  + " draw");
    System.out.println(
            player3.getName() + win2 + " win,"
                    + " " + lose2 + " lose, " + draw2 + " draw");
    }

    public static void main(String[] args) {
        try {
            int num = Integer.parseInt(args[0]);
            RandomJankenPlayer player1 = new RandomJankenPlayer("Yamada");
            RandomJankenPlayer player2 = new RandomJankenPlayer("Suzuki");
            RandomJankenPlayer player3 = new RandomJankenPlayer("Tanaka");
            Judge judge = new Judge("Sato");
            judge.setPlayers(player1, player2, player3);
            judge.play(num);
        } catch (Exception e) {
            System.out.println("this requires an integer argument.");
        }
    }
}

/*
public class RandomJankenPlayer {
    private String name;//private:ReadOnly
    public RandomJankenPlayer(String name){
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Hand showHand(){
        Hand play;
        double rnd = Math.random();
        if(rnd < 1.0/3.0){
            play = Hand.ROCK;
        }else if (rnd < 2.0/3.0){
            play = Hand.PAPER;
        }else{
            play = Hand.SCISSORS;
        }
        return play;
    }
    // main
    public static void main(String[] args){
        RandomJankenPlayer player1 = new RandomJankenPlayer("Yamada");
        RandomJankenPlayer player2 = new RandomJankenPlayer("Suzuki");
        Hand hand1, hand2;
        for(int i=0; i<10; i++){
            hand1 = player1.showHand();
            hand2 = player2.showHand();
            System.out.println(i+")"+
                               "["+player1.getName()+"]"+hand1+" vs "+
                               "["+player2.getName()+"]"+hand2);
        }
    }
}

*/
/*
enum Hand {ROCK, PAPER, SCISSORS}
*/
/*
enum Result {WIN,LOSE,DRAW}
*/

 試したこと

2人の場合について勝敗判定するプログラムを作成してみました

 補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

こんにちは、少し説明が長くなりますが順を追ってわかりやすく説明したいと思います。
int型の変数nに自然数を入力した状態から説明します。

1.乱数を使うにはimort java.util.Random; 

これをインポートします。そして、Main関数内にて Random rand = new Random(); 
を宣言します。player1 = rand.nextInt(n);で0からn - 1までの整数をランダムに出力します。
今回はplayerが3人なのでn = 3にします。

2.どの2人が対戦したのか カウントするための配列を用意する.
要素数が3の配列を準備します。
0番目:Yamada vs Suzuki の回数
1番目:Suzuki vs Tanaka の回数
2番目:Tanaka vs Yamada の回数
を後でカウントします。私が書いたソースコードではswitch文で処理しています。

3.選ばれた2人がそれぞれどの手を出すか乱数を使って出力
ここも1で説明した乱数を使います。
グーが0 チョキが1 パーが2に対応しています。

4.勝ち負け引き分けの判定をする。
勝ち負け引き分けの判定ですべての場合を出してif文で評価してもいいですが
もっと効率的な方法があります。次の表をご覧ください。

player1の手 player2の手 結果 2つの整数の差を3で割ったときのあまり
0 0 引き分け 0
2 1 player1の負け,player2の勝ち 1
1 2 player1の勝ち,player2の負け 2

他の場合もありますが,上の表のように
(player1の手) - (player2の手)を3で割った余り0,1,2がそれぞれの結果と対応します。
ただし、(player1の手) - (player2の手)が負の整数になったときは余りが-2などになるので
プログラム上では、(player1の手) - (player2の手) + 3を3で割ったときの余りを求めます。

5.3人 それぞれの勝ち負け引き分けの回数をカウントする配列を用意する
今回用意する配列は2次配列です。(サイズは3*3)
内容は

Yamadaの引き分けの回数 Suzukiの負けた回数 Suzukiの勝った回数
Suzukiの引き分けの回数 Suzukiの負けた回数 Suzukiの勝った回数
Tanakaの引き分けの回数 Tanakaの負けた回数 Tanakaの勝った回数

となります。4で説明した方法で判定し それぞれの回数をカウントします。

6.配列を使って効率的に結果表示する。
最後の結果表示ではもちろんfor文を使うのですが,

playerの名前String []player = {"Yamada","Suzuki","Tanaka"};
結果        String []result_text = {"Draw","Lose","Win"}; 
を使うとfor文の中で変数iをインクリメントしながら効率的に表示できると思います。

説明が長くなってすいません。表を使ってわかりやすく説明したつもりですが
何かわからなかったところがあればまたご連絡ください。
私が書いたソースコードを載せておきます。

import java.util.Random;
import java.util.Scanner;

public class Midi{
    public static void main(String[] args){

         Scanner sc = new Scanner(System.in);
         String line = sc.nextLine();
         int n = Integer.parseInt(line);
         Random rand = new Random();

         int []battle_num = {0,0,0};  //どの2人が対戦したのか カウントするための配列。
         int [][]result = new int[3][3]; 
         for(int j = 0; j < 3; j++){
            for(int k = 0; k < 3; k ++){ 
                result[j][k] = 0;
            }
        }
         int player1;
         int player2;
         for(int i = 0; i < n; i++){
             player1 = 0;
             player2 = 0;
             while(player1 == player2){
                 player1 = rand.nextInt(3); //どの2人が選ばれるか
                 player2 = rand.nextInt(3);
             }
             switch(player1 + player2){ //最初は3で割った余りを求めようと思ったがそれだと要素の番号がずれる
                case 1:
                    battle_num[0]++;
                    break;
                case 2:
                    battle_num[2]++;
                    break;
                case 3:
                    battle_num[1]++;
                    break;
                default:
                    break;
             } //どの2人が対戦したのか カウントします。
             int player1_hand = rand.nextInt(3); //グーが0,チョキが1,パーが2
             int player2_hand = rand.nextInt(3);

             switch((player1_hand - player2_hand + 3) % 3){
                 case 0: //引き分け
                     result[player1][0]++;
                     result[player2][0]++;
                     break;
                 case 1: //player1が負け,player2が勝ち
                     result[player1][1]++;
                     result[player2][2]++;
                     break;
                 case 2: //player1が勝ち,player2が負け
                     result[player1][2]++;
                     result[player2][1]++;
                     break;
                 default:
                     break;
             }
         }
         //さぁ、結果の表示だ
         String []player = {"Yamada","Suzuki","Tanaka"};
         String []result_text = {"Draw","Lose","Win"};
         System.out.println("対戦回数:" + n + "回"); //printfのほうがいいかもしれません
         for(int i = 0; i < 3; i++){
             System.out.println(player[i % 3] + " VS " + player[(i + 1) % 3] + ":" + battle_num[i] + "回");
         }
         for(int i = 0; i < 3; i++){
             System.out.print(player[i] + ":");
             for(int j = 0; j < 3; j++){
                 System.out.print(result_text[j] + ":" + result[i][j] + " ");
             }
             System.out.println();
         }
    }
}


結果の例

対戦回数:100回
Yamada VS Suzuki:34回
Suzuki VS Tanaka:30回
Tanaka VS Yamada:36回
Yamada:Draw:25 Lose:23 Win:22 
Suzuki:Draw:18 Lose:21 Win:25 
Tanaka:Draw:23 Lose:23 Win:20 

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/11 23:38

    ちなみに出力結果では 3人がそれぞれ負けた回数の和と勝った回数の和は等しいです。(当然ですが...)
    そして、その和をmとすると3人がそれぞれ引き分けだった回数の和は(n - m) * 2になります。
    引き分けの時はじゃんけんをした"2人"の引き分け回数がカウントされるから2倍になります。

    キャンセル

  • 2018/04/11 23:41

    私が回答に載せたものだと対戦回数が100回の時,
    (3人がそれぞれ負けた回数) = (3人がそれぞれ勝った回数) = 67で、
    (3人がそれぞれ引き分けだった回数) = (100 - 67) * 2 = 66となっています。

    キャンセル

  • 2018/04/12 10:20

    非常に丁寧でわかりやすい回答でした!
    おかげさまでなんとかなりそうです。ありがとうございました!!

    キャンセル

  • 2018/04/12 12:13 編集

    ike-0315さんが書いたクラスのところをそのままにして、「じゃんけんの判定」と
    「playerの名前、勝ち負け引き分けの判定などを配列にする」のところを
    私が説明したものに変えれば私か載せたソースコードより短くてわかりやすくなるかもしれません。

    キャンセル

+1

次の二つを解決すれば良いです。

  1. playerを配列やリストで管理すること
  2. [0, 人数)の整数のうち、2つを重複なくランダムに選択すること

2番目はいろいろな実装が考えられますが(※)、最も単純なのは次の方法でしょう。

Random rand = new Random();
int idx1 = rand.nextInt(人数);
int idx2 = idx1;

while(idx1 == idx2) {
    idx2 = rand.nextInt(人数);
}

あとはidx1番目のプレイヤーとidx2番目のプレイヤーを戦わせればよいです。


※ [0, 人数)の整数リストをシャッフルし、最初の二つを選択する方法が効率が良い。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/12 10:22

    ランダムに数字を生成することでプレーヤーをランダムに選択できるのですね...!
    参考になりました。回答ありがとうございます

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.18%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る