cs193p – Assignment #2 Task #5

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

Add a text label somewhere which desribes the results of the last consideration by the CardMatchingGame of a card choice by the user. Examples: “Matched J♥ J♠ for 4 points.” or “6♦ J♣ don’t match! 2 point penalty!” or “8♦” if only one card is chosen or even blank if no cards are chosen. Do not violate MVC by building UI in your Model. “UI” is anything you are going to present to the user. This must work properly in either mode of Required Task 3.

Lets muse a little bit about what to put where … How the actual text look like, e.g. you could use another language, or other wording, or even if you want to separated the card descriptions by spaces or commas, has nothing to do with the game but with the presentation and should be part of the view. However after you have matched cards, the view itself does not know which cards have been selected last, and cannot even derive that information from the model. It also does not know anything about a penalty or bonus. This information needs to be provided by the model.

Start by adding a label to your story board. Because it needs to be blank when the game start, you can remove the text (as shown here). However this makes the label invisible in storyboard, which might create problems later on. If you place some meaning full text here, you could remove it in e.g. viewDidLoad. Because the text for this label could be larger than the available space, adjust the auto-shrink property or the text size:
cs193p – assignment #2 task #5 - flip description

Create an outlet to the label:

@property (weak, nonatomic) IBOutlet UILabel *flipDescription;

The label will be set with each update of the user interface, according to two new public properties (which we will add later on) of the cart-matching-game class. If there is a valid game we create a string with all the description of chosen cards, by looping over them and putting their contents strings into a new array, which is concatenated using spaces as separators. Depending on the current score change the text is adjusted accordingly:

- (void)updateUI
{
    ...
    if (self.game) {
        NSString *description = @"";        
        if ([self.game.lastChosenCards count]) {
            NSMutableArray *cardContents = [NSMutableArray array];
            for (Card *card in self.game.lastChosenCards) {
                [cardContents addObject:card.contents];
            }
            description = [cardContents componentsJoinedByString:@" "];
        }        
        if (self.game.lastScore > 0) {
            description = [NSString stringWithFormat:@"Matched %@ for %d points.", description, self.game.lastScore];
        } else if (self.game.lastScore < 0) {

            description = [NSString stringWithFormat:@"%@ don’t match! %d point penalty!", description, -self.game.lastScore];
        }        
        self.flipDescription.text = description;
    }
}

Add the two new properties to the model, make them read only for the public, and privately writable:

// CardMatchingGame.h
@property (nonatomic, readonly) NSArray *lastChosenCards;
@property (nonatomic, readonly) NSInteger lastScore;

// CardMatchingGame.m
@property (nonatomic, strong) NSArray *lastChosenCards;
@property (nonatomic, readwrite) NSInteger lastScore;

When choosing a card the cards array is generated by adding the current card to the “other cards”.
Instead of setting the score directly, set the new last-score property and use it at the end to calculate the new score:

- (void)chooseCardAtIndex:(NSUInteger)index
{
            ...
            self.lastScore = 0;
            self.lastChosenCards = [otherCards arrayByAddingObject:card];
                ...
                    self.lastScore = matchScore * MATCH_BONUS;                    
                ...
                    self.lastScore = - MISMATCH_PENALTY;
            ...
            self.score += self.lastScore - COST_TO_CHOOSE;
            ...
}

The complete code is available on github.

Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailFacebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Flattr this!

8 thoughts on “cs193p – Assignment #2 Task #5”

  1. self.game will ALWAYS return a non-0 result, because of lazy instantiation, in your code this line will initialise your game when you call updateUI after pressing the dealButton, game will be then be initialised again when you start the game by clicking a covered card

    1. Paul once (I suppose it was more often, otherwise I would not remember) mentioned that we should not worry about performance issues when calling getters and setters, especially when it will take much longer to draw the graphics than calling the properties. Instance variables should only be used inside the getter and setter method of their properties, or from inside an init method … It’s a programming philosophy which I would only break if I really need that couple of nano seconds … but it’s only a philosophy, everybody is entitled to have their own 😉

  2. I’m a bit struggling with this MVC thing. Can you please explain why you are putting the lastChosenCards in the Model and not in the ViewController?

    1. MVC is a design philosophy (pattern? strategy?). You can follow it, you don’t have to …

      Also there is a grey area, where parts might fit in different places … e.g. the lastCosenCards … I have put it in the model (at least I think I did, it’s quite some time and my code lacks documentation) because it does not hold view specific information and I could imagine that another card-matching game using another view and view controller might need this functionality, too …

  3. Hi,
    You use the line below to initialize description
    NSString *description = @””;

    Is there a difference if I use:
    NSString *description = [[NSString alloc] init];

    Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *