(JAVA) I'm Having Trouble With Making a Yahtzee Class and Getting the Appropriate number of rolls at the end

Viewed 52

The goal for this class is to have an int with a desired number of rolls. From this number the class will roll 5 dice and determine if the rolls are a yahtzee, full house, large straight, four of a kind, three of a kind, or nothing (loser). Where I'm having trouble is building a proper if statement to vet the large straights and the loser rolls. Those rolls always produce numbers that are vastly bigger than the initial test of 5000 rolls. Any help would be greatly appreciated. Below is my Yahtzee class and then below that is my current driver.

       public class Yahtzee {

      public int rolls;

  public void getYahtzee(int rolls){
   int yahtzee = 0;
   int fullHouse = 0;
   int largeStraight = 0;
   int four = 0;
   int three = 0;
   int losers = 0;
   for (int i = 0; i <= rolls; i++){
      int dice1=(int)(Math.random()*6+1);
      int dice2=(int)(Math.random()*6+1);
      int dice3=(int)(Math.random()*6+1);
      int dice4=(int)(Math.random()*6+1); 
      int dice5=(int)(Math.random()*6+1);
      int[] dice = new int[]{dice1, dice2, dice3, dice4, dice5};
      int[] counts = new int[6];
      for (int x=0; x<5; x++)
        counts[dice[x]-1]++;
       boolean check2 = false;
       boolean check3 = false;
       boolean check4 = false;
        for (int x: counts) {
            check2 |= (x==2);
            check3 |= (x==3); 
            check4 |= (x==4);
        if (x==5) { 
            yahtzee += 1;
        } else if (x==1) {
            largeStraight += 1;
        } else if(check2 && check3) {
            fullHouse += 1;
        } else if (x==3) {
            three += 1; 
        } else if (x==4){
            four += 1;  
        } else if (x==0){
            losers += 1;
        }
        }

   }
  double percentage1 = (double)yahtzee/(double)rolls;
  double percentage2 = (double)fullHouse/(double)rolls;
  double percentage3 = (double)largeStraight/(double)rolls;
  double percentage4 = (double)four/(double)rolls;
  double percentage5 = (double)three/(double)rolls;
  double percentage6 = (double)losers/(double)rolls;
  System.out.println("Number of Rolls: " + rolls);
  System.out.println("----------------------------");
  System.out.println("Number of Yahtzees: " + yahtzee);
  System.out.println("Yahtzee Percentage: " + percentage1 + "%" +  "\n");
  System.out.println("Number of Full Houses: " + fullHouse);
  System.out.println("Full House Percentage: " + percentage2 + "%" +  "\n");
  System.out.println("Number of Large Straights: " + largeStraight);
  System.out.println("Large Straight Percentage: " + percentage3 + "%" +  "\n");
  System.out.println("Number of Four of a Kinds: " + four);
  System.out.println("Four of a Kind Percentage: " + percentage4 + "%" +  "\n");
  System.out.println("Three of a Kind: " + three);
  System.out.println("Three of a Kind Percentage: " + percentage5 + "%" +  "\n");
  System.out.println("Number of Losers: " + losers);
  System.out.println("Losers Percentage: " + percentage6 + "%" +  "\n");
   
     }


   }

    /* This is my driver class */
      public class Driver {
         public static void main(String[] args){
              Yahtzee yt = new Yahtzee();
                yt.getYahtzee(5000);
}

}

2 Answers

It's not a perfect system because a yahtzee counts as a yahtzee, 4 of a kind, and 3 of a kind, but you can change that in the logic if you want. This should be an excellent base plate: (You will need to change your print statements because they are off by x100 of a percent (says 0.2% instead of 20% ) )

public void getYahtzee(int rolls) {
    int yahtzee       = 0 ;
    int fullHouse     = 0 ;
    int largeStraight = 0 ;
    int four          = 0 ;
    int three         = 0 ;
    int losers        = 0 ;

    for (int i = 0; i <= rolls; i++) {
        ArrayList<Integer> dice = new ArrayList<>();
        // roll and add 5 die
        for (int j = 0; j < 5; ++j)
            dice.add((int) (Math.random() * 6 + 1));

        Collections.sort(dice);
        System.out.println(dice); // optional

        int[] dieCount = new int[6];

        for (int j = 0; j < 5; ++j)
            ++dieCount[dice.get(j) - 1];

        boolean isTwoKind = false;
        boolean isThreeKind = false;
        boolean isFourKind = false;
        boolean isFiveKind = false;
        boolean isLargeStr = false;
        boolean isFullHouse = false;

        for (int j = 0; j < 6; ++j) {
            if (dieCount[j] >= 3)
                isThreeKind = true;
            if (dieCount[j] >= 4)
                isFourKind = true;
            if (dieCount[j] >= 5)
                isFiveKind = true;
        }

        for (int j = 0; j < 4; ++j) // large straight (all 5)
        {
            if ((dice.get(j) + 1) != dice.get(j + 1))
                break;

            if (j == 3)
                isLargeStr = true;
        }

        // full house

        for (int j = 0; j < 6; ++j) // cycle through 6 dice counts
        {
            if (dieCount[j] == 2)
                isTwoKind = true;
        }

        if (isTwoKind && isThreeKind)
            isFullHouse = true;

        int modCount = 0;

        if (isThreeKind) {
            ++three;
            ++modCount;
        }

        if (isFourKind) {
            ++four;
            ++modCount;
        }

        if (isFiveKind) {
            ++yahtzee;
            ++modCount;
        }

        if (isLargeStr) {
            ++largeStraight;
            ++modCount;
        }

        if (isFullHouse) {
            ++fullHouse;
            ++modCount;
        }

        if (modCount == 0)
            ++losers;
    }

There are a few problems with the vetting logic.

check2 |= (x == 2);
check3 |= (x == 3);
...
else if (check2 && check3) {
                    fullHouse += 1;
                }

When the count of any face is 3 or 4, both conditions will be satisfied, and a full house will be counted (incorrectly).

Example

dice: [1, 1, 1, 2, 3]
counts: [3, 1, 1, 0, 0, 0]

And as you mentioned, the counts of straights and losers are significantly higher than they should be. The root of this bug is the iteration over counts giving and opportunity for the same roll to count for MANY different scores. As an example my first roll counted +3 for losers and +1 for large straight.

I think you may have been trying to do something similar to this, where the conditions are all counted, and the scores are then marked separately outside of the loop (this way they can only be counted once).

            int x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0;
            
            for (int x : counts) {
                if (x == 5) x5++;
                if (x == 4) x4++;
                if (x == 3) x3++;
                if (x == 2) x2++;
                if (x == 1) x1++;
            }

            if (x5 == 1) {
                yahtzee++;
            } else if (x4 == 1) {
                four++;
            } else if (x3 == 1 && x2 == 1) {
                fullHouse++;
            } else if (x3 == 1) {
                three++;
            } else if (x1 == 5) {
                if (!(counts[0] == 1 && counts[5] == 1)) { // hacky way to determine LS. can't have 6 and 1 in same roll.
                    largeStraight++;
                } else {
                    losers++;
                }
            } else {
                losers++;
            }

Instead of:

            boolean check2 = false;
            boolean check3 = false;
            boolean check4 = false;
            for (int x : counts) {
                check2 |= (x == 2);
                check3 |= (x == 3);
                check4 |= (x == 4);
                if (x == 5) {
                    yahtzee += 1;
                } else if (x == 1) {
                    largeStraight += 1;
                } else if (check2 && check3) {
                    fullHouse += 1;
                } else if (x == 3) {
                    three += 1;
                } else if (x == 4) {
                    four += 1;
                } else if (x == 0) {
                    losers += 1;
                }
            }

That way only one score is marked per roll. Also, currently the program rolls 5001 times. If you want to keep the loop counter starting at zero, then you'll need to update the exit condition.

for (int i = 0; i < rolls; i++) {

Chris C.

Related