onstwedder.com

All that you have is your soul

0 notes &

Cocoa coding: Blackjack tutorial - part 2

So let’s start with 1 and 2 from the list: a deck of playing cards.

I will add two classes to the empty project: a Card class and a Deck class. At first, these class will be quite basic. We’ll test them via NSLog and there’s no graphical interface concerning them (yet). Also, I am not going to worry about Model-View-Controller (MVC) yet.

So let’s start with the Card-class. 

1) Click on “New File”, choose Mac OS X, Cocoa Class, Objective-C Class - Leave everything default (So it’s a subclass of NSObject) and click Next.

2) In the New File dialog type at File Name: Card.m 
Leave the defaults, so it will also create a Card.h 

3) Now in the Card.h I am going to add a suit and a cardId.

The cardId is a NSInteger

The cardId can be anything from 1 up to 13. (Where we decide 1=ace, 2-10=2-10, 11=Jack, 12=Queen, 13=King. 

The suit will be declared an enumeration. 

4) I’ll add a couple of methods to our Card class. 

  • an init method to initialize a card with a specific cardId and suit;
  • a return cardId as a string (for future stuff and logging)
  • a return Suit as string (for future stuff and logging)
  • a return pip-value.
  • a describe card as string method (mostly for logging);

The pipValue is going to be the value of the card in our blackjack counting. So basically cardId 2-10 is going to return 2-10, a Jack,Queen and King are pipvalue 10 and the ace will return either 1 or 11. For now we’ll just return 11. (and add a TO DO comment to the code. 

that would result in the following Card.h file

#import <Cocoa/Cocoa.h>
typedef enum { Hearts, Spades, Diamonds, Clubs } Suit; @interface Card : NSObject { NSInteger cardId; Suit suit; } @property NSInteger cardId; @property Suit suit; -(id) initWithCardId:(NSInteger) aCardId suit:(Suit) aSuit; -(NSString *) cardIdAsString; -(NSString *) suitAsString; -(NSInteger) pipValue; @end

5) The implementation of these methods are going to be added to the Card.m file.

#import "Card.h"

@implementation Card

@synthesize suit, cardId;

-(id) initWithCardId:(NSInteger) aCardId suit:(Suit) aSuit{
	if (self = [super init])
	{
		self.suit = aSuit;
		self.cardId = aCardId;
		
	}
	return self;
}

-(NSString *) suitAsString{
	switch (self.suit) {
		case Hearts:
			return @"Hearts";
			break;
		case Diamonds:
			return @"Diamonds";
			break;
		case Spades:
			return @"Spades";
			break;
		case Clubs:
			return @"Clubs";
			break;
		default:
			return nil;
			break;
	}
}


//TODO: Ace can be 1 or 11. At the moment it is just always 11.
-(NSInteger) pipValue {
	switch (self.cardId) {
		case 1:
			return 11;
			break;
		case 11:
			return 10;
			break;
		case 12:
			return 10;
			break;
		case 13:
			return 10;
			break;
		default:
			return self.cardId;
			break;
	}
}


-(NSString *) cardIdAsString{
	switch (self.cardId) {
		case 1:
			return @"Ace";
			break;
		case 11:
			return @"Jack";
			break;
		case 12:
			return @"Queen";
			break;
		case 13:
			return @"King";
			break;
		default:
			return [NSString stringWithFormat:@"%d", self.cardId];
			break;
	}
}

-(NSString *) description{
	return [NSString stringWithFormat:@"%@ %@", [self suitAsString], [self cardIdAsString]];
}

@end

I’d say it’s pretty easy. The InitWithCardId: suit: will make it possible to create a card I’d want. if I’d call the init with :7 :hearts, i’d get a 7 hearts. a :12 :clubs would return a queen of clubs.

The description is called when you NSLog an instance of this class to a NSString. You’ll see this used later on in the deck. 

6) Next: the Deck class. Create a new file, like 1 and 2, but now with the name Deck.h;

7) The Deck should have an array of Card.  It should be able to shuffle and to draw a card from the deck (and return a card object of class Card.

The Array of Card has to be mutable, because we are changing stuff to it.

The methods (or the functionality as you will) of the deck was described in the previous part. So i’ve added declarations of those methods.

So here’s the Deck.h

#import <Cocoa/Cocoa.h>
@class Card; @interface Deck : NSObject { NSMutableArray *cards; } -(Card *) drawCard; -(void) shuffle; @end

So then it is time for the implementation of Deck. I’d only declared with the @class Card, that there is a class Card used, but that Xcode doesn’t need to know here, what it actually looks like.

For now let’s just focus on the initialization of the cards in the Deck.m. 

#import "Deck.h"
#import "Card.h"

@implementation Deck

#pragma mark -
#pragma mark initialization
-(id) init {
	if (self = [super init])
	{
		cards = [[NSMutableArray alloc] init];
		
		for (int suit = 0; suit <= 3; suit++)
		{
			for (int cardId = 1; cardId <= 13; cardId++)
			{
			    [cards addObject:[[Card alloc] initWithCardId:cardId suit:suit]];
			}
		}		
	}
	return self;
}

#pragma mark -
#pragma mark Deck Functionality
-(void)shuffle{	
}

//TODO: implement the drawing of cards. atm it just returns nil.
-(Card *) drawCard{
	return nil;
}

-(NSString *) description{
	return [NSString stringWithFormat:@"cards : %@", cards];
}

@end

As you can see both methods shuffle and drawCard aren’t functional yet. You might have read Objective-C was very simple once you get the hang of it. But just declaring empty functions like i just did, and expecting it to work magically is a bit too much to ask. However making these tutorials are time-consuming and i will add these functions in the next part.

On a site note, I’ve added the #pragma mark -  and #pragma mark (text) to show how you can add some structure in your source and Xcode. The #pragma mark - adds a new section and the other one shows the text in the editor’s overview for this class.

Anyway, If you build and run now, you’ll see a nice application open with the title: tutorial21. Unfortunately there is nothing yet to do in this app, but if you’ll open console ( Run / Console or shift/cmd/R) you’ll see a nice deck full of cards:

date 22:03:46.810 tutorial21[6169:a0f] cards : (

    ”Hearts Ace”,

    ”Hearts 2”,

   …

    ”Hearts King”,

    ”Spades Ace”,

   …

So something must be working.

One other important thing to mention before I go on, is that the Card objects I have added to cards aren’t released. This used to be very wrong, but since Xcode 2 or 3, it’s possible to turn on a garbage collection (like Java). 

Now since I am relatively new to Objective-C myself and I feel I might accidentally add an error and especially those nasty memory leaks are a pain in the everywhere. So I’ve decided to be lame and just turn on the garbage collection. Which turns out to be fine on a OS X device.

However If you’re ever going to program apps for an IOS device, there will be no garbage collection option and you’ll have to retain/release objects yourself. If you don’t know how, that’s a whole different tutorial (that I don’t have yet).

The good news for now is, since this tutorial is for a mac (OS X) you can do the same thing, by opening Project Info, Clicking the build tab, Search for the setting Objective-C Garbage Collection and turn it’s value to “Required”.

If you won’t, you’ll get memory leaks on the creating-a-card,-adding-it-to-the-cards-array-and-not-releasing-it.

*This is part of a objective-C, cocoa tutorial, that will result in a working blackjack for a os x*.

Previous chapter: blackjack tutorial - part 1
Next chapter: blackjack tutorial - part 3

Filed under blackjack objective-c mac osx coding Cocoa Tutorial Xcode