23JON
@23JON (23 JON)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

じゃんけんプログラムを作る

Q&A

Closed

Johnの手はグー、パー、チョキ、グー、グー、パー、チョキ、グー・・・と出力し、Paulの手はランダムに出力するプログラムを作成したいと思い、以下のようにしたのですが、Johnの手が期待しているのとは違って出力されてしまいます。
(ちなみに、このじゃんけんプログラムは3回先に勝ったほうが勝ちとしています)

/** ジャンケン の通常のコンピュータ プレイヤ */
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) {

    switch(num%4){
    case 1: return goo;
        case 2: return par;
        case 3: return choki; 
        case 0: return goo; 
        }num++;  return goo;
    }
}

実行結果

実行結果:

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

Aiko de Sho
Match 1-2:
Jhon's hand is Par
Paul's hand is Goo

Match 1: Jhon won.

Match 2: Jan Ken Pon!
Match 2-1:
Jhon's hand is Goo
Paul's hand is Par

Match 2: Paul won.

Match 3: Jan Ken Pon!
Match 3-1:
Jhon's hand is Goo
Paul's hand is Choki

Match 3: Jhon won.

Match 4: Jan Ken Pon!
Match 4-1:
Jhon's hand is Goo
Paul's hand is Goo

Aiko de Sho
Match 4-2:
Jhon's hand is Par
Paul's hand is Choki

Match 4: Paul won.

Match 5: Jan Ken Pon!
Match 5-1:
Jhon's hand is Goo
Paul's hand is Choki

Match 5: Jhon won.

Jhon is a champion.
Jhon: 3 wins
Paul: 2 wins

自分のプログラムでは

public Hand showHand(int match, int num) {

    switch(num%4){
      case 1: return goo;
        case 2: return par;
        case 3: return choki; 
        case 0: return goo; 
        }num++;  return goo;
    }

となっており、一番最後にreturn goo;としていることで
おそらく勝敗が決まるごとにわざわざリセットされて、グーから始まるのだとは思いますが、return goo;がないとエラーとなってしまいます。

num 回目の変数は match 勝負目に応じて都度リセットされるわけですから「ゲームを通して今何回目か」を管理する別の変数を用意するとよい(つまり、showHand に渡すのは、match や num じゃなくて「今何回目か」を表す変数に変更する。)と思ったのですが、それをどうやってプログラムすればいいのかがわかりません

ここで、勝敗が決まっても関係なく、グー、パー、チョキ、グー・・・とするにはどうしたらいいですか。
どうすれば(OrderedComputerPlayerのどこをどう直せば)、期待している実行結果となりますか。よろしくお願いいたします。

(ちなみに、期待する実行結果は例えば以下のようになる)

期待している結果

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

Aiko de Sho
Match 1-2:
Jhon's hand is Par
Paul's hand is Goo

Match 1: Jhon won.

Match 2: Jan Ken Pon!
Match 2-1:
Jhon's hand is Choki
Paul's hand is Par

Match 2: Jhon won.

Match 3: Jan Ken Pon!
Match 3-1:
Jhon's hand is Goo
Paul's hand is Par

Match 3: Paul won.

Match 4: Jan Ken Pon!
Match 4-1:
Jhon's hand is Goo
Paul's hand is Par

Match 4: Paul won.

Match 5: Jan Ken Pon!
Match 5-1:
Jhon's hand is Par
Paul's hand is Goo

Match 5: John won.

Jhon is a champion.
Jhon: 3 wins
Paul: 2 wins

前回も同じ内容の質問をしましたが、前回の質問は少し説明不足なところがあったかもしれないので、じゃんけんプログラムに必要であろうプログラムをすべて載せておきます。

BigMounthPlayer.java

import javax.swing.*;

/** おしゃべりなプレイヤ */
public class BigMouthPlayer extends NormalComputerPlayer {
    /** コンストラクタ */
    public BigMouthPlayer(String name) {
    super(name);
    }

    public void youWon() {
    super.youWon();
    if (wins == matches) { // チャンピオンになったとき
        showMessage("I'm the champion.");
    }
    else {
        showMessage("I'm a great Janken Player.");
    }
    }

    public void youLost() {
    super.youLost();
    showMessage("Damn it!");
    }

    /** ウィンドウと標準出力にmesgを表示する
     *   mesgの前に自分の名前をつける
     */
    protected void showMessage(String mesg) {
    String nameMesg = getName() + ": ";
    System.out.println(nameMesg + mesg);
    JOptionPane.showMessageDialog(null, nameMesg + mesg);
    }

}

Choki.java

public class Choki implements Hand {
    public String toString() {
    return "Choki";
    }
}

Goo.java

public class Goo implements Hand {
    public String toString() {
    return "Goo";
    }
}

GooPlayer.java

public class GooPlayer extends Player {
    private Hand goo;

    /** コンストラクタ, プレイヤの名前を指定する */
    public GooPlayer(String name) {
    super(name);
    goo = new Goo();
    }

    /** match回目の勝負のnum回目のプレイヤの手を出す
     *  Player の showHand をオーバーライド
     * 常にグーを出す
     */
    public Hand showHand(int match, int num) {
    return goo;
    }
}

Hand.java

public interface Hand {
    /** 手を表す文字列を返す */
    String toString();
}

HumanPlayer.java

import javax.swing.*;

public class HumanPlayer extends Player {
    protected Hand   hands[];  // プレイヤの手

    /** コンストラクタ */
    public HumanPlayer(String name) {
    super(name);
    // 手を設定する
    hands = new Hand[3];
    hands[0] = new Goo();
    hands[1] = new Choki();
    hands[2] = new Par();
    }

    /** match回目の勝負のnum回目のプレイヤの手を選ぶ
     *  Player の showHand をオーバーライド
     */
    public Hand showHand(int match, int num) {
    // ダイアログを表示して手を選ばせる
    //  selectedは選んだ手の,配列handsの要素番号になっている
    int selected =
        JOptionPane.showOptionDialog(null, "Select Your Hand",
                     "Select Your Hand",
                     JOptionPane.YES_NO_OPTION,
                     JOptionPane.QUESTION_MESSAGE, 
                     null, hands, null);
    Hand hand = hands[selected];
    return hand;
    }
}

Janken.java

/** ジャンケンを開始するためのクラス */
public class Janken {
    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);

        // 3回勝負でジャンケンの開始
        judge.startJankens(3);
    }
    catch (JankenException e) {
        System.err.println("Error: " + e.getMessage());
    }
    }
}

Janken2.java

/** ジャンケンを開始するためのクラス */
/* HumanPlayer の名前は
     java Janken2 HUMAN_NAME
   のようにコマンドライン引数で指定する (指定しなかった場合は GEN になる).
 */
public class Janken2 {
    public static void main(String args[]) {
    try {
        Judge judge = new Judge(); // 審判の作成

        // プレイヤの作成と審判への登録
        String humanName = "GEN";
        if (args.length >= 1) {
        humanName = args[0];
        }
        Player human = new HumanPlayer(humanName);
        judge.registPlayer(human);

        Player mah = new BigMouthPlayer("MAH");
        judge.registPlayer(mah);

        // 3回勝負でジャンケンの開始
        judge.startJankens(3);
    }
    catch (JankenException e) {
        System.err.println("Error: " + e.getMessage());
    }
    }
}

JankenErr.java

/** ジャンケンを開始するためのクラス */
public class JankenErr {
    public static void main(String args[]) {
    try {
        Judge judge = new Judge(); // 審判の作成

        // プレイヤの作成と審判への登録
        Player jhon = new NormalComputerPlayer("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());
    }
    }
}

JankenException.java

* じゃんけんに関する例外 */
public class JankenException extends Exception {
    public JankenException() {
    super();
    }

    public JankenException(String msg) {
    super(msg);
    }
}

Judge.java

import javax.swing.*;

/** じゃんけん の審判のクラス */
public class Judge {
    protected Player players[];      // プレイヤの配列
    protected int    numOfPlayers;   // プレイヤの数
    protected int    wins[];         // 勝ち数を記録する配列

    /** コンストラクタ */
    public Judge() {
    // 2人のプレイヤの配列を作成し、各要素はnullに初期化
    players = new Player[2];
    players[0] = players[1] = null;

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

    // 2人の勝ち星数の配列を作成し、各要素を0に初期化
    wins = new int[2];
    wins[0] = wins[1] = 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++;   // 手の回数を増やす
        // 掛け声
        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);
    }
    return hands;
    }

    /** ジャンケンの勝負を判定をする。
     *   勝負がついた場合は 勝者のPlayerの配列を返す。
     *   あいこの場合は null を返す。
     *   なお、2人勝負の場合は常に勝者は1人である
     */
    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;
    }

    /** 各プレイヤの勝ち数を調べてチャンピオンを決める
     *   つまり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);
    }
}

NormalComputerPlayer.java

/** ジャンケン の通常のコンピュータ プレイヤ */
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 hand = random.nextInt(3);
    if (hand == 0) {
        return goo;
    } else if (hand == 1) {
        return choki;
    } else {
        return par;
    }
    }
}

OrderedComputerPlayer.java

/** ジャンケン の通常のコンピュータ プレイヤ */
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) {

    switch(num%4){
    case 1: return goo;
        case 2: return par;
        case 3: return choki; 
        case 0: return goo; 
        }num++;    return goo;
    }
}

Par.java

public class Par implements Hand {
    public String toString() {
    return "Par";
    }
}

Player.java

/** ジャンケン プレイヤの抽象クラス */
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);
}
0

8Answer

前回の質問の継続のようですが何故過去の質問の回答に対する結果や返答などが何もないのでしょうか?

return goo;がないとエラーとなってしまいます。

switchにdefaultがないのでどの条件にもマッチしなかった時にswitchを抜けてます。
ちなみにここのnum++はどのような意図で書かれてるのでしょうか?
何も意味をなしてないように見えますが

マッチに関わらず継続した試合回数を元にするならJudgeクラスでgetHandメソッド呼び出しているところで渡すnumを総試合回数にするか、OrderedComputerPlayerで受け取ったnumを使わずに独自のカウンターを実装するなどすればどうでしょうか?
これは設計思想にもよると思いますが、個人的には後者を選びますかね。(matchとnumはマッチ数と各マッチでの回数と仕様が決まってそうなので)

実装で言うと、各手(グーチョキパー)がプレイヤーごとにインスタンス変数として持っているのはちょっと無駄に見えるかなーって思ってます。
それで前回の回答ではenumに書き換えたのですが

以前別の質問への回答でも書きましたが、IntelliJ IDEAやEclipse等のIDE、もしくはVS Codeの様なプログラミングに対応したエディタ等は使用されていないのでしょうか?
以前も言いましたがインデントや不要なコードがいくつか見られ、とても読みにくいものとなっています。
IDE等を使用すればここらへんを自動で指摘修正してくれます。
また動作確認もステップ実行やブレークポイント等でひと目でわかるので導入されてはどうでしょうか?

0Like

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

1.前回の質問の継続のようですが何故過去の質問の回答に対する結果や返答などが何もないのでしょうか?

すみませんでした。
回答を拝見しましたが、enumなど習っていないプログラミング言語が存在したため、また
それをどのように使って実装すればいいのかよくわからなく、自分のJavaプログラミングの実力(初めてちょうど一ヶ月)程度ではそれに対しての返答もしようがありませんでした。
また、申し遅れましたが、これは大学の課題なので、できれば上記に上げてあるプログラムをもとに実装していただけるととても助かります。

2.switchにdefaultがないのでどの条件にもマッチしなかった時にswitchを抜けてます。

一応

public Hand showHand(int match, int num) {
        
	switch(num%4){
	case 1: return goo;
        case 2: return par;
        case 3: return choki; 
        case 0: return goo; 
        default:
        }return goo;
    }

のようにしましたが、特に変化がありませんでした。

3.マッチに関わらず継続した試合回数を元にするならJudgeクラスでgetHandメソッド呼び出しているところで渡すnumを総試合回数にするか、OrderedComputerPlayerで受け取ったnumを使わずに独自のカウンターを実装するなどすればどうでしょうか?
これは設計思想にもよると思いますが、個人的には後者を選びますかね。

それの実装例を見せてくれるととても助かります。

5.以前も言いましたがインデントや不要なコードがいくつか見られ、とても読みにくいものとなっています。

以降そうさせていただきます。

厚かましい質問内容で申し訳ございませんが、よろしくお願いします

0Like

のようにしましたが、特に変化がありませんでした。

default時の終了条件がないのでswitch文抜けますね。
別に予想外の値の時はグーを返すと言った実装になっているので別に問題はないとは思いますが、今回は判定式が剰余なので0~3までで自明なので

    switch(num%4){
        case 2: return par;
        case 3: return choki;
        default: return goo;
    }

のような形でも問題ないと思います。
ここらへんはswitch文の基本的な文法なので、教科書等を確認されることを勧めます。

それの実装例を見せてくれるととても助かります。

OrderedComputerPlayerのインスタンス変数に適当なカウンターを定義してshowHandメソッドの判定式を (counter++)%4 のようにするのはどうでしょうか?

0Like

Comments

  1. @23JON

    Questioner

    回答ありがとうございます。
    おっしゃっていることは身にしみて理解しているのですが、その
    「counter」
    は、numやmatchを使ってどのように定義すればいいのでしょうか。
  2. 最初に述べたように受け取ったnumの値を使用せずに、OrderedComputerPlayer内に独自にカウンタを定義する方法について説明しています。
    インスタンス変数の宣言、初期化の方法については把握されていますでしょうか?

それをどのように使って実装すればいいのかよくわからなく、自分のJavaプログラミングの実力(初めてちょうど一ヶ月)程度ではそれに対しての返答もしようがありませんでした。

これに関しては前回の自分の回答が希望のものを逸脱していることくらいは元より理解しています。
今回の質問自体が前回の他の回答者さんのアドバイスを元に修正されたものと見受けられるので、そちらに対して何もアクションもなくクローズもしていないことが気になりました。

0Like

あまりごちゃごちゃ書くと混乱させそうなので簡単にまとめると

  1. Judgeクラスで総試合数のカウンター(名前はcounterでもsumでもおまかせします)を定義する
  2. numと一緒にインクリメントする
  3. ○○PlayerのshowHandメソッドの第3引数に入れる

が今のコードをあまり崩さずに実装できると思います。コード全体のシェイプアップは他の回答者さんにおまかせします。

0Like

Comments

  1. @23JON

    Questioner

    回答ありがとうございます。
    「numと一緒にインクリメント」
    して、counterやsumを定義する方法を教えてほしいです。
    勿論、それを定義する際にmatchやnumは使用するのでしょうが、
    どのようにそれらを使用すればいいかということです。
  2. 書き方がよくなかったかもしれませんが、上の番号は理解しやすいように実装の順番を示したものです。
    ※「インクリメントして定義」というのは順序が違います。(変数は定義してからでないとインクリメント等操作できません。)

    クラス内での変数の定義方法は基本的内容ですのでテキストの序盤にも記載があると思います。

    https://www.javadrive.jp/start/const/index2.html#section3

    それとコーディングとは直接関係ないですが、そのじゃんけんでは総試合回数(例:`counter`)はmatchやnumとは関係ありません。※match試合目のnum回目という情報から総試合回数を判断できません。

    コード例は後で示します。
  3. @23JON

    Questioner

    ご回答ありがとうございます。
    自分も考えて、後ほど示してくださるコードを確認し、以後の勉強に役立てます。
Judge.java
public class Judge {
    protected Player players[];      // プレイヤの配列
    protected int    numOfPlayers;   // プレイヤの数
    protected int    wins[];         // 勝ち数を記録する配列
/*追加*/int counter = 0; // 総試合数のカウンター

// 略

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

        do {  // 勝者が決まるまで繰り返す
            num++;   // 手の回数を増やす
/*追加*/    counter++; // numと一緒に総試合数をインクリメント
            // 掛け声
            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++) {
            // カウンターをshowHandで使うので引数にする
/*変更*/    hands[i] = players[i].showHand(match, num, counter);
        }
        return hands;
    }

// 略

}
Player.java
public abstract class Player {

// 略

    // 総試合数のカウンターを渡す
    public abstract Hand showHand(int match, int num, int counter);
}

※他の○○Playerクラスも引数counterを受け取れるように編集してください。
※OrderedComputerPlayerクラスは@ligunさんの回答を確認して編集してください。
※動作するか確認していませんので、目的に合うように適宜修正してください。

0Like

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

ちなみに、私は以下のように回答しました。

/** ジャンケン の通常のコンピュータ プレイヤ */
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 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);
}
import javax.swing.*;

public class HumanPlayer extends Player {
    protected Hand   hands[];  // プレイヤの手

    /** コンストラクタ */
    public HumanPlayer(String name) {
	super(name);
	// 手を設定する
	hands = new Hand[3];
	hands[0] = new Goo();
	hands[1] = new Choki();
	hands[2] = new Par();
    }

    /** match回目の勝負のnum回目のプレイヤの手を選ぶ
     *  Player の showHand をオーバーライド
     */
    public Hand showHand(int match, int num, int counter ) {
	// ダイアログを表示して手を選ばせる
	//  selectedは選んだ手の,配列handsの要素番号になっている
	int selected =
	    JOptionPane.showOptionDialog(null, "Select Your Hand",
					 "Select Your Hand",
					 JOptionPane.YES_NO_OPTION,
					 JOptionPane.QUESTION_MESSAGE, 
					 null, hands, null);
	Hand hand = hands[selected];
	return hand;
    }
}
** ジャンケン の通常のコンピュータ プレイヤ */
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 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;
	}
    }
}
実行結果
$ java Janken
Match 1: Jan Ken Pon!
Match 1-1:
Jhon's hand is Goo
Paul's hand is Par

Match 1: Paul won.

Match 2: Jan Ken Pon!
Match 2-1:
Jhon's hand is Par
Paul's hand is Goo

Match 2: Jhon won.

Match 3: Jan Ken Pon!
Match 3-1:
Jhon's hand is Choki
Paul's hand is Choki

Aiko de Sho
Match 3-2:
Jhon's hand is Goo
Paul's hand is Goo

Aiko de Sho
Match 3-3:
Jhon's hand is Goo
Paul's hand is Goo

Aiko de Sho
Match 3-4:
Jhon's hand is Par
Paul's hand is Par

Aiko de Sho
Match 3-5:
Jhon's hand is Choki
Paul's hand is Par

Match 3: Jhon won.

Match 4: Jan Ken Pon!
Match 4-1:
Jhon's hand is Goo
Paul's hand is Goo

Aiko de Sho
Match 4-2:
Jhon's hand is Goo
Paul's hand is Goo

Aiko de Sho
Match 4-3:
Jhon's hand is Par
Paul's hand is Goo

Match 4: Jhon won.

Jhon is a champion.
Jhon: 3 wins
Paul: 1 wins
0Like

お疲れさまでした。
実装できたようで何よりです。

動作的には問題ないと思いますが一点だけ述べると、今回は引数でカウンタを受け取るのでshowHandメソッド内でのインクリメントはなくてもいいかなと思います。

0Like

Your answer might help someone💌