23JON
@23JON (23 JON)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

じゃんけんを三人でするプログラム

Q&A

Closed

下記のプログラムをすべて使って、じゃんけんを三人でするプログラムを作成したいのですが、ここで注意すべきことは、三人でじゃんけんをする時は、一回のじゃんけんで勝者が一人ではない場合があるということです。

このとき、例えば三人がそれぞれグー、グー、チョキなどの手を出したとしたとき、グー、グーと出した人同士でじゃんけんをし、そこから勝者(または、再びあいこになった場合にはもう一度じゃんけんをする処理)を出すというプログラム処理を「Judge.java」で行いたいのですが、どうしたらいいのかわかりません。

教えていただけるととても助かります。

現状のコード:

public class Choki implements Hand {
    public String toString() {
    return "Choki";
    }
}
public class Goo implements Hand {
    public String toString() {
    return "Goo";
    }
}
public interface Hand {
    /** 手を表す文字列を返す */
    String toString();
}
/** ジャンケンを開始するためのクラス */
public class JankenErr {
    public static void main(String args[]) {
    try {
        Judge judge = new Judge(); // 審判の作成

        // プレイヤの作成と審判への登録
        Player jhon = new OrderedComputerPlayer("Jhon");
        judge.registPlayer(jhon);
        Player paul = new NormalComputerPlayer("Paul");
        judge.registPlayer(paul);
        Player george = new NormalComputerPlayer("George");
        judge.registPlayer(george);

        // 3回勝負でジャンケンの開始
        judge.startJankens(3);
    }
    catch (JankenException e) {
        System.err.println(e.getMessage());
    }
    }
}
/* じゃんけんに関する例外 */
public class JankenException extends Exception {
    public JankenException() {
    super();
    }

    public JankenException(String msg) {
    super(msg);
    }
}
import javax.swing.*;

/** じゃんけん の審判のクラス */
public class Judge {
    protected Player players[];      // プレイヤの配列
    protected int    numOfPlayers;   // プレイヤの数
    protected int    wins[];         // 勝ち数を記録する配列
    int counter=0;
    /** コンストラクタ */
    public Judge() {
    // 2人のプレイヤの配列を作成し、各要素はnullに初期化
    players = new Player[3];
    players[0] = players[1] = players[2] = null;

    // プレイヤの数は0に初期化
    numOfPlayers = 0;  

    // 2人の勝ち星数の配列を作成し、各要素を0に初期化
    wins = new int[3];
    wins[0] = wins[1] = wins[2] = 0;
    }

    /** じゃんけんをするプレイヤを知らされる */
    public void registPlayer(Player player) throws JankenException {
    if (numOfPlayers < players.length) {
        // まだ余裕があるので登録
        players[numOfPlayers] = player;
        numOfPlayers++;  // プレイヤの数を増やす
    }
    else {
        throw new JankenException("too many players");
    }
    }

    /** matches回勝負のじゃんけんを開始する
     *   つまり、誰かがmatches回勝つまでじゃんけんをする
     */
    public void startJankens(int matches) throws JankenException {
    if (numOfPlayers < players.length) {
        throw new JankenException("need more players");
    }
    // プレイヤにmatches回勝負であることを知らせる
    notifyMatches(matches);

    int match = 1; // match回目の勝負
    while (!isEndOfJankens(matches)) { // 誰かがmatches回勝つまで繰り返す
        startOneJanken(match); // match回目のじゃんけんを行う

        match++;
    }

    // matches回勝負のチャンピオンを調べる
    Player[] champions = getChampions(matches);
    // チャンピオンのメッセージを表示
    showChampionsMessage(champions);
    }

    /** matches回勝負のじゃんけんが終わったか判定 */
    protected boolean isEndOfJankens(int matches) {
    // プレイヤの1人でもmatches回勝っていたら終わり
    for (int i = 0; i < numOfPlayers; i++) {
        if (wins[i] == matches) { // matches回勝っていた
        return true;
        }
    }
    return false; // 誰もmatches回勝っていない
    }

    /** match回目のじゃんけんを開始する */
    protected void startOneJanken(int match) {
        int      num = 0;  // 何回目の手か
    Player[] winners;  // 勝者の配列

    do {  // 勝者が決まるまで繰り返す
            num++;   // 手の回数を増やす
            counter++;
        // 掛け声
        showJankenMessage(match, num);

        // 各プレイヤの手を得る
        Hand hands[] = getHands(match, num);
        // 手を表示
        showHandsMessage(hands, match, num);
        // 勝者を判定する
        winners = judge(hands);
    } while (winners == null);

    // 勝者を表示
    showWinnersMessage(winners, match);
    // プレイヤに勝敗を知らせる
    notifyResult(winners);
    }


    /** match回目の勝負のnum回目の全プレイヤの手を配列で返す */
    protected Hand[] getHands(int match, int num) {
    // players[i]の手はhands[i]に入れる
    Hand hands[] = new Hand[numOfPlayers];
    for (int i = 0; i < numOfPlayers; i++) {
        hands[i] = players[i].showHand(match, num, counter);
    }
    return hands;
    }

    /** ジャンケンの勝負を判定をする。
     *   勝負がついた場合は 勝者のPlayerの配列を返す。
     *   あいこの場合は null を返す。
     *   なお、2人勝負の場合は常に勝者は1人である
     */
    protected Player[] judge(Hand hands[]) {
    // 勝者の判定をする
    Player[] winner;
    if ((hands[0] instanceof Goo  && hands[1] instanceof Choki && hands[2] instanceof Choki)
            || (hands[0] instanceof Choki && hands[1] instanceof Par && hands[2] instanceof Par)
            || (hands[0] instanceof Par && hands[1] instanceof Goo && hands[2] instanceof Goo)) {
        winner = new Player[1];
        winner[0] = players[0];
        wins[0]++;
    }else if  ((hands[0] instanceof Goo && hands[1] instanceof Par && hands[2] instanceof Goo)
            || (hands[0] instanceof Choki && hands[1] instanceof Goo && hands[2] instanceof Choki)
            || (hands[0] instanceof Par && hands[1] instanceof Choki && hands[2] instanceof Par)) {
        winner = new Player[2];
        winner[0] = players[1];
        wins[1]++;
    }else if  ((hands[0] instanceof Goo && hands[1] instanceof Goo && hands[2] instanceof Par)
            || (hands[0] instanceof Choki && hands[1] instanceof Choki && hands[2] instanceof Goo)
            || (hands[0] instanceof Par && hands[1] instanceof Par && hands[2] instanceof Choki)) {
        winner = new Player[3];
        winner[0] = players[2];
        wins[2]++;
    }else if  ((hands[0] instanceof Goo && hands[1] instanceof Goo && hands[2] instanceof Choki)
            || (hands[0] instanceof Choki && hands[1] instanceof Choki && hands[2] instanceof Par)
            || (hands[0] instanceof Par && hands[1] instanceof Par && hands[2] instanceof Goo)) {
       //ここの処理(0と1が勝負して、0が勝つ処理)
        winner = new Player[1];
        winner[0] = players[1];
        wins[0]++;
    }else if  ((hands[0] instanceof Goo && hands[1] instanceof Goo && hands[2] instanceof Choki)
            || (hands[0] instanceof Choki && hands[1] instanceof Choki && hands[2] instanceof Par)
            || (hands[0] instanceof Par && hands[1] instanceof Par && hands[2] instanceof Goo)) {
       //ここの処理(0と1が勝負して、1が勝つ処理)
        winner = new Player[2];
        winner[0] = players[1];
        wins[1]++;
    }else if  ((hands[0] instanceof Goo  && hands[1] instanceof Choki && hands[2] instanceof Goo)
            || (hands[0] instanceof Choki && hands[1] instanceof Par && hands[2] instanceof Choki)
            || (hands[0] instanceof Par && hands[1] instanceof Goo && hands[2] instanceof Par)) {
       //ここの処理(0と2が勝負して、0が勝つ処理)
        winner = new Player[1];
        winner[0] = players[0];
        wins[0]++;
    }else if  ((hands[0] instanceof Goo  && hands[1] instanceof Choki && hands[2] instanceof Goo)
            || (hands[0] instanceof Choki && hands[1] instanceof Par && hands[2] instanceof Choki)
            || (hands[0] instanceof Par && hands[1] instanceof Goo && hands[2] instanceof Par)) {
       //ここの処理(0と2が勝負して、2が勝つ処理)
        winner = new Player[3];
        winner[0] = players[2];
        wins[2]++;
    }else if  ((hands[0] instanceof Goo && hands[1] instanceof Par && hands[2] instanceof Par)
        || (hands[0] instanceof Choki && hands[1] instanceof Goo && hands[2] instanceof Goo)
        || (hands[0] instanceof Par && hands[1] instanceof Choki && hands[2] instanceof Choki)) {
       //ここの処理(1と2が勝負して、1が勝つ処理)
        winner = new Player[2];
        winner[0] = players[1];
        wins[1]++;
    }else if  ((hands[0] instanceof Goo && hands[1] instanceof Par && hands[2] instanceof Par)
        || (hands[0] instanceof Choki && hands[1] instanceof Goo && hands[2] instanceof Goo)
        || (hands[0] instanceof Par && hands[1] instanceof Choki && hands[2] instanceof Choki)) {
       //ここの処理(1と2が勝負して、2が勝つ処理)
        winner = new Player[3];
        winner[0] = players[2];
        wins[2]++;
    }

    else {
        // あいこ
        winner = null;
    }

    return winner;
    }

    /** 各プレイヤの勝ち数を調べてチャンピオンを決める
     *   つまりmatches回勝ったプレイヤがチャンピオンである
     *   3人以上の場合はチャンピオンが2人以上出る場合がある
     */
    protected Player[] getChampions(int matches) {
    // チャンピオンは最大 (プレイヤ数 -1)人いるので
        //   numOfPlayers-1 の長さの配列を作っておく
    Player champions[] = new Player[numOfPlayers-1];

    // 各プレイヤの勝ち数を調べてチャンピオンを決める
    int championsIndex = 0;
    for (int playersIndex = 0; playersIndex < numOfPlayers;
         playersIndex++) {
        if (wins[playersIndex] == matches) {
        // matches回勝っているのでチャンピオン
        champions[championsIndex] = players[playersIndex];
        championsIndex++;
        }
    }

    // 配列championsの残りの要素はnullにする
    for (; championsIndex < champions.length; championsIndex++) {
        champions[championsIndex] = null;
    }

    return champions;
    }

    /** 何回勝負かプレイヤに知らせる */
    protected void notifyMatches(int matches) {
    for (int i = 0; i < numOfPlayers; i++) {
        players[i].setMatches(matches);
    }
    }

    /** じゃんけんの結果を各プレイヤに知らせる
     *    引数winnersは勝者の配列
     */
    protected void notifyResult(Player[] winners) {
    // 外側のループはプレイヤのループ
    for (int playersIndex = 0;
         playersIndex < numOfPlayers; playersIndex++) {
        boolean won = false;  // players[playersIndex]が勝ったかどうか

        // players[playersIndex]が配列winnersに含まれているか調べる
        // 内側のループは勝者のループ
        for (int winnersIndex = 0; winnersIndex < winners.length;
         winnersIndex++) {
        if (winners[winnersIndex] == players[playersIndex]) {
            // players[playersIndex]は勝った
            won = true;
        }
        }

        // プレイヤに勝敗を知らせる
        if (won) players[playersIndex].youWon();
        else     players[playersIndex].youLost();
    }
    }

    /** ウィンドウと標準出力にメッセージを表示する
     *   showXxxxMessageメソッドから呼ばれる下請メソッド
     */
    protected void showMessage(String mesg) {
    System.out.println(mesg);
    JOptionPane.showMessageDialog(null, mesg);
    }

    /** じゃんけんぽん のメッセージを表示 */
    protected void showJankenMessage(int match, int num) {
    if (num == 1) { // 1回目は じゃんけんぽん
        showMessage("Match " + match + ": Jan Ken Pon!");
    }
    else { // 2回目以降は あいこでしょ
        showMessage("Aiko de Sho");
    }
    }

    /** プレイヤの手のメッセージを表示 */
    protected void showHandsMessage(Hand[] hands, int match, int num) {
    String handMesg = "Match " + match + "-" + num + ":\n"; 
    for (int i = 0; i < numOfPlayers; i++) {
        handMesg +=  players[i].getName() + "'s hand is "
        + hands[i].toString() + "\n";
    }
    showMessage(handMesg);
    }

    /** ジャンケンの各回の勝者のメッセージを表示 */
    protected void showWinnersMessage(Player[] winners, int match) {
    String mesg = "Match " + match + ": ";
    for (int i = 0; i < winners.length; i++) {
        mesg +=  winners[i].getName() + " won.\n";
    }
    showMessage(mesg);
    }

    /** チャンピオンのメッセージを表示 */
    protected void showChampionsMessage(Player[] champions) {
    // チャンピオンのメッセージ
    String championMesg = "";
    for (int i = 0; i < champions.length && champions[i] != null; i++) {
        championMesg += champions[i].getName() + " is a champion.\n";
    }

    // 各プレイヤが何勝したかのメッセージ
    String winNumMesg = "";
    for (int i = 0; i < numOfPlayers; i++) {
        winNumMesg += players[i].getName() + ": " + wins[i] + " wins\n";
    }

    // メッセージを表示
    showMessage(championMesg + winNumMesg);
    }
}
/** ジャンケン の通常のコンピュータ プレイヤ */
public class NormalComputerPlayer extends Player {
    protected Hand  goo, choki, par;
    protected java.util.Random random; // 手を決めるときに使う乱数

    /** コンストラクタ, プレイヤの名前を指定する */
    public NormalComputerPlayer(String name) {
    super(name);
    // 手を設定する
    goo = new Goo();
    choki = new Choki();
    par = new Par();
    random = new java.util.Random();
    }

    /** match回目の勝負のnum回目のプレイヤの手を出す
     *  Player の showHand をオーバーライド
     */
    public Hand showHand(int match, int num, int counter) {
    int hand = random.nextInt(3);
    if (hand == 0) {
        return goo;
    } else if (hand == 1) {
        return choki;
    } else {
        return par;
    }
    }
}
/** ジャンケン の通常のコンピュータ プレイヤ */
public class OrderedComputerPlayer extends Player {
    protected Hand  goo, choki, par;
    // 手を決めるときに使う乱数

    /** コンストラクタ, プレイヤの名前を指定する */
    public OrderedComputerPlayer(String name) {
    super(name);
    // 手を設定する
    goo = new Goo();
    choki = new Choki();
    par = new Par();

    }

    /** match回目の勝負のnum回目のプレイヤの手を出す
     *  Player の showHand をオーバーライド
     */
    public Hand showHand(int match, int num, int counter) {

    switch((counter++)%4){
        case 2: return par;
        case 3: return choki; 
        default:  return goo;
        }
    }
}
public class Par implements Hand {
    public String toString() {
    return "Par";
    }
}
/** ジャンケン プレイヤの抽象クラス */
public abstract class Player {
    protected String name;     // プレイヤの名前
    protected int    matches;  // matches回勝負(matches回先に勝った方が勝ち)
    protected int    wins;     // プレイヤの勝利数
    protected int    losts;    // プレイヤの負け数

    /** コンストラクタ, プレイヤの名前を指定する */
    public Player(String name) {
    this.name = name;   // プレイヤの名前
    wins = losts = 0;   // 勝敗を初期化
    }

    /** プレイヤの名前を返す */
    public String getName() {
    return name;
    }

    /** 何回勝負か設定するメソッド
     */
    public void setMatches(int matches) {
    this.matches = matches;
    }

    /** 
     *   勝ったことを知らされるメソッド
     */
    public void youWon() {
    wins++;
    }

    /** 
     *   負けたことを知らされるメソッド
     */
    public void youLost() {
      losts++;
    }


    /** match回目の勝負のnum回目のプレイヤの手を出す
     *   抽象メソッドなので,サブクラスでオーバーライドする
     */
    public abstract Hand showHand(int match, int num, int counter);
}
0

12Answer

judgeメソッドの基本的な考え方は下記の感じでどうでしょうか?
前回同様Handをenumにしていますが、どうしてもclassで実装したい場合はHandのequalsメソッドをオーバーライドすると同等の処理ができると思います。

Player[] judge(Hand[] hands) {
    var handList = Arrays.asList(hands);
    if(handList.stream().distinct().count() != 2) return null; /* あいこ */
    if(!handList.contains(Hand.Goo)) {
        /* チョキの勝ち */
    }
    if(!handList.contains(Hand.Choki)) {
        /* パーの勝ち */
    }
    if(!handList.contains(Hand.Par)) {
        /* グーの勝ち */
    }
}
1Like

学校の課題は自分でやらないと意味がないのでアドバイスにとどめます。

  • (前の質問でも他の回答者さんがおっしゃっていましたが、)前提としてグー、チョキ、パーを区別するためにいちいちclassを作るのは無駄ですし、比較する際に扱いにくいです。いちいちinstanceofで判定なんて馬鹿らしいのでenumを使うようにしましょう。
  • judgeで3人のすべての手のパターンを場合分けするのは間違いではないですが、それではじゃんけんのアルゴリズムを理解していないように見えます。そもそも拡張性が皆無です(プレイヤーが4人、5人と増えれば増えるだけ煩雑になりますし、今回のようにあいこのときに何かするという場合には手がつけられなくなります)。せっかく手を配列にしているのですから、リストに変換するなどしてよりよい実装方法を考えてください。
  • 例えば、リストが「グーを含まない」「チョキを含まない」「パーを含まない」のように場合分けすればもっと読みやすくなると思います。
  • 本題の、あいこのとき最後の1人になるまでじゃんけんを続ける方法ですが、例えば、勝ちの手のプレイヤーをwinnersリストに入れてリストのサイズが1になるまでループ(逆に負けの手のプレイヤーをlosersリストに入れてサイズがプレイヤー数-1になるまでループでも同じ)なんていうのはどうでしょうか。
0Like

これ、文法的に間違ってて正常にコンパイルが通らないような気がするのですがどこまで動作確認できてますでしょうか?
もう少し詳細なエラーや疑問点、詰まっていること等があればより適切な回答が得られやすいと思います。

0Like

あと以前から少し気になっていたことですが、Qiitaでもstackoverflowでも規約違反ではありませんが、マルチポストはあまりマナー的におすすめはしません。
正直規約とかではないので行為自体は自由ではあるしあまり強くは述べたくありませんが、最低限各投稿先への情報の展開や解決した事項へのクローズはしてほしいところです。

マルチポストに関する感情は下記ページの回答がうまく言語化できていて自分の肌感覚的にも近いと感じたのでご一読いただければと思います。
マルチポストとはなんですか?何か問題があるのでしょうか?

0Like

// 勝者の判定をするの場所のif文をもっとシンプルにできるはずです。
人数が何人(2以上)いても勝者が出る条件は何かと考えてみてください。
法則性が見えてくるはずです。
網羅するプログラムを作成するのは、楽ですが、可読性が悪かったり、拡張性がなかったりするのでおすすめしません。

0Like

別に勝者が一人に定まらなくても良いと考えたので、
三人でじゃんけんをして、あいこ(全員の手が異なる場合)ならもう一度じゃんけんをし、
そうでなければ、勝者が二人だろうが勝者を決めるじゃんけんプログラムを考え、
Judge.javaを以下のようにしましたがエラーが出てしまいました。

import javax.swing.*;

/** じゃんけん の審判のクラス */
public class Judge {
    protected Player players[];      // プレイヤの配列
    protected int    numOfPlayers;   // プレイヤの数
    protected int    wins[];         // 勝ち数を記録する配列
    int counter=0;
    /** コンストラクタ */
    public Judge() {
	// 2人のプレイヤの配列を作成し、各要素はnullに初期化
	players = new Player[3];
	players[0] = players[1] = players[2] = null;

	// プレイヤの数は0に初期化
	numOfPlayers = 0;  

	// 2人の勝ち星数の配列を作成し、各要素を0に初期化
	wins = new int[3];
	wins[0] = wins[1] = wins[2] = 0;
    }

    /** じゃんけんをするプレイヤを知らされる */
    public void registPlayer(Player player) throws JankenException {
	if (numOfPlayers < players.length) {
	    // まだ余裕があるので登録
	    players[numOfPlayers] = player;
	    numOfPlayers++;  // プレイヤの数を増やす
	}
	else {
	    throw new JankenException("too many players");
	}
    }

    /** matches回勝負のじゃんけんを開始する
     *   つまり、誰かがmatches回勝つまでじゃんけんをする
     */
    public void startJankens(int matches) throws JankenException {
	if (numOfPlayers < players.length) {
	    throw new JankenException("need more players");
	}
	// プレイヤにmatches回勝負であることを知らせる
	notifyMatches(matches);

	int match = 1; // match回目の勝負
	while (!isEndOfJankens(matches)) { // 誰かがmatches回勝つまで繰り返す
	    startOneJanken(match); // match回目のじゃんけんを行う

	    match++;
	}

	// matches回勝負のチャンピオンを調べる
	Player[] champions = getChampions(matches);
	// チャンピオンのメッセージを表示
	showChampionsMessage(champions);
    }

    /** matches回勝負のじゃんけんが終わったか判定 */
    protected boolean isEndOfJankens(int matches) {
	// プレイヤの1人でもmatches回勝っていたら終わり
	for (int i = 0; i < numOfPlayers; i++) {
	    if (wins[i] == matches) { // matches回勝っていた
		return true;
	    }
	}
	return false; // 誰もmatches回勝っていない
    }

    /** match回目のじゃんけんを開始する */
    protected void startOneJanken(int match) {
        int      num = 0;  // 何回目の手か
	Player[] winners;  // 勝者の配列

	do {  // 勝者が決まるまで繰り返す
            num++;   // 手の回数を増やす
            counter++;
	    // 掛け声
	    showJankenMessage(match, num);
	    
	    // 各プレイヤの手を得る
	    Hand hands[] = getHands(match, num);
	    // 手を表示
	    showHandsMessage(hands, match, num);
	    // 勝者を判定する
	    winners = judge(hands);
	} while (winners == null);

	// 勝者を表示
	showWinnersMessage(winners, match);
	// プレイヤに勝敗を知らせる
	notifyResult(winners);
    }


    /** match回目の勝負のnum回目の全プレイヤの手を配列で返す */
    protected Hand[] getHands(int match, int num) {
	// players[i]の手はhands[i]に入れる
	Hand hands[] = new Hand[numOfPlayers];
	for (int i = 0; i < numOfPlayers; i++) {
	    hands[i] = players[i].showHand(match, num, counter);
	}
	return hands;
    }

    /** ジャンケンの勝負を判定をする。
     *   勝負がついた場合は 勝者のPlayerの配列を返す。
     *   あいこの場合は null を返す。
     *   なお、2人勝負の場合は常に勝者は1人である
     */
    protected Player[] judge(Hand hands[]) {
	// 勝者の判定をする
	Player[] winner;
	if ((hands[0] instanceof Goo  && hands[1] instanceof Choki && hands[2] instanceof Choki)
            || (hands[0] instanceof Choki && hands[1] instanceof Par && hands[2] instanceof Par)
            || (hands[0] instanceof Par && hands[1] instanceof Goo && hands[2] instanceof Goo)) {
	    winner = new Player[1];
	    winner[0] = players[0];
	    wins[0]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Par && hands[2] instanceof Goo)
            || (hands[0] instanceof Choki && hands[1] instanceof Goo && hands[2] instanceof Choki)
            || (hands[0] instanceof Par && hands[1] instanceof Choki && hands[2] instanceof Par)) {
	    winner = new Player[2];
	    winner[0] = players[1];
	    wins[1]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Goo && hands[2] instanceof Par)
            || (hands[0] instanceof Choki && hands[1] instanceof Choki && hands[2] instanceof Goo)
            || (hands[0] instanceof Par && hands[1] instanceof Par && hands[2] instanceof Choki)) {
	    winner = new Player[3];
	    winner[0] = players[2];
	    wins[2]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Goo && hands[2] instanceof Choki)
            || (hands[0] instanceof Choki && hands[1] instanceof Choki && hands[2] instanceof Par)
            || (hands[0] instanceof Par && hands[1] instanceof Par && hands[2] instanceof Goo)) {
	  
	    winner = new Player[1] && new Player[2];
	    winner[0] = players[1] && players[2];
	    wins[0]++;
	}else if  ((hands[0] instanceof Goo  && hands[1] instanceof Choki && hands[2] instanceof Goo)
            || (hands[0] instanceof Choki && hands[1] instanceof Par && hands[2] instanceof Choki)
            || (hands[0] instanceof Par && hands[1] instanceof Goo && hands[2] instanceof Par)) {
	   
	    winner = new Player[1] && new Player[3];
	    winner[0] = players[0] && players[2];
	    wins[0]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Par && hands[2] instanceof Par)
	    || (hands[0] instanceof Choki && hands[1] instanceof Goo && hands[2] instanceof Goo)
	    || (hands[0] instanceof Par && hands[1] instanceof Choki && hands[2] instanceof Choki)) {
	  
	    winner = new Player[2] && new Player[3];
	    winner[0] = players[1] && players[2];
	    wins[1]++;
	}
	else {
	    // あいこ
	    winner = null;
	}

	return winner;
    }

    /** 各プレイヤの勝ち数を調べてチャンピオンを決める
     *   つまりmatches回勝ったプレイヤがチャンピオンである
     *   3人以上の場合はチャンピオンが2人以上出る場合がある
     */
    protected Player[] getChampions(int matches) {
	// チャンピオンは最大 (プレイヤ数 -1)人いるので
        //   numOfPlayers-1 の長さの配列を作っておく
	Player champions[] = new Player[numOfPlayers-1];

	// 各プレイヤの勝ち数を調べてチャンピオンを決める
	int championsIndex = 0;
	for (int playersIndex = 0; playersIndex < numOfPlayers;
	     playersIndex++) {
	    if (wins[playersIndex] == matches) {
		// matches回勝っているのでチャンピオン
		champions[championsIndex] = players[playersIndex];
		championsIndex++;
	    }
	}

	// 配列championsの残りの要素はnullにする
	for (; championsIndex < champions.length; championsIndex++) {
	    champions[championsIndex] = null;
	}
	
	return champions;
    }

    /** 何回勝負かプレイヤに知らせる */
    protected void notifyMatches(int matches) {
	for (int i = 0; i < numOfPlayers; i++) {
	    players[i].setMatches(matches);
	}
    }

    /** じゃんけんの結果を各プレイヤに知らせる
     *    引数winnersは勝者の配列
     */
    protected void notifyResult(Player[] winners) {
	// 外側のループはプレイヤのループ
	for (int playersIndex = 0;
	     playersIndex < numOfPlayers; playersIndex++) {
	    boolean won = false;  // players[playersIndex]が勝ったかどうか

	    // players[playersIndex]が配列winnersに含まれているか調べる
	    // 内側のループは勝者のループ
	    for (int winnersIndex = 0; winnersIndex < winners.length;
		 winnersIndex++) {
		if (winners[winnersIndex] == players[playersIndex]) {
		    // players[playersIndex]は勝った
		    won = true;
		}
	    }

	    // プレイヤに勝敗を知らせる
	    if (won) players[playersIndex].youWon();
	    else     players[playersIndex].youLost();
	}
    }

    /** ウィンドウと標準出力にメッセージを表示する
     *   showXxxxMessageメソッドから呼ばれる下請メソッド
     */
    protected void showMessage(String mesg) {
	System.out.println(mesg);
	JOptionPane.showMessageDialog(null, mesg);
    }
	
    /** じゃんけんぽん のメッセージを表示 */
    protected void showJankenMessage(int match, int num) {
	if (num == 1) { // 1回目は じゃんけんぽん
	    showMessage("Match " + match + ": Jan Ken Pon!");
	}
	else { // 2回目以降は あいこでしょ
	    showMessage("Aiko de Sho");
	}
    }

    /** プレイヤの手のメッセージを表示 */
    protected void showHandsMessage(Hand[] hands, int match, int num) {
	String handMesg = "Match " + match + "-" + num + ":\n";	
	for (int i = 0; i < numOfPlayers; i++) {
	    handMesg +=  players[i].getName() + "'s hand is "
		+ hands[i].toString() + "\n";
	}
	showMessage(handMesg);
    }

    /** ジャンケンの各回の勝者のメッセージを表示 */
    protected void showWinnersMessage(Player[] winners, int match) {
	String mesg = "Match " + match + ": ";
	for (int i = 0; i < winners.length; i++) {
	    mesg +=  winners[i].getName() + " won.\n";
	}
	showMessage(mesg);
    }

    /** チャンピオンのメッセージを表示 */
    protected void showChampionsMessage(Player[] champions) {
	// チャンピオンのメッセージ
	String championMesg = "";
	for (int i = 0; i < champions.length && champions[i] != null; i++) {
	    championMesg += champions[i].getName() + " is a champion.\n";
	}

	// 各プレイヤが何勝したかのメッセージ
	String winNumMesg = "";
	for (int i = 0; i < numOfPlayers; i++) {
	    winNumMesg += players[i].getName() + ": " + wins[i] + " wins\n";
	}

	// メッセージを表示
	showMessage(championMesg + winNumMesg);
    }
}

ここで、例えば(上記Judge.javaの一部)

 winner = new Player[1] && new Player[2];
	    winner[0] = players[0] && players[1];
	    wins[0]++;

のような処理は自分なりには、勝者がPlayer[1]とPlayer[2]の二人で、
winner[0]にそれらを代入しているつもりなのですが、実行結果は

$ javac JankenErr.java
./Judge.java:135: エラー: 二項演算子'&&'のオペランド型が不正です
	    winner = new Player[1] && new Player[2];
	                           ^
  最初の型: Player[]
  2番目の型: Player[]
./Judge.java:136: エラー: 二項演算子'&&'のオペランド型が不正です
	    winner[0] = players[1] && players[2];
	                           ^
  最初の型: Player
  2番目の型: Player
./Judge.java:142: エラー: 二項演算子'&&'のオペランド型が不正です
	    winner = new Player[1] && new Player[3];
	                           ^
  最初の型: Player[]
  2番目の型: Player[]
./Judge.java:143: エラー: 二項演算子'&&'のオペランド型が不正です
	    winner[0] = players[0] && players[2];
	                           ^
  最初の型: Player
  2番目の型: Player
./Judge.java:149: エラー: 二項演算子'&&'のオペランド型が不正です
	    winner = new Player[2] && new Player[3];
	                           ^
  最初の型: Player[]
  2番目の型: Player[]
./Judge.java:150: エラー: 二項演算子'&&'のオペランド型が不正です
	    winner[0] = players[1] && players[2];
	                           ^
  最初の型: Player
  2番目の型: Player
エラー6個

のようになってしまいます。
&&を使うのがおかしいということはわかりますが、では期待している結果にするにはコードをどう書けばいいのですか。

よろしくお願いします。

0Like

一応以下のように書き換えては見ました。

 protected Player[] judge(Hand hands[]) {
	// 勝者の判定をする
	Player[] winner;
	if ((hands[0] instanceof Goo  && hands[1] instanceof Choki && hands[2] instanceof Choki)
            || (hands[0] instanceof Choki && hands[1] instanceof Par && hands[2] instanceof Par)
            || (hands[0] instanceof Par && hands[1] instanceof Goo && hands[2] instanceof Goo)) {
	    winner = new Player[1];
	    winner[0] = players[0];
	    wins[0]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Par && hands[2] instanceof Goo)
            || (hands[0] instanceof Choki && hands[1] instanceof Goo && hands[2] instanceof Choki)
            || (hands[0] instanceof Par && hands[1] instanceof Choki && hands[2] instanceof Par)) {
	    winner = new Player[2];
	    winner[0] = players[1];
	    wins[1]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Goo && hands[2] instanceof Par)
            || (hands[0] instanceof Choki && hands[1] instanceof Choki && hands[2] instanceof Goo)
            || (hands[0] instanceof Par && hands[1] instanceof Par && hands[2] instanceof Choki)) {
	    winner = new Player[3];
	    winner[0] = players[2];
	    wins[2]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Goo && hands[2] instanceof Choki)
            || (hands[0] instanceof Choki && hands[1] instanceof Choki && hands[2] instanceof Par)
            || (hands[0] instanceof Par && hands[1] instanceof Par && hands[2] instanceof Goo)) {
	  
	    winner = new Player[1]; 
            winner = new Player[2];
	    winner[0] = players[0]; 
            winner[0] = players[1];
	    wins[0]++;
	}else if  ((hands[0] instanceof Goo  && hands[1] instanceof Choki && hands[2] instanceof Goo)
            || (hands[0] instanceof Choki && hands[1] instanceof Par && hands[2] instanceof Choki)
            || (hands[0] instanceof Par && hands[1] instanceof Goo && hands[2] instanceof Par)) {
	   
	    winner = new Player[1]; 
            winner = new Player[3];
	    winner[0] = players[0]; 
            winner[0] = players[2];
	    wins[0]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Par && hands[2] instanceof Par)
	    || (hands[0] instanceof Choki && hands[1] instanceof Goo && hands[2] instanceof Goo)
	    || (hands[0] instanceof Par && hands[1] instanceof Choki && hands[2] instanceof Choki)) {
	  
	    winner = new Player[2]; 
            winner = new Player[3];
	    winner[0] = players[1]; 
            winner[0] = players[2];
	    wins[1]++;
	}
	else {
	    // あいこ
	    winner = null;
	}

	return winner;
    }

ただし、実行結果は以下のようになりました。

$ java JankenErr
Match 1: Jan Ken Pon!
Match 1-1:
Jhon's hand is Goo
Paul's hand is Par
George's hand is Par

Exception in thread "main" java.lang.NullPointerException
	at Judge.showWinnersMessage(Judge.java:259)
	at Judge.startOneJanken(Judge.java:89)
	at Judge.startJankens(Judge.java:47)
	at JankenErr.main(JankenErr.java:16)

勝者の数にあった配列を定義して、各要素に1プレイヤーずつ代入すれば良いと思います。

とありますが、これはおそらく一番上の

protected Player[] judge(Hand hands[]) {
	// 勝者の判定をする
	Player[] winner;

を書き換えるということなのだとは思いますが、これを書き換えると、最後の
return winner
も書き換える必要があると思うのです。

それをどのようにコードに表現するのか教えていただけるととても助かります。

0Like

任意の長さの配列を定義する方法はきちんと理解できていますか?
まずはコードに落とし込む前に各分岐直下にでもそれぞれの判定で勝者が何人で何番目の人が勝ちかをまずはコメントで書いてみてはどうでしょうか?

次にその人数で生成した配列をインスタンス化してwinnerに代入
winnerの各要素に勝者を代入
winnerをreturnする。

といった順番で考えていけば自分がどこで詰まっているか把握できないでしょうか?

質問者さんは現状のコードを維持されることを重視して実装をあまり変えることは考えていないようなので追加で質問されていることの対処方法のみを書いていますが、他の部分でのエラー処理が必要だったり今後の課題の追加で変更が大きく必要になってくるのではないかなと感じています。

これどこまでが課題で与えられた仕様で、どこからが自由に変更していい部分なのですかね……
正直、書かれている仕様で課題が与えられているとしたら、初学者向けだとしてもかなり微妙な書き方だなと

0Like

回答ありがとうございます。

これどこまでが課題で与えられた仕様で、どこからが自由に変更していい部分なのですかね……
正直、書かれている仕様で課題が与えられているとしたら、初学者向けだとしてもかなり微妙な書き方だなと

課題で与えられた以下のJavaプログラム(二人のじゃんけんプログラム)を変えて
三人でじゃんけんするプログラムにしています。

protected Player[] judge(Hand hands[]) {
	// 勝者の判定をする
	Player[] winner;
	if ((hands[0] instanceof Goo  && hands[1] instanceof Choki)
	    || (hands[0] instanceof Choki  && hands[1] instanceof Par)
	    || (hands[0] instanceof Par && hands[1] instanceof Goo)) {
	    // players[0]の勝ち
	    winner = new Player[1];
	    winner[0] = players[0];
	    wins[0]++;
	}
	else if ((hands[1] instanceof Goo  && hands[0] instanceof Choki)
	    || (hands[1] instanceof Choki  && hands[0] instanceof Par)
	    || (hands[1] instanceof Par && hands[0] instanceof Goo)) {
	    // players[1]の勝ち
	    winner = new Player[1];
	    winner[0] = players[1];
	    wins[1]++;
	}
	else {
	    // あいこ
	    winner = null;
	}

	return winner;
    }

任意の長さの配列を定義する方法はきちんと理解できていますか?
まずはコードに落とし込む前に各分岐直下にでもそれぞれの判定で勝者が何人で何番目の人が勝ちかをまずはコメントで書いてみてはどうでしょうか?

 protected Player[] judge(Hand hands[]) {
	// 勝者の判定をする
	Player[] winner;
	if ((hands[0] instanceof Goo  && hands[1] instanceof Choki && hands[2] instanceof Choki)
            || (hands[0] instanceof Choki && hands[1] instanceof Par && hands[2] instanceof Par)
            || (hands[0] instanceof Par && hands[1] instanceof Goo && hands[2] instanceof Goo)) {
	    winner = new Player[1];//一人が勝ち
	    winner[0] = players[0];//勝者
	    wins[0]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Par && hands[2] instanceof Goo)
            || (hands[0] instanceof Choki && hands[1] instanceof Goo && hands[2] instanceof Choki)
            || (hands[0] instanceof Par && hands[1] instanceof Choki && hands[2] instanceof Par)) {
	    winner = new Player[1];//1人が勝ち
	    winner[0] = players[1];//勝者
	    wins[1]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Goo && hands[2] instanceof Par)
            || (hands[0] instanceof Choki && hands[1] instanceof Choki && hands[2] instanceof Goo)
            || (hands[0] instanceof Par && hands[1] instanceof Par && hands[2] instanceof Choki)) {
	    winner = new Player[1];//1人が勝ち
	    winner[0] = players[2];//勝者
	    wins[2]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Goo && hands[2] instanceof Choki)
            || (hands[0] instanceof Choki && hands[1] instanceof Choki && hands[2] instanceof Par)
            || (hands[0] instanceof Par && hands[1] instanceof Par && hands[2] instanceof Goo)) {
	 
            winner = new Player[2];//二人が勝ち
	    winner[0] = players[0]; //勝者
            winner[0] = players[1];//勝者
	    wins[0]++;
	}else if  ((hands[0] instanceof Goo  && hands[1] instanceof Choki && hands[2] instanceof Goo)
            || (hands[0] instanceof Choki && hands[1] instanceof Par && hands[2] instanceof Choki)
            || (hands[0] instanceof Par && hands[1] instanceof Goo && hands[2] instanceof Par)) {
	   
            winner = new Player[2];//二人が勝ち
	    winner[0] = players[0]; //勝者
            winner[0] = players[2];
	    wins[0]++;
	}else if  ((hands[0] instanceof Goo && hands[1] instanceof Par && hands[2] instanceof Par)
	    || (hands[0] instanceof Choki && hands[1] instanceof Goo && hands[2] instanceof Goo)
	    || (hands[0] instanceof Par && hands[1] instanceof Choki && hands[2] instanceof Choki)) {
	  
            winner = new Player[2];//二人が勝ち
	    winner[0] = players[1]; //勝者
            winner[0] = players[2];
	    wins[1]++;
	}
	else {
	    // あいこ
	    winner = null;
	}

	return winner;
    }

次にその人数で生成した配列をインスタンス化してwinnerに代入
winnerの各要素に勝者を代入

そのやり方、というかコードがよくわかりません。
いろいろ試していますが、やはりエラーになってしまいます。

0Like

課題で与えられた以下のJavaプログラム(二人のじゃんけんプログラム)を変えて
三人でじゃんけんするプログラムにしています。

うーん、やはり元からこのような作りなのですね。
基本的な文法を学ぶための課題でデザインパターン等の演習ではないのである程度仕方ないことだとは理解できますが、あまり良い例題ではなく変な癖が付きそうですね。

とは言え与えられた形式で回答しなければいけないと思うのでもう少し説明をします。
だいぶ近づいてきているとは思います。

else if  ((hands[0] instanceof Goo  && hands[1] instanceof Choki && hands[2] instanceof Goo)
            || (hands[0] instanceof Choki && hands[1] instanceof Par && hands[2] instanceof Choki)
            || (hands[0] instanceof Par && hands[1] instanceof Goo && hands[2] instanceof Par)) {
            winner = new Player[2];//二人が勝ち
            winner[0] = players[0]; //勝者
            winner[0] = players[2];
            wins[0]++;
    }

例えばここの部分は配列の定義はあっています。
次に勝者を渡すところですが、2人分の配列を用意したので、1つ目と2つ目の要素それぞれにプレイヤーを入れないといけませんよね?
今はここが間違っているため2個めの要素がnullになって、その後の処理でエラーになっているように見えます。

また、勝利数も同様に複数人が勝っている場合はそれぞれ加算しないといけないと思います。

0Like

ligunさん。
回答ありがとうございました。
おかげさまで回答にたどり着くことができました。

0Like

Your answer might help someone💌