Card Games and Deck Preparation, Methods/Objects the wrong way to do it?

Discussion in 'Mac Programming' started by MorphingDragon, Jun 6, 2010.

  1. MorphingDragon macrumors 603

    MorphingDragon

    Joined:
    Mar 27, 2009
    Location:
    The World Inbetween
    #1
    Im designing a game engine for use with card games. (Ill post the source-code when I get back home) I have an NSObject Subclass called Card, which has the variables

    Code:
    //(S)pades, (C)lubs, (H)earts, (D)iamonds, (J)oker
    char type;
    
    //(1)Ace ... (11)Joker, (12)Queen, (13)King (0)Joker
    int number;
    
    //2 of Clubs, King of Spades etc
    NSString *cardName;
    
    and the method
    Code:
    -(void)setVariablesWithType:(char)t number:(int)n name:(NSString *)name {
    
    type = t;
    number = n;
    
    switch (name) {
     switch code to set full name of cards
    }
    
    
    Anyway, I have a subclass of NSMutableArray called Deck with the methods (void)prepare; (Adds 54 cards to the deck) and (Card *)drawRandomCard; (Avoids the need for a rather complicated shuffle method, and deletes the card from the array)

    I didn't quite think through the how I was going to implement the prepare method.

    I thought of using some loops, [variable copy], a temp card object; and some preprocessor macros... But doesn't copy only copy the pointer and arrays only hold pointers? (Making the temporary object style useless)

    Am I approaching this the wrong way?
     
  2. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #2
    Just saying that subclassing an NSMutableArray for something like this is most likely not the right thing to do. Your deck of cards is not a mutable array. It should be its own class, derived from NSObject, and possibly have a member of type NSMutableArray or implement its data storage any other way you like.

    If you make it a subclass of NSMutableArray, then I can use all NSMutableArray methods, and most likely the results will be nonsense.

    And an NSArray holds reference counted objects. So you create an NSCard object (reference count 1), add it to the NSArray (reference count 2), and the drawRandomCard removes it from the array (reference count 1) and hands it to you (still reference count 1); you are now the owner.
     
  3. MorphingDragon thread starter macrumors 603

    MorphingDragon

    Joined:
    Mar 27, 2009
    Location:
    The World Inbetween
    #3
    I get up to preparing the deck then I get stuck at how to get what I want without a '10' being returned.
    Code:
    //
    //  Card.h
    //  CardDeck
    //
    //  Created by Robert Litchfield on 6/06/10.
    //  Copyright 2010 __MyCompanyName__. All rights reserved.
    //
    
    #import <Cocoa/Cocoa.h>
    
    
    @interface Card : NSObject {
    	//(S)pades, (C)lubs, (H)earts, (D)iamonds, (J)oker
    	char suit;
    	
    	//(1)Ace ... (11)Joker, (12)Queen, (13)King (0)Joker
    	int number;
    	
    	//2 of Clubs, King of Spades etc
    	NSMutableString *cardName;
    }
    @property (readwrite, copy) NSMutableString *cardName;
    @property (readwrite) int number;
    @property (readwrite) char suit;
    
    -(void)setVariablesWithType:(char)t number:(int)n;
    -(void)print;
    -(void)dealloc;
    @end
    
    
    Code:
    //
    //  Card.m
    //  CardDeck
    //
    //  Created by Robert Litchfield on 6/06/10.
    //  Copyright 2010 MissingBoxStudio. All rights reserved.
    //
    
    #import "Card.h"
    
    
    @implementation Card
    	
    @synthesize cardName;
    @synthesize number;
    @synthesize suit;
    
    -(void)setVariablesWithType:(char)t number:(int)n{
    	suit = t;
    	number = n;
    
    	NSString *tempString = [[NSString alloc] init];
    	NSString *temp2String = [[NSString alloc] init];
    	
    	//Merge Strings
    	//Preferbly, find a way to use less lines of code. 
    	
    	switch (n) {
    		case 1:
    			tempString = @"Ace of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 2:
    			tempString = @"2 of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 3:
    			tempString = @"3 of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 4:
    			tempString = @"4 of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 5:
    			tempString = @"5 of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 6:
    			tempString = @"6 of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 7:
    			tempString = @"7 of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 8:
    			tempString = @"8 of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 9:
    			tempString = @"9 of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 10:
    			tempString = @"10 of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 11:
    			tempString = @"Jack of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 12:
    			tempString = @"Queen of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 13:
    			tempString = @"King of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		default:
    			tempString = @"Joker";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    	}
    	
    	switch (t) {
    		case 's':
    			temp2String = @"Spades";
    			[cardName appendString:temp2String];
    			break;
    		case 'c':
    			temp2String = @"Clubs";
    			[cardName appendString:temp2String];
    			break;
    		case 'd':
    			temp2String = @"Diamonds";
    			[cardName appendString:temp2String];
    			break;
    		case 'h':
    			temp2String = @"Hearts";
    			[cardName appendString:temp2String];
    			break;
    		default:
    			break;
    	}
    	[tempString release];
    	[temp2String release];
    	
    	[self print];
    }
    
    -(void)print{
    	//For debugging purposes
    	NSLog(@"%c, %i, %@", suit, number, cardName);
    }
    -(void)dealloc{
    	[cardName release];
    	[super dealloc];
    }
    @end
    
    Code:
    //
    //  Deck.h
    //  CardDeck
    //
    //  Created by Robert Litchfield on 7/06/10.
    //  Copyright 2010 MissingBoxStudio. All rights reserved.
    //
    
    #import <Cocoa/Cocoa.h>
    #import "Card.h"
    
    
    @interface Deck : NSObject {
    	NSMutableArray *deck;
    	NSMutableArray *usedPile;
    }
    
    -(void)prepare;
    -(Card *)drawRandomCard;
    -(void)printDeck;
    -(void)printUsedPile;
    @end
    
    
    Code:
    //
    //  Deck.m
    //  CardDeck
    //
    //  Created by Robert Litchfield on 7/06/10.
    //  Copyright 2010 __MyCompanyName__. All rights reserved.
    //
    
    #import "Deck.h"
    
    
    @implementation Deck
    
    -(void)prepare {
    	int i;
    	char suit;
    	
    	[deck release];
    	[usedPile release];
    		
        Card *tempCard = [[Card alloc] init];
    	suit = 's';
    	for (i = 1; i <= 13; ++i) {
    		[tempCard setVariablesWithType:suit number:i];
    		//Add object by copying tempCard
    	}
    	//[tempCard release];
    }
    -(void)printDeck {
    	NSLog(@"Printing Deck");
    }
    @end
    
    Maybe I should be more clearer at what I want to do...

    I want to quickly create an array of 54 Card objects with correct suit, number, name etc.
     
  4. JoshDC macrumors regular

    Joined:
    Apr 8, 2009
    #4
    How about making the suit and value a couple of enums?

    Code:
    typedef enum Suit {
    	Spade = 0,
    	Heart = 1,
    	Club = 2,
    	Diamond = 3,
    } Suit;
    
    Similarly for the values. Then just two loops:

    Code:
    for (int suit = 0; suit < 4; suit++) {
    	for (int value = 1; value < 14; value++) {
    		[tempCard setVariablesWithType:suit number:value];
    	}
    }
    
    I don't quite understand why you're storing the cardName. Wouldn't it be easier to have it a read only property that gets calculated when it's read?

    Also the value switch statement could be:

    Code:
    	switch (n) {
    		case 1:
    			tempString = @"Ace of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 11:
    			tempString = @"Jack of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 12:
    			tempString = @"Queen of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		case 13:
    			tempString = @"King of ";
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    		default:
    			tempString = [NSString stringWithFormat:@"%i of", n];
    			cardName = [NSMutableString stringWithString:tempString];
    			break;
    	}
    
    
    I'm ignoring the jokers for simplicity, shouldn't be hard to add them though. A joker can be red or black if it matters to your game.
     
  5. Littleodie914 macrumors 68000

    Littleodie914

    Joined:
    Jun 9, 2004
    Location:
    Rochester, NY
    #5
    Note: All this code is untested, I don't have Xcode with me right now. :)

    I have a few suggestions. First, I don't think that your Card type should be mutable. You should be able to create a card using an init method like so:

    Code:
    - (id)initWithSuit:(char)suit number:(int)number;
    This avoids the copy calls altogether, though I want to mention that the copy method does copy the actual object. The object returned from copy should be completely independent from the original, and should be treated as a newly-allocated and newly-initialized object that you are responsible for retaining/releasing.

    Your cardName method is a bit obfuscated, as all instances of NSObject respond to a method:

    Code:
    - (NSString *)description;
    You should probably move your cardName code into description.

    Finally, I think it would be helpful to maintain Suit as its own class, simply so it can provide its own implementation of the description method as well. Then, in your description method in Card, you could save a large amount of code by implementing it as:
    Code:
    - (NSString *)description {
        NSString *cardName = [[NSString alloc] initWithFormat:@"%d of %@", number, [suit description]];
        
        return [cardName autorelease];
    }
    
    Finally, don't implement accessor methods (getters/setters) that require more than one variable. Eg. write 'setNumber' and 'setSuit', not 'setNumber andSuit'. What if you only want to set one of those values? A good time (really the only good time) to provide an object with all of the information it needs is at initialization, hence the init method I mentioned above.

    Good luck, happy coding! :)

    Edit: In the description implementation of Card, I forgot to include handling cases when the 'number' field is not intended to represent a number at all. Perhaps in addition to making Suit its own class, you should also create a FaceValue class that encapsulates the type of card. Then FaceValue could implement description and return @"2" for number types, and @"Queen" for other types.
     
  6. MorphingDragon thread starter macrumors 603

    MorphingDragon

    Joined:
    Mar 27, 2009
    Location:
    The World Inbetween
    #6
    "cardName" is only temporary, and will be removed when I'm happy with the backend logic. Its just being used to help readability of the outputs.

    ---

    Ill try some of those things tomorrow, its 3AM here. @_@.

    The setter/getter methods for the variables are created by the @synthesize directive.
     
  7. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #7
    Hint to simplify your switch statement:

    Code:
    static NSArray* cardNames = [[NSArray arrayWithObjects:
      @"Joker", @"Ace", @"2", @"3", ... 
      @"Jack", @"Queen", @"King", nil ] retain];
    
    The first hint should have been the fact that the case values were simple sequential numbers, and each case had virtually identical repeated code. That's exactly the kind of pattern that should scream "Simplify me!".

    By the way, the red-hilited fragment is a lying comment:
    Code:
    	//(1)Ace ... [COLOR="Red"](11)Joker[/COLOR], (12)Queen, (13)King (0)Joker
    
    And you're doing the memory management wrong in your implementation of setVariablesWithType:number:.
     
  8. lloyddean macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #8
    Seems to me you're making this way more compicated than it needs to be.

    A 'card' can simply be a 'char'

    A 'deck' an array of 52 'card's.

    Init the 'deck' array with the values 0 - 51.

    Shuffle the 'deck' with a single loop iterating every entry, 0 - 51, in the 'deck' and swapping it with another 'card' at a random in position, 0 - 51, within the 'deck'.

    The face value and suite are simple to derive.

    suit = card / 13; // produces 0 - 3
    face = card % 13; // produces 0 - 12

    Suite names can also be looked up in a simple array:

    const char* suiteName[] = { "C", "D", "H", "S" };

    Card value names can be looked up in simple array:

    const char* faceName[] = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };

    So cards are nothing more than a number 0 - 51 and everything else derived from the card numer.
     
  9. MorphingDragon thread starter macrumors 603

    MorphingDragon

    Joined:
    Mar 27, 2009
    Location:
    The World Inbetween
    #9
    (For me) Its easier to work with Cocoa when I have Foundation objects. Plus having an object say 'Player' with an array for their Hand, their Pile in some games could make some of the logic easier. (I say could as Im at my parent's house and only have a laptop running GNUStep under linux and cant really test the code)

    then you could say [player1/self/whatever drawCard:[deck drawRandomCard]];

    And why create a complicated loop to shuffle the array when you could just draw it randomly on the spot.

    int i = random() % [deck size//Whatever the proper ArrayLength method is];
    return [deck objectAtIndex:i];

    Then if the deck runs out, you can use arrayWithArray: to replace the deck with the used pile.
     
  10. MorphingDragon thread starter macrumors 603

    MorphingDragon

    Joined:
    Mar 27, 2009
    Location:
    The World Inbetween
    #10
    New code (Mostly works :d)

    Code:
    //
    //  Card.h
    //  CardDeck
    //
    //  Created by Robert Litchfield on 6/06/10.
    //  Copyright 2010 MissingBoxStudio. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface Card : NSObject {
    	//(S)pades, (C)lubs, (H)earts, (D)iamonds, (J)oker
    	char suit;
    	//(1)Ace ... (11)Jack, (12)Queen, (13)King (0)Joker
    	int number;
    }
    @property (readwrite) int number;
    @property (readwrite) char suit;
    
    -(id)initWithSuit:(char)t number:(int)n;
    -(void)setNumber:(int)i andSuit:(char)c;
    -(void)print;
    @end
    
    Code:
    //
    //  Card.m
    //  CardDeck
    //
    //  Created by Robert Litchfield on 6/06/10.
    //  Copyright 2010 MissingBoxStudio. All rights reserved.
    //
    
    #import "Card.h"
    
    @implementation Card
    	
    @synthesize number;
    @synthesize suit;
    
    -(id)initWithSuit:(char)t number:(int)n{
    	//Initilaise Card Object
    	[super init];
    	
    	//Set Variables
    	suit = t;
    	number = n;
    	
    	return self;
    }
    -(void)setNumber:(int)i andSuit:(char)c {
    	suit = c;
    	number = i;
    }
    -(void)print{
    	//For debugging purposes
    	NSLog(@"Card: %c, %i, %@", suit, number, [self description]);
    }	
    -(NSString *)description{
    	//For debugging purposes
    	
    	NSString *cardName = [[NSString alloc] init];
    	NSString *numberName = [[NSString alloc] init];
    	NSString *suitName = [[NSString alloc] init];
    	
    	//Generate Card Name
    	switch ([self number]) {
    		case 0:
    			numberName = [NSString stringWithString:@"Joker"];
    			break;
    		case 1:
    			numberName = [NSString stringWithString:@"Ace of "];
    			break;
    		case 11:
    			numberName = [NSString stringWithString:@"Jack of "];
    			break;
    		case 12:
    			numberName = [NSString stringWithString:@"Queen of "];
    			break;
    		case 13:
    			numberName = [NSString stringWithString: @"King of "];
    			break;
    		default:
    			numberName = [NSString stringWithFormat:@"%i of ", [self number]];
    			break;
    	}	
    	
    	switch ([self suit]) {
    		case 'j':
    			suitName = [NSString stringWithString:@"Joker"];
    			break;
    		case 's':
    			suitName = [NSString stringWithString:@"Spades"];
    			break;
    		case 'c':
    			suitName = [NSString stringWithString:@"Clubs"];
    			break;
    		case 'd':
    			suitName = [NSString stringWithString:@"Diamonds"];
    			break;
    		case 'h':
    			suitName = [NSString stringWithString:@"Hearts"];
    			break;
    		default:
    			break;
    	}
    	
    	cardName = [numberName stringByAppendingString:suitName];
    	
    	[numberName release];
    	[suitName release];
    	
    	//I get double release error trying to release cardName... help?
    	return cardName;
    }
    @end
    
    Code:
    //
    //  Deck.h
    //  CardDeck
    //
    //  Created by Robert Litchfield on 7/06/10.
    //  Copyright 2010 MissingBoxStudio. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import "Card.h"
    
    @interface Deck : NSObject {
    	NSMutableArray *deck;
    	NSMutableArray *graveyard;
    }
    
    -(void)prepare;
    -(Card *)drawRandomCard;
    -(void)printDeck;
    -(void)printGraveyard;
    @end
    
    Code:
    //
    //  Deck.m
    //  CardDeck
    //
    //  Created by Robert Litchfield on 7/06/10.
    //  Copyright 2010 MissingBoxStudio. All rights reserved.
    //
    
    #import "Deck.h"
    
    @implementation Deck
    
    -(id)init{
        if ((self = [super init])) {
    		srandom(time(NULL));
    		
    		deck = [[NSMutableArray alloc] initWithCapacity:54];
    		graveyard = [[NSMutableArray alloc] initWithCapacity:54];
        }
        return self;
    }
    -(void)dealloc {
    		
    	NSLog(@"Releasing Arrays");
    	[deck release];
    	[graveyard release];
    	
    	
    	NSLog(@"Deallocating");
    	[super dealloc];
    }
    -(void)prepare {
    	//Destroy current Deck arrays if any
    	[deck removeAllObjects];
    	[graveyard removeAllObjects];
    	
    	//Prepare new deck
    	
    	int i;
    	char c;
    	
    	for (i = 1, c = 's'; i <= 13; ++i) { 
    		[deck addObject:[[Card alloc] initWithSuit:c number:i]];
    	}
    	for (i = 1, c = 'c'; i <= 13; ++i) { 
    		[deck addObject:[[Card alloc] initWithSuit:c number:i]];
    	}
    	for (i = 1, c = 'd'; i <= 13; ++i) { 
    		[deck addObject:[[Card alloc] initWithSuit:c number:i]];
    	}
    	for (i = 1, c = 'h'; i <= 13; ++i) { 
    		[deck addObject:[[Card alloc] initWithSuit:c number:i]];
    	}
    	for (i = 1, c = 'j'; i <= 2; ++i) { 
    		[deck addObject:[[Card alloc] initWithSuit:c number:0]];
    	}	
    	
    	[self printDeck];
    	
    }
    -(void)printDeck {
    	int i;
    	for (i = 0; i < [deck count]; ++i ) {
    		NSLog(@"Deck: %@", [[deck objectAtIndex:i] description]);
    	}
    }
    -(void)printGraveyard {
    	int i;
    	for (i = 0; i < [graveyard count]; ++i ) {
    		NSLog(@"Graveyard: %@", [[graveyard objectAtIndex:i] description]);
    	}
    }
    -(Card *)drawRandomCard {
    	int i =  random() % [deck count];
    	
    	Card *temp = [deck objectAtIndex:i];
    	[deck removeObjectAtIndex:i];
    
    	NSLog(@"Drew %@", [temp description]);
    	
    	return temp;
    }
    @end
    
    
    Im having two problems,

    When creating the Description string, trying to autorelease cardName returns a double release error.

    I also have this strange error appearing, when deallocating a Deck object and when it is listing the contents of the deck.

    Code:
    
    The Debugger has exited with status 0.
    [Session started at 2010-06-07 21:52:40 +1200.]
    2010-06-07 21:52:40.790 CardDeck[8643:10b] Deck: Ace of Spades
    2010-06-07 21:52:40.797 CardDeck[8643:10b] Deck: 2 of Spades
    2010-06-07 21:52:40.800 CardDeck[8643:10b] Deck: 3 of Spades
    2010-06-07 21:52:40.803 CardDeck[8643:10b] Deck: 4 of Spades
    2010-06-07 21:52:40.806 CardDeck[8643:10b] Deck: 5 of Spades
    2010-06-07 21:52:40.809 CardDeck[8643:10b] Deck: 6 of Spades
    2010-06-07 21:52:40.812 CardDeck[8643:10b] Deck: 7 of Spades
    2010-06-07 21:52:40.814 CardDeck[8643:10b] Deck: 8 of Spades
    2010-06-07 21:52:40.817 CardDeck[8643:10b] Deck: 9 of Spades
    2010-06-07 21:52:40.820 CardDeck[8643:10b] Deck: 10 of Spades
    2010-06-07 21:52:40.822 CardDeck[8643:10b] Deck: Jack of Spades
    2010-06-07 21:52:40.824 CardDeck[8643:10b] Deck: Queen of Spades
    2010-06-07 21:52:40.827 CardDeck[8643:10b] Deck: King of Spades
    2010-06-07 21:52:40.830 CardDeck[8643:10b] Deck: Ace of Clubs
    2010-06-07 21:52:40.832 CardDeck[8643:10b] Deck: 2 of Clubs
    2010-06-07 21:52:40.834 CardDeck[8643:10b] Deck: 3 of Clubs
    2010-06-07 21:52:40.837 CardDeck[8643:10b] Deck: 4 of Clubs
    2010-06-07 21:52:40.839 CardDeck[8643:10b] Deck: 5 of Clubs
    2010-06-07 21:52:40.843 CardDeck[8643:10b] Deck: 6 of Clubs
    2010-06-07 21:52:40.846 CardDeck[8643:10b] Deck: 7 of Clubs
    2010-06-07 21:52:40.848 CardDeck[8643:10b] Deck: 8 of Clubs
    2010-06-07 21:52:40.851 CardDeck[8643:10b] Deck: 9 of Clubs
    2010-06-07 21:52:40.853 CardDeck[8643:10b] Deck: 10 of Clubs
    2010-06-07 21:52:40.855 CardDeck[8643:10b] Deck: Jack of Clubs
    2010-06-07 21:52:40.857 CardDeck[8643:10b] Deck: Queen of Clubs
    2010-06-07 21:52:40.860 CardDeck[8643:10b] Deck: King of Clubs
    2010-06-07 21:52:40.862 CardDeck[8643:10b] Deck: Ace of Diamonds
    2010-06-07 21:52:40.865 CardDeck[8643:10b] Deck: 2 of Diamonds
    2010-06-07 21:52:40.867 CardDeck[8643:10b] Deck: 3 of Diamonds
    2010-06-07 21:52:40.870 CardDeck[8643:10b] Deck: 4 of Diamonds
    2010-06-07 21:52:40.872 CardDeck[8643:10b] Deck: 5 of Diamonds
    2010-06-07 21:52:40.874 CardDeck[8643:10b] Deck: 6 of Diamonds
    2010-06-07 21:52:40.877 CardDeck[8643:10b] Deck: 7 of Diamonds
    2010-06-07 21:52:40.879 CardDeck[8643:10b] Deck: 8 of Diamonds
    2010-06-07 21:52:40.882 CardDeck[8643:10b] Deck: 9 of Diamonds
    2010-06-07 21:52:40.884 CardDeck[8643:10b] Deck: 10 of Diamonds
    2010-06-07 21:52:40.886 CardDeck[8643:10b] Deck: Jack of Diamonds
    2010-06-07 21:52:40.889 CardDeck[8643:10b] Deck: Queen of Diamonds
    2010-06-07 21:52:40.892 CardDeck[8643:10b] Deck: King of Diamonds
    2010-06-07 21:52:40.895 CardDeck[8643:10b] Deck: Ace of Hearts
    2010-06-07 21:52:40.897 CardDeck[8643:10b] Deck: 2 of Hearts
    2010-06-07 21:52:40.899 CardDeck[8643:10b] Deck: 3 of Hearts
    2010-06-07 21:52:40.902 CardDeck[8643:10b] Deck: 4 of Hearts
    2010-06-07 21:52:40.906 CardDeck[8643:10b] Deck: 5 of Hearts
    2010-06-07 21:52:40.909 CardDeck[8643:10b] Deck: 6 of Hearts
    2010-06-07 21:52:40.913 CardDeck[8643:10b] Deck: 7 of Hearts
    2010-06-07 21:52:40.965 CardDeck[8643:10b] Deck: 8 of Hearts
    2010-06-07 21:52:40.967 CardDeck[8643:10b] Deck: 9 of Hearts
    2010-06-07 21:52:40.970 CardDeck[8643:10b] Deck: 10 of Hearts
    2010-06-07 21:52:40.972 CardDeck[8643:10b] Deck: Jack of Hearts
    2010-06-07 21:52:40.973 CardDeck[8643:10b] Deck: Queen of Hearts
    2010-06-07 21:52:40.978 CardDeck[8643:10b] Deck: King of Hearts
    2010-06-07 21:52:40.981 CardDeck[8643:10b] Deck: JokerJoker
    2010-06-07 21:52:40.984 CardDeck[8643:10b] Deck: JokerJoker
    2010-06-07 21:52:40.986 CardDeck[8643:10b] Drew 9 of Clubs
    2010-06-07 21:52:40.989 CardDeck[8643:10b] Drew King of Diamonds
    2010-06-07 21:52:40.990 CardDeck[8643:10b] Drew JokerJoker
    2010-06-07 21:52:40.994 CardDeck[8643:10b] Drew 7 of Spades
    2010-06-07 21:52:40.996 CardDeck[8643:10b] Drew 8 of Hearts
    2010-06-07 21:52:40.998 CardDeck[8643:10b] Drew 4 of Spades
    2010-06-07 21:52:41.001 CardDeck[8643:10b] Drew Jack of Diamonds
    2010-06-07 21:52:41.003 CardDeck[8643:10b] Drew 2 of Hearts
    2010-06-07 21:52:41.005 CardDeck[8643:10b] Deck: Ace of Spades
    2010-06-07 21:52:41.006 CardDeck[8643:10b] Deck: 2 of Spades
    2010-06-07 21:52:41.007 CardDeck[8643:10b] Deck: 3 of Spades
    2010-06-07 21:52:41.011 CardDeck[8643:10b] Deck: 5 of Spades
    
    [Session started at 2010-06-07 21:52:41 +1200.]
    GNU gdb 6.3.50-20050815 (Apple version gdb-967) (Tue Jul 14 02:15:14 UTC 2009)
    Copyright 2004 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "powerpc-apple-darwin".sharedlibrary apply-load-rules all
    2010-06-07 21:52:41.014 CardDeck[8643:10b] Deck: 6 of Spades
    2010-06-07 21:52:41.016 CardDeck[8643:10b] Deck: 8 of Spades
    2010-06-07 21:52:41.019 CardDeck[8643:10b] Deck: 9 of Spades
    2010-06-07 21:52:41.021 CardDeck[8643:10b] Deck: 10 of Spades
    2010-06-07 21:52:41.023 CardDeck[8643:10b] Deck: Jack of Spades
    2010-06-07 21:52:41.024 CardDeck[8643:10b] Deck: Queen of Spades
    2010-06-07 21:52:41.028 CardDeck[8643:10b] Deck: King of Spades
    2010-06-07 21:52:41.030 CardDeck[8643:10b] Deck: Ace of Clubs
    2010-06-07 21:52:41.032 CardDeck[8643:10b] Deck: 2 of Clubs
    2010-06-07 21:52:41.034 CardDeck[8643:10b] Deck: 3 of Clubs
    2010-06-07 21:52:41.037 CardDeck[8643:10b] Deck: 4 of Clubs
    2010-06-07 21:52:41.150 CardDeck[8643:10b] Deck: 5 of Clubs
    2010-06-07 21:52:41.152 CardDeck[8643:10b] Deck: 6 of Clubs
    2010-06-07 21:52:41.158 CardDeck[8643:10b] Deck: 7 of Clubs
    2010-06-07 21:52:41.161 CardDeck[8643:10b] Deck: 8 of Clubs
    2010-06-07 21:52:41.164 CardDeck[8643:10b] Deck: 10 of Clubs
    2010-06-07 21:52:41.216 CardDeck[8643:10b] Deck: Jack of Clubs
    2010-06-07 21:52:41.218 CardDeck[8643:10b] Deck: Queen of Clubs
    2010-06-07 21:52:41.221 CardDeck[8643:10b] Deck: King of Clubs
    2010-06-07 21:52:41.223 CardDeck[8643:10b] Deck: Ace of Diamonds
    2010-06-07 21:52:41.223 CardDeck[8643:10b] Deck: 2 of Diamonds
    2010-06-07 21:52:41.228 CardDeck[8643:10b] Deck: 3 of Diamonds
    2010-06-07 21:52:41.230 CardDeck[8643:10b] Deck: 4 of Diamonds
    2010-06-07 21:52:41.232 CardDeck[8643:10b] Deck: 5 of Diamonds
    2010-06-07 21:52:41.235 CardDeck[8643:10b] Deck: 6 of Diamonds
    2010-06-07 21:52:41.238 CardDeck[8643:10b] Deck: 7 of Diamonds
    2010-06-07 21:52:41.240 CardDeck[8643:10b] Deck: 8 of Diamonds
    2010-06-07 21:52:41.243 CardDeck[8643:10b] Deck: 9 of Diamonds
    2010-06-07 21:52:41.245 CardDeck[8643:10b] Deck: 10 of Diamonds
    2010-06-07 21:52:41.247 CardDeck[8643:10b] Deck: Queen of Diamonds
    2010-06-07 21:52:41.249 CardDeck[8643:10b] Deck: Ace of Hearts
    2010-06-07 21:52:41.252 CardDeck[8643:10b] Deck: 3 of Hearts
    2010-06-07 21:52:41.254 CardDeck[8643:10b] Deck: 4 of Hearts
    2010-06-07 21:52:41.257 CardDeck[8643:10b] Deck: 5 of Hearts
    2010-06-07 21:52:41.260 CardDeck[8643:10b] Deck: 6 of Hearts
    2010-06-07 21:52:41.263 CardDeck[8643:10b] Deck: 7 of Hearts
    2010-06-07 21:52:41.265 CardDeck[8643:10b] Deck: 9 of Hearts
    2010-06-07 21:52:41.267 CardDeck[8643:10b] Deck: 10 of Hearts
    2010-06-07 21:52:41.270 CardDeck[8643:10b] Deck: Jack of Hearts
    2010-06-07 21:52:41.272 CardDeck[8643:10b] Deck: Queen of Hearts
    2010-06-07 21:52:41.274 CardDeck[8643:10b] Deck: King of Hearts
    2010-06-07 21:52:41.277 CardDeck[8643:10b] Deck: JokerJoker
    2010-06-07 21:52:41.279 CardDeck[8643:10b] Graveyard: 9 of Clubs
    2010-06-07 21:52:41.281 CardDeck[8643:10b] Graveyard: King of Diamonds
    2010-06-07 21:52:41.282 CardDeck[8643:10b] Graveyard: JokerJoker
    2010-06-07 21:52:41.287 CardDeck[8643:10b] Graveyard: 7 of Spades
    2010-06-07 21:52:41.347 CardDeck[8643:10b] Graveyard: 8 of Hearts
    2010-06-07 21:52:41.350 CardDeck[8643:10b] Graveyard: 4 of Spades
    2010-06-07 21:52:41.352 CardDeck[8643:10b] Graveyard: Jack of Diamonds
    2010-06-07 21:52:41.354 CardDeck[8643:10b] Graveyard: 2 of Hearts
    2010-06-07 21:52:41.355 CardDeck[8643:10b] 1
    2010-06-07 21:52:41.356 CardDeck[8643:10b] Releasing Arrays
    2010-06-07 21:52:41.357 CardDeck[8643:10b] Deallocating
    Attaching to process 8643.
    (gdb) 
    
    Ive spent about 2 hours now in the documentation trying different versions of dealloc. The debugger is highlighting [pool drain].

    Stepping into returns this code.
    Code:
    sharedlibrary apply-load-rules all
    Attaching to process 9155.
    Single stepping until exit from function objc_msgSend_rtp, 
    which has no line number information.
    Current language:  auto; currently objective-c
    Program received signal:  “EXC_BAD_ACCESS”.
    kill
    
    EDIT: It definitely has something to do with draining the pool in my test code. Everything works perfectly apart from when it comes to draining a pool. It works fine with GC or removing the autorelease pool, but that doesn't make any sense.... Getting it working without GC would be awesome though.

    EG, this works perfectly. (Notice the lack of memory management coding)

    Code:
    #import <Foundation/Foundation.h>
    #import "Card.h"
    #import "Deck.h"
    
    int main (int argc, const char * argv[]) {
    	Deck *gameDeck = [[Deck alloc] init];
    	[gameDeck prepare];
    	
    	int i, c;
    	for (i = 0, c = [[gameDeck deck] count] - 1; i <= c; ++i) {
    		[gameDeck drawRandomCard];
    	}
    	
    	[gameDeck printDeck];
    	NSLog(@"Again");
    	[gameDeck prepare];
        return 0;
    }
    
    EDIT2: Critique welcome.
     
  11. Catfish_Man macrumors 68030

    Catfish_Man

    Joined:
    Sep 13, 2001
    Location:
    Portland, OR
    #11
    Didn't read all of it, but a suggestion (note: having the loop variable declarations in the loop header requires being in C99 mode. Googling Xcode C99 mode should find instructions on where that's set easily enough):
    Code:
    -(void)prepare {
    	//Destroy current Deck arrays if any
    	[deck removeAllObjects];
    	[graveyard removeAllObjects];
    	
    	//Prepare new deck
            char *suits = "scdh";
            for (int suitIdx = 0; suitIdx < 4; ++suitIdx) {
                for (int i = 1, c = 's'; i <= 13; ++i) { 
    		[deck addObject:[[[Card alloc] initWithSuit:suits[suitIdx] number:i]] autorelease];
    	    }
            }
    
            //Add the jokers; this could be a loop as you had it,
            //but I think with only two iterations it's clearer that it's "different from the others" this way
            Card *joker = [[[Card alloc] initWithSuit:'j' number:0] autorelease];
            [deck addObject: joker];
            [deck addObject: [[joker copy] autorelease]];
    	
    	[self printDeck];
    }
    
     
  12. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #12
    Exactly what are those 3 assignments intended to do? Who owns the objects? What effect does ownership have later, when you assign another value to the variables?

    In what way is this code better than:
    Code:
    	NSString *cardName = @"";
    
    or:
    Code:
    	NSString *cardName = nil;
    
    Your code looks like cargo-cult programming to me.

    Who has ownership of numberName and suitName at the point you are calling release on them? If you don't know, then you should review the memory management guide's rules of ownership.

    Who has ownership of cardName when it's being returned? Is it autoreleased or not at the point it's returned?
     
  13. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #13
    If you are doing live draws, the deck could simply be a long long. Methods would look something like (.h file omitted):

    Code:
    - (void)shuffle { theDeck = 0; }
    - (NSString *)drawCard {
        NSString    *theDraw;
        // these constants would actually be ivars
        char    *suits[4] = { "Diamonds", "Clubs", "Hearts", "Spades" };
        char    *faces[4] = { "Jack", "Queen", "King", "Ace" };
        long long  cardMask;
        int     aCard;
        int     cardVals;
        BOOL didDraw = NO;
        if ( -1 == theDeck ) return @""; // no cards left
        while ( !didDraw ) {
            aCard = random() % 54;
            cardMask = 1 << aCard;
            didDraw = ( 0 == ( cardMask&theDeck ) );
            if ( didDraw ) theDeck |= cardMask;
        }
        if ( 51 < aCard ) {
            // set the draw ivars to a Joker value
            lastDrawnCard = -1;
            lastDrawnSuit = -1;
            return @"Joker";
        } else {
            // get the suit
            cardVals = aCard % 13;
            if ( cardVals > 8 ) {
                // note: Ace = 12 (highest number )
                theDraw = [NSString stringWithCString:faces[cardVals - 9]];
            } else {
                theDraw = [NSString stringWithFormat:@"%d", cardVals + 2];
            }
            // save the card number in an ivar
           lastDrawnCard = cardVals;
            cardVals = aCard / 13;
            theDraw = [theDraw appendFormat:@" of %s",[NSString stringWithCString:suits[cardVals]];
            // save the suit in an ivar for reference
            lastDrawnSuit = cardVals;
    }
    - (int)lastDraw {
        // lowest byte is the card value, 2-10, Jack = 11, Ace = 14
        // higher byte is the suit number
        return ( lastDrawnCard + 2 )|( lastDrawnSuit << 8 );
    }
    
     
  14. MorphingDragon thread starter macrumors 603

    MorphingDragon

    Joined:
    Mar 27, 2009
    Location:
    The World Inbetween
    #14
  15. PatrickCocoa macrumors 6502a

    Joined:
    Dec 2, 2008
    #15
    Make sure to do some tests of randomness on your final output. Random numbers are trickier than they appear, and things that you do with them that look like they should deliver random results sometimes don't. There is a lot of practical literature on this issue.

    When you think you're done, deal a hand and note the first card. Do that 100 times and look at the data you collect. No spades? No aces? There may be a problem.
     

Share This Page