import acm.io.*; import acm.program.*; import acm.util.*;
public class Yahtzee extends GraphicsProgram implements YahtzeeConstants {
public static void main(String[] args) { new Yahtzee().start(args); }
public void run() {
IODialog dialog = getDialog(); nPlayers = dialog.readInt("Enter number of players"); playerNames = new String[nPlayers];
for (int i = 1; i <= nPlayers; i++) playerNames[i - 1] = dialog.readLine("Enter name for player " + i);
display = new YahtzeeDisplay(getGCanvas(), playerNames); scores = new int[nPlayers][N_CATEGORIES]; used = new int[nPlayers][N_CATEGORIES];
currentPlayer = 0; dice = new int[N_DICE];
playGame();
}
private void playGame() {
for(int i = 0; i < N_SCORING_CATEGORIES; i++)
for(currentPlayer = 0; currentPlayer < nPlayers; currentPlayer++) {
rollDiceSequence();
selectCategorySequence();
}
computeTotalScores();
determineWinner();
}
private void rollDiceSequence() {
display.printMessage(playerNames[currentPlayer] + "'s turn! Click \"Roll Dice\" button to roll the dice");
display.waitForPlayerToClickRoll(currentPlayer + 1);
rollDice();
display.printMessage("Select the dice you wish to re-roll and click \"Roll Again\"");
display.waitForPlayerToSelectDice();
reRollDice();
display.printMessage("Select the dice you wish to re-roll and click \"Roll Again\"");
display.waitForPlayerToSelectDice();
reRollDice();
}
private void rollDice() {
for(int i = 0; i < N_DICE; i++) dice[i] = rgen.nextInt(1, 6);
display.displayDice(dice);
}
private void reRollDice() {
for(int i = 0; i < N_DICE; i++) if(display.isDieSelected(i)) dice[i] = rgen.nextInt(1, 6);
display.displayDice(dice);
}
private void selectCategorySequence() {
int category;
display.printMessage("Select a category for this roll");
while(usedCategory(category = display.waitForPlayerToSelectCategory()));
int score = checkAndScoreCategory(category);
used[currentPlayer][category-1] = 1; scores[currentPlayer][category-1] = score; scores[currentPlayer][TOTAL-1] += score;
display.updateScorecard(category,currentPlayer+1,score);
display.updateScorecard(TOTAL,currentPlayer+1,scores[currentPlayer][TOTAL-1]);
}
private int checkAndScoreCategory(int category) {
switch(category) {
case ONES: case TWOS: case THREES: case FOURS: case FIVES: case SIXES: return addNs(category);
case THREE_OF_A_KIND: return nOfAKind(3);
case FOUR_OF_A_KIND: return nOfAKind(4);
case FULL_HOUSE: return fullHouse();
case SMALL_STRAIGHT: return straight(4);
case LARGE_STRAIGHT: return straight(5);
case CHANCE: return chance();
case YAHTZEE: if(nOfAKind(5) > 0) return 50;
default: return 0;
}
}
private int addNs(int n) {
int score = 0;
for(int i = 0; i < N_DICE; i++) if(dice[i] == n) score += n;
return score;
}
private int[] generateTrackingArray() {
int[] tracking = new int[6];
for(int i = 0; i < N_DICE; i++) tracking[dice[i]-1]++;
return tracking;
}
private int nOfAKind(int n) {
int[] tracking = generateTrackingArray();
for(int i = 0; i < tracking.length; i++) if(tracking[i] >= n) return chance();
return 0;
}
private int fullHouse() {
int[] tracking = generateTrackingArray();
for(int i = 0; i < tracking.length; i++) if((tracking[i] > 0 && tracking[i] < 2) || tracking[i] > 3) return 0;
return 25;
}
private int straight(int n) {
int[] tracking = generateTrackingArray();
int counter = 0;
for(int i = 0; i < tracking.length && counter < n; i++)
if(tracking[i] == 0) counter = 0;
else counter++;
return (counter == n ? (n == 4 ? 30 : 40) : 0);
}
private int chance() {
int sum = 0;
for(int i = 0; i < N_DICE; i++) sum += dice[i];
return sum;
}
private boolean usedCategory(int category) {
for(int i = 0; i < N_CATEGORIES; i++)
if(used[currentPlayer][category-1] == 1) {
display.printMessage("You've already selected that category!");
return true;
}
return false;
}
private void computeTotalScores() {
for(int i = 0; i < nPlayers; i++) {
for(int j = 0; j < UPPER_SCORE-1; j++) scores[i][UPPER_SCORE-1] = scores[i][j];
if(scores[i][UPPER_SCORE-1] > 63) {
scores[i][UPPER_BONUS-1] = 35;
scores[i][TOTAL-1] += 35;
}
for(int j = THREE_OF_A_KIND-1; j < CHANCE; j++) scores[i][LOWER_SCORE-1] = scores[i][j];
display.updateScorecard(UPPER_SCORE,i,scores[i][UPPER_SCORE-1]);
display.updateScorecard(UPPER_BONUS,i,scores[i][UPPER_BONUS-1]);
display.updateScorecard(LOWER_SCORE,i,scores[i][LOWER_SCORE-1]);
display.updateScorecard(TOTAL,i,scores[i][TOTAL-1]);
}
}
private void determineWinner() {
int winner = 0;
for(int i = 0; i < nPlayers; i++) if(scores[winner][TOTAL-1] < scores[i][TOTAL-1]) winner = i;
display.printMessage(playerNames[winner] + " is the winner with a total score of " + scores[winner][TOTAL-1]);
}
private int nPlayers, currentPlayer;
private String[] playerNames;
private YahtzeeDisplay display;
private RandomGenerator rgen = new RandomGenerator();
private int[][] scores, used;
private int[] dice;
}