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