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?

Replies

I'm not sure I understand what you want to do exactly.


There is something I miss in your post.

You speak of 52 * 52 * 52 combinations.

But when first card is selected, 2nd must be different, 3rd different from the first 2

So that would make 52 * 51 * 50 = 132600 combinations (without the jokers). How are jokers used ?

Can 2 or 3 jokers be in a draw ?


So, basically, what does A1, B1, C1 exactly means, with real cards and jokers ?


But if your question is how to build the combination of 3 cards in 52, would be in Swift (very similar in objc)


for firstCard in 1...52 {
     for secondCard in 1...52 where secondCard != firstCard {
          for thirdCard in 1...52 where thirdCard != firstCard && thirdCard != secondCard {
               print"draw is", cards[firstCard], cards[secondCard], cards[thirdCard])
          }
     }
}


But that does not account for jokers, until further information.

The cards can be the same. If I have three jokers they can be all A’s of spades if they want to be because there are multiple decks in play. So you need to calculate every possible combination for the jokers to see what the best possible hand could be.

So please explain more clearly, you have your game in mind, we have not.


You have 3 different decks of 52 cards ?

WHere are the jokers, in each deck ?

How do you draw 3 cards ? One from each deck ? How are jokers inserted ?

etc…, do need clarification.


What is now precisely your coding problem ?

Is it to generate the 140,608 comninations ?

If so, code is straightforward (Swift, bet objc will be very similar), without insertion of jokers (see previous questions)


for firstCard in 1...52 { 
     for secondCard in 1...52  { 
          for thirdCard in 1...52  { 
               print"draw is", cards[firstCard], cards[secondCard], cards[thirdCard]) 
          } 
     } 
}

It isn’t a standard poker game so it isn’t relevant to figure out why. I need a dynamic way for the loop to go “deeper” be joker. I have the exact functionality you have and it works perfectly. But I have to have a function for each number of jokers, that seems like a hack. So one joker in the card array only can be 52 possibilities. An array with two jokers can be 52 * 52 and so on. Your array, like mine, isn’t dynamic in its depth of nested loops. If I have to use our current methods I have to say if one joker then do this function. If three jokers then do this one. There should be a way to create a single loop whose depth is determined by the number of jokers.

It was still hard to understand, but hope I got it

I need a dynamic way for the loop to go “deeper” be joker.

the number of loops depend on the number of jokers.

There should be a way to create a single loop whose depth is determined by the number of jokers.

This sheds some light on what you want…



So I did this, some type of recursiveness (still in Swift).


let nbJokers = 3
let nbCards = 52
var allDraws = [[Int]]()

func addJoker() {
   
    if allDraws == [] {
        // for the first series
        for i in 1...nbCards {
            allDraws.append([i])
        }
        return
    }
    var currentDraws = [[Int]]()
    for i in 1...nbCards {
        for var draw in allDraws {
            draw.append(i)
            currentDraws.append(draw)
        }
    }
    allDraws = currentDraws
}

for joker in 1...nbJokers {
    addJoker()
    print("Joker \(joker) counted", allDraws.count)
}


I get the expected results:

Joker 1 counted 52

Joker 2 counted 2704

Joker 3 counted 140608


Is it what you were looking for ?

If not, please explain very clearly.

If yes, don't forget to close the thread.

Thanks for your help. It isn’t what I’m after but that’s ok. I’ll just create different methods for the different numbers of jokers. These functions are for evaluating the hand score after a cards have been dealt. It is far easier to check the possible score/value of the hand by substituting the joker than it is to do it any other way. My goal was to say ok the cards have been dealt, let’s remove any jokers and replace it with a card and check the value of the hand. The only way to do that is that the joker has to be substituted for every possible value it can be and the check the value of the hand through my other existing functions.

Now that you have more clearly described the problem, here is a possible solution:


setup a "bestValue" float and a "bestHand" array


set up a recursive method 'cycle'


cycle -

loop through each card in the hand

if this hand card is a joker then

loop through all cards in the deck (1-52)

replace this hand card with that card

call cycle with the modified hand

if there are no jokers in this (possibly modified) hand

test hand for value

if better than current bestValue then reset bestValue and call this hand the bestHand

bestValue and bestHand determined

And that is how I have it and it works perfectly. However for more than one joker, you must replace all jokers and then test. Therefore you need every possible combination of jokers tested.

Note that the method "cycle" is called multiple times from within the method "cycle" using a modified hand in which one or more jokers are replaced with each of the 52 other cards. Note that within the method "cycle" the modified hand is not tested for value if it has a joker in it.


This is recursive programming. Stare at it for a while until you go "oh, I see!"

PBK and edgeoftheatlas,


PBK is right, although moving the pseudo-code into Swift will be challenging until you get the right point of view about how recursion works. additionally, PBK's phrase "loop through each card in the hand" can be absorbed directly in the recursion.


i'd describe the recursion this way: for a hand of cards that is represented as say x = [3,2,53,4,53], with real cards being 1...52 and a joker as 53, it helps to think of finding the value of score or the value of the hand by breaking it out is "prefix" and "suffix" terms:


the value of [3,2,53,4,53]

is the value of [] and [3,2,53,4,53] joined

is the value of [3] and [2,53,4,53] joined

is the value of [3,2] and [53,4,53] joined

is the maximum value of [3,2,x] and [4,53] joined, for each possible x

is the value of [3,2,x,4] and [53] joined

is the maximum value of [3,2,x,4,y] and [] joined, for each possible y

is the "no jokers" value of [3,2,x,4,y]


when you look at it like this, i suggest a simple recursion, but it requires a little subtlety to get things started


-- a function that i call "noJokersValue" that returns the value of any hand that has NO jokers.


-- a function that i call "value" that returns the value of any hand (jokers or not, as many jokers as you like, for a hand of any length) by kicking off a recursive call to a function that figures out the value of a hand with prefix [] and suffix [3,2,53,4,53]


-- this recursive function when called then looks at the suffix.

(1) if the suffix is empty, evaluate the "no jokers" value of the prefix (it has no jokers)

(2) if the suffix is not empty, identify and remove the first card in the suffix

(2a) if the card is not a joker, add it to the prefix and recurse with the remaining suffix

(2b) if the card is a joker, loop over all possible substitutions for the card, adding each to the prefix and recursing with the remaining suffix. pick the biggest of all 52 of these.


so i have the following code for your consideration. it evaluates every hand to have a value of "1," but prints the hand so that you can see you're getting all possible combinations. the code also does not depend on the length of the array.


import Foundation

// assume cards are numbered 1...52 as you suggested
// use 53 to represent a Joker
let kJoker = 53

// this first function assigns a value to every hand that has no jokers.
// for this demonstration, we assume that the value of any hand will
// be non-negative.
func noJokersValue(hand: ArraySlice<Int>) -> Int {
  print(hand)
  return 1
}

// the value function assigns a value for any hand of cards.  it's AN ENTRY POINT that
// calls a more general, recursive helper function to figure out the value of a
// hand that has been separated into a prefix and a suffix, e.g., separating [2,3,4,53,8]
// into prefix = [2,3,4] and suffix = [53,8], where the prefix has NO jokers, and the
// suffix MAY HAVE jokers.  to get the process started, separate the hand into
// an empty prefix and suffix = the given hand, i.e., [] and [2,3,4,53,8].
func value(hand: [Int]) -> Int {
  return value(prefix: [], suffix: hand[0...(hand.count)-1])
}

// this function does the real recursion work.  when called, we know that the prefix has no jokers in it.
func value(prefix: ArraySlice<Int>, suffix: ArraySlice<Int>) -> Int {
  // if there are no cards left to move from the suffix to the prefix, just return
  // the ordinary value of the prefix, since it was the original hand and has no jokers
  if suffix.isEmpty {
  return noJokersValue(hand: prefix)
  }

  // otherwise, identify and remove the first card from the suffix
  let nextCard = suffix.first!
  let newSuffix = suffix.dropFirst()

  // if the first card in the suffix IS NOT a joker, make a direct recursive call by
  // removing the first card of the suffix and adding it to the prefix.
  if nextCard != kJoker {
  return value(prefix: prefix + [nextCard], suffix: newSuffix)
  }

  // but if this first card IS a joker, we recursively look through all
  // possible substitutions of the joker with a legitimate card, adding
  // each possible substitution to the prefix.  we get the value
  // after each substitution is made, and if it's bigger than what we
  // had seen before, remember it
  var maxValue = 0 // assumes all values will be non-negative
  for card in 1...52 {
  let nextValue = value(prefix: prefix + [card], suffix: newSuffix)
  if nextValue > maxValue {
  maxValue = nextValue
  }
  }
  // return the largest value seen
  return maxValue
}

let x = [3,2,kJoker,4,kJoker]
print(value(hand: x))


one syntactic point: some arguments are typed as ArraySlice<Int>. you can certainly pass such a function a real Array of Int, but when you start using .suffix(), you get an ArraySlice, which is a fancy way of saying: "it's not a real array, but a reference you can use" that works perfectly well later when using (some) functions like .isEmpty() or additional .suffix() calls. it removes the burden of, at every level, creating a new Array in memory and it will run faster with ArraySlice.


hope that helps,

DMG

This prefix and suffix makes no sense to me. Trying to translate to objective c is also very difficult. Thanks for your help...

I'm lost. How can you call a method to get the next possible card? I'm so confused...

This works but I have to see if there are any more jokers and dig deeper into combinations.


         // vars
        NSArray *jokersArray = [self makeArrayOfJokers:valueSortedArray];
        NSMutableArray *noJokersArray = [self makeArrayofNoJokers:valueSortedArray];
        HandRank highestRank = HandRankNone;
        NSMutableArray *fullDeck = [NSMutableArray new];
       
        // cycle
        for(Suit suit = SuitClubs; suit <= SuitSpades; ++suit){
            //NSLog(@"suit: %d", suit);
           
            // cycle
            for(int value = CardAce; value <= CardKing; ++value){
                // create
                Card *card = [[Card alloc] initWithSuit:suit value:value];
               
                // add
                [fullDeck addObject:card];
                //NSLog(@"card %@ = suit: %d value: %d", card, card.suit, card.value);
            }
        }
       
        // cycle
        for(int i = 0; i < fullDeck.count; i++){
            // vars
            Card *card = [fullDeck objectAtIndex:i];
            //NSLog(@"card %@ = suit: %d value: %d", card, card.suit, card.value);
           
            // check
            if(jokersArray.count > 1){
                // cycle
                for(int j = 0; j < fullDeck.count; j++){
                    // vars
                    Card *subcard = [fullDeck objectAtIndex:j];
                    NSMutableArray *newCardArray = [noJokersArray mutableCopy];
                   
                    // add
                    [newCardArray addObject:card];
                    [newCardArray addObject:subcard];
                   
                    // vars
                    NSArray *newValueSortedArray = [newCardArray sortedArrayUsingDescriptors:@[valueDescriptor]];
                    HandRank newHandRank = [self getHandRank:newValueSortedArray];
                   
                    // check
                    if(newHandRank > highestRank){
                        // set
                        highestRank = newHandRank;
                       
                        NSLog(@"new high rank %@", [self getHandRankName:highestRank]);
                    }
                }
            }
            else{
                // vars
                NSMutableArray *newCardArray = [noJokersArray mutableCopy];
               
                // add
                [newCardArray addObject:card];
               
                // vars
                NSArray *newValueSortedArray = [newCardArray sortedArrayUsingDescriptors:@[valueDescriptor]];
                HandRank newHandRank = [self getHandRank:newValueSortedArray];
               
                // check
                if(newHandRank > highestRank){
                    // set
                    highestRank = newHandRank;
                   
                    NSLog(@"new high rank %@", [self getHandRankName:highestRank]);
                }
            }
        }



I just don't know how to make it dynamic in the depth for which it checks the combinations of jokers.

Following your psuedo code, I'm still lost. This for now just goes one by one and replaces the jokers 52 times. I don't understand how to send it back throug a cycle method?!?!?!?


// vars
    NSMutableArray *cardArray = [valueSortedArray mutableCopy];
    
    // cycle
    for(Card *card in valueSortedArray){
        // check
        if(card.value == CardJoker){
            // cycle
            for(int i = 0; i < fullDeck.count; i++){
                // vars
                Card *tempCard = [fullDeck objectAtIndex:i];
                
                // replace
                [cardArray replaceObjectAtIndex:[valueSortedArray indexOfObject:card] withObject:tempCard];
            }
        }
    }

hi,


please let me apologize for posting Swift code. everything i read in the thread was either pseudo-code or Swift, and i failed to read the last three words of your original post, which were "in obj c?"


also, i have moved this response out to the main level of the thread, just so we don't keep indenting everyone else's reply from here on.


on language that i have used: prefix and suffix are simply terms to denote the first part of an array and the second part of an array. example: [2,3,4,5,6] might be split as a prefix of [2,3,4] and a suffix of [5,6]. if so, the trick is to move the leading 5 from the suffix into the prefix and recursively consider prefix [2,3,4,5] and suffix [6] ... and then as prefix [2,3,4,5,6] and suffix []. when a joker is the lead item of a suffix, that's when one must loop over what to append to the prefix when replacing removing the joker at from the start of the suffix.


it may take me awhile to come up with an Obj-C equivalent -- i haven't written any Obj-C since Swift came out; NSArray and NSMutableArray are different critters; and even remembering how to carry out the simplest of operations is rusty. and i keep getting these error messages "Expected ';' after expression" !


if anyone else wants to jump in before i come back to this, please do! apart from massaging the code and syntax to handle extracting the first item from an NSMutableArray and appending it to an NSMutableArray, the algorithm does work.


i hope to have more later, if i can get up the courage to try some Obj-C !

DMG