/*
This program is a simple card game. The user sees a card and
tries to predict whether the next card will be higher or
lower. Aces are the lowest-valued cards. If the user makes
three correct predictions, the user wins. If not, the
user loses.
This program is almost the same as the applet, HighLowGUI2.java,
modified to use a JFrame instead of a JApplet. As a demonstration,
a WindowListener has been added to ask whether the user really
wants to quit, when the user closes the window.
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class HighLowFrame extends JFrame
{
Image cardImages; // This will be an image that contains pictures
// of all the playing cards. It is provided
// as a parameter to the constructor of this
// class of this class and is used in the
// drawCard method in nested class HighLowCanvas.
// (The images are stored in a file named
// "smallcards.gif".)
boolean runStandAlone; // This is set to true in the main routine,
// to indicate that the frame is being run
// as a stand-alone program (rather than being
// opened by an applet, for example). If this
// variable is true when the user closes the
// window, then System.exit() will be called
// to end the program.
public static void main(String[] args)
{
// Main program simply opens a frame belonging
// to this class, and sets the variable "runStandAlone"
// in that frame to true. The image file for the
// cards is loaded using a "Toolkit" and is provided
// as a parameter to the constructor.
Image cards = Toolkit.getDefaultToolkit().getImage("smallcards.gif");
HighLowFrame game = new HighLowFrame(cards);
game.runStandAlone = true;
}
public HighLowFrame(Image cards)
{
// The constructor. The parameter must be an image
// containing the card images. I've done things this
// way because images have to be loaded in different
// ways in applets and in stand-alone programs.
// A HighLowCanvas occupies the CENTER position of the layout.
// On the bottom is a panel that holds three buttons. The
// HighLowCanvas object listens for ActionEvents from the
// buttons and does all the real work of the program.
super("High Low Card Game"); // Call constructor to give
// a title to the window.
cardImages = cards;
setBackground( new Color(130,50,40) );
HighLowCanvas board = new HighLowCanvas();
getContentPane().add(board, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
buttonPanel.setBackground( new Color(220,200,180) );
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
JButton higher = new JButton( "Higher" );
higher.addActionListener(board);
buttonPanel.add(higher);
JButton lower = new JButton( "Lower" );
lower.addActionListener(board);
buttonPanel.add(lower);
JButton newGame = new JButton( "New Game" );
newGame.addActionListener(board);
buttonPanel.add(newGame);
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
// Closing is taken care of by the following WindowListener,
// so we don't want any default close operation.
addWindowListener( new WindowAdapter()
{
// This window listener responds when the user
// clicks the window's close box by giving the
// user a chance to change his mind.
public void windowClosing(WindowEvent evt)
{
int response = JOptionPane.showConfirmDialog(null,
"Do you really want to quit?");
if (response == JOptionPane.YES_OPTION)
{
dispose();
if (runStandAlone)
System.exit(0);
}
}
} );
pack(); // Make the frame just large enough to hold
// the components that it contains.
setResizable(false); // Don't allow the user to change
// the size of the frame.
setLocation(150,100);
show(); // Make the frame appear on the screen.
} // end constructor
class HighLowCanvas extends JPanel implements ActionListener
{
// A nested class that displays the cards and does all the work
// of keeping track of the state and responding to user events.
Deck deck; // A deck of cards to be used in the game.
Hand hand; // The cards that have been dealt.
String message; // A message drawn on the canvas, which changes
// to reflect the state of the game.
boolean gameInProgress; // Set to true when a game begins and to false
// when the game ends.
Font bigFont; // Font that will be used to display the message.
Font smallFont; // Font that will be used to draw the cards.
HighLowCanvas()
{
// Constructor. Creates fonts, sets the foreground and
// background colors, and starts the first game.
// ALSO SETS PREFERRED SIZE so that the size can be
// used when the frame is packed.
setPreferredSize(new Dimension(310,120));
setBackground( new Color(0,120,0) );
setForeground( Color.green );
smallFont = new Font("SansSerif", Font.PLAIN, 12);
bigFont = new Font("Serif", Font.BOLD, 14);
doNewGame();
} // end constructor
public void actionPerformed(ActionEvent evt)
{
// Respond when the user clicks on a button by calling
// the appropriate procedure. Note that the canvas is
// registered as a listener in frame's constructor.
String command = evt.getActionCommand();
if (command.equals("Higher"))
doHigher();
else if (command.equals("Lower"))
doLower();
else if (command.equals("New Game"))
doNewGame();
} // end actionPerformed()
void doHigher()
{
// Called by actionPerformmed() when user clicks "Higher" button.
// Check the user's prediction. Game ends if user guessed
// wrong or if the user has made three correct predictions.
if (gameInProgress == false)
{
// If the game has ended, it was an error to click "Higher",
// So set up an error message and abort processing.
message = "Click \"New Game\" first!";
repaint();
return;
}
hand.addCard( deck.dealCard() ); // Deal a card to the hand.
int cardCt = hand.getCardCount();
Card thisCard = hand.getCard( cardCt - 1 ); // Card just dealt.
Card prevCard = hand.getCard( cardCt - 2 ); // The previous card.
if ( thisCard.getValue() < prevCard.getValue() )
{
gameInProgress = false;
message = "Too bad! You lose.";
}
else if ( thisCard.getValue() == prevCard.getValue() )
{
gameInProgress = false;
message = "Too bad, you lose on ties!";
}
else if ( cardCt == 4)
{
gameInProgress = false;
message = "OK! You win!";
}
else
{
message = "Right! Try for " + cardCt + ".";
}
repaint();
} // end doHigher()
void doLower()
{
// Called by actionPerformmed() when user clicks "Lower" button.
// Check the user's prediction. Game ends if user guessed
// wrong or if the user has made three correct predictions.
if (gameInProgress == false)
{
// If the game has ended, it was an error to click "Lower",
// So set up an error message and abort processing.
message = "Click \"New Game\" first!";
repaint();
return;
}
hand.addCard( deck.dealCard() ); // Deal a card to the hand.
int cardCt = hand.getCardCount();
Card thisCard = hand.getCard( cardCt - 1 ); // Card just dealt.
Card prevCard = hand.getCard( cardCt - 2 ); // The previous card.
if ( thisCard.getValue() > prevCard.getValue() )
{
gameInProgress = false;
message = "Too bad! You lose.";
}
else if ( thisCard.getValue() == prevCard.getValue() )
{
gameInProgress = false;
message = "Too bad, you lose on ties.";
}
else if ( cardCt == 4)
{
gameInProgress = false;
message = "Great! You win!";
}
else
{
message = "Right! Try for " + cardCt + ".";
}
repaint();
} // end doLower()
void doNewGame()
{
// Called by the constructor, and called by actionPerformed() if
// the use clicks the "New Game" button. Start a new game.
if (gameInProgress)
{
// If the current game is not over, it is an error to try
// to start a new game.
message = "Finish the game first!";
repaint();
return;
}
deck = new Deck(); // Create the deck and hand to use for this game.
hand = new Hand();
deck.shuffle();
hand.addCard( deck.dealCard() ); // Deal the first card into the hand.
message = "Is the next card higher or lower?";
gameInProgress = true;
repaint();
} // end doNewGame()
public void paintComponent(Graphics g)
{
// This method draws the message at the bottom of the
// canvas, and it draws all of the dealt cards spread out
// across the canvas. If the game is in progress, an
// extra card is dealt representing the card to be dealt next.
super.paintComponent(g);
g.setFont(bigFont);
g.drawString(message,10,getSize().height-10);
g.setFont(smallFont);
int cardCt = hand.getCardCount();
for (int i = 0; i < cardCt; i++)
drawCard(g, hand.getCard(i), 30 + i * 70, 15);
if (gameInProgress)
drawCard(g, null, 30 + cardCt * 70, 15);
} // end paintComponent()
void drawCard(Graphics g, Card card, int x, int y)
{
// Draws a card as a 40 by 60 rectangle with
// upper left corner at (x,y). The card is drawn
// in the graphics context g. If card is null, then
// a face-down card is drawn. The cards are taken
// from an image file, smallcards.gif.
if (card == null)
{
// Draw a face-down card
g.setColor(Color.blue);
g.fillRect(x,y,40,60);
g.setColor(Color.white);
g.drawRect(x+3,y+3,33,53);
g.drawRect(x+4,y+4,31,51);
}
else
{
int row = 0;
switch (card.getSuit())
{
case Card.CLUBS: row = 0; break;
case Card.HEARTS: row = 1; break;
case Card.SPADES: row = 2; break;
case Card.DIAMONDS: row = 3; break;
}
int sx, sy; // coords of upper left corner in the source image.
sx = 40*(card.getValue() - 1);
sy = 60*row;
g.drawImage(cardImages, x, y, x+40, y+60,
sx, sy, sx+40, sy+60, this);
}
}
} // end nested class HighLowCanvas
} // end class HighLowFrame
Back to Lesson 33 Examples
Back to Java Main Page