001 /*
002 Copyright (c) 2005 Garrett Smith
003 The MIT License
004 
005 Permission is hereby granted, free of charge, to any person obtaining a copy 
006 of this software and associated documentation files (the "Software"), to deal
007 in the Software without restriction, including without limitation the rights
008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
009 copies of the Software, and to permit persons to whom the Software is 
010 furnished to do so, subject to the following conditions:
011 
012 The above copyright notice and this permission notice shall be included in all 
013 copies or substantial portions of the Software.
014 
015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
021 THE SOFTWARE.
022 */
023 
024 // $Id: Hand.java.html,v 1.1 2005/06/14 06:50:55 gsmith Exp $
025 
026 package garrettsmith.blackjack;
027 
028 import garrettsmith.playingcards.*;
029 
030 /**
031  * Represents a player's hand of cards.
032  *
033  @author Garrett Smith, gsmith at northwestern dot edu
034  @version Blackjack v1.0
035  @since Blackjack v1.0
036  */
037 public class Hand {
038 
039     private        CardList     _cards        = null;
040     private final  Blackjack    _blackjack;
041     private        boolean      _isPlayerDone = false;
042     private        boolean      _isDealerPlayNeeded = true;
043     private        double       _wager;
044     private        SplitCounter _splitCounter = new SplitCounter();
045     private        boolean      _isEvaluationNeeded = true;
046 
047     Handfinal double wager,
048           final Blackjack blackjack,
049           final CardList cards ) {
050           _wager = wager;
051           _blackjack = blackjack;
052           _cards = cards;
053     }
054 
055     /**
056      * Returns the highest hand value without busting, if possible.  For example, a hand
057      * with a nine and an ace is scored as 20, but a hand with a nine, five, and an
058      * ace is worth 15.
059      
060      @see #getValue()
061      */
062     public
063     int getBestValue() {
064         return Blackjack.calculateBestValue_cards );
065     }
066 
067     /**
068      * Returns the value of the hand assuming all aces are worth 1.
069      *
070      @return the  value of the hand assuming any aces are worth 1
071      @see #getBestValue()
072      */
073     public
074     int getValue() {
075         return Blackjack.calculateValue_cards );
076     }
077     
078     /**
079      * Returns the player's cards that represent this hand.
080      *
081      @return <code>List</code> of <code>Card</code> objects
082      @see garrettsmith.playingcards.Card
083      */
084     public
085     CardList getCards() {
086         return _cards;
087     }
088 
089     /**
090      * Returns the card that the dealer displays to the players.
091      *
092      @return corresponding to the card that the dealer displays to the
093      *         players.
094      */
095     public
096     Card getDealerCard() {
097         return _blackjack.getDealerCard();
098     }
099 
100     /**
101      * Calculates the value of the dealer's card assuming an ace is worth 1.
102      *
103      @return the value of the dealer's card assuming an ace is worth 1
104      */
105     public
106     int getDealerValue() {
107         return Blackjack.calculateValue_blackjack.getDealerCard() );
108     }
109 
110     /**
111      * Returns whether this hand has gone over 21.
112      */
113     public
114     boolean isBusted() {
115         return Blackjack.calculateValue_cards 21 );
116     }
117 
118     /**
119      * Returns whether a double down is allowed at this point in the game.
120      *
121      @return <code>true</code> if a double down is allowed, <code>false</code>
122      *         if not
123      */
124     public
125     boolean isDoubleDownAllowed() {
126         int value = this.getValue();
127         if _cards.size() != return false;
128         if hasSplit() && !_blackjack.getRules().canDoubleAfterSplit() ) return false;
129         if ( ( value < || value > 11 && _blackjack.getRules().isDoubleDownRestricted() )
130             return false;
131         return true;
132     }
133 
134     /**
135      * Returns whether standing is allowed at this point in the game.
136      */
137     public
138     boolean isStandAllowed() {
139         return true;
140     }
141 
142     /**
143      * Returns the amount that was bet on this hand.
144      */
145     public
146     double getWager() {
147         return _wager;
148     }
149 
150     /**
151      * Returns whether <code>move</code> is allowed at this point in the game.
152      */
153     public
154     boolean isMoveAllowedMove move ) {
155         if Move.HIT.equalsmove ) ) {
156             return this.isHitAllowed();
157         }
158         else if Move.STAND.equalsmove ) ) {
159             return this.isStandAllowed();
160         }
161         else if Move.SURRENDER.equalsmove ) ) {
162             return this.isSurrenderAllowed();
163         }
164         else if Move.DOUBLE.equalsmove ) ) {
165             return this.isDoubleDownAllowed();
166         }
167         else if Move.SPLIT.equalsmove ) ) {
168             return this.isSplitAllowed();
169         }
170         else {
171             throw new IllegalStateException"unknown move: " + move.value() );
172         }
173     }
174 
175     /**
176      * Returns whether a hit is allowed at this point in the hand.
177      *
178      @return <code>true</code> if a hit is allowed, <code>false</code> if not
179      */
180     public
181     boolean isHitAllowed() {
182         return this.getValue() <= 21 );
183     }
184 
185     /**
186      * Tells whether the hand is soft.  A soft hand is where one of the cards
187      * in the hand is an ace and where ace may take the value of 1 or 11
188      * without causing the total value of the hand to exceed 21.
189      *
190      @return <code>true</code> if the hand is soft, <code>false</code> if
191      *          not
192      */
193     public
194     boolean isSoft() {
195         return Blackjack.isSoft_cards );
196     }
197 
198     /**
199      * Returns whether a split is allowed at this point in the hand.
200      *
201      @return <code>true</code> if a split is allowed, <code>false</code> if
202      *         not
203      */
204     public
205     boolean isSplitAllowed() {
206 
207         // you must have 2 cards and only 2 cards to split
208         if _cards.size() != return false;
209         Card card1 = Card _cards.get);
210         Card card2 = Card _cards.get);
211 
212         // you may only split two face cards or two identical non-face cards
213         final boolean hasTwoFaceCards = Blackjack.isNonAceFaceCardcard1 && Blackjack.isNonAceFaceCardcard2 );
214         final boolean hasIdenticalCards = card1.getValue().equalscard2.getValue() );
215         if !hasTwoFaceCards || hasIdenticalCards ) ) return false;
216 
217         // the rules may only allow one original hand to be split a few times;
218         // check to make sure that the maximum hasn't been exceeded
219         if this.getSplitCount() >= _blackjack.getRules().getMaxSplits() ) return false;
220 
221         // you may resplit aces depending on the rules
222         if hasSplit() 
223              && Card.Value.ACE.equalscard1.getValue() )
224              && ! _blackjack.getRules().isResplittingAcesAllowed() ) return false;
225 
226         // if all of these conditions have been met, a split is allowed
227         return true;
228     }
229 
230     /**
231      * Returns the state of this hand as a human-readable String.
232      */
233     public String toString() {
234         return "Hand[_wager=" + _wager + ",_isPlayerDone=" 
235             + _isPlayerDone + ",_cards=" + Blackjack.cardsToString_cards "]";
236     }
237 
238     /**
239      * Returns whether a surrender is allowed.
240      *
241      @return <code>true</code> if a surrender is allowed, <code>false</code>
242      *         if not
243      */
244     public
245     boolean isSurrenderAllowed() {
246         return _cards.size() == 2
247                  && _blackjack.getRules().canSurrenderLate()
248                  && !hasSplit() );
249     }
250 
251     /**
252      * Performs a double down.  A single, final card is issued and the
253      * player's wager is doubled.  No additional action can be taken
254      * after a double down.
255      *
256      * @returns a <code>List</code> of <code>Card</code>s that represent
257      *          the player's final hand
258      @throws NotAllowedException if a double down is not allowed
259      */
260     void doubleDown() 
261         throws NotAllowedException, NoMoreCardsException {
262         if !this.isDoubleDownAllowed() ) {
263             throw new NotAllowedException"double down" );
264         }
265         _cards.add_blackjack.getCard() );
266         _isPlayerDone = true;
267         _wager *= 2;
268     }
269 
270     boolean isInPlay() {
271         return !isPlayerDone() && !isBusted() );
272     }
273 
274     boolean isEvaluationNeeded() {
275         return _isEvaluationNeeded;
276     }
277 
278     void surrender() {
279         _isPlayerDone = true;
280         _isDealerPlayNeeded = false;
281         _isEvaluationNeeded = false;
282     }
283 
284     boolean isDealerPlayNeeded() {
285         return _isDealerPlayNeeded;
286     }
287     
288     int getSplitCount() {
289         return _splitCounter.getCount();
290     }
291 
292     /**
293      * Performs a hit.  A single card is issued.
294      *
295      * @returns a <code>List</code> of <code>Card</code> objects that
296      *          represent the player's current hand
297      @throws NotAllowedException if a hit is not allowed
298      */
299     void hit()
300         throws NotAllowedException, NoMoreCardsException {
301         if !this.isHitAllowed() ) {
302             throw new NotAllowedException"a hit is not allowed at this time");
303         }
304         _cards.add_blackjack.getCard() );
305     }
306 
307     boolean isPlayerDone() {
308         return _isPlayerDone;
309     }
310 
311     /**
312      * Performs a split.  A reference to a new, second
313      <code>Hand</code> will be returned; the 
314      <code>Hand</code> that this method was invoked on will
315      * represent the other hand.
316      *
317      * @returns representing the new, second hand resulting from the split
318      */
319     Hand split()
320         throws NotAllowedException, NoMoreCardsException {
321         if !this.isSplitAllowed() ) {
322             throw new NotAllowedException"split is not allowed" );
323         }
324         CardList newCards = new CardList();
325         newCards.add_cards.remove) );
326         _cards.add_blackjack.getCard() );
327         newCards.add_blackjack.getCard() );
328         _splitCounter.increment();
329         return new Hand_wager, _blackjack, newCards, _splitCounter );
330     }
331 
332     void stand()
333         throws NotAllowedException {
334         if !this.isStandAllowed() ) {
335             throw new NotAllowedException"stand is not allowed at this time");
336         }
337         _isPlayerDone = true;
338     }
339 
340     void addCard() {
341         _cards.add_blackjack.getCard() );
342     }
343 
344     private
345     Handdouble wager,
346           Blackjack blackjack,
347           CardList newCards,
348           SplitCounter splitCounter ) {
349         thiswager, blackjack, newCards );
350         _splitCounter = splitCounter;
351     }
352 
353     private boolean hasSplit() {
354         return _splitCounter._count > 0;
355     }
356 
357     private class SplitCounter {
358 
359         private int _count = 0;
360 
361         private SplitCounter() {}
362 
363         private int getCount() {
364             return _count;
365         }
366 
367         private void increment() {
368             _count++;
369         }
370     }
371 }