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