Info

Programmer by day, artist by night

Posts from the Developing iOS7 Apps for iPhone and iPad (Fall 2013) by Stanford University Category

Assignment 3 (Set Card Matching Game with History) from “Developing iOS7 Apps for iPhone and iPad (Fall 2013) by Stanford University” took a bit longer than usual to complete. The major highlights of the assignment are:

  • Set card matching in addition to the playing card game implemented in the last assignment
  • Status history access via segueing through Navigation Bar button

With an object oriented approach, it was easy to keep the logic in the CardMatchingGame model the same for both Set Card and Playing Card. Here is a list of changes since the previous assignment:

  • Allowing 2 or 3 card for Playing card game
  • Not disabling match-mode slider during gameplay, as it doesn’t make sense to click Redeal card button twice for a new match mode
    • Previous behavior:
      • Click Re-deal button
      • Choose match-mode
      • Click Re-deal button
    • Current behavior:
      • Choose match-mode
      • Click Re-deal button
  • Status moved out of the model into the ViewController
  • Removed cheat mode for debugging

Download Solution to Assignment 3: Set Card Matching Game with History

Here is the latest update to the Matchismo card game model. The polymorphism principle was applied by removing the reference to PlayingCardDeck in CardGameViewController and replacing it with a generic Deck. A sub-class PlayingCardGameViewController was created which overrode the abstract method createDeck in CardGameViewController.

Update to the Matchismo Card Game Models Based on Lecture 6 (Polymorphism principle applied)

Update to the Matchismo Card Game Models Based on Lecture 6 (Polymorphism principle applied)

Lecture 5 from “Developing iOS7 Apps for iPhone and iPad (Fall 2013) by Stanford University” explained View Controller life cycles. Here is a simple experiment to see it in action.

Notice the viewDidLoad method runs only once. Whereas viewWillAppear and viewDidAppear runs every time the view comes alive. And as the view goes away, viewWillDisappear and viewDidDisappear runs.

Even though it’s almost a child-like experiment, it’s the experience that helps reinforce learning. To experiment on your own, create an Xcode project and choose Tabbed Application from the templates. In the FirstViewController.m file, add the following code. We simply print out a log message as a view appears and disappears from screen.

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    NSLog(@"--Hello--");    
    NSLog(@"Step 1: view did load");
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    NSLog(@"Step 2: view will appear");
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSLog(@"Step 3: view did appear");
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    NSLog(@"Step 4: view will disappear");
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    NSLog(@"Step 5: view did disappear");
    NSLog(@"--Bye--");
}

Feel free to add more sophisticated views and watch them in action 🙂

Attached is the solution to the Assignment 2: Matchismo 2 (3-Card Matching Game) from the course “Developing iOS7 Apps for iPhone and iPad (Fall 2013)” by Stanford University (available in iTunes). The attached solution is not limited to a 2-card or 3-card matching game. The same method can be used for n-cards.

The solution addresses all the required tasks in the Assignment. The scoring mechanism implemented is a very simplified approach based on what was already shown in the lectures. While the iOS related tasks were easy to implement, the 3-card matching logic took some thought. There are obviously many approaches to matching a 3-card game. The solution attached is based on the CardMatchingGame model.

The model already stores the chosen and matched states of each card. While it may be tempting to create separate procedures to loop through the number of cards being played and matched, this is not required as the model already holds that information. All we need to do is simply to ask it.

The implementation also adds 2 features not required in the assignment. It presents the user with an alert (UIAlertView) when re-dealing the cards. This was easy to implement via UIAlertViewDelegate. A quick jump to the documentation shows how to do this. The other feature that was added was via the method – (void)shouldDisableGame. This disables the last remaining cards from being clicked if they cannot be matched.

A quick video demonstrating the solution in action.

Please download the attachment for full details – it contains the Xcode 5 project for Matchismo. Just unzip the file matchismo.zip and open Matchismo.xcodeproj

Download Solution to Assignment 2: Matchismo 2 (3-Card Matching Game)

The core matching logic is pasted below with inline code comments:

- (void)chooseCardAtIndex:(NSUInteger)index
{
    Card *card = [self cardAtIndex:index];
    
    if (!card.isMatched) {
        if (card.isChosen) {
            card.chosen = NO;
            self.status = @"";
        } else {
            // match against other cards
            
            // First we store the cards that are chosen and not matched in currentChosenCards
            NSMutableArray *currentChosenCards = [[NSMutableArray alloc] init];
            NSMutableString *statusCurrentChosenCards = [[NSMutableString alloc] init];
            for (Card *otherCard in self.cards) {
                if (otherCard.isChosen && !otherCard.isMatched) {
                    [currentChosenCards addObject:otherCard];
                    [statusCurrentChosenCards appendFormat:@"%@ ", otherCard.contents];
                }
            }
            if ([currentChosenCards count]) {
                self.status = [[NSString stringWithFormat:@"Chose %@ to match with: ", card.contents] stringByAppendingString:statusCurrentChosenCards];
            } else {
                self.status = [NSString stringWithFormat:@"Chose %@", card.contents];
            }

            
            // The model is already tracking how many cards are currently chosen and not matched
            // So all we need to do is match that count with the number of cards we are playing with
            // We do a -1 because currentChosenCards doesn't include the card that was just clicked
            if ([currentChosenCards count] == self.numberOfCardsToPlayWith-1) {
                int matchScore = [card match:currentChosenCards];
                if (matchScore) {
                    self.score += matchScore * MATCH_BONUS;
                    for (Card *otherCard in currentChosenCards) {
                        otherCard.matched = YES;
                    }
                    card.matched = YES;
                    self.status = [[NSString stringWithFormat:@"Scored: %d. Match found for: %@ ", matchScore * MATCH_BONUS, card.contents] stringByAppendingString:statusCurrentChosenCards];
                } else {
                    self.score -= MISMATCH_PENALTY;
                    for (Card *otherCard in currentChosenCards) {
                        otherCard.chosen = NO;
                    }
                    self.status = [[NSString stringWithFormat:@"Penalty: %d. No match found for: %@ ", MISMATCH_PENALTY, card.contents] stringByAppendingString:statusCurrentChosenCards];
                }
            }
        
            self.score -= COST_TO_CHOOSE;
            card.chosen = YES;
        }
    }
    
    // This is not part of the assignment. It's just a nice way to end the game.
    // If the last remaning cards do not match, the game should freeze those cards
    // from being clicked and end the game.
    [self shouldDisableGame];
}

Here is my solution to Assignment 1: Matchismo from the course “Developing iOS7 Apps for iPhone and iPad” (Fall 2013) by Stanford University.

There are just a few differences with the “official” solution as shown in the Lecture 3 video / slide .

  • Did not create a separate method createDeck to instantiate PlayingCardDeck (see line 13)
  • Instead of creating a new object Card, I just created a string to see if content is nil (see line 30, 31)
  • I moved self.flipCount++ inside the control statement that draws a random card (see line 35). Now a flip is counted only when you are looking at the card content/front. This way the maximum flip count equals to the total number of cards in deck, i.e. 52.
#import "CardGameViewController.h"
#import "PlayingCardDeck.h"

@interface CardGameViewController ()
@property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
@property (nonatomic) int flipCount;
@property (strong, nonatomic) Deck *deck;
@end

@implementation CardGameViewController

- (Deck *)deck {
    if (!_deck) _deck = [[PlayingCardDeck alloc] init];
    return _deck;
}

- (void)setFlipCount:(int)flipCount
{
    _flipCount = flipCount;
    self.flipsLabel.text = [NSString stringWithFormat:@"Flips: %d", self.flipCount];
    NSLog(@"flipCount changed to: %d", self.flipCount);
}

- (IBAction)touchCardButton:(UIButton *)sender {
    if ([sender.currentTitle length]) {
        [sender setBackgroundImage:[UIImage imageNamed:@"cardback"]
                          forState:UIControlStateNormal];
        [sender setTitle:@"" forState:UIControlStateNormal];
    } else {
        NSString *cardContent = [[self.deck drawRandomCard] contents];
        if (cardContent) {
            [sender setBackgroundImage:[UIImage imageNamed:@"cardfront"]
                              forState:UIControlStateNormal];
            [sender setTitle:cardContent forState:UIControlStateNormal];
            self.flipCount++;
        }
    }
}

@end

If you completed Lecture 2 of the “Developing iOS7 Apps for iPhone and iPad (Fall 2013) by Stanford University” you will see that in total 4 model classes were created:

  • Card
  • PlayingCard
  • Deck
  • PlayingCardDeck

If you are new object oriented programming it might be a little difficult to wrap your head around all the classes and how they relate to each other, what methods they inherit, override, etc. So here is a class diagram overview that shows the 4 classes and their relations. I have mentioned all the public and private properties and methods.

All the models created in Lecture 2 of Developing iOS7 Apps for iPhone and iPad (Fall 2013) by Stanford University

All the models created in Lecture 2 of Developing iOS7 Apps for iPhone and iPad (Fall 2013) by Stanford University

You might find this diagram handy for referencing back and forth as you continue developing the Matchismo game in the forthcoming lectures.

Remember, PlayingCard is just a subclass of Card. Deck is a collection of Cards. PlayingCardDeck is a collection of PlayingCards 🙂