This is CardPile.m in view mode; [Download] [Up]
/* indent:4 tabsize:8 font:fixed-width */ #import "CardPile.h" #import <Solitaire/CardSet.h> #if defined (WIN32) #define random() rand() #define srandom(x) srand(x) #else #import <libc.h> #endif @implementation CardPile /*" Instances of this class provide low-level functionality for card games. CardPiles contain an ordered list of Card objects which can be added to, removed from, or shuffled by clients of the class. "*/ + (void) initialize /*" Sets a random seed based on the time before initializing the class. "*/ { if (self == [CardPile class]) { srandom(time(0)); } } - init /*" Calls our designated initializer #initForCardSize: with CS_SMALL as the argument. "*/ { [self initForCardSize:CS_SMALL]; return self; } - initForCardSize:(CardSize)aSize /*" Our designated initializer. aSize can be one of CS_SMALL or CS_LARGE, for small or large cards. The new pile will contain no cards. "*/ { [super init]; cardSize = aSize; cards = [[NSMutableArray allocWithZone:[self zone]] init]; return self; } - (void) setCardSize:(CardSize)aSize /*" Sets our card size. It should be one of CS_SMALL or CS_LARGE. If the current cards are of a different size than aSize they'll all be resized and recached. "*/ { if (aSize != cardSize) { // have to change all the cards to the right class Card* newCard; Card* oldCard; int i; int cardCount = [cards count]; for (i = 0; i < cardCount; i++) { oldCard = [cards objectAtIndex:i]; if (aSize == CS_SMALL) { newCard = [[SmallCard allocWithZone:[self zone]] initSuit:[oldCard suit] value:[oldCard value] faceUp:[oldCard isFaceUp]]; } else { newCard = [[Card allocWithZone:[self zone]] initSuit:[oldCard suit] value:[oldCard value] faceUp:[oldCard isFaceUp]]; } // They will be inserted into the card list which // will retain them. [cards removeObjectAtIndex:i]; [cards insertObject:newCard atIndex:i]; [newCard release]; } cardSize = aSize; } } - (CardSize) cardSize /*" Returns the current size of our cards. "*/ { return cardSize; } - (void) dealloc /*" Releases our resources (our cards). "*/ { [self empty]; [cards release]; [super dealloc]; } - (void) addCard:(Card*)aCard /*" Adds aCard to the top of our deck. "*/ { return [self insertCard:aCard at:CS_TOP]; } - (void) insertCard:(Card*)aCard at:(int)aPosition /*" Adds a card to the pile at the specified position. The constants CS_TOP and CS_BOTTOM can be used to specify the top and bottom of the pile. "*/ { if (aCard != nil) { if (aPosition == CS_TOP) { [cards addObject:aCard]; } else { [cards insertObject:aCard atIndex:aPosition]; } } } - (void) addPile:(CardPile*)aCardPile /*" Adds aCardPile to the top of our cards we already have. "*/ { return [self insertPile:aCardPile at:CS_TOP]; } - (void) addCopyOfPile:(CardPile*)aCardPile /*" Acts as a cover for #insertCopyOfCardPile:at:, but always adds cards to the top of a pile. "*/ { return [self insertCopyOfPile:aCardPile at:CS_TOP]; } - (void) insertPile:(CardPile*)aCardPile at:(int)aPosition /*" Adds another pile of cards to this pile at a specific position. The constants CS_TOP and CS_BOTTOM can be used to specify the top and bottom of the pile, respectively. "*/ { int cardIndex; if (aPosition == CS_TOP) { for (cardIndex = 0; cardIndex < [aCardPile cardCount]; cardIndex++) { [cards addObject:[aCardPile cardAtIndex:cardIndex]]; } } else { for (cardIndex = 0; cardIndex < [aCardPile cardCount]; cardIndex++) { [cards insertObject:[aCardPile cardAtIndex:cardIndex] atIndex:aPosition++]; } } } - (void) insertCopyOfPile:(CardPile*)aCardPile at:(int)aPosition /*" Adds another pile of cards to this pile at a specific position. The constants CS_TOP and CS_BOTTOM can be used to specify the top and bottom of the pile, respectively. The cards added are copies of (and independent from) the source cards. "*/ { int cardIndex; if (aPosition == CS_TOP) { for (cardIndex = 0; cardIndex < [aCardPile cardCount]; cardIndex++) { [cards addObject:[[[aCardPile cardAtIndex:cardIndex] copy] autorelease]]; } } else { for (cardIndex = 0; cardIndex < [aCardPile cardCount]; cardIndex++) { [cards insertObject:[[[aCardPile cardAtIndex:cardIndex] copy] autorelease] atIndex:aPosition++]; } } } - (void)removeCard:(Card*)aCard /*" Remove a specific card from the pile. The card's retain count will drop by one. "*/ { if (aCard != nil) { [cards removeObject:aCard]; } } - (void) addDeck /*" Adds a full deck of cards to the top of the pile, neatly ordered. "*/ { int suitCounter, valueCounter; for (valueCounter = CS_LOWVALUE; valueCounter <= CS_HIGHVALUE; valueCounter++) { for (suitCounter = CS_LOWSUIT; suitCounter <= CS_HIGHSUIT; suitCounter++) { if (cardSize == CS_SMALL) { [self insertCard:[[[SmallCard allocWithZone:[self zone]] initSuit:suitCounter value:valueCounter] autorelease] at:CS_TOP]; } else if (cardSize == CS_LARGE) { [self insertCard:[[[Card allocWithZone:[self zone]] initSuit:suitCounter value:valueCounter] autorelease] at:CS_TOP]; } } } } - (void) empty /*" Removes all our cards. "*/ { [cards removeAllObjects]; } - (void) flip /*" Turns the pile over, reversing the order of the cards and the orientation of each card. "*/ { int cardIndex; Card* tmpCard; for (cardIndex = [cards count]- 1; cardIndex >= 0; cardIndex--) { tmpCard = [[cards objectAtIndex:cardIndex] retain]; [tmpCard flip]; [cards removeObjectAtIndex:cardIndex]; [cards addObject:tmpCard]; [tmpCard release]; } } - (void) shuffle /*" Randomly re-order all card objects contained in the pile. "*/ { Card* temp; int counter; int swapIndex; int cardCount = [cards count]; for (counter = 0; counter < cardCount - 1; counter++) { // changed by erikk for more true randomness to the shuffle... swapIndex = random() % (cardCount); if (swapIndex == counter) continue; temp = [cards objectAtIndex:counter]; [cards replaceObjectAtIndex:counter withObject:[cards objectAtIndex:swapIndex]]; [cards replaceObjectAtIndex:swapIndex withObject:temp]; } } - (Card*) cardAtIndex:(int)aPosition /*" Allow a client to find out what card is at a given position in the pile. The constants CS_TOP and CS_BOTTOM can be used to specify the top and bottom of the pile, respectively. If aPosition is less than zero or larger the number of cards we have, nil is returned. "*/ { if (aPosition == CS_TOP) { aPosition = [cards count]- 1; if (aPosition == -1 || aPosition >= [cards count]) { return nil; } } return [cards objectAtIndex:aPosition]; } - (Card*) topCard /*" Returns our top card or nil if we don't have any cards. "*/ { return [self cardAtIndex:CS_TOP]; } - (Card*) dealTopCard /*" Removes our top card from the deck and returns it. If we don't have any cards then nil is returned. "*/ { Card* topCard = [self cardAtIndex:CS_TOP]; [topCard retain]; if (topCard != nil) { [self removeCard:topCard]; } return [topCard autorelease]; } - (Card*) bottomCard /*" Returns our bottom card or nil if we don't have any cards. "*/ { return [self cardAtIndex:CS_BOTTOM]; } - (int) indexOfCard:(Card*)aCard /*" Returns the index of aCard if it is in our pile. If not then NSNotFound is returned. "*/ { return (int)[cards indexOfObject:aCard]; } - (int) cardCount /*" Returns the number of cards in our pile. "*/ { return [cards count]; } - (id) initWithCoder:(NSCoder *)aDecoder /*" Unarchives a CardPile instance. "*/ { cards = [[aDecoder decodeObject] retain]; [aDecoder decodeValuesOfObjCTypes:"i", &cardSize]; return self; } - (void) encodeWithCoder:(NSCoder *)aCoder /*" Archives a CardPile instance. "*/ { [aCoder encodeObject:cards]; [aCoder encodeValuesOfObjCTypes:"i", &cardSize]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.