Matchismo: solution of Assignment 2 of CS193P (2013/2014)

Matchismo is a simple card game based on assignment 2 of course CS193P “Developing Apps for iOS” from Stanford University. In this game you have to match cards (from a poker deck) by suit or by rank in order to gain points. Of course matching by rank gives you more points. You can also choose the number of cards you want to match between 2 and 3.

From an OO point of view, I have written the code in order to make the project more extensible and changeable. In particular the match method in PlayingCard.m let you match any number of cards and not only two or three. This is possible thanks to recursion, as you can see below.

Download Matchismo assignment 2 of CS193P

/// Recursive version of match. It lets you
/// calculate the matching-score of two or
/// more cards.
///
/// Example: [1♥, 5♣, 7♣, 2♥]
/// 1♥ match 5♣, 1♥ match 7♣, 1♥ match 2♥
/// 5♣ match 7♣, 5♣ match 2♥
/// 7♣ match 2♥
///
- (int)match:(NSArray *)otherCards
{
    int score = 0;

    if ([otherCards count] != 0) {
        if ([otherCards count] == 1) {
            PlayingCard *otherCard = [otherCards firstObject];
            if ([self.suit isEqualToString:otherCard.suit]) {
                return score = 1;
            } else if (self.rank == otherCard.rank) {
                return score = 4;
            }
        } else {
            for (Card *otherCard in otherCards) score += [self match:@[otherCard]];
            PlayingCard *otherCard = [otherCards firstObject];
            score += [otherCard match:[otherCards subarrayWithRange:NSMakeRange(1, [otherCards count] - 1)]];
        }
    }
    return score;
}

Any question? Please, leave a comment below! 🙂

17 comments

  1. shouldn’t there be “[otherCards firstObject] = PlayingCard *otherCard” instead of “PlayingCard *otherCard = [otherCards firstObject]” ?

    Because seems like you are assigning first object of the otherCards array to a PlayingCard * object every time for loop pick a Card *otherCard from the array. So for loop does the same thing over and over again.

  2. I’m still having trouble with that last line. Is it necessary to call score += again there or couldn’t you call [match otherCard…] directly?

    • Thank you very much John! Yes, that last line is necessary.
      Say you have [1♥, 5♣, 7♣, 2♥]. Then

      1♥ match 5♣, 1♥ match 7♣, 1♥ match 2♥
      gives you
      score = 0 + 0 + 1 = 1

      5♣ match 7♣, 5♣ match 2♥
      gives you
      score = 1 + 0 = 1

      7♣ match 2♥
      gives you
      score = 0

      score += [otherCard match:[otherCards subarray….]]; lets you get score = 1 + 1 + 0 = 2. Otherwise you would get the last calculated score which is 0!

      Hope this helps!

  3. Hi Mau,
    I look for solution of assignment 2 about the deal button.

    Because, as beginner, I ask myself if writing (in VC.m):
    ——————————————–
    – (IBAction)deal
    {
    self.game = nil;
    [self updateUI];
    }
    ——————————————–
    is not too rough…?

    Moreover that I don’t set:

    self.scoreLabel.text = @”Score: 0″;
    self.cardMatchingMode.enabled = YES;

    as you do…

    Thanks for your enlightened view,
    Guillaume

    • Thanks Guillaume!

      Well, I think you might create a method inside your model (say “resetGame”) where you should put all that model business and call it inside “deal”. In this case, if you want to restart the game you have just to set it to nil and refresh the UI… so I think it is fine if you type the code inside the controller.

      When you restart the game, the score has to be 0 and you must choose if you want to play using 2 or 3 matching-mode. So I thought “deal” was a good place to put that piece of code!

      Hope this helps.

  4. thanks for your great code
    i do the assignment but i face a problem and i need help
    this my chooseCardAtIndex it’s little different but it work-(void)chooseCardAtIndex:(unsigned int)cardIndex WithMode:(int)cardMatchingGameMode
    {
    Card* choosenCard=[self cardAtIndex:cardIndex];
    self.matchOtherCardsScore=0;
    int temp=0;
    if(!choosenCard.isMatched)
    {
    if(choosenCard.isChoosen)
    {
    choosenCard.choosen=NO;
    }
    else
    {
    for (Card* otherCard in self.cards) {
    if (!otherCard.isMatched && otherCard.isChoosen) {
    [self.matchotherCrads addObject:otherCard];
    if ([self.matchotherCrads count]==cardMatchingGameMode) {
    self.matchOtherCardsScore=[choosenCard match:self.matchotherCrads];
    if (self.matchOtherCardsScore) {
    self.matchOtherCardsScore*=MAtch_Bonus;
    self.score+=temp*MAtch_Bonus;
    for (Card* card in self.matchotherCrads) {
    card.matched=YES;
    }
    otherCard.matched=YES;

    }
    else
    {
    for (Card* otherCard in self.cards) {
    if (!otherCard.isMatched && otherCard.isChoosen)
    {
    otherCard.choosen=NO;
    }
    choosenCard.choosen=YES;
    }
    self.matchOtherCardsScore-=MAtch_PENALTY;
    self.score-=MAtch_PENALTY;
    }

    break;
    }
    // if wee nedd to decrease on all flips even they are matched cards
    }

    }
    }
    self.score-=FLIP_COST;
    choosenCard.choosen=YES;
    self.matchotherCrads=nil;
    [self.matchotherCrads addObject:choosenCard];
    }
    }
    //////////
    – (NSArray *)cardsTryMatching
    {
    return self.matchotherCrads;
    }
    // at view controller
    – (void)updateTouchCardButtonDescriptionLabel
    {
    if (self.game.matchOtherCardsScore > 0) {
    self.lastConsiderationLabel.text = [NSString stringWithFormat:@”Matched %@ for %ld points!”,[[self.game cardsTryMatching] componentsJoinedByString:@”,”],
    (long)self.game.matchOtherCardsScore];
    }
    else if (self.game.matchOtherCardsScore < 0) {
    self.lastConsiderationLabel.text = [NSString stringWithFormat:@"%@ don't match! %ld points penalty!",[[self.game cardsTryMatching] componentsJoinedByString:@","],
    (long)self.game.matchOtherCardsScore];
    } else {
    NSArray* arr=[self.game cardsTryMatching] ;
    self.lastConsiderationLabel.text = [arr componentsJoinedByString:@","];
    }
    }

    all of the code work will but the problem is when display the array it does not display the objects instead it display the addresses like "”
    i don’t know why ?!

    • Hi!

      I have not read your code carefully (I need more time), but I wonder: have you implemented the description method inside the Card class?

      If you take a look at the documentation for componentsJoinedByString you find: Each element in the array must handle description!

      • thanks this is great and very helpful for me i really don’t implement description function and no it’s work 🙂
        thanks for your quick reply and sorry as I’m a beginner

  5. i observe something when calculate the penalty at 3 mode matching , matching score is always -2 penalty
    as here in the code
    ///
    self.matchOtherCardsScore-=MAtch_PENALTY;
    //
    where when we calculate the bonus we calculate it for each card as we say “score+=”, so i sugest that also penalty should be for every card by calculate it like
    ///
    self.matchOtherCardsScore-=MAtch_PENALTY*(self.cardMatchingMode -1);

Leave a Reply

Required fields are marked *.