Source/Deck.m
author Jens Alfke <jens@mooseyard.com>
Wed May 28 12:47:10 2008 -0700 (2008-05-28)
changeset 8 45c82a071aca
parent 0 e9f7ba4718e1
permissions -rw-r--r--
* Got it working with latest iPhone SDK.
* Fixed some text alignment issues that showed up on PlayingCards.
* Working on persistence and move-tracking for Game.
     1 /*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
     2     http://developer.apple.com/samplecode/GeekGameBoard/
     3     Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
     4 
     5     Redistribution and use in source and binary forms, with or without modification, are permitted
     6     provided that the following conditions are met:
     7 
     8     * Redistributions of source code must retain the above copyright notice, this list of conditions
     9       and the following disclaimer.
    10     * Redistributions in binary form must reproduce the above copyright notice, this list of
    11       conditions and the following disclaimer in the documentation and/or other materials provided
    12       with the distribution.
    13 
    14     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
    15     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
    16     FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
    17     BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    18     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
    19     PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
    20     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
    21     THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    22 */
    23 #import "Deck.h"
    24 #import "Card.h"
    25 #import "Stack.h"
    26 #import "QuartzUtils.h"
    27 #import "GGBUtils.h"
    28 
    29 
    30 @interface Deck ()
    31 - (void) setCards: (NSMutableArray*)cards;
    32 - (void) x_showTopCard;
    33 @end
    34 
    35 
    36 @implementation Deck
    37 
    38 
    39 - (id) init
    40 {
    41     self = [super init];
    42     if (self != nil) {
    43         self.bounds = (CGRect){{0,0},[Card cardSize]};
    44         self.cornerRadius = 8;
    45         self.backgroundColor = kAlmostInvisibleWhiteColor;
    46         self.borderColor = kHighlightColor;
    47         self.cards = [NSMutableArray array];
    48     }
    49     return self;
    50 }
    51 
    52 - (id) initWithCardsOfClass: (Class)klass
    53 {
    54     self = [self init];
    55     if (self != nil) {
    56         // Create a full deck of cards:
    57         NSRange serials = [klass serialNumberRange];
    58         for( int i=serials.location; i<NSMaxRange(serials); i++ ) {
    59             Card *card = [[klass alloc] initWithSerialNumber: i
    60                                                     position: CGPointZero];
    61             [_cards addObject: card];
    62             [card release];
    63         }
    64         [self x_showTopCard];
    65     }
    66     return self;
    67 }
    68 
    69 
    70 - (void) dealloc
    71 {
    72     [_cards release];
    73     [super dealloc];
    74 }
    75 
    76 
    77 - (NSArray*) cards                          {return _cards;}
    78 - (void) setCards: (NSMutableArray*)cards   {setObj(&_cards,cards);}
    79 
    80 - (Card*) topCard   {return (Card*)_bit;}
    81 
    82 
    83 - (void) setBit: (Bit*)bit
    84 {
    85     NSAssert(NO,@"Don't call -setBit");
    86 }
    87 
    88 
    89 - (void) x_removeObsoleteCard: (Card*)card
    90 {
    91     if( [_cards containsObject: card] && card != _bit )
    92         RemoveImmediately(card);
    93 }
    94 
    95 
    96 /** Sync up my display with the _cards array. The last element of _cards should be shown,
    97     and no others (they shouldn't even be in the layer tree, for performance reasons.) */
    98 - (void) x_showTopCard
    99 {
   100     Card *curTopCard = [_cards lastObject];
   101     if( curTopCard != _bit ) {
   102         if( _bit ) {
   103             // Remove card that used to be the top one
   104             if( [_cards containsObject: _bit] )   // wait till new card animates on top of it
   105                 [self performSelector: @selector(x_removeObsoleteCard:) withObject: _bit afterDelay: 1.0];
   106             else
   107                 RemoveImmediately(_bit);
   108         }
   109         _bit = curTopCard;
   110         if( curTopCard ) {
   111             if( curTopCard.superlayer==self ) {
   112                 [self addSublayer: curTopCard]; // move to top
   113                 curTopCard.position = GetCGRectCenter(self.bounds);
   114             } else {
   115                 if( curTopCard.superlayer )
   116                     ChangeSuperlayer(curTopCard, self, -1);
   117                 curTopCard.position = GetCGRectCenter(self.bounds);
   118                 if( ! curTopCard.superlayer )
   119                     [self addSublayer: curTopCard];
   120             }
   121         }
   122     }
   123 }
   124 
   125 
   126 - (void) shuffle
   127 {
   128     int n = _cards.count;
   129     NSMutableArray *shuffled = [NSMutableArray arrayWithCapacity: n];
   130     for( ; n > 0; n-- ) {
   131         int i = random() % n;
   132         Card *card = [_cards objectAtIndex: i];
   133         [shuffled addObject: card];
   134         [_cards removeObjectAtIndex: i];
   135     }
   136     self.cards = shuffled;
   137     [self x_showTopCard];
   138 }
   139 
   140 
   141 - (void) flip
   142 {
   143     int n = _cards.count;
   144     NSMutableArray *flipped = [NSMutableArray arrayWithCapacity: n];
   145     while( --n >= 0 ) {
   146         Card *card = [_cards objectAtIndex: n];
   147         card.faceUp = ! card.faceUp;
   148         [flipped addObject: card];
   149     }
   150     self.cards = flipped;
   151     [self x_showTopCard];
   152 }
   153 
   154 
   155 - (void) addCard: (Card*)card
   156 {
   157     [_cards addObject: card];
   158     [self x_showTopCard];
   159 }
   160 
   161 - (void) addCardAtBottom: (Card*)card
   162 {
   163     [_cards insertObject: card atIndex: 0];
   164     if( _cards.count==1 )
   165         [self x_showTopCard];
   166 }
   167 
   168 - (void) addCardAtRandom: (Card*)card
   169 {
   170     // Put the card at some random location, but _not_ on top (unless the deck is empty.)
   171     int n = _cards.count;
   172     if( n==0 )
   173         [self addCard: card];
   174     else
   175         [_cards insertObject: card atIndex: (random() % (n-1))];
   176 }
   177 
   178 
   179 - (void) addCards: (NSArray*)cards
   180 {
   181     [_cards addObjectsFromArray: cards];
   182     [self x_showTopCard];
   183 }
   184 
   185 
   186 - (BOOL) addBit: (Bit*)bit
   187 {
   188     if( [bit isKindOfClass: [DraggedStack class]] ) {
   189         // Convert a DraggedStack back to a group of Cards:
   190         for( Bit *subBit in [(DraggedStack*)bit bits] )
   191             if( ! [self addBit: subBit] )
   192                 return NO;
   193         return YES;
   194     } else if( [bit isKindOfClass: [Card class]] ) {
   195         [self addCard: (Card*)bit];
   196         return YES;
   197     } else
   198         return NO;
   199 }
   200 
   201 
   202 - (Card*) removeTopCard
   203 {
   204     Card *card = [_cards lastObject];
   205     if( card ) {
   206         [[card retain] autorelease];
   207         [_cards removeLastObject];
   208         _bit = nil;   // keep it from being removed from superlayer by _showTopCard
   209         [self x_showTopCard];
   210     }
   211     return card;
   212 }
   213 
   214 
   215 - (NSArray*) removeAllCards
   216 {
   217     NSArray *removedCards = [[_cards retain] autorelease];
   218     self.cards = [NSMutableArray array];
   219     [removedCards makeObjectsPerformSelector: @selector(removeFromSuperlayer)];
   220     [self x_showTopCard];
   221     return removedCards;
   222 }
   223 
   224 
   225 #pragma mark -
   226 #pragma mark BITHOLDER INTERFACE:
   227 
   228 
   229 - (Bit*) canDragBit: (Bit*)bit
   230 {
   231     if( bit == _bit ) {
   232         [bit retain];
   233         [_cards removeObjectIdenticalTo: bit];
   234         _bit = nil;   // prevent the card from being removed from my layer
   235         [self x_showTopCard];
   236         return [bit autorelease];
   237     } else
   238         return nil;
   239 }
   240 
   241 - (void) cancelDragBit: (Bit*)bit
   242 {
   243     [self addCard: (Card*)bit];
   244 }
   245 
   246 - (void) draggedBit: (Bit*)bit to: (id<BitHolder>)dst   {}
   247 
   248 
   249 - (void) setHighlighted: (BOOL)h    
   250 {
   251     [super setHighlighted: h];
   252     self.borderWidth = h ?6 :0;
   253 }
   254 
   255 - (BOOL) canDropBit: (Bit*)bit atPoint: (CGPoint)point
   256 {
   257     return [bit isKindOfClass: [Card class]] || [bit isKindOfClass: [DraggedStack class]];
   258 }
   259 
   260 - (BOOL) dropBit: (Bit*)bit atPoint: (CGPoint)point
   261 {
   262     return [self addBit: bit];
   263 }
   264 
   265 
   266 
   267 @end