Simulation de lancer de dés en Java
Pour l'un de mes laboratoires, j'ai besoin d'écrire un programme Java complet qui simulera un jeu de pari "très simple". Les spécifications sont les suivantes: simuler le lancer de 3 dés. Si vous lancez trois six, vous gagnez$20; if you throw three of any other value then you win $dix; si vous lancez deux dés de même valeur, vous gagnez$5. If none of the conditions above are met, then you would lose $1.
Exemples d'exécutions: lancer de dés
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
Le code résultant que j'ai écrit pour résoudre ce problème est le suivant:
/**
* 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++;
}
}
}
Le problème que je rencontre avec cette approche est que bien que le code fonctionne comme il est censé le faire, j'aimerais avoir un moyen plus simple d'écrire les deux-en-un-genre au lieu d'avoir trois instructions «si». Mon but est de créer une déclaration "ou" à trois voies au lieu de comparer les dés 1 avec les dés 2 et 3, et les dés 2 avec les dés 1 et 3, etc ...
else if (dice1 == dice2 || dice1 == dice3 || dice2 == dice3) {
System.out.println("Congratulations : You threw TWO - " + somethings?? + "s");
System.out.println("You win $5");
Si je devais faire cela, comment pourrais-je alors imprimer la valeur de la paire que j'ai identifiée?
Réponses
Bienvenue dans CodeReview. Concernant votre problème, une solution rapide est:
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'opérateur ternaire rend le code plus compact, mais dans ce cas, je pense qu'il est un peu moins lisible qu'une chaîne de if-else.
Quelques autres suggestions:
- La boucle while peut être remplacée par une boucle for plus pratique. De:
À:int round = 1; while(round<=3){ //... round++; }for(int round = 1; round <= 3; round++) { //... } - La déclaration de plusieurs variables sur une seule ligne
int dice1, dice2, dice3;n'est pas considérée comme une bonne pratique en Java. - Au lieu de générer un aléatoire
floatpuis de le convertir en unint, générez directement unintavecThreadLocalRandom.current().nextInt(6). Docs . - Vous pouvez imprimer la première ligne avec
System.out.format. De:
À: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) - Les noms de classe doivent être PascalCase . Au lieu de
Lab6_part3vous, vous pouvez le nommerLab6Part3. - Déclarez une constante pour le nombre de tours, pour faciliter le changement. Par exemple:
public class Lab6Part3 { private static final int ROUNDS = 3; public static void main(String[] args) { for(int round = 1; round <= ROUNDS; round++) { //... } }
Une autre approche consiste à générer trois nombres avec Random#intset à calculer les fréquences:
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
}
Vous n'avez pas besoin de 3 instructions else_if. Il y a 3 scénarios où vous êtes dans un cas «à deux pour un genre». dice1 == dice2, dice1 == dice3, dice2 == dice3. Votre premier bloc if capture 2 de ces scénarios. La seule autre option est si dice2 == dice3.
Si vous y réfléchissez, votre troisième bloc else_If créerait toujours une véritable évaluation dans l'un des deux premiers blocs, de sorte que votre code ne l'atteindra jamais.
// 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");
}
} // Two of a kind (PRINT "dice1") else if (dice1 == dice2 || dice1 == dice3) {
Veuillez ne pas faire ça. Si vous souhaitez utiliser le demi-câlin else, écrivez-le toujours sur deux lignes consécutives.
}
else if (dice1 == dice2 || dice1 == dice3) {
// Two of a kind (PRINT "dice1")
Il y a deux raisons.
- Si je veux savoir que la structure est terminée, de cette façon je peux voir simplement en regardant une ligne après le
}. Avec votre original, je devrais regarder un nombre arbitraire de lignes pour la prochaine déclaration. Cela devient d'autant plus grave que les blocs de commentaires s'allongent. Il est tout à fait possible d'écrire un commentaire plus grand qu'un seul écran. Cela signifie qu'au lieu de simplement faire défiler un peu plus loin, j'aurais besoin de faire défiler le commentaire pour voir qu'il y a unelseblocage. - Si quelqu'un utilise quelque chose qui reformate le code pour mettre le
elsesur la même ligne que le}, il devra de toute façon déplacer le commentaire. Ensuite, même s'ils le reformatent, le commentaire se déplacera. Cela provoque une confusion dans le contrôle de code source. Donc, dites-le simplement comme le reformaterait depuis le début.
Les langages de style C en général ont une gestion des blocs confuse. Parce qu'ils utilisent à la }fois pour terminer la structure et simplement pour terminer le bloc dans une structure continue. C'est-à-dire qu'ils n'ont aucun moyen de dire que la ifstructure se termine plutôt que de continuer avec une elsesorte. Pour compenser, nous devons utiliser des conventions de codage. Et l'une des conventions les plus simples, qui transcende le style, est de ne jamais mettre une accolade ( }ou {) à plus d'une ligne du mot-clé associé s'il y en a un.