Source/Deck.m
changeset 0 e9f7ba4718e1
child 4 d781b00f3ed4
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Source/Deck.m	Fri Mar 07 11:43:02 2008 -0800
     1.3 @@ -0,0 +1,267 @@
     1.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
     1.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
     1.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
     1.7 +
     1.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
     1.9 +    provided that the following conditions are met:
    1.10 +
    1.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
    1.12 +      and the following disclaimer.
    1.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
    1.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
    1.15 +      with the distribution.
    1.16 +
    1.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
    1.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
    1.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
    1.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    1.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
    1.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
    1.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
    1.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.25 +*/
    1.26 +#import "Deck.h"
    1.27 +#import "Card.h"
    1.28 +#import "Stack.h"
    1.29 +#import "QuartzUtils.h"
    1.30 +#import "GGBUtils.h"
    1.31 +
    1.32 +
    1.33 +@interface Deck ()
    1.34 +- (void) setCards: (NSMutableArray*)cards;
    1.35 +- (void) x_showTopCard;
    1.36 +@end
    1.37 +
    1.38 +
    1.39 +@implementation Deck
    1.40 +
    1.41 +
    1.42 +- (id) init
    1.43 +{
    1.44 +    self = [super init];
    1.45 +    if (self != nil) {
    1.46 +        self.bounds = CGRectMake(0,0,kCardWidth,kCardHeight);
    1.47 +        self.cornerRadius = 8;
    1.48 +        self.backgroundColor = kAlmostInvisibleWhiteColor;
    1.49 +        self.borderColor = kHighlightColor;
    1.50 +        self.cards = [NSMutableArray array];
    1.51 +    }
    1.52 +    return self;
    1.53 +}
    1.54 +
    1.55 +- (id) initWithCardsOfClass: (Class)klass
    1.56 +{
    1.57 +    self = [self init];
    1.58 +    if (self != nil) {
    1.59 +        // Create a full deck of cards:
    1.60 +        NSRange serials = [klass serialNumberRange];
    1.61 +        for( int i=serials.location; i<NSMaxRange(serials); i++ ) {
    1.62 +            Card *card = [[klass alloc] initWithSerialNumber: i
    1.63 +                                                    position: CGPointZero];
    1.64 +            [_cards addObject: card];
    1.65 +            [card release];
    1.66 +        }
    1.67 +        [self x_showTopCard];
    1.68 +    }
    1.69 +    return self;
    1.70 +}
    1.71 +
    1.72 +
    1.73 +- (void) dealloc
    1.74 +{
    1.75 +    [_cards release];
    1.76 +    [super dealloc];
    1.77 +}
    1.78 +
    1.79 +
    1.80 +- (NSArray*) cards                          {return _cards;}
    1.81 +- (void) setCards: (NSMutableArray*)cards   {setObj(&_cards,cards);}
    1.82 +
    1.83 +- (Card*) topCard   {return (Card*)_bit;}
    1.84 +
    1.85 +
    1.86 +- (void) setBit: (Bit*)bit
    1.87 +{
    1.88 +    NSAssert(NO,@"Don't call -setBit");
    1.89 +}
    1.90 +
    1.91 +
    1.92 +- (void) x_removeObsoleteCard: (Card*)card
    1.93 +{
    1.94 +    if( [_cards containsObject: card] && card != _bit )
    1.95 +        RemoveImmediately(card);
    1.96 +}
    1.97 +
    1.98 +
    1.99 +/** Sync up my display with the _cards array. The last element of _cards should be shown,
   1.100 +    and no others (they shouldn't even be in the layer tree, for performance reasons.) */
   1.101 +- (void) x_showTopCard
   1.102 +{
   1.103 +    Card *curTopCard = [_cards lastObject];
   1.104 +    if( curTopCard != _bit ) {
   1.105 +        if( _bit ) {
   1.106 +            // Remove card that used to be the top one
   1.107 +            if( [_cards containsObject: _bit] )   // wait till new card animates on top of it
   1.108 +                [self performSelector: @selector(x_removeObsoleteCard:) withObject: _bit afterDelay: 1.0];
   1.109 +            else
   1.110 +                RemoveImmediately(_bit);
   1.111 +        }
   1.112 +        _bit = curTopCard;
   1.113 +        if( curTopCard ) {
   1.114 +            if( curTopCard.superlayer==self ) {
   1.115 +                [self addSublayer: curTopCard]; // move to top
   1.116 +                curTopCard.position = GetCGRectCenter(self.bounds);
   1.117 +            } else {
   1.118 +                if( curTopCard.superlayer )
   1.119 +                    ChangeSuperlayer(curTopCard, self, -1);
   1.120 +                curTopCard.position = GetCGRectCenter(self.bounds);
   1.121 +                if( ! curTopCard.superlayer )
   1.122 +                    [self addSublayer: curTopCard];
   1.123 +            }
   1.124 +        }
   1.125 +    }
   1.126 +}
   1.127 +
   1.128 +
   1.129 +- (void) shuffle
   1.130 +{
   1.131 +    int n = _cards.count;
   1.132 +    NSMutableArray *shuffled = [NSMutableArray arrayWithCapacity: n];
   1.133 +    for( ; n > 0; n-- ) {
   1.134 +        int i = random() % n;
   1.135 +        Card *card = [_cards objectAtIndex: i];
   1.136 +        [shuffled addObject: card];
   1.137 +        [_cards removeObjectAtIndex: i];
   1.138 +    }
   1.139 +    self.cards = shuffled;
   1.140 +    [self x_showTopCard];
   1.141 +}
   1.142 +
   1.143 +
   1.144 +- (void) flip
   1.145 +{
   1.146 +    int n = _cards.count;
   1.147 +    NSMutableArray *flipped = [NSMutableArray arrayWithCapacity: n];
   1.148 +    while( --n >= 0 ) {
   1.149 +        Card *card = [_cards objectAtIndex: n];
   1.150 +        card.faceUp = ! card.faceUp;
   1.151 +        [flipped addObject: card];
   1.152 +    }
   1.153 +    self.cards = flipped;
   1.154 +    [self x_showTopCard];
   1.155 +}
   1.156 +
   1.157 +
   1.158 +- (void) addCard: (Card*)card
   1.159 +{
   1.160 +    [_cards addObject: card];
   1.161 +    [self x_showTopCard];
   1.162 +}
   1.163 +
   1.164 +- (void) addCardAtBottom: (Card*)card
   1.165 +{
   1.166 +    [_cards insertObject: card atIndex: 0];
   1.167 +    if( _cards.count==1 )
   1.168 +        [self x_showTopCard];
   1.169 +}
   1.170 +
   1.171 +- (void) addCardAtRandom: (Card*)card
   1.172 +{
   1.173 +    // Put the card at some random location, but _not_ on top (unless the deck is empty.)
   1.174 +    int n = _cards.count;
   1.175 +    if( n==0 )
   1.176 +        [self addCard: card];
   1.177 +    else
   1.178 +        [_cards insertObject: card atIndex: (random() % (n-1))];
   1.179 +}
   1.180 +
   1.181 +
   1.182 +- (void) addCards: (NSArray*)cards
   1.183 +{
   1.184 +    [_cards addObjectsFromArray: cards];
   1.185 +    [self x_showTopCard];
   1.186 +}
   1.187 +
   1.188 +
   1.189 +- (BOOL) addBit: (Bit*)bit
   1.190 +{
   1.191 +    if( [bit isKindOfClass: [DraggedStack class]] ) {
   1.192 +        // Convert a DraggedStack back to a group of Cards:
   1.193 +        for( Bit *subBit in [(DraggedStack*)bit bits] )
   1.194 +            if( ! [self addBit: subBit] )
   1.195 +                return NO;
   1.196 +        return YES;
   1.197 +    } else if( [bit isKindOfClass: [Card class]] ) {
   1.198 +        [self addCard: (Card*)bit];
   1.199 +        return YES;
   1.200 +    } else
   1.201 +        return NO;
   1.202 +}
   1.203 +
   1.204 +
   1.205 +- (Card*) removeTopCard
   1.206 +{
   1.207 +    Card *card = [_cards lastObject];
   1.208 +    if( card ) {
   1.209 +        [[card retain] autorelease];
   1.210 +        [_cards removeLastObject];
   1.211 +        _bit = nil;   // keep it from being removed from superlayer by _showTopCard
   1.212 +        [self x_showTopCard];
   1.213 +    }
   1.214 +    return card;
   1.215 +}
   1.216 +
   1.217 +
   1.218 +- (NSArray*) removeAllCards
   1.219 +{
   1.220 +    NSArray *removedCards = [[_cards retain] autorelease];
   1.221 +    self.cards = [NSMutableArray array];
   1.222 +    [removedCards makeObjectsPerformSelector: @selector(removeFromSuperlayer)];
   1.223 +    [self x_showTopCard];
   1.224 +    return removedCards;
   1.225 +}
   1.226 +
   1.227 +
   1.228 +#pragma mark -
   1.229 +#pragma mark BITHOLDER INTERFACE:
   1.230 +
   1.231 +
   1.232 +- (Bit*) canDragBit: (Bit*)bit
   1.233 +{
   1.234 +    if( bit == _bit ) {
   1.235 +        [bit retain];
   1.236 +        [_cards removeObjectIdenticalTo: bit];
   1.237 +        _bit = nil;   // prevent the card from being removed from my layer
   1.238 +        [self x_showTopCard];
   1.239 +        return [bit autorelease];
   1.240 +    } else
   1.241 +        return nil;
   1.242 +}
   1.243 +
   1.244 +- (void) cancelDragBit: (Bit*)bit
   1.245 +{
   1.246 +    [self addCard: (Card*)bit];
   1.247 +}
   1.248 +
   1.249 +- (void) draggedBit: (Bit*)bit to: (id<BitHolder>)dst   {}
   1.250 +
   1.251 +
   1.252 +- (void) setHighlighted: (BOOL)h    
   1.253 +{
   1.254 +    [super setHighlighted: h];
   1.255 +    self.borderWidth = h ?6 :0;
   1.256 +}
   1.257 +
   1.258 +- (BOOL) canDropBit: (Bit*)bit atPoint: (CGPoint)point
   1.259 +{
   1.260 +    return [bit isKindOfClass: [Card class]] || [bit isKindOfClass: [DraggedStack class]];
   1.261 +}
   1.262 +
   1.263 +- (BOOL) dropBit: (Bit*)bit atPoint: (CGPoint)point
   1.264 +{
   1.265 +    return [self addBit: bit];
   1.266 +}
   1.267 +
   1.268 +
   1.269 +
   1.270 +@end