Fixed: An exception in the Go game if you mouse down on the board but then drag to the captured-pieces area and release the mouse.
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.
5 Redistribution and use in source and binary forms, with or without modification, are permitted
6 provided that the following conditions are met:
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.
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.
26 #import "QuartzUtils.h"
31 - (void) setCards: (NSMutableArray*)cards;
32 - (void) x_showTopCard;
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];
52 - (id) initWithCardsOfClass: (Class)klass
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];
77 - (NSArray*) cards {return _cards;}
78 - (void) setCards: (NSMutableArray*)cards {setObj(&_cards,cards);}
80 - (Card*) topCard {return (Card*)_bit;}
83 - (void) setBit: (Bit*)bit
85 NSAssert(NO,@"Don't call -setBit");
89 - (void) x_removeObsoleteCard: (Card*)card
91 if( [_cards containsObject: card] && card != _bit )
92 RemoveImmediately(card);
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
100 Card *curTopCard = [_cards lastObject];
101 if( curTopCard != _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];
107 RemoveImmediately(_bit);
111 if( curTopCard.superlayer==self ) {
112 [self addSublayer: curTopCard]; // move to top
113 curTopCard.position = GetCGRectCenter(self.bounds);
115 if( curTopCard.superlayer )
116 ChangeSuperlayer(curTopCard, self, -1);
117 curTopCard.position = GetCGRectCenter(self.bounds);
118 if( ! curTopCard.superlayer )
119 [self addSublayer: curTopCard];
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];
136 self.cards = shuffled;
137 [self x_showTopCard];
143 int n = _cards.count;
144 NSMutableArray *flipped = [NSMutableArray arrayWithCapacity: n];
146 Card *card = [_cards objectAtIndex: n];
147 card.faceUp = ! card.faceUp;
148 [flipped addObject: card];
150 self.cards = flipped;
151 [self x_showTopCard];
155 - (void) addCard: (Card*)card
157 [_cards addObject: card];
158 [self x_showTopCard];
161 - (void) addCardAtBottom: (Card*)card
163 [_cards insertObject: card atIndex: 0];
164 if( _cards.count==1 )
165 [self x_showTopCard];
168 - (void) addCardAtRandom: (Card*)card
170 // Put the card at some random location, but _not_ on top (unless the deck is empty.)
171 int n = _cards.count;
173 [self addCard: card];
175 [_cards insertObject: card atIndex: (random() % (n-1))];
179 - (void) addCards: (NSArray*)cards
181 [_cards addObjectsFromArray: cards];
182 [self x_showTopCard];
186 - (BOOL) addBit: (Bit*)bit
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] )
194 } else if( [bit isKindOfClass: [Card class]] ) {
195 [self addCard: (Card*)bit];
202 - (Card*) removeTopCard
204 Card *card = [_cards lastObject];
206 [[card retain] autorelease];
207 [_cards removeLastObject];
208 _bit = nil; // keep it from being removed from superlayer by _showTopCard
209 [self x_showTopCard];
215 - (NSArray*) removeAllCards
217 NSArray *removedCards = [[_cards retain] autorelease];
218 self.cards = [NSMutableArray array];
219 [removedCards makeObjectsPerformSelector: @selector(removeFromSuperlayer)];
220 [self x_showTopCard];
226 #pragma mark BITHOLDER INTERFACE:
229 - (Bit*) canDragBit: (Bit*)bit
233 [_cards removeObjectIdenticalTo: bit];
234 _bit = nil; // prevent the card from being removed from my layer
235 [self x_showTopCard];
236 return [bit autorelease];
241 - (void) cancelDragBit: (Bit*)bit
243 [self addCard: (Card*)bit];
246 - (void) draggedBit: (Bit*)bit to: (id<BitHolder>)dst {}
249 - (void) setHighlighted: (BOOL)h
251 [super setHighlighted: h];
252 self.borderWidth = h ?6 :0;
255 - (BOOL) canDropBit: (Bit*)bit atPoint: (CGPoint)point
257 return [bit isKindOfClass: [Card class]] || [bit isKindOfClass: [DraggedStack class]];
260 - (BOOL) dropBit: (Bit*)bit atPoint: (CGPoint)point
262 return [self addBit: bit];