For loop question

Basically I have an array of jokers for a card game. The number of jokers in this array can be any number really. What I need to do is loop through every possible combination of those jokers being any of the other 52 cards. So something like this needs to happen:


Jokers array (A, B, C)

1-52 representing each of the 52 possible cards.

Results for looping:


A1, B1, C1

A1, B1, C2

...

A1, B1, C52

A1, B2, C1

A1, B1, C2

...

A1, B2, C52

...

A1, B52, C52

A2, B1, C1

...

A52, B52, C52

So this scenario would be 140,608 possible combinations: 52 * 52 * 52, since there are 3 jokers.


How would I write this in obj c?

I believe I have it working. I tried to get both ways working and was able to get the cycle from PBK to work. Here is my code:


-(void)cycleArray:(NSMutableArray *)array{
    // vars
    NSMutableArray *newArray = [array mutableCopy];
    NSSortDescriptor *valueDescriptor = [[NSSortDescriptor alloc] initWithKey:@"value" ascending:YES];
    NSInteger jokerCount = [self getJokerCount:newArray];
    
    // check
    if(jokerCount > 0){
        // cycle
        for(Card *card in array){
            // check
            if(card.value == CardJoker){
                // cycle
                for(int i = 0; i < fullDeck.count; i++){
                    // vars
                    Card *tempCard = [fullDeck objectAtIndex:i];
                    
                    // replace
                    [newArray replaceObjectAtIndex:[array indexOfObject:card] withObject:tempCard];
                    
                    // cycle
                    [self cycleArray:newArray];
                }
            }
        }
    }
    else{
        // vars
        /*NSMutableArray *display = [NSMutableArray new];
        
        // cycle
        for(Card *card in newArray){
            // vars
            NSString *displayString = [NSString stringWithFormat:@"v:%d - s:%d", card.value, card.suit];
            
            // add
            [display addObject:displayString];
        }
        
        NSLog(@"cards at check: %@", display);*/
        
        // vars
        NSArray *newValueSortedArray = [newArray sortedArrayUsingDescriptors:@[valueDescriptor]];
        HandRank newHandRank = [self getHandRank:newValueSortedArray];
        
        // check
        if(newHandRank > handRank){
            // set
            handRank = newHandRank;
            
            //NSLog(@"new high rank %@", [self getHandRankName:handRank]);
        }
    }
}


Thank you to everyone for all your help! This works although very slow when three or more jokers, it should work for now.

hi,


glad to hear you've figured this out, and yes, it will be slow with lots of jokers. there are just a lot of loops to run and a lot of possibilities to check, although those loops are hidden in the recursion rather than writing them directly.


for what it's worth, i did hack out something in Obj-C that somewhat mirrors what i wrote earlier in Swift -- and i also added in a check to be sure to not duplicate any regular card (integer in 1...52) in the process. this is what i got (it's very clunky):


#import <Foundation/Foundation.h>

  // this is the function that should evaluate a hand that has no jokers
  // the value should be non-negative, with higher return values meaning
  // better hands
int nonJokerValue(NSArray* handOfCards) {
  return 1;
}

int valueHelper(NSArray* part1, NSArray* part2) {
  // if part2 is empty, then part1 is all non-jokers, so evaluate it here.
  // for now, print it (to see we get all possibilities) and return
  // its nonJokerValue
  if ([part2 count] == 0) {
    NSLog(@"%@", part1);
    return nonJokerValue(part1);
  }

  // otherwise, get first element of part2
  NSObject* firstObj = [part2 firstObject];
  // form a new part2 with the first object removed
  NSMutableArray* newPart2 = [[NSMutableArray alloc] initWithArray: part2];
  [newPart2 removeObjectAtIndex:0];


  // what we do now depends on the first card in part2.  if it's a regular card
  // in the deck (a number 1...52), just append it to the newFirstPart
  // and make the recursive call
  if (![firstObj isEqual: @53]) {
  // get a mutable version of the first part
    NSMutableArray* newPart1 = [[NSMutableArray alloc] initWithArray: part1];
    [newPart1 addObject: firstObj];
    return valueHelper(newPart1,newPart2);
  }

  // no look through all possible substitutions for the joker moving forward
  // with a regular card and and use the largest value ever seen
  int maxValue = 0;
  for (int i = 1; i <= 52; i++) {
  // copy the first part
    NSMutableArray* newPart1 = [[NSMutableArray alloc] initWithArray: part1];
  // skip over the case of repeating a regular card that's already there
    if ([newPart1 containsObject: [NSNumber numberWithInt: i]]) {
      continue;
    }
  // append next number to try with the first part
    [newPart1 addObject: [NSNumber numberWithInt: i]];
  // get the value for this new part1/part2 pair, and update
  // maxValue if it's larger
    int v = valueHelper(newPart1,newPart2);
    if (v>maxValue) {
      maxValue = v;
    }
  }
  return maxValue;
}

  // main entry point to evaluating a hand of cards
int value(NSArray* someArray) {
  return valueHelper(@[], someArray);
}

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    NSLog(@"%i", value(@[@2, @3, @53, @5, @53]));
  }
  return 0;
}


feel free to use or ignore, as you wish.


good luck,

DMG

Good to hear you got it working. Now optimization....


Consider this:


1) NSInteger jokerCount = [self getJokerCount:newArray];

Better - from getJokerCount return the count of the first joker or some number that indicates no jokers. Then, if you find a joker go immediately to that card. No need for for(Card *card in array){ if(card.value == CardJoker){ ...


2) NSSortDescriptor *valueDescriptor = [[NSSortDescriptor alloc] initWithKey:@"value" ascending:YES];

You only need this if there are no jokers; move it inside the "else"


3) NSMutableArray *newArray = [array mutableCopy];

You only need this if there is a joker; move it inside the jokerCount>0 (or >=0)

(Use "array" in NSArray *newValueSortedArray = [newArray sortedArrayUsingDescriptors:@[valueDescriptor]];)



Recursive stuff is fascinating.

For loop question
 
 
Q