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
|