cs193p – Assignment #1 Task #2

Please note, this blog entry is from a previous course. You might want to check out the current one.

Be sure to include all the code for the four classes shown in the first two lectures: Card, Deck, PlayingCard and PlayingCardDeck. You must type this code in (e.g., do not copy and paste it from somewhere). The whole point of this Required Task is to gain experience editing code in Xcode and to get used to Objective-C syntax.

Start implementing the classes provided on the slides of lecture #2. The base structure of the Card class has already been added during the lecture. Add its public interface and the match method.

// Card.h
@property (strong, nonatomic) NSString *contents;
@property (nonatomic, getter=isChosen) BOOL chosen;
@property (nonatomic, getter=isMatched) BOOL matched;
- (int)match:(NSArray *)otherCards;

// Card.m
- (int)match:(NSArray *)otherCards
{
    int score = 0;
    for (Card *card in otherCards) {
        if ([card.contents isEqualToString:self.contents]) {
            score = 1;
        }
    }
    return score;
}

Add a new class for the Deck. Add its public interface (don’t forget to include the Card class to access it within your new class) and implement its methods as well as the getter for lazy instantiation.

// Deck.h
#import "Card.h"
...
- (void)addCard:(Card *)card atTop:(BOOL)atTop;
- (void)addCard:(Card *)card;
- (Card *)drawRandomCard;

// Deck.m
- (NSMutableArray *)cards
{
    if (!_cards) _cards = [[NSMutableArray alloc] init];
    return _cards;
}

- (void)addCard:(Card *)card atTop:(BOOL)atTop
{
    if (atTop) {
        [self.cards insertObject:card atIndex:0];
    } else {
        [self.cards addObject:card];
    }
}

- (void)addCard:(Card *)card
{
    [self addCard:card atTop:NO];
}

- (Card *)drawRandomCard
{
    Card *randomCard = nil;    
    if ([self.cards count]) {
        unsigned index = arc4random() % [self.cards count];
        randomCard = self.cards[index];
        [self.cards removeObjectAtIndex:index];
    }    
    return randomCard;
}

Add another new class PlayingCard as sub class of Card. Add its public interface and implement its methods. Don’t forget to synthesize the suit property because both setter & getter are used.

// PlayingCard.h
@property (strong, nonatomic) NSString *suit;
@property (nonatomic) NSUInteger rank;
+ (NSArray *)validSuits;
+ (NSArray *)rankStrings;
+ (NSUInteger)maxRank;

// PlayingCard.m
@synthesize suit = _suit;
+ (NSArray *)validSuits
{
    return @[@"♥️", @"♦️", @"♠️", @"♣️"];
}

+ (NSArray *)rankStrings
{
    return @[@"?", @"A", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"J", @"Q", @"K"];
}

+ (NSUInteger)maxRank
{
    return [[self rankStrings] count] - 1;
}

- (NSString *)contents
{
    return [[PlayingCard rankStrings][self.rank] stringByAppendingString:self.suit];
}

- (void)setSuit:(NSString *)suit
{
    if ([[PlayingCard validSuits] containsObject:suit]) {
        _suit = suit;
    }
}

- (NSString *)suit
{
    return _suit ? _suit : @"?";
}

- (void)setRank:(NSUInteger)rank
{
    if (rank <= [PlayingCard maxRank]) {
        _rank = rank;
    }
}

The last class PlayingCardDeck is a sub class of Deck. Add its initializer:

- (instancetype)init
{
    self = [super init];    
    if (self) {
        for (NSString *suit in [PlayingCard validSuits]) {
            for (NSUInteger rank = 1; rank <= [PlayingCard maxRank]; rank++) {
                PlayingCard *card = [[PlayingCard alloc] init];
                card.rank = rank;
                card.suit = suit;
                [self addCard:card];
            }
        }
    }    
    return self;
}

For task #1 you could see that the code was working, because you could actually click on the card and saw how it changed … Only implementing the mere model classes, does nothing. We could – or better should – add unit tests … which I am naturally to lazy – at least for now …

For a quick function test, create a new deck when the view controller has loaded, and draw random cards:

#import "PlayingCardDeck.h"
...
- (void)viewDidLoad
{
    PlayingCardDeck *deck = [[PlayingCardDeck alloc] init];
    for (int i = 0; i < 53; i++) {
        NSLog(@"%@", [deck drawRandomCard].contents);
    }    
}

The complete code is available on github.

FacebooktwitterredditpinterestlinkedintumblrmailFacebooktwitterredditpinterestlinkedintumblrmail

Leave a Reply

Your email address will not be published.