Javaでのサイコロ投げシミュレーション

Oct 30 2020

私のラボの1つでは、「非常に単純な」サイコロ賭けゲームをシミュレートする完全なJavaプログラムを作成する必要があります。仕様は次のとおりです。3つのサイコロを投げるシミュレーションを行います。あなたが3つの6を投げるなら、あなたは勝ちます$20; if you throw three of any other value then you win $10; 同じ値のサイコロを2つ投げると、勝ちます$5. If none of the conditions above are met, then you would lose $1.1。

実行例:サイコロを投げる

Dice 1 : 2     Dice 2 : 1    Dice 3 : 2
Congratulations : You threw TWO - 2s
You win $5 Dice 1 : 2 Dice 2 : 2 Dice 3 : 2 Congratulations : You threw THREE - 2s You win $10

Dice 1 : 4    Dice 2 : 6    Dice 3 : 3
Unfortunately : You did not throw anything of value
You lose $1

この問題を解決するために私が書いた結果のコードは次のとおりです。

/**
 * SRN: 507-147-9
 */
public class Lab6_part3 {

    public static void main(String[] args) {

        // define vars
        int round = 1;
        int dice1, dice2, dice3;

        while (round <= 3) {

            dice1 = 1 + (int)(Math.random() * 6);
            dice2 = 1 + (int)(Math.random() * 6);
            dice3 = 1 + (int)(Math.random() * 6);

            System.out.println();
            System.out.println("Dice 1 : " + dice1 + "    Dice 2 : " + dice2 + "    Dice 3 : " + dice3);

            // Three of a kind
            if ((dice1 == dice2) && (dice1 == dice3)) { // 3-of-a-kind (D1)                              

                // Rolls three sixes
                if (dice1 == 6) {
                    System.out.println("Congratulations : You threw THREE - 6s");
                    System.out.println("You win $20");
                } else {
                    // Rolls three of anything else
                    System.out.println("Congratulations : You threw THREE - " + dice1 + "s");
                    System.out.println("You win $10"); } } // Two of a kind (PRINT "dice1") else if (dice1 == dice2 || dice1 == dice3) { System.out.println("Congratulations : You threw TWO - " + dice1 + "s"); System.out.println("You win $5");
            } 
            
            // Two of a kind (PRINT "dice2")
            else if (dice2 == dice1 || dice2 == dice3) {                              
                System.out.println("Congratulations : You threw TWO - " + dice2 + "s");
                System.out.println("You win $5"); } // Two of a kind (PRINT "dice3") else if (dice3 == dice1 || dice3 == dice2) { System.out.println("Congratulations : You threw TWO - " + dice3 + "s"); System.out.println("You win $5");
            } 
            // Did not throw anything of value
            else {
                System.out.println("Unfortunately : You did not throw anything of value");
                System.out.println("You lose $1");
            }
            round++;
        }
    }
}

このアプローチで私が遭遇している問題は、コードは想定どおりに機能しますが、3つの「if」ステートメントを使用する代わりに、より簡単な方法で2つの文を記述したいということです。これでの私の目標は、dice1をdice 2および3と比較したり、dice2をdice1および3と比較したりする代わりに、3方向の「or」ステートメントを作成することです。

else if (dice1 == dice2 || dice1 == dice3 || dice2 == dice3) {                              
    System.out.println("Congratulations : You threw TWO - " + somethings?? + "s");
    System.out.println("You win $5"); 

それを行うとしたら、特定したペアの値をどのように印刷できるでしょうか。

回答

7 Marc Oct 30 2020 at 14:37

CodeReviewへようこそ。あなたの問題に関して、迅速な解決策は次のとおりです。

else if (dice1 == dice2 || dice1 == dice3 || dice2 == dice3) {       
    int doubleNum = dice1 == dice2 ? dice1 : dice1 == dice3 ? dice1 : dice3;
    System.out.println("Congratulations : You threw TWO - " + doubleNum + "s");
    System.out.println("You win $5"); 
}

三項演算子はコードをよりコンパクトにしますが、この場合、のチェーンよりも少し読みにくいと思いますif-else。

他のいくつかの提案:

  • whileループは、より便利なforループに置き換えることができます。から:
    int round = 1;
    while(round<=3){
        //...
        round++;
    }
    
    に:
    for(int round = 1; round <= 3; round++) {
        //...
    }
    
  • 1行で複数の変数を宣言することは、Javaでは良い習慣int dice1, dice2, dice3;とは見なされません。
  • ランダムを生成してfloatからにキャストする代わりにint、intwithを直接生成しThreadLocalRandom.current().nextInt(6)ます。ドキュメント。
  • 最初の行はSystem.out.format。で印刷できます。から:
    System.out.println();
    System.out.println("Dice 1 : " + dice1 + "    Dice 2 : " + dice2 + "    Dice 3 : " + dice3);
    
    に:
    System.out.format("%nDice 1 :  %d    Dice 2 : %d    Dice 3 : %n", dice1, dice2, dice3)
    
  • クラス名はPascalCaseである必要があります。代わりにLab6_part3名前を付けることができますLab6Part3。
  • 変更しやすいように、ラウンド数の定数を宣言します。例えば:
    public class Lab6Part3 {
    
        private static final int ROUNDS = 3;
    
        public static void main(String[] args) {
            for(int round = 1; round <= ROUNDS; round++) {
                //...
            }
    }
    

別のアプローチはRandom#ints、周波数を使用して3つの数値を生成し、計算することです。

Random r = new Random();
// Generate three random numbers from 1 to 6
IntStream diceRolls = r.ints(3, 1, 7);

// Generate map of frequencies
Map<Integer, Long> freq = diceRolls.boxed()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

boolean winner = false;
for (Entry<Integer, Long> entry : freq.entrySet()) {
    int number = entry.getKey();
    long times = entry.getValue();
    if (times == 3) {
        // Three of a kind ...
        winner = true;
    } else if (times == 2) {
        // Two of a kind...
        System.out.println("Congratulations : You threw TWO - " + number + "s");
        System.out.println("You win $5");
        winner = true;
    }
}
if(!winner) {
    // Did not throw anything of value
}
2 SavvasParastatidis Oct 30 2020 at 21:40

3つのelse_ifステートメントは必要ありません。「2つの種類」のケースにある3つのシナリオがあります。dice1 == dice2、dice1 == dice3、dice2 == dice3。最初のifブロックがこれらのシナリオの2つをキャッチします。他の唯一のオプションは、dice2 == dice3の場合です。

あなたがそれについて考えるならば、あなたの3番目のelse_Ifブロックは常に最初の2つのブロックの1つで真の評価を作成するので、あなたのコードは決してそれに到達しません。

// Two of a kind (PRINT "dice1")
else if (dice1 == dice2 || dice1 == dice3) {
    System.out.println("Congratulations : You threw TWO - " + dice1 + "s");
    System.out.println("You win $5"); } // Two of a kind (PRINT "dice2") else if (dice2 == dice3) { System.out.println("Congratulations : You threw TWO - " + dice2 + "s"); System.out.println("You win $5");
}
2 mdfst13 Oct 31 2020 at 18:20
        }
        
        // Two of a kind (PRINT "dice1")
        else if (dice1 == dice2 || dice1 == dice3) {

これをしないでください。半抱きしめたものを使いたい場合はelse、必ず2行連続で書いてください。

        }
        else if (dice1 == dice2 || dice1 == dice3) {
          // Two of a kind (PRINT "dice1")

2つの理由があります。

  1. 構造が完成したことを知りたい場合は、このようにして、を過ぎた1行を見るだけで確認できます}。あなたのオリジナルでは、次のステートメントまで任意の数の行を探す必要があります。コメントブロックが長くなると、これは特に悪くなります。1画面よりも背の高いコメントを書くことは完全に可能です。つまり、単に少し遠くにスクロールするのではなく、コメントを過ぎてページを下に移動し、elseブロックがあることを確認する必要があります。
  2. 誰かがコードを再フォーマットelseしてと同じ行に置くものを使用した場合}、とにかくコメントを移動する必要があります。そうすれば、フォーマットを元に戻しても、コメントは移動します。これにより、ソース管理に混乱が生じます。ですから、リフォーマッターが最初からそうするように言ってください。

一般に、Cスタイルの言語には、紛らわしいブロック処理があります。なぜなら、それら}は構造を終了するためと、継続する構造内のブロックを終了するための両方を使用するからです。つまり、ある種のif構造が終了しているelseのか、継続しているのかを言う方法がありません。これを補うために、コーディング規約を使用する必要があります。また、スタイルを超越する最も単純な規則の1つは、関連するキーワードがある場合は、中括弧(}または{)を1行以上離さないことです。