
/*

   This applet is a simple form of solitaire in which the user plays
   cards into positions in a 5-by-5 grid.  The object is to get the
   best possible poker hands in each of the five rows, five columns,
   and two diagonals.  However, the applet does not compute any kind
   of score.
   
   (The following tag makes it possible to test this applet using
    appletviewer PokerSolitaire.java:

      <applet code="PokerSolitaire.class" width=370 height=420>
      </applet>
   )

*/

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class PokerSolitaire extends Applet implements MouseListener {

   Deck deck;       // A deck that is used for dealing the cards.
   
   Card nextCard;   // If no game is in progress, then nextCard is null,
                    // and if a game is in progress then nextCard is the
                    // next card that the user has to play on the board.
                    
   int cardsPlayed; // The number of cards that have been played in a
                    // game so far.  This is zero at the beginning of the
                    // game.  Each time the user plays a card, it goes 
                    // up by one.  When it reaches 25, the game is over.

   String message;  // A message that is displayed at the bottom of
                    //   the applet.

   Image cardpics;  // An image that contains the cards.  Each card is 40-by-60
                    //    pixels.  The cards are arranged in 4 rows and 13 columns,
                    //    according to suit and value.  The order of the suits
                    //    is clubs, hearts, spades, diamonds.  The order of the
                    //    values puts ace at the beginning.  This image is
                    //    loaded from the file smallcards.gif.

   

   /**
    *  The init method of an applet is called by the system to
    *  initialize the applet.  In this case, a background color
    *  is set, the applet is set to listen for mouse events on
    *  itself, the card image is loaded, some variables are
    *  initialized, and the startGame() method is called to start
    *  the first game.
    */
   public void init() {
      setBackground( new Color(75,200,0) );
      addMouseListener(this);
      cardpics = getImage(getCodeBase(), "smallcards.gif");
      setFont( new Font("Serif", Font.BOLD, 14) );
      deck = new Deck();
      startGame();
   }
   
   
   /**
    *  This method is called at the beginning of each game to
    *  set up everything for a new game.
    */
   void startGame() {
      deck.shuffle();
      nextCard = deck.dealCard();  // The first card the user sees.
      message = "Click where you want to place card";
      cardsPlayed = 0;
      repaint();
   }
   

   /**
    *  This method is called by the mousePressed() routine when
    *  the user clicks on one of the spaces in the grid.  The 
    *  parameters give the row and column of the space where the
    *  user clicked.  (Note that this routine is called only if
    *  a game is actually in progress.)
    *    The purpose of this routine is to move nextCard onto 
    *  the grid at the specified position (but it should only do 
    *  this if that position is not already occupied by another
    *  card).  Then it either ends the game or deals the next
    *  card, depending on whether the number of cards played 
    *  has reached 25.
    */
   void playCard(int row, int col) {
      Graphics g = getGraphics();
      drawCard(g,nextCard,120+50*col,10+70*row);
      cardsPlayed++;
      if (cardsPlayed == 25) {
         nextCard = null;
         message = "Click anywhere to start a new game";
         drawMessage(g,message);
      }
      else {
         nextCard = deck.dealCard();
      }
      drawCard(g,nextCard,30,200);
      g.dispose();
   }
   

   /*
    *  The paint method is called by the system when the applet needs
    *  to be repainted.  It draws the grid of cards, a message, and
    *  the next card.
    */
   public void paint(Graphics g) {
         
      g.setColor( new Color(150,75,0) ); // Draw a border around the applet.
      g.drawRect(0,0,369,419);
      g.drawRect(1,1,367,417);
      
      g.setColor(Color.black);           // Draw nextCard.
      g.drawString("Next card",10,190);
      drawCard(g,nextCard,30,200);

      drawMessage(g,message);  // Draw message at the bottom of the applet.
      
      // Now, draw the cards that are in the grid.
      
      for (int row = 0; row < 5; row++) {
         for (int col = 0; col < 5; col++) {
               // Draw the card on the board in position (row,col).
            int x = 120 + 50*col;   // x-coord of upper left corner of card
            int y = 10 +  70*row;  // y-coord of upper left corner of card
            drawCard(g,null,x,y);
         }
      }
      
   } // end paint()
   
   
   /*
    *  Responds when the user clicks on the applet.  If the previous
    *  game is over, a new game is started.  (We can tell that the game
    *  is over because nextCard is null.)  Otherwise, if the user 
    *  clicks on the grid, the playCard() routine is called to play
    *  a card at that position on the grid.
    */
   public void mousePressed(MouseEvent evt) {
      if (nextCard == null) {
         startGame();
         return;
      }
      int x = evt.getX();  // convenient name for x-coord of mouse
      int y = evt.getY();  // convenient name for y-coord of mouse
      if (x < 120 || x > 370 || y < 10 || y > 350)
         return;
      int row = (y - 5)  / 70;
      int col = (x - 115) / 50;
      if (row >= 0 && row < 5 && col >= 0 && col < 5)
         playCard(row,col);
   }
   
   
   /*  
    *  Draw the specified message string on a blue background
    *  at the bottom of the applet.
    */
   private void drawMessage(Graphics g, String message) {
      g.setColor(new Color(220,220,255)); 
      g.fillRect(30,370,310,30);
      g.setColor( new Color(0,0,200) );
      g.drawRect(30,370,309,29);
      g.drawRect(31,371,307,27);
      if (message != null) {  // Only draw the message if message is non-null.
         FontMetrics fm = getFontMetrics(getFont());  // for centering the string
         int w = fm.stringWidth(message);     // width of message string
         g.drawString( message, 185 - w/2, 390 );
      }
   }


   /*
    *  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 blank gray space is drawn.  The cards are taken
    *  from an image file, smallcards.gif.
    */
   private void drawCard(Graphics g, Card card, int x, int y) {
       if (card == null) {  
             // Draw a blank gray space.
         g.setColor(Color.lightGray);
         g.fillRect(x,y,40,60);
         g.setColor(Color.black);
         g.drawRect(x,y,39,60);
      }
      else {
         int col = card.getValue() - 1;  // Column of the card in cardpics.
         int row = 0;                    // Row of the card in cardpics.
         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*col;
         sy = 60*row;
         g.drawImage(cardpics, x, y, x+40, y+60, 
                                 sx, sy, sx+40, sy+60, this);
      }
   }
   

   /*
    *  Return the size of the applet.  The size MUST be 370 by 420.
    *  Not meant to be called except by the system.
    */
   public Dimension getPreferredSize() {
      return new Dimension(370,420);
   }
   

   /*
    *  Other mouse routines required by the MouseListener interface.
    *  In this applet, these don't do anything.  
    */
   public void mouseClicked(MouseEvent evt) { }
   public void mouseReleased(MouseEvent evt) { }
   public void mouseEntered(MouseEvent evt) { }
   public void mouseExited(MouseEvent evt) { }


} // end class CardsDemo
