Assig 6
Assig 6
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.util.Random;;
/**
* Assig6 class which includes main() for creating a "Timed High-Card" game.
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*
*/
public class Assig6
{
public static void main(String[] args)
{
//Creates a new Controller that begins the game.
CardGameController gameController = new CardGameController("Build",
CardGameModel.NUM_CARDS_PER_HAND, CardGameModel.NUM_PLAYERS);
}
}
/**
* Controller class that initializes a View and a Model.
* Includes methods that control input and updates the view when data changes.
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*
*/
class CardGameController
{
private CardGameModel gameModel;
private CardGameView gameView;
private GameMouseAdapter currentMouseAdapter;
//Initializes the view and model, updating the view to the model's
specifications
public CardGameController(String gameName, int numPlayers, int numCardsPerHand)
{
gameView = new CardGameView(gameName, numCardsPerHand, numPlayers);
gameModel = new CardGameModel();
gameModel.init(this, gameView);
}
//Validates the card the user selects for the left pile
public boolean leftSelection(JLabel cardLabel)
{
int stackValue =
getValueOfCard(gameView.pnlPlayArea.getComponent(0).getName().charAt(0));
int playerValue = getValueOfCard(cardLabel.getName().charAt(0));
if(validSelection(stackValue, playerValue))
{
gameView.pnlHumanHand.remove(cardLabel);
gameView.pnlPlayArea.remove(0);
gameView.pnlPlayArea.add(cardLabel, 0);
gameView.pnlPlayArea.validate();
gameView.pnlPlayArea.repaint();
gameModel.addCardToPlayer(this);
gameView.pnlHumanHand.validate();
gameView.pnlHumanHand.repaint();
gameView.setVisible(true);
gameModel.noPlay = false;
return true;
}
else
{
final JOptionPane pane = new JOptionPane("Not a valid selection.");
final JDialog d = pane.createDialog((JFrame) null, "Try again");
d.setLocationRelativeTo(gameView.pnlComputerHand);
d.setVisible(true);
return false;
}
}
//Validates the card the user selects for the right pile
public boolean rightSelection(JLabel cardLabel)
{
int stackValue =
getValueOfCard(gameView.pnlPlayArea.getComponent(2).getName().charAt(0));
int playerValue = getValueOfCard(cardLabel.getName().charAt(0));
if(validSelection(stackValue, playerValue))
{
gameView.pnlHumanHand.remove(cardLabel);
gameView.pnlPlayArea.remove(2);
gameView.pnlPlayArea.add(cardLabel, 2);
gameView.pnlPlayArea.validate();
gameView.pnlPlayArea.repaint();
gameModel.addCardToPlayer(this);
gameView.pnlHumanHand.validate();
gameView.pnlHumanHand.repaint();
gameView.setVisible(true);
gameModel.noPlay = false;
return true;
}
else
{
final JOptionPane pane = new JOptionPane("Not a valid selection.");
final JDialog d = pane.createDialog((JFrame) null, "Try again");
d.setLocationRelativeTo(gameView.pnlComputerHand);
d.setVisible(true);
return false;
}
}
/**
* Model class that establishes the framework for the
* "Timed High-Card" game. Includes accessors and mutators
* that the Controller can use to access and change data.
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*
*/
class CardGameModel
{
// Initializes the number of cards in each hand and the number
// of players
static final int NUM_CARDS_PER_HAND = 7;
static final int NUM_PLAYERS = 2;
// Initializes the label arrays that will contain the images
// and text that will be displayed on the GUI.
public JLabel[] computerLabels = new JLabel[NUM_CARDS_PER_HAND];
public JLabel[] humanLabels = new JLabel[NUM_CARDS_PER_HAND];
public JLabel[] playedCardLabels = new JLabel[NUM_PLAYERS];
public JLabel[] playLabelText = new JLabel[NUM_PLAYERS + 2];
public boolean noPlay = false;
public int yourScore = 0;
public int computerScore = 0;
private CardGameFramework build;
private CardGameView myCardTable;
// Default constructor
public CardGameModel()
{
setCardFramework();
}
myCardTable.timerPanel.add(btnTimer);
myCardTable.timerPanel.add(lblTimer);
/** Area dedicated to the timer **/
/**
* JFrame class that controls the positioning of the panels and cards within a
* GUI.
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*/
class CardGameView extends JFrame
{
static int MAX_CARDS_PER_HAND = 56;
static int MAX_PLAYERS = 2; // for now, we only allow 2 person games
/**
* Constructor which creates a JFrame, using the parameters to determine the
* title and number of panels used
*
* @param String title, int numCardsPerHand, int numPlayers
*/
public CardGameView(String title, int numCardsPerHand, int numPlayers)
{
super(title);
pnlComputerHand = new JPanel();
pnlPlayArea = new JPanel();
pnlHumanHand = new JPanel();
timerPanel = new JPanel();
/**
* MouseAdapter class that handles how the game processes a user
* clicking on a card
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*
*/
class GameMouseAdapter extends MouseAdapter
{
private CardGameController controller;
/**
* Constructor that sets myCardTable and build
*
* @param CardTable myCardTable, CardGameFramework build
*/
public GameMouseAdapter(CardGameController controller)
{
this.controller = controller;
}
/*
* (non-Javadoc)
*
* @see java.awt.event.MouseAdapter#mousePressed(java.awt.event.MouseEvent)
*/
// Selects the card the user clicks on and
// places it into the play area
@Override
public void mousePressed(MouseEvent e)
{
final String componentName = e.getComponent().getName();
controller.processPlayerTurn(componentName);
}
/*
* (non-Javadoc)
*
* @see java.awt.event.MouseAdapter#mouseReleased(java.awt.event.MouseEvent)
*/
@Override
public void mouseReleased(MouseEvent e)
{
super.mouseReleased(e);
}
}
/**
* Class that stores images of cards into a two-dimensional array
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*/
class GUICard
{
private static Icon[][] iconCards = new ImageIcon[14][4];
// 14 = A thru K + joker
private static Icon iconBack;
static boolean iconsLoaded = false;
/**
* Card class which holds suit and value of a card
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*
*/
class Card
{
public enum Suit
{
clubs, diamonds, hearts, spades
};
/**
* Constructor - constructor for the Card Class
*
* @param value The value of the card
* @param suit The suit of the card
*/
public Card(char value, Suit suit)
{
set(value, suit);
}
/**
* Mutator that accepts the legal values established in the earlier section
*
* @param value The value of the card
* @param suit The suit of the card
* @return Returns a boolean indicating whether or not the values were set
*/
public boolean set(char value, Suit suit)
{
value = Character.toUpperCase(value);
if (isValid(value, suit))
{
this.suit = suit;
this.value = value;
this.errorFlag = false;
return true;
}
this.errorFlag = true;
return false;
}
/**
* Accessor for suit
*
* @return Returns the current card's suit
*/
public Suit getSuit()
{
return suit;
}
/**
* Accessor for value
*
* @return the value
*/
public char getValue()
{
return value;
}
/**
* Accessor for errorFlag
*
* @return the errorFlag
*/
public boolean isErrorFlag()
{
return errorFlag;
}
/**
* Stringizer method that the client can use prior to displaying the card.
*
* @return Returns a string representation of a card
*/
@Override
public String toString()
{
if (errorFlag)
return "** illegal **";
return value + " of " + suit;
}
/**
* Constructor called when client does not pass parameter
*/
public Card()
{
this('A', Card.Suit.spades);
}
/**
* Tests equality between two Card
*
* @param card A card that will be compared with current card
* @return Returns a boolean indicating whether or not they are equal
*/
public boolean equals(Card card)
{
if (card.getSuit() == this.getSuit() && card.getValue() == this.getValue()
&& card.isErrorFlag() == this.isErrorFlag())
return true;
return false;
}
/**
* Helper method that returns true or false, depending on the legality of the
* parameters
*
* @param value Character variable for value of card
* @param suit Suit variable for suit of card
* @return Returns a boolean indicating whether or not the card is valid
*/
private boolean isValid(char value, Suit suit)
{
char[] values =
{ 'A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'X' };
for (char acceptedValue : values)
{
if (acceptedValue == value)
{
return true;
}
}
return false;
}
/**
* Class that represents the cards held by a single player.
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*
*/
class Hand
{
public static final int MAX_CARDS = 100;
/**
* Default constructor
*/
public Hand()
{
myCards = new Card[MAX_CARDS];
resetHand();
}
/**
* Removes all cards from the hand (in the simplest way).
*/
public void resetHand()
{
for (int i = 0; i < numCards; i++)
{
if (myCards[i] == null)
return;
myCards[i] = null;
}
numCards = 0;
}
/**
* adds a card to the next available position in the myCards array. This is an
* object copy, not a reference copy, since the source of the Card might destroy
* or change its data after our Hand gets it -- we want our local data to be
* exactly as it was when we received it.
*
* @param card A card that will be added to the hand
* @return Returns a boolean indicating whether or not a card is added
*/
public boolean takeCard(Card card)
{
if (numCards < MAX_CARDS)
{
myCards[numCards++] = new Card(card.getValue(), card.getSuit());
return true;
}
return false;
}
/**
* Returns and removes the card in the top occupied position of the array.
*
* @return Returns a card from the top occupied position of the array
*/
public Card playCard(int index)
{
if (numCards > 0 && index < numCards)
{
/*
* Card topCard = myCards[--numCards]; //deebee modified myCards[numCards]
=
* null; return topCard;
*/
Card retCard = myCards[index];
myCards[index] = null;
return retCard;
}
return inspectCard(-1);
}
/**
* Accessor for an individual card.
*
* @return Returns a card with errorFlag = true if k is bad.
*/
public Card inspectCard(int k)
{
if (k < 0 || k >= numCards)
{
return new Card('F', Card.Suit.spades);
}
return myCards[k];
}
/**
* Accessor for numCards
*
* @return Returns the integer value for numCards
*/
public int getNumCards()
{
return numCards;
}
/**
* Stringizer method that the client can use prior to displaying the entire
* hand.
*
* @return Returns a string representation of a hand
*/
@Override
public String toString()
{
if (numCards > 0)
{
String retString = "Hand = ";
retString += "(";
for (int i = 0; i < numCards; i++)
{
retString += " " + myCards[i] + ",";
}
retString = retString.substring(0, retString.length() - 1);
retString += " )";
return retString;
}
return "Empty hand";
}
/**
* Class that represents the source of the cards for dealing and, as the game
* progresses, the place from which players can receive new cards
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*
*/
class Deck
{
public static final int MAX_CARDS = 6 * 56;
/**
* Constructor that populates the arrays and assigns initial values to members.
*
* @param numPacks int
*/
public Deck(int numPacks)
{
allocateMasterPack();
init(numPacks);
}
/**
* Default Constructor
*/
public Deck()
{
this(1);
}
/**
* Shuffles the deck of cards using the Fisher-Yates shuffle algorithm
*/
public void shuffle()
{
Random random = new Random();
for (int i = topCard; i > 0; i--)
{
int index = random.nextInt(i);
Card tempCard = cards[index];
cards[index] = cards[i];
cards[i] = tempCard;
}
}
/**
* Removes card from top of deck and returns it
*
* @return Returns a Card from the top of the deck
*/
public Card dealCard()
{
if (topCard >= 0)
{
Card dealtCard = new Card();
while (topCard-- > 0)
{
dealtCard = cards[topCard];
if (dealtCard != null)
{
break;
}
}
cards[topCard + 1] = null;
if(dealtCard != null)
return dealtCard;
}
return inspectCard(-1);
}
/**
* Accessor for card, checks if the card asked for is valid
*
* @param k An integer representing the kth card in the deck
* @return Returns the kth Card in the array cards
*/
public Card inspectCard(int k)
{
if (k < 0 || k > topCard)
{
return new Card('F', Card.Suit.spades);
}
return cards[k];
}
/**
* Re-populates the deck based on the numPacks using masterPack
*
* @param numPacks The amount of packs a deck will have
*/
public void init(int numPacks)
{
if (!setNumPacks(numPacks))
return;
cards = new Card[numPacks * 56];
int count = 0;
for (int i = 0; i < numPacks; i++)
{
for (Card card : masterPack)
{
cards[count] = card;
count++;
if (count == numPacks * 56)
break;
}
}
this.topCard = numPacks * 56 - 1;
}
/**
* Mutator method sets value of numPacks after checked for validity
*
* @param numPacks The amount of packs a deck will have
* @return Returns true if numPacks was valid and set
*/
public boolean setNumPacks(int numPacks)
{
if (numPacks * 56 > MAX_CARDS || numPacks <= 0)
return false;
this.numPacks = numPacks;
return true;
}
/**
* Builds a masterPack with all 52 cards
*/
private static void allocateMasterPack()
{
if (masterPack == null)
{
masterPack = new Card[56];
Card.Suit[] suits =
{ Card.Suit.clubs, Card.Suit.diamonds, Card.Suit.hearts,
Card.Suit.spades };
int count = 0;
for (Card.Suit suit : suits)
{
for (char value : Card.valuRanks)
{
masterPack[count] = new Card(value, suit);
count++;
}
}
}
}
/**
* Accessor for cards
*
* @return Returns an array of Card objects
*/
public Card[] getCards()
{
return this.cards;
}
/**
* Accessor for topCard
*
* @return Returns the integer topCard
*/
public int getTopCard()
{
return this.topCard;
}
// one of many ways to assure at least one full deal to all players
if (numCardsPerHand < 1 || numCardsPerHand > numPacks
* (52 - numUnusedCardsPerPack) / numPlayers)
numCardsPerHand = numPacks * (52 - numUnusedCardsPerPack) / numPlayers;
// allocate
this.unusedCardsPerPack = new Card[numUnusedCardsPerPack];
this.hand = new Hand[numPlayers];
for (k = 0; k < numPlayers; k++)
this.hand[k] = new Hand();
deck = new Deck(numPacks);
// assign to members
this.numPacks = numPacks;
this.numJokersPerPack = numJokersPerPack;
this.numUnusedCardsPerPack = numUnusedCardsPerPack;
this.numPlayers = numPlayers;
this.numCardsPerHand = numCardsPerHand;
for (k = 0; k < numUnusedCardsPerPack; k++)
this.unusedCardsPerPack[k] = unusedCardsPerPack[k];
return hand[k];
}
// add jokers
for (k = 0; k < numPacks; k++)
for (j = 0; j < 4 - numJokersPerPack; j++)
deck.removeCard(new Card('X', Card.Suit.values()[j]));
enoughCards = true;
for (k = 0; k < numCardsPerHand && enoughCards; k++)
{
for (j = 0; j < numPlayers; j++)
if (deck.getNumCards() > 0)
hand[j].takeCard(deck.dealCard());
else
{
enoughCards = false;
break;
}
}
return enoughCards;
}
// Sorts hands using the sort method
void sortHands()
{
int k;
return hand[playerIndex].takeCard(deck.dealCard());
}
}
/**
* Timer class that utilizes multithreading to initialize a counter
* that increases while Thread.sleep is active.
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*
*/
class Timer extends Thread
{
private static long seconds = 0;
private JLabel lblTimer;
private JButton btnTimer;
private boolean isSleeping;
/**
* @return the isSleeping
*/
public boolean isSleeping() {
return isSleeping;
}
/**
* @param isSleeping the isSleeping to set
*/
public void setSleeping(boolean isSleeping) {
this.isSleeping = isSleeping;
}
/**
* @return the seconds
*/
public static long getSeconds() {
return seconds;
}
/**
* @param seconds the seconds to set
*/
public static void setSeconds(long seconds) {
Timer.seconds = seconds;
}
public Timer(JLabel lblTimer, JButton btnTimer) {
this.lblTimer = lblTimer;
this.btnTimer = btnTimer;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
doNothing();
}
/**
* ActionListener class that starts and stops a timer when
* the timer button is clicked.
*
* @author Moises Bernal, Debajyoti Banerjee, and Nicholas Tippner
*
*/
class TimerButtonListener implements ActionListener
{
private Timer timer;
private JLabel lblTimer;
private JButton btnTimer;
/**
* Constructor class
*
* @param lblTimer
* @param btnTimer
*/
public TimerButtonListener(JLabel lblTimer, JButton btnTimer) {
timer = new Timer(lblTimer, btnTimer);
this.lblTimer = lblTimer;
this.btnTimer = btnTimer;
}