Simulazione di lancio di dadi in Java

Oct 30 2020

Per uno dei miei laboratori ho bisogno di scrivere un programma Java completo che simuli un gioco di scommesse "molto semplice". Le specifiche sono le seguenti: simula il lancio di 3 dadi. Se lanci tre sei, vinci$20; if you throw three of any other value then you win $10; se lanci due dadi dello stesso valore, vinci$5. If none of the conditions above are met, then you would lose $1.

Esempi di esecuzioni: lancio dei dadi

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

Il codice risultante che ho scritto per risolvere questo problema è il seguente:

/**
 * 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++;
        }
    }
}

Il problema che sto incontrando con questo approccio è che, sebbene il codice funzioni come dovrebbe, mi piacerebbe avere un modo più semplice per scrivere il doppio invece di avere tre istruzioni "if". Il mio obiettivo in questo è creare un'istruzione a tre vie "o" invece di confrontare i dadi1 con i dadi 2 e 3 e i dadi 2 con i dadi 1 e 3, ecc ...

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

Se lo facessi, come potrei poi stampare il valore della coppia che ho identificato?

Risposte

7 Marc Oct 30 2020 at 14:37

Benvenuto in CodeReview. Per quanto riguarda il tuo problema, una soluzione rapida è:

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"); 
}

L'operatore ternario rende il codice più compatto, ma in questo caso credo sia un po 'meno leggibile di una catena di if-else.

Pochi altri suggerimenti:

  • Il ciclo while può essere sostituito da un ciclo for più conveniente. A partire dal:
    int round = 1;
    while(round<=3){
        //...
        round++;
    }
    
    Per:
    for(int round = 1; round <= 3; round++) {
        //...
    }
    
  • La dichiarazione di più variabili in una riga int dice1, dice2, dice3;non è considerata una buona pratica in Java.
  • Invece di generare un random floate poi lanciarlo in un int, genera direttamente un intcon ThreadLocalRandom.current().nextInt(6). Docs .
  • È possibile stampare la prima riga con System.out.format. A partire dal:
    System.out.println();
    System.out.println("Dice 1 : " + dice1 + "    Dice 2 : " + dice2 + "    Dice 3 : " + dice3);
    
    Per:
    System.out.format("%nDice 1 :  %d    Dice 2 : %d    Dice 3 : %n", dice1, dice2, dice3)
    
  • I nomi delle classi dovrebbero essere PascalCase . Invece di Lab6_part3dargli un nome Lab6Part3.
  • Dichiarare una costante per il numero di round, per facilitare la modifica. Per esempio:
    public class Lab6Part3 {
    
        private static final int ROUNDS = 3;
    
        public static void main(String[] args) {
            for(int round = 1; round <= ROUNDS; round++) {
                //...
            }
    }
    

Un altro approccio consiste nel generare tre numeri Random#intse calcolare le frequenze:

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

Non è necessario disporre di 3 istruzioni else_if. Ci sono 3 scenari in cui ti trovi in ​​un caso "two-fo-a-kind". dice1 == dice2, dice1 == dice3, dice2 == dice3. Il tuo primo blocco if cattura 2 di questi scenari. L'unica altra opzione è se dice2 == dice3.

Se ci pensi, il tuo terzo blocco else_If creerebbe sempre una vera valutazione in uno dei primi due blocchi, quindi il tuo codice non lo raggiungerà mai.

// 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) {

Per favore, non farlo. Se vuoi utilizzare il mezzo coccolato else, scrivilo sempre su due righe consecutive.

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

Ci sono due ragioni.

  1. Se voglio sapere che la struttura è finita, in questo modo posso vedere solo guardando una riga oltre il file }. Con il tuo originale, dovrei guardare un numero arbitrario di righe alla dichiarazione successiva. Ciò diventa particolarmente negativo quando i blocchi dei commenti si allungano. È del tutto possibile scrivere un commento più alto di una singola schermata. Significa che invece di scorrere semplicemente un po 'più in là, dovrei scorrere oltre il commento per vedere che c'è un elseblocco.
  2. Se qualcuno usa qualcosa che riformatta il codice per mettere il elsesulla stessa riga di }, dovrà comunque spostare il commento. Quindi, anche se lo formattano di nuovo, il commento si sposterà. Ciò causa la confusione nel controllo del codice sorgente. Quindi mettila come farebbe il riformattatore dall'inizio.

I linguaggi in stile C in generale hanno una gestione dei blocchi confusa. Perché usano }sia per terminare la struttura sia solo per terminare il blocco in una struttura continua. Cioè non hanno modo di dire che la ifstruttura sta finendo invece di continuare con elsequalcosa di simile. Per compensare, dobbiamo usare le convenzioni di codifica. E una delle convenzioni più semplici, che trascende lo stile, è quella di non mettere mai una parentesi graffa ( }o {) più di una riga di distanza dalla parola chiave associata se ce n'è una.