1 import java.applet.*;
    2 import java.awt.*;
    3 import java.awt.event.*;
    4 import java.lang.Math;
    5 
    6 /**
    7  * Applet to show BlackJack odds
    8  * Creation date: (02/5/2002 10:16:43 AM)
    9  * @author: Andrew Freed, arf132@psu.edu
   10  */
   11 
   12 /*
   13 Development of this applet was sponsored by the Penn State Fund for 
   14 Excellence in Learning and Teaching (FELT), project "Java-based 
   15 Teaching of Mathematics in Information Sciences and Technology",
   16 supervised by Frank Ritter and David Mudgett.
   17 */
   18 
   19 public class BlackjackApplet extends Applet {
   20   private Label  lblInfo    = new Label("Odds of busting: ");
   21   private Label   lblUser    = new Label("User hand:");
   22   private Button   btnDeal     = new Button("Deal");
   23   private Button  btnHit    = new Button("Hit!");
   24   private Button  btnStand    = new Button("Stand");
   25   private Label   lblUserHand    = new Label("<Your hand>");
   26   private Label  lblSum    = new Label("Sum: ");
   27 
   28   private int deck[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
   29   private int numDecks = 1; //Change this to simulate more decks
   30   private int cardsDealt = 0; //To figure out when it is time to reshuffle
   31   private int numHighAces = 0; //To help counting functions determine hand value/bust odds
   32 
   33 //Deal two random cards to user's hand
   34 private void deal()
   35 {
   36   //Re-shuffle if half of deck is used
   37   if( cardsDealt > (numDecks * 52 /2) )
   38     initDeck();
   39 
   40   String newHand = "";
   41   String newCard;
   42 
   43   lblUserHand.setText("");
   44 
   45   for( int i=1; i<=2; i++)
   46   {
   47     newCard = getRandomCard();
   48     newHand = addNewCard(newHand, newCard);
   49   }
   50 
   51   btnHit.setEnabled(true);
   52   btnStand.setEnabled(true);
   53   btnDeal.setEnabled(false);
   54   btnHit.requestFocus();
   55 
   56   lblUserHand.setText(newHand);
   57   calculateBustOdds(newHand);
   58 
   59 }
   60 
   61 //Add one card to the user's hand
   62 private void hit()
   63 {
   64   String myHand = lblUserHand.getText();
   65   String newCard = getRandomCard();
   66   myHand = addNewCard(myHand, newCard);
   67 
   68   lblUserHand.setText(myHand);
   69   calculateBustOdds(myHand);
   70 
   71 }
   72 
   73 //End a user's turn, calculate card sum.  Prepare for next deal.
   74 private void stand()
   75 {
   76   String myHand = lblUserHand.getText();
   77   int sum = sumCards(myHand);
   78   if( sum <= 21 )
   79     lblInfo.setText("Safe play... but would you have won with " + sum + "?");
   80   else
   81     lblInfo.setText("Tough luck, but such is gambling...");
   82 
   83   btnHit.setEnabled(false);
   84   btnStand.setEnabled(false);
   85   btnDeal.setEnabled(true);
   86   btnDeal.requestFocus();
   87 }
   88 
   89 //Counts enough Aces as ones to stay below 21
   90 private int sumCards(String myCards)
   91 {
   92   int result = highSum(myCards);
   93 
   94   while( result > 21 && numHighAces > 0 )
   95   {
   96     result -= 10;
   97     numHighAces--;
   98   }
   99 
  100   return result;
  101 }
  102 
  103 //Counts all Aces as ones -- this helps find probability for busting
  104 // Example: 9 A sums to 20, but has zero probability of busting
  105 private int lowSumCards(String myCards)
  106 {
  107   int result = highSum(myCards);
  108   
  109   while( numHighAces > 0 )
  110   {
  111     result -= 10;
  112     numHighAces--;
  113   }
  114 
  115   return result;
  116 }
  117 
  118 //This should never be called directly.  Either call sumCards or lowSumCards.
  119 //Both of those functions handle the "lowering" of the Ace cards.
  120 //For a hand like A A A this function will return 33. lowSumCards would return 3 and
  121 // sumCards would return 13 on the same hand
  122 private int highSum(String myCards)
  123 {
  124   int result = 0;
  125   numHighAces = 0;
  126 
  127   //Read all values from user hand
  128   for( int idx = 0; idx < myCards.length(); idx++ )
  129   {
  130     String myCard = myCards.substring(idx, idx+1);
  131 
  132     //Hand will contain spaces, skip these
  133     if( myCard.equals(" ") )
  134     {
  135       continue;
  136     }
  137 
  138     else if( myCard.equals("J") || myCard.equals("Q") || 
  139          myCard.equals("K") )
  140       result += 10;
  141 
  142     //If you read in a "1", it is part of a "10".  Thus skip the next character
  143     else if( myCard.equals("1") )
  144     {
  145       result += 10;
  146       idx++;
  147     }
  148 
  149     else if( myCard.equals("A") )
  150     {
  151       result += 11;
  152       numHighAces++;
  153     }
  154     
  155     //If it is a 2-9, we can just add this
  156     else
  157       result += Integer.parseInt(myCard);
  158   }
  159 
  160   return result;
  161 }
  162 
  163 private void calculateBustOdds(String myHand)
  164 {
  165   //For the busting odds, we want the lowest possible sum, with each A=1
  166   int sum = lowSumCards(myHand);
  167   if (sum > 21)
  168   {
  169     lblInfo.setText("You bust!");
  170     lblSum.setText("Sum: " + sum);
  171     btnHit.setEnabled(false);
  172     btnStand.setEnabled(false);
  173     btnDeal.setEnabled(true);
  174     btnDeal.requestFocus();
  175     return;
  176   }
  177   else if (sum == 21)
  178   {
  179     lblInfo.setText("21! You win!");
  180     lblSum.setText("Sum: 21");
  181     btnHit.setEnabled(false);
  182     btnStand.setEnabled(false);
  183     btnDeal.setEnabled(true);
  184     btnDeal.requestFocus();
  185     return;
  186   }
  187   else if (sum < 12)
  188   {
  189     // It is possible that we have a 10-value card and an ace.
  190     // The low sum is then 11, but the high sum is 21, Blackjack!
  191     sum = sumCards(myHand);
  192     
  193     //Need to check if we have Blackjack
  194     if( sum == 21 )
  195     {
  196       lblInfo.setText("21! You win!");
  197       lblSum.setText("Sum: 21");
  198       btnHit.setEnabled(false);
  199       btnStand.setEnabled(false);
  200       btnDeal.setEnabled(true);
  201       btnDeal.requestFocus();
  202       return;
  203     }
  204 
  205     //Standard case, we still cannot bust because our low value is 11 or less
  206     //But we still want to display the sum counting as many high-aces as possible
  207     lblSum.setText("Sum: " + sum);
  208     lblInfo.setText("You cannot bust on your next card!");
  209     btnHit.requestFocus();
  210     return;
  211   }
  212   else // between 12 and 20, most common case
  213   {
  214     lblSum.setText("Sum: " + sum);
  215     btnHit.requestFocus();
  216   }
  217 
  218   // Margin is between 1 and 9
  219   int margin = 21 - sum;
  220   int totalCards = 0;    // remaining cards
  221   int availCards = 0;    // safe cards
  222 
  223   //You can always safely get an Ace
  224   totalCards += deck[0];
  225   availCards += deck[0];
  226 
  227   //You can never safely add a 10, J, Q, K since margin always < 10
  228   totalCards += deck[9];
  229   totalCards += deck[10];
  230   totalCards += deck[11];
  231   totalCards += deck[12];
  232 
  233   //Rememeber that deck[1] = "2", deck[2] = "3", etc by the array storage of the deck
  234   for( int idx = 1; idx <= 8; idx++ )
  235   {
  236     if( idx + 1 <= margin )
  237       availCards += deck[idx];
  238 
  239     //Always add to total cards
  240     totalCards += deck[idx];
  241   }
  242 
  243   double odds = ( (double) availCards ) /double) totalCards);
  244   String output = "There are " + availCards + " out of the " + 
  245         totalCards + " remaining cards with which you will not bust. ";
  246   output += ("P = " + doubleToString(odds));
  247 
  248   lblInfo.setText(output);
  249 
  250   return;
  251 }
  252   
  253 //Simple function to add one new card to a hand
  254 private String addNewCard(String myHand, String myCard)
  255 {
  256   String result = myHand;
  257   if( myCard == "0" )
  258     result += (" 10 ");
  259   else
  260     result += (" " + myCard + " ");
  261 
  262   return result;
  263 }
  264 
  265 private String getRandomCard()
  266 {
  267   String result = "";
  268 
  269   // myRand is between 0 and 12, inclusive
  270   int myRand = -1;
  271   boolean newCard = false;
  272 
  273   while(!newCard)
  274   {
  275     myRand = (int) ( 13 * java.lang.Math.random() );
  276     
  277     //With the given random value, make sure there is a card of that type available!
  278     if( deck[myRand] >= 0 )
  279       newCard = true;
  280   }
  281 
  282   deck[myRand]--;
  283   cardsDealt++;
  284   int cardNum = myRand;
  285 
  286   switch( cardNum )
  287   {
  288     case 0:  result = "A"; break;
  289     case 9:  result = "0"; break; // deck[9] is count of "10" cards
  290     case 10:  result = "J"; break;
  291     case 11:  result = "Q"; break;
  292     case 12:  result = "K"; break;
  293 
  294     //[1] = "2", [2] = "3", etc.
  295     default:  result = Integer.toString(++cardNum);
  296   }
  297 
  298   return result;
  299 }
  300 
  301 //This function takes a floating point value and returns a string with two decimal digits
  302 private String doubleToString( double myNum )
  303 {
  304   String result = "";
  305   String buf = "" + myNum + "";
  306 
  307   //Seems that this should always be the case, given myNum is float.
  308   int pos = buf.indexOf(".");
  309   if( pos != -1)
  310   {
  311     if( buf.length() - pos > 3 )
  312       result = buf.substring(0, buf.indexOf(".") + 3);
  313     else
  314       result = buf;
  315   }
  316   else
  317   {
  318     result = buf;
  319   }
  320 
  321   return result;
  322 }
  323 
  324 //Shuffles the deck.  Notice that this is actually just resetting the deck array,
  325 //so that all the card values are available again. Cards are instead selected in 
  326 //random order by the getRandomCard() function.
  327 private void initDeck()
  328 {
  329   lblInfo.setText("Shuffling...");
  330   for( int i=0; i < 13; i++ )
  331   {
  332     deck[i] = 4 * numDecks;
  333   }
  334   
  335   btnHit.setEnabled(false);
  336   btnStand.setEnabled(false);
  337   btnDeal.setEnabled(true); // should already be enabled...
  338   lblInfo.setText("Shuffling complete.  Please hit 'Deal' to get a new hand");
  339 
  340   btnDeal.requestFocus();
  341 }
  342 
  343 /**
  344  * Initializes the applet.
  345  */
  346 public void init() {
  347   try {
  348     super.init();
  349     setName("BlackjackApplet");
  350     setLayout(null);
  351     setSize(500, 350);
  352 
  353     lblInfo.setBounds(10,70,480,30);
  354     lblUser.setBounds(10, 10, 70, 30);
  355     btnDeal.setBounds(300, 160, 50, 30);
  356     btnHit.setBounds(300, 190, 50, 30);
  357     btnStand.setBounds(300, 220, 50, 30);
  358     lblUserHand.setBounds(80, 10, 200, 30);
  359     lblSum.setBounds(10,30,100,30);
  360     
  361     add(lblInfo);
  362     add(lblUser);
  363     add(btnDeal);
  364     add(btnHit);
  365     add(btnStand);
  366     add(lblUserHand);
  367     add(lblSum);
  368 
  369 
  370       btnDeal.setActionCommand("btnDeal");
  371       btnDeal.addActionListener(new java.awt.event.ActionListener(){
  372         public void actionPerformed(java.awt.event.ActionEvent e)
  373         {
  374           deal();
  375         }
  376       });
  377       btnHit.setActionCommand("btnHit");
  378       btnHit.addActionListener(new java.awt.event.ActionListener(){
  379         public void actionPerformed(java.awt.event.ActionEvent e)
  380         {
  381           hit();
  382         }
  383       });
  384       btnStand.setActionCommand("btnStand");
  385       btnStand.addActionListener(new java.awt.event.ActionListener(){
  386         public void actionPerformed(java.awt.event.ActionEvent e)
  387         {
  388           stand();
  389         }
  390       });
  391 
  392     initDeck();
  393 
  394   } catch (java.lang.Throwable Exc) {
  395     handleException(Exc);
  396   }
  397 }
  398     
  399 /**
  400  * Called whenever the part throws an exception.
  401  * @param exception java.lang.Throwable
  402  */
  403 private void handleException(java.lang.Throwable exception) {
  404   //Currently exceptions are not handled since the applet does not have
  405   //stdout or stderr available to it.
  406 }
  407 
  408 //Main function allows you to run this applet as an application
  409 /**
  410  * main entrypoint - starts the part when it is run as an application
  411  * @param args java.lang.String[]
  412  */
  413 public static void main(java.lang.String[] args) {
  414   try {
  415     Frame frame = new java.awt.Frame();
  416     BlackjackApplet aBlackjackApplet;
  417     Class iiCls = Class.forName("BlackjackApplet");
  418     ClassLoader iiClsLoader = iiCls.getClassLoader();
  419     aBlackjackApplet = (BlackjackApplet)java.beans.Beans.instantiate(iiClsLoader,"BlackjackApplet");
  420     frame.add("Center", aBlackjackApplet);
  421     frame.setSize(aBlackjackApplet.getSize());
  422     frame.addWindowListener(new java.awt.event.WindowAdapter() {
  423       public void windowClosing(java.awt.event.WindowEvent e) {
  424         System.exit(0);
  425       };
  426     });
  427     frame.show();
  428     java.awt.Insets insets = frame.getInsets();
  429     frame.setSize(frame.getWidth() + insets.left + insets.right, frame.getHeight() + insets.top + insets.bottom);
  430     frame.setVisible(true);
  431   } catch (Throwable exception) {
  432     System.err.println("Exception occurred in main() of java.applet.Applet");
  433     exception.printStackTrace(System.out);
  434   }
  435 }
  436 
  437 }
  438 
HTML generated by Java2Html, © 2000 Think Tank Ltd, Douglas, Isle Of Man. All rights reserved