Yatzy
Yatzy is a dice rolling game where players aim to get particular die combinations.
This program counts probability of each such combinations. They are:
- All five ones,
- All five twos,
- Same for threes, fours, fives and sixes,
- One pair: two dice with the same number,
- Two pairs: just like in (4), but repeats on two different numbers,
- Three of a kind: three dice with the same number,
- Four of a kind: four dice with the same number,
- Small straight: numbers 1, 2, 3, 4, 5 present,
- Large straight: numbers 2, 3, 4, 5, 6 present.
- Full house: one pair and one triple,
- Yatzy: all five dice with the same number.
Code
package com.github.coderodde.prob.yatzy;
import java.util.Arrays;
/**
*
* @version 1.0.1 (Nov 2, 2024)
* @since 1.0.0 (Nov 1, 2024)
*/
public final class YatzyProbabilityCounter {
private static final int N = 6;
private final int[] dice = new int[5];
private final int[] counters = new int[N + 1];
public YatzyProbabilityCounter() {
for (int i = 0; i < dice.length; i++) {
dice[i] = 1;
}
}
public boolean inc() {
for (int i = dice.length - 1; i >= 0; i--) {
if (dice[i] < N) {
dice[i]++;
for (int j = i + 1; j < dice.length; j++) {
dice[j] = 1;
}
return true;
}
}
return false;
}
public int getNumberOfYatzyConfigurations() {
return (int) Math.pow(N, dice.length);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(dice.length);
for (final int die : dice) {
sb.append(die);
}
return sb.toString();
}
public static void main(String[] args) {
final YatzyProbabilityCounter ypc = new YatzyProbabilityCounter();
final int numberOfConfigurations = ypc.getNumberOfYatzyConfigurations();
final String outputFormat =
String.format(
"%%%dd",
Integer.toString(numberOfConfigurations).length());
int diceCombinationNumber = 1;
int ones = 0;
int twos = 0;
int threes = 0;
int fours = 0;
int fives = 0;
int sixes = 0;
int onePairs = 0;
int twoPairs = 0;
int threeOfKind = 0;
int fourOfKind = 0;
int smallStraights = 0;
int largeStraights = 0;
int fullHouses = 0;
int yatzies = 0;
do {
final String diceCombinationNumberString =
String.format(outputFormat,
diceCombinationNumber);
System.out.printf("Dice combination %s: %s\n",
diceCombinationNumberString,
ypc.toString());
diceCombinationNumber++;
if (ypc.isOnes()) {
ones++;
}
if (ypc.isTwos()) {
twos++;
}
if (ypc.isThrees()) {
threes++;
}
if (ypc.isFours()) {
fours++;
}
if (ypc.isFives()) {
fives++;
}
if (ypc.isSixes()) {
sixes++;
}
if (ypc.isOnePair()) {
onePairs++;
}
if (ypc.isTwoPairs()) {
twoPairs++;
}
if (ypc.isThreeOfKind()) {
threeOfKind++;
}
if (ypc.isFourOfKind()) {
fourOfKind++;
}
if (ypc.isSmallStraight()) {
smallStraights++;
}
if (ypc.isLargeStraight()) {
largeStraights++;
}
if (ypc.isFullHouse()) {
fullHouses++;
}
if (ypc.isYatzy()) {
yatzies++;
}
} while (ypc.inc());
System.out.println("\nGenerated all the probabilities.\n");
final Fractional fractionalOnes =
new Fractional(ones, numberOfConfigurations).gcd();
final Fractional fractionalTwos =
new Fractional(twos, numberOfConfigurations).gcd();
final Fractional fractionalThrees =
new Fractional(threes, numberOfConfigurations).gcd();
final Fractional fractionalFours =
new Fractional(fours, numberOfConfigurations).gcd();
final Fractional fractionalFives =
new Fractional(fives, numberOfConfigurations).gcd();
final Fractional fractionalSixes =
new Fractional(sixes, numberOfConfigurations).gcd();
final Fractional fractionalOnePair =
new Fractional(onePairs, numberOfConfigurations).gcd();
final Fractional fractionalTwoPairs =
new Fractional(twoPairs, numberOfConfigurations).gcd();
final Fractional fractionalThreeOfKind =
new Fractional(threeOfKind, numberOfConfigurations).gcd();
final Fractional fractionalFourOfKind =
new Fractional(fourOfKind, numberOfConfigurations).gcd();
final Fractional fractionalSmallStraights =
new Fractional(smallStraights, numberOfConfigurations).gcd();
final Fractional fractionalLargeStraights =
new Fractional(largeStraights, numberOfConfigurations).gcd();
final Fractional fractionalFullHouses =
new Fractional(fullHouses, numberOfConfigurations).gcd();
final Fractional fractionalYatzies =
new Fractional(yatzies, numberOfConfigurations).gcd();
//// Printing statistics:
System.out.printf("Ones (all ones) : %s\n", fractionalOnes);
System.out.printf("Twos (all twos) : %s\n", fractionalTwos);
System.out.printf("Threes (all threes): %s\n", fractionalThrees);
System.out.printf("Fours (all fours) : %s\n", fractionalFours);
System.out.printf("Fives (all fives) : %s\n", fractionalFives);
System.out.printf("Sixes (all sixes) : %s\n", fractionalSixes);
System.out.println();
System.out.printf("One pair (two same numbers): %s\n", fractionalOnePair);
System.out.printf("Two pairs (two different pairs): %s\n", fractionalTwoPairs);
System.out.printf("Three of a kind (three same numbers): %s\n", fractionalThreeOfKind);
System.out.printf("Four of a kind (four same numbers): %s\n", fractionalFourOfKind);
System.out.printf("Small straights (1, 2, 3, 4, 5): %s\n", fractionalSmallStraights);
System.out.printf("Large straights (2, 3, 4, 5, 6): %s\n", fractionalLargeStraights);
System.out.printf("Full houses (one pair, one triple): %s\n", fractionalFullHouses);
System.out.printf("Yatzies (all same numbers): %s\n", fractionalYatzies);
}
public boolean isOnes() {
return isParticular(1);
}
public boolean isTwos() {
return isParticular(2);
}
public boolean isThrees() {
return isParticular(3);
}
public boolean isFours() {
return isParticular(4);
}
public boolean isFives() {
return isParticular(5);
}
public boolean isSixes() {
return isParticular(6);
}
public boolean isOnePair() {
loadCounterArray();
for (final int c : counters) {
if (c == 2) {
return true;
}
}
return false;
}
public boolean isTwoPairs() {
loadCounterArray();
int pairs = 0;
for (final int c : counters) {
if (c == 2) {
pairs++;
}
}
return pairs == 2;
}
public boolean isThreeOfKind() {
loadCounterArray();
for (final int c : counters) {
if (c == 3) {
return true;
}
}
return false;
}
public boolean isFourOfKind() {
loadCounterArray();
for (final int c : counters) {
if (c == 4) {
return true;
}
}
return false;
}
public boolean isSmallStraight() {
loadCounterArray();
for (int i = 1; i <= 5; i++) {
final int c = counters[i];
if (c != 1) {
return false;
}
}
return true;
}
public boolean isLargeStraight() {
loadCounterArray();
for (int i = 2; i <= 6; i++) {
final int c = counters[i];
if (c != 1) {
return false;
}
}
return true;
}
public boolean isFullHouse() {
loadCounterArray();
boolean two = false;
boolean three = false;
for (final int c : counters) {
if (c == 2) {
two = true;
} else if (c == 3) {
three = true;
}
}
return two && three;
}
public boolean isYatzy() {
loadCounterArray();
final int firstDie = dice[0];
for (int i = 1; i < dice.length; i++) {
if (firstDie != dice[i]) {
return false;
}
}
return true;
}
private void loadCounterArray() {
Arrays.fill(counters, 0);
for (final int d : dice) {
counters[d]++;
}
}
private boolean isParticular(final int die) {
for (final int d : dice) {
if (d != die) {
return false;
}
}
return true;
}
}
final class Fractional {
private final int numerator;
private final int denominator;
Fractional(final int numerator, final int denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
double asDouble() {
return ((double) numerator) / ((double) denominator);
}
Fractional gcd() {
int a = numerator;
int b = denominator;
while (b != 0) {
final int t = b;
b = a % b;
a = t;
}
return new Fractional(numerator / a,
denominator / a);
}
@Override
public String toString() {
return numerator + " / " + denominator + " = " + asDouble();
}
}
... and it outputs:
Line 1: 11111
Line 2: 11112
Line 3: 11113
Line 4: 11114
Line 5: 11115
Line 6: 11116
Line 7: 11121
.
.
.
Line 7770: 66656
Line 7771: 66661
Line 7772: 66662
Line 7773: 66663
Line 7774: 66664
Line 7775: 66665
Line 7776: 66666
Generated all the probabilities.
Ones: 1 / 7776 = 1.286008230452675E-4
Twos: 1 / 7776 = 1.286008230452675E-4
Threes: 1 / 7776 = 1.286008230452675E-4
Fours: 1 / 7776 = 1.286008230452675E-4
Fives: 1 / 7776 = 1.286008230452675E-4
Sixes: 1 / 7776 = 1.286008230452675E-4
One pair: 475 / 648 = 0.7330246913580247
Two pairs: 25 / 108 = 0.23148148148148148
Three of a kind: 125 / 648 = 0.19290123456790123
Four of a kind: 25 / 1296 = 0.019290123456790122
Small straights: 5 / 324 = 0.015432098765432098
Large straights: 5 / 324 = 0.015432098765432098
Full houses: 25 / 648 = 0.038580246913580245
Yatzies: 1 / 1296 = 7.716049382716049E-4
Critique request
I would like to receive any commentary regarding my work.
Line 1: 11111->Dice combination 1: 11111, things likeOne pair: 475 / 648,Large straights: 5 / 324would benefit from a header clarifying what these fractions mean. \$\endgroup\$6^5possible dice combinations and calculated how many of them much each criterion). \$\endgroup\$