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