Info

Programmer by day, artist by night

Archive for

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 🙂

What’s in iOS7: 4 major layers

Starting from the bottom to top:

Core OS

  • OS X Kernel
  • Mach 3.0
  • BSD
  • Sockets
  • Security
  • Power Management
  • Keychain Access
  • Certificates
  • File System
  • Bonjour

Core Services

  • Collections
  • Address Book
  • Networking
  • File Access
  • SQLite
  • Core Location
  • Net Services
  • Threading
  • Preferences
  • URL Utilities
Media

  • Core Audio
  • Open AL
  • Audio Mixing
  • Audio Recording
  • Video Playback
  • JPEG, PNG, TIFF
  • PDF
  • Quartz (2D)
  • Core Animation
  • OpenGL ES

Cocoa Touch

  • Multi-Touch
  • Core Motion
  • View Hierarchy
  • Localization
  • Controls
  • Alerts
  • Web View
  • Map Kit
  • Image Picker
  • Camera

Platform Components:

  1. Tools: Xcode 5, Instruments
  2. Language: Objective-C
  3. Frameworks: Foundation, UIKit, Core Data, Map Kit, Core Motion
  4. Design Strategies: MVC

Controller-View Communication Types

  • Outlets: Target-Action
  • Delegates: will, should, did type of methods
  • Data source delegates: data at, count

Controller-Model Communication Types

  • Notification and KVO

Card Object

contents
chosen
matched
-(int)match:

Experimenting with the Card class

Since the Card class was created in this lecture, here are some experiments with the Card class in main.m.
10 cards created starting with 0, 1, 2 … 9. A single random card is generated with content range from 0 to 19.

Output 1 (with a match):
2013-11-02 04:33:46.900 Cards[40876:303] New card content: 3
2013-11-02 04:33:46.902 Cards[40876:303] We found a match. Score: 1

Output 2 (with no match):
2013-11-02 04:34:26.295 Cards[40882:303] New card content: 18
2013-11-02 04:34:26.296 Cards[40882:303] Sorry, no match found.

#import
#import "Card.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool {

        NSMutableArray *cards = [[NSMutableArray alloc] init];
        // insert code here...
        for (int i = 0; i < 10; i++) {
            Card *card = [[Card alloc] init];
            card.contents = [NSString stringWithFormat:@"%d", i];
            [cards addObject:card];
        }

        Card *newCard = [[Card alloc] init];
        int randomNumber = arc4random() % (cards.count + 10);
        newCard.contents = [NSString stringWithFormat:@"%d", randomNumber];

        NSLog(@"New card content: %@", newCard.contents);

        int score = [newCard match:cards];
        if (score) {
            NSLog(@"We found a match. Score: %d", score);
        } else {
            NSLog(@"Sorry, no match found.");
        }
    }
    return 0;
}

The Stanford University has released a new course “Developing iOS7 Apps for iPhone and iPad by Stanford University” on iTunes 2 days ago, October 31, 2013.

https://itunes.apple.com/us/course/developing-ios-7-apps-for/id733644550

So far, Lecture 1 to 4 has been released. In contrast to the previous semester, this time Paul Hegarty stresses more on the importance of meeting the prerequisites. This is understandable from the viewpoint that the vast amount of topics that will be covered in about 10 weeks. Previous Object Oriented Programming experience is thus paramount. The prerequisites are also especially important if you are an actual student at Stanford and you have to keep up in order to complete the course in 10 weeks.

However for the rest of us non-Stanford students, we can take the course at our own pace. Drilling down on specific classes, branching out to other technologies and object oriented programming techniques to our hearts content. However keeping up with the course does have some satisfaction as you can always look forward to the videos as they come out. So if you want to actually keep up, I highly recommend you drop all other side-learning objectives and dive in and immerse yourself from head to toe on this course.

This series of blog posts will cover all the topics taught in the course as it unfolds with summary of the notes and slides, actual code and experience of taking the course. So we will begin with Day 1, Lecture 1.

Who might this series of blog posts and notes be useful for? 

Someone who is following the course and interested in various experiments to further strengthen the learning process.