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

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

ただいまの
回答率

87.36%

Java Enum (ほぼ初めての)使い方は合っていますか?

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 4
  • VIEW 1,697

score 993

Java:「じゃんけんゲーム」でコンパイルしてもスコアが反映されない状態です・・・
上記質問への回答で幸いにもコメントを頂き、ほぼ初めてのEnumを使って実装し直してみました。
実装してみたものの3つの状態グーチョキパー1,2,3しか無いものでもEnumにするメリットがいまいち分からず、
戸惑いながらの実装でこのような使い方で合っているのか自信がありません。

コードの添削をteratailで依頼するのはいいか
添削については賛否があるようですが、差し支えない範囲で改善点や間違った使い方などあればご指摘ご教示頂けると助かります。

-追記-
ご教示頂いたことを意識して書き直しました。
なるべく人や物や行動などのオブジェクト指向も意識したつもりです。
まだまだ改善するところはあるかと思いますが自分なりにはとても満足しています。
ありがとうございました。

出力結果

CPU1   vs CPU2
グー  vs グー  引分
チョキ vs チョキ 引分
パー  vs パー  引分
チョキ vs パー  勝者 CPU1
グー  vs パー  勝者 CPU2
チョキ vs パー  勝者 CPU1
パー  vs パー  引分
チョキ vs グー  勝者 CPU2
チョキ vs グー  連勝 CPU2
パー  vs パー  引分
パー  vs チョキ 連勝 CPU2
チョキ vs パー  勝者 CPU1

最終勝者は CPU1

書き直したプログラム

package _memo;

import java.util.Random;

public class memo_qa147649 {

    public static void main(String[] args) {

        Player[] players = new Player[2];
        players[0] = new Player("CPU1");
        players[1] = new Player("CPU2");

        System.out.printf("%n最終勝者は %s%n", game(players, 3).name);

    }

    private static class Player {

        private String name;
        private int wins;
        private Hands hand;

        Player(String name) {
            this.name = name;
            this.wins = 0;
        }
    }

    private static Player game(Player[] players, int winCount) {
        Player winner = null;
        Player lastWinner = null;
        Player theWinner = null;

        Hands[] hand = new Hands[2];

        System.out.printf("%s   vs %s%n", players[0].name, players[1].name);

        while (theWinner == null) {

            players[0].hand = Hands.choice();
            players[1].hand = Hands.choice();

            System.out.printf("%s vs %s ", players[0].hand.text, players[1].hand.text);

            WLD wld = rsp(players[0].hand, players[1].hand);

            if (wld == WLD.DRAW) {
                System.out.println(WLD.DRAW.text);
                continue;
            }

            if (wld == WLD.WIN) {
                winner = players[0];
            } else
                winner = players[1];

            if (lastWinner == winner) {
                lastWinner = winner;
                System.out.printf("連勝 %s%n", winner.name);
            } else {
                winner.wins += 1;
                lastWinner = winner;
                System.out.printf("勝者 %s%n", winner.name);
            }

            if (winner.wins == winCount) {
                theWinner = winner;
            }
        }
        return theWinner;
    }

    private static WLD rsp(Hands hand1, Hands hand2) {
        WLD wld = WLD.DRAW;

        if (hand1 != hand2) {

            switch (hand1) {

            // player1:グー
            case ROCK:
                if (hand2 == Hands.SCISSORS) {
                    wld = WLD.WIN;
                } else {
                    wld = WLD.LOSE;
                }
                break;

            // player1:チョキ
            case SCISSORS:
                if (hand2 == Hands.PAPER) {
                    wld = WLD.WIN;
                } else {
                    wld = WLD.LOSE;
                }
                break;

            // player1:パー
            case PAPER:
                if (hand2 == Hands.ROCK) {
                    wld = WLD.WIN;
                } else {
                    wld = WLD.LOSE;
                }
                break;
            }
        }
        return wld;
    }

    private enum WLD {
        DRAW(-1, "引分"), LOSE(0, "負け"), WIN(1, "勝ち");
        private final int id;
        private final String text;

        private WLD(final int id, final String text) {
            this.id = id;
            this.text = text;
        }
    }

    private enum Hands {
        ROCK(0, "グー "), SCISSORS(1, "チョキ"), PAPER(2, "パー ");

        private final int id;
        private final String text;

        private Hands(final int id, final String text) {
            this.id = id;
            this.text = text;
        }

        private static Hands choice() {
            //r:1:グー s:2:チョ p:3:パー
            Random rnd = new Random();
            return getHands(rnd.nextInt(3));
        }

        private int getInt() {
            return this.id;
        }

        private String getText() {
            return this.text;
        }

        private static Hands getHands(final int id) {
            Hands[] Handss = Hands.values();
            for (Hands hand : Handss) {
                if (hand.getInt() == id) {
                    return hand;
                }
            }
            return null;
        }
    }
}

-以下初期プログラム-

package _memo;

import java.util.Random;

import _memo.Enums.Jnk;

public class qa147558 {

    private static int rsp(Jnk h1, Jnk h2) {
        int win = -1;

        int a = Jnk.p.getInt();
        if (h1 != h2) {

            switch (h1) {

            case r:
                // =1=グー
                if (h2 == Jnk.s) {
                    win = 0;
                } else {
                    win = 1;
                }
                break;
            case s:
                // =2=チョ
                if (h2 == Jnk.p) {
                    win = 0;
                } else {
                    win = 1;
                }
                break;
            case p:
                // =3=パー
                if (h2 == Jnk.r) {
                    win = 0;
                } else {
                    win = 1;
                }
                break;
            }
        }
        return win;
    }

    public static void main(String[] args) {

        int winner = -1;
        int lastwin = -2;
        int[][] players = { { 0, 0 }, { 1, 0 } };

        String[] m_p = { "CPU1", "CPU2" };
        System.out.printf("%svs%s%n", m_p[0], m_p[1]);

        Random rnd = new Random();

        while (winner < 0) {

            //Enum型 r:1:グー s:2:チョ p:3:パー
            Jnk[] hand = new Jnk[2];
            hand[0] = Jnk.getJnk(rnd.nextInt(3) + 1);
            hand[1] = Jnk.getJnk(rnd.nextInt(3) + 1);

            int win = rsp(hand[0], hand[1]);

            System.out.printf("%svs%s ", hand[0].getText(), hand[0].getText());

            if (win == -1) {
                System.out.println("引分");
                continue;
            }
            if (lastwin == win) {
                lastwin = -2;
                System.out.printf("連勝 %s%n", m_p[win]);
            } else {
                players[win][1] += 1;
                lastwin = win;
                System.out.printf("勝者 %s%n", m_p[win]);
            }
            if (players[win][1] == 3) {
                winner = win;
            }
        }
        System.out.println();
        System.out.printf("最終勝者は %s%n", m_p[winner]);
    }
}


Enum

package _memo;

public class Enums {
    public static enum Jnk {
        //出力の桁合わせで「チョキ」は「チョ」としています。
        r(1, "グー"), s(2, "チョ"), p(3, "パー");

        private final int id;
        private final String text;

        private Jnk(final int id, final String text) {
            this.id = id;
            this.text = text;
        }
        public int getInt() {
            return this.id;
        }
        public String getText() {
            return this.text;
        }
        public static Jnk getJnk(final int id) {
            Jnk[] Jnks = Jnk.values();
            for (Jnk jnk : Jnks) {
                if (jnk.getInt() == id) {
                    return jnk;
                }
            }
            return null;
        }
    }
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

+11

質問の本題から逸れますが…

3つの状態グーチョキパー1,2,3しか無いものでもEnumにするメリットがいまいち分からず、

逆です。3つしかないからこそEnumを使うメリットがあるのです。

仮にグーチョキパーをintで表すとします。グーチョキパーはそれぞれ1,2,3で表すことにします。
今、手を引数に取り手を出力するメソッドを作りたいとします。
手はintで表すことにしていましたから、引数の型はintになります。つまり、こうなります。

public static void printHand (int hand) {
    switch(hand) {
    case 1:
        System.out.println("グー");
        break;
    case 2:
        System.out.println("チョキ");
        break;
    case 3:
        System.out.println("パー");
        break;
    }
}


これをプログラムする側からしたら、このhandは1か2か3だという前提で組みます。しかし、使う側からすれば、それ以外の数値を入れることもできてしまうのです。
例えばこのメソッドに4を渡したとすると、メソッド名から何かを出力するはずなのですが、何も出力しません。これはまだ軽微なほうだと思われますが、「想定しているもの以外が引数としてわたる」というバグの温床になります。

ここでEnumを使うと、「手としてHand型を要求する」「Hand型のオブジェクトはr,s,pの3つのみで、これら以外が存在しない」事で、引数として渡せるものを制限し、バグの可能性を少なくできます。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/09/20 20:38

    >3つしかないからこそEnumを使うメリットがある
    >引数として渡せるものを制限し、バグの可能性を少なくできます。
    なるほど!!これまた目からウロコです!!!
    すみません、ベストアンサーどちらにも付けたいのですが1つしか無く。。。
    白紙から作り直して精進します。

    キャンセル

checkベストアンサー

+3

連勝とかの計算は面倒なので、ジャンケン部分だけ。

Main.java

import rps.Game;
import rps.Game.Result;
import rps.Hand;


class Main {
    public static void main(String[] args) {
        for(int i = 0; i < 10; ++i) {
            Hand hand1 = Hand.choose();
            Hand hand2 = Hand.choose();

            Result result = Game.judge(hand1, hand2);
            System.out.println(
                String.format("%s %ss %s.", hand1, result, hand2)
            );
        }
    }
}

rps/Hand.java

package rps;

import java.util.Random;


public enum Hand {
    ROCK, PAPER, SCISSORS;

    public static Hand choose() {
        return values[
            random.nextInt(values.length)
        ];
    }
    @Override 
    public String toString() {
        return this.name().toLowerCase();
    }

    //
    private static final Random random = new Random();
    private static final Hand[] values = Hand.values();
}

rps/Game.java

package rps;

import rps.Hand;


public class Game {
    public enum Result {
        LOSE, DRAW, WIN;

        @Override 
        public String toString() {
            return this.name().toLowerCase();
        }
    }

    public static Result judge(Hand mine, Hand other) {
        if(mine == Hand.ROCK) {
            if(other == Hand.SCISSORS) return Result.WIN;
            if(other == Hand.PAPER)    return Result.LOSE;

            return Result.DRAW;
        }
        if(mine == Hand.PAPER) {
            if(other == Hand.ROCK)     return Result.WIN;
            if(other == Hand.SCISSORS) return Result.LOSE;

            return Result.DRAW;
        }
        {   
        // mine == Hand.SCISSORS
            if(other == Hand.PAPER)    return Result.WIN;
            if(other == Hand.ROCK)     return Result.LOSE;

            return Result.DRAW;
        }
    }
}

Wandbox

全体的にmainメソッドの仕事が多過ぎだと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/09/20 20:22

    なるほど!!目からウロコです!!!
    Enumって定数保存しておく場所としか思っていませんでした^^;
    そういうことでしたか。。。
    そこでじゃんけんの抽選もしてしまうとは私の頭が硬すぎました。
    コードをよく見ながら自分なりに実装し直してみます。

    キャンセル

  • 2018/09/20 20:26

    命名やクラスの分け方などもとてもシンプルで読みやすくスッと頭の中に入ってきてます。
    どうしても1文字変数の癖が抜けなくてそこも直さなければいけないとおもいました。

    キャンセル

  • 2018/09/20 20:29

    写経しないで白紙から作り直してみた後もう一度見比べてみます。
    ありがとうございました。

    キャンセル

0

使い方あってると思いますよ。(動かしていないのであしからず)
気になったとこを上げると、
enumは同じソース内でいいと思います。個人の意見ですが。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/09/20 20:16

    ありがとうございます安心しました。
    うまく認識しない気がして外に出してしまいました。
    他の意見が無いようでしたら後ほどクローズさせていただきます。

    キャンセル

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

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

関連した質問

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