package cse1030.games; import java.util.Collections; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; /** * A utility class that encodes a subset of the rules for the game Yahtzee. * * @author CSE1030_F13_14 * */ public class Yahtzee { private static int FIRST = 0; private static int SECOND = 1; private static int THIRD = 2; private static int FOURTH = 3; private static int FIFTH = 4; private Yahtzee() { // private and empty by design } /** * The number of six-sided dice used in a standard game of Yahtzee. */ public static final int NUMBER_OF_DICE = 5; /** * Returns true if the list contains a three of a kind. * *

A three of a kind is defined as at least three dice having * the same value. * * @param dice list of dice * @pre. dice.size() == Yahtzee.NUMBER_OF_DICE * @return true if the list contains a three of a kind */ public static boolean isThreeOfAKind(List dice) { List copy = new ArrayList(dice); Collections.sort(copy); boolean result = copy.get(FIRST).getValue() == copy.get(THIRD).getValue() || copy.get(SECOND).getValue() == copy.get(FOURTH).getValue() || copy.get(THIRD).getValue() == copy.get(FIFTH).getValue(); return result; } /** * Returns true if the list contains a four of a kind. * *

A four of a kind is defined as at least four dice having * the same value. * * @param dice list of dice * @pre. dice.size() == Yahtzee.NUMBER_OF_DICE * @return true if the list contains a four of a kind */ public static boolean isFourOfAKind(List dice) { List copy = new ArrayList(dice); Collections.sort(copy); boolean result = copy.get(FIRST).getValue() == copy.get(FOURTH).getValue() || copy.get(SECOND).getValue() == copy.get(FIFTH).getValue(); return result; } /** * Returns true if the list contains a five of a kind. * *

A five of a kind is defined as all five dice having * the same value. * * @param dice list of dice * @pre. dice.size() == Yahtzee.NUMBER_OF_DICE * @return true if the list contains a five of a kind */ public static boolean isFiveOfAKind(List dice) { /* List copy = new ArrayList(dice); Collections.sort(copy); boolean result = copy.get(FIRST).getValue() == copy.get(FIFTH).getValue(); return result; */ Set copy = new TreeSet(dice); return copy.size() == 1; } /** * Returns true if the list contains a full house. * * A full house is defined as having two dice of the * same value and three dice of the same value. * * @param dice list of dice * @pre. dice.size() == Yahtzee.NUMBER_OF_DICE * @return true if the list contains a full house */ public static boolean isFullHouse(List dice) { List uniq = new ArrayList(new TreeSet(dice)); boolean result = uniq.size() == 1; if (uniq.size() == 2) { result = Collections.frequency(dice, uniq.get(0)) >= 2 && Collections.frequency(dice, uniq.get(1)) >= 2; } return result; } /** * Returns true if the list contains a small straight. * *

A small straight is defined as at least four dice in sequential * order. * * @param dice list of dice * @pre. dice.size() == Yahtzee.NUMBER_OF_DICE * @return true if the list contains a small straight */ public static boolean isSmallStraight(List dice) { List copy = new ArrayList(dice); Collections.sort(copy); boolean result = longestSequence(copy) >= 4; return result; } /** * Returns true if the list contains a large straight. * *

A large straight is defined as five dice in sequential * order. * * @param dice list of dice * @pre. dice.size() == Yahtzee.NUMBER_OF_DICE * @return true if the list contains a large straight */ public static boolean isLargeStraight(List dice) { List copy = new ArrayList(dice); Collections.sort(copy); boolean result = longestSequence(copy) == 5; return result; } /** * Returns the length of the longest sequence for a sorted list * of dice. * *

A sequential series of dice is a sorted series where each * die value is one larger than the previous die value. * * @param dice list of dice * @pre. dice.size() > 0 * @pre. dice must be sorted in increasing order * @return true if the list is a sequential series */ private static int longestSequence(List dice) { // the length of the longest sequence int longest = 1; // the length of the current sequence int length = 1; // the current value in the sequence int curr = dice.get(0).getValue(); for (int i = 1; i < dice.size(); i++) { // the next value to check int next = dice.get(i).getValue(); if (next == curr + 1) { // the current sequence grows by 1 length++; // the longest sequence might increase longest = Math.max(longest, length); } else if (next != curr) { // not in sequence, a new sequence starts length = 1; } // set the current value of the sequence for the next iteration curr = next; } return longest; } private static double toPercent(int x, int y) { return 100.0 * x / y; } /** * Performs a simulation to compute the odds of rolling each of the * Yahtzee categories. The results are printed to the console. * See the lab for details. * * @param args not used */ public static void main(String[] args) { int threeOfAKind = 0; int fourOfAKind = 0; int fiveOfAKind = 0; int fullHouse = 0; int smallStraight = 0; int largeStraight = 0; final int TRIALS = 1000000; for (int i = 0; i < TRIALS; i++) { List dice = new ArrayList(); for (int j = 0; j < Yahtzee.NUMBER_OF_DICE; j++) { dice.add(new Die()); } if (Yahtzee.isThreeOfAKind(dice)) { threeOfAKind++; } if (Yahtzee.isFourOfAKind(dice)) { fourOfAKind++; } if (Yahtzee.isFiveOfAKind(dice)) { fiveOfAKind++; } if (Yahtzee.isFullHouse(dice)) { fullHouse++; } if (Yahtzee.isSmallStraight(dice)) { smallStraight++; } if (Yahtzee.isLargeStraight(dice)) { largeStraight++; } } System.out.println("Three of a kind: " + toPercent(threeOfAKind, TRIALS) + "%"); System.out.println("Four of a kind: " + toPercent(fourOfAKind, TRIALS) + "%"); System.out.println("Five of a kind: " + toPercent(fiveOfAKind, TRIALS) + "%"); System.out.println("Full house: " + toPercent(fullHouse, TRIALS) + "%"); System.out.println("Small straight: " + toPercent(smallStraight, TRIALS) + "%"); System.out.println("Large straight: " + toPercent(largeStraight, TRIALS) + "%"); } }