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