package YahtzeePackage;
import java.awt.event.*;
import java.util.Arrays;
import javax.swing.*;
/** Represents the group of 5 dice in a Yahtzee game, also the roll button
Contains the DieButton and Die objects */
public class Dice implements YahtzeeConstants
{
private Die[] dice; // array of dice
private int[] sortedDice; // sorted array of dice values
private DieButton[] button; // array of buttons that show dice and can be held
private JButton rollButton; // the button that rolls the dice
private JPanel panel; // panel for holding buttons and dice
private JFrame frame; // reference to the frame
private Timer timer; // used for die animation
private int timerCount; // user for die animation
public Dice(JFrame frame)
{
dice = new Die[5];
sortedDice = new int[5];
button = new DieButton[5];
this.frame = frame;
DiceListener listener = new DiceListener();
timer = new Timer(TIMER_ROLL_DELAY, new TimerListener());
panel = (JPanel)frame.add(new JPanel());
panel.setLayout(null);
panel.setBounds(DICE_X, DICE_Y, ROLL_X + ROLL_WIDTH, ROLL_HEIGHT);
for (int i = 0; i < 5; i++) { // create dice
dice[i] = new Die();
button[i] = new DieButton(i, this, listener, panel);
}
rollButton = (JButton)panel.add(new JButton());
rollButton.setBounds(ROLL_X, 0, ROLL_WIDTH, ROLL_HEIGHT);
rollButton.setBackground(ROLL_COLOR);
rollButton.addActionListener(listener);
rollButton.addKeyListener(listener);
rollButton.setFocusPainted(false);
rollButton.setFont(ROLL_FONT);
setToFirstRoll();
disableRolling(); // they need to start a game first
} // end Dice()
public class DiceListener implements ActionListener, KeyListener {
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) { }
public void keyPressed(KeyEvent e) // looks for number keys or enter
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
rollButton.doClick();
else
switchHold(e.getKeyChar() - '1'); // 0 - 4
}
public void actionPerformed(ActionEvent e)
{
if (Player.getCurrentPlayer() == null) return;
if (e.getSource() == rollButton) { // roll button hit
if (isAllHeld()) return;
Player player = Player.getCurrentPlayer();
player.rollDice();
if (player.getNumRolls() < 3)
rollButton.setText(ROLL_STRING[player.getNumRolls()]); // set to Roll 2 or Roll 3
else
rollButton.setEnabled(false); // they have no more rolls
}
else { // hold button hit
for (int i = 0; i < 5; i++)
if (button[i].isSource(e))
switchHold(i);
}
}
} // end Dice Listener
/** Sets all dice to unheld, sets roll button to first roll, hides dice icons */
final public void setToFirstRoll()
{
for (Die d: dice)
d.held = false;
rollButton.setEnabled(true);
rollButton.setText(ROLL_STRING[0]);
rollButton.requestFocusInWindow();
updateButtons();
}
/** Called when the game has finished, disables holding and roll button */
final public void disableRolling()
{ rollButton.setEnabled(false); }
/** Center's the dice panel within the frame */
public void center()
{
int fWidth = frame.getWidth();
int pWidth = panel.getWidth();
panel.setBounds((fWidth - pWidth) / 2 - 8, DICE_Y, pWidth, panel.getHeight());
}
/** Calls animate on each die button */
public void animate(int tCount) {
for (DieButton d: button)
d.animate(tCount); }
/** Updates the die buttons to reflect any changes */
public void updateButtons() {
for (DieButton d: button)
d.update();
}
/** Calls animate on each die */
public void setAnimate(boolean on)
{
if (on && !timer.isRunning()) { // do we need to start the timer
timer.start();
timerCount = 0;
}
else if (!on && timer.isRunning()) { // stop the timer?
timer.stop();
updateButtons();
if (getXofaKind(5) > 0) // if there's a yahtzee
Player.getCurrentPlayer().yahtzee();
}
}
public class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e)
{
if(++timerCount < TIMER_ROLL_END)
animate(timerCount);
else
setAnimate(false);
} }
/** Calls roll() on each die, and then sorts the array into ascending order */
public void roll()
{
setAnimate(true);
for (int i = 0; i < 5; i++)
sortedDice[i] = dice[i].roll();
Arrays.sort(sortedDice);
}
/** Returns a value from 1 to 6 */
public int getValue(int i)
{ return dice[i].value; }
/** Returns true if dice[i] is being held */
public boolean isHeld(int i)
{ return dice[i].held; }
/** Returns true if all die are held */
public boolean isAllHeld()
{
for (Die d: dice)
if (!d.held)
return false;
return true;
}
/** Switches the hold value of a die */
public void switchHold(int i)
{
if (i < 0 || i > 4) return; // check out of bounds
setAnimate(false);
int num = (Player.getCurrentPlayer()).getNumRolls();
if (num == 1 || num == 2)
dice[i].held = !dice[i].held;
button[i].update(); // move die to proper position
}
/**********************************************************************************************************************************************/
// All these functions are for determining a players score
/* Returns how many dice are showing x */
private int getOccurence(int x)
{
int sum = 0;
for (Die d: dice)
if (d.value == x)
sum++;
return sum;
}
/** Returns which number is on the most amount of dice, 0 if there is none */
private int mostCommonNumber()
{
int[] amount = new int[7];
int leader = 0; // amount[0] = 0
for (Die d: dice) amount[d.value]++;
for (int i = 1; i <= 6; i++) {
if (amount[i] > amount[leader])
leader = i;
else if (amount[leader] == amount[i])
leader = 0;
}
return leader;
}
/** Returns the sum of all the dice */
public int sumAll() {
int sum = 0;
for (Die d: dice)
sum += d.value;
return sum;
}
/** Returns the score for an x slot, i.e if x=3 then it returns the 3's score */
public int getXScore(int x)
{ return (getOccurence(x) * x); }
/** Returns the score for a x of a kind - 3, 4, and 5(Yahtzee) */
public int getXofaKind(int x)
{ return (getOccurence(mostCommonNumber()) >= x ? sumAll() : 0); }
/** Returns the score for a full house if they have it. Note: array must be sorted */
public int getFullHouse()
{
int a = sortedDice[0];
int b = sortedDice[4];
if (sortedDice[1] != a || sortedDice[3] != b || a == b)
return 0;
else if (sortedDice[2] != a && sortedDice[2] != b)
return 0;
else
return 25;
}
/** Returns the score for a small straight (4 in a row). Note: array must be sorted */
public int getSmallStraight()
{
boolean[] x = new boolean[6];
for (int i = 0; i < 5; i++)
x[sortedDice[i] - 1] = true;
// small straight is either (0,1,2,3), (2,3,4,5), or (1,2,3,4)
if (x[2] && x[3] && ( (x[0] && x[1]) || (x[4] && x[5]) || (x[1] && x[4]) ))
return 30;
else
return 0;
}
/** Returns the score for a large straight (5 in a row). Note: array must be sorted */
public int getLargeStraight()
{
int num = sortedDice[0];
for (int i = 1; i < 5; i++)
if (sortedDice[i] != ++num)
return 0;
return 40;
}
/** Returns the chance score, which is the sum of all dice */
public int getChance()
{ return sumAll(); }
/** Represents a single die */
public class Die
{
public int value; // current value (showing face)
public boolean held; // if its being held
public Die() {
value = 1;
held = false; }
public int roll() {
if (!held) value = (int)(Math.random() * 6) + 1;
return value; }
}
} // end Dice class