0

I'm making a memory game in iOS. There is a 4x4 grid and I want to know the logic of how can I generate random numbers not greater than 4. These numbers will be assigned to 16 cells of 4x4 grid. But when I apply the functions of random numbers it generate lets say 2 6 times, but in a 4x4 grid I want it to generate one number max 4 times. Here is how I'm doing it:

for (int i=0; i<16; i++) {
        int r = arc4random() % 4;
        NSLog(@"r = %d at i = %d",r,i);
    }

But it generates one number more than 4 times. One more problem I just found that there is a chance that a number never occurs say 0 occurs 4 times, 2 occurs 8 times and 3 occurs 4 times so 1 will be skipped. Kindly address that problem too.

Chaudhry Talha
  • 7,231
  • 11
  • 67
  • 116
  • Please confirm - each number 0, 1, 2, and 3 should each appear exactly 4 times. Correct? That's the only way you can fill 16 spots where no one number happens more than 4 times. – rmaddy Jan 15 '15 at 06:25
  • @rmaddy yes that is true. One more problem I just realized that there is a chance that a number never occurs. Kindly address that problem too. – Chaudhry Talha Jan 15 '15 at 06:31
  • @TalhaCh Sorry, but you're not listening at all at this point. It's all in Bair's answer and in the comments below it. – Lyndsey Scott Jan 15 '15 at 06:32
  • @TalhaCh Not possible. To fill 16 spots with 4 numbers where no one number can occur more than 4 times, this means all 4 numbers MUST occur exactly 4 times each. – rmaddy Jan 15 '15 at 06:33
  • @LyndseyScott I got my answer. Which I was not getting before. :) – Chaudhry Talha Jan 15 '15 at 06:35
  • @TalhaCh Glad to hear :) – Lyndsey Scott Jan 15 '15 at 06:36

2 Answers2

4

You don't want to allow more than 4 of each 1 .. 4. Nevertheless, you want to fill a 4x4 grid, this implies that there must be 4 of each number. Assume otherwise, then you will end up with less than 16 numbers. What I recommend you do is create an array that contains four of each number and shuffle it using this answer and place the numbers appropriately.

Community
  • 1
  • 1
Dair
  • 15,910
  • 9
  • 62
  • 107
  • What about the number that generates 6 times from the total of 16 times? If I apply check on `NSArray` in which I'll store these 16 numbers the for loop is running only 16 times and it may not fill the `NSArray`. I saw the link it'll help me in shuffle which I'll use but right now the problem is different. – Chaudhry Talha Jan 15 '15 at 06:23
  • 2
    @TalhaCh Put the number 1 in the array 4 times. Put the number 2 in the array 4 times, as well as for 3 and 4. You now have 16 numbers in the array, each 4 times. Now shuffle the array. Done. – rmaddy Jan 15 '15 at 06:27
  • 1
    @TalhaCh: I think you are going about this the wrong way. You have a `4x4` grid. It has `4*4 = 16` elements. If you max the number of times you can see each number to `4` times, you MUST have 4 of each number. The amount of each number you have will NEVER be random with this restraint. (So you never have to worry about the more than 4 case) What is random is the position on the grid that they are placed. – Dair Jan 15 '15 at 06:28
  • @maddy Thnx. Haha. That would be a much bigger grid. – Dair Jan 15 '15 at 06:28
  • @rmaddy good point though. Thank You now I understand what bair was trying to say. Thanks again both :) – Chaudhry Talha Jan 15 '15 at 06:34
1

You can generate random numbers between 1..4 which does not exceed 4 times of each numbers using this solution

//create the property to add the integers
@property (nonatomic, strong) NSMutableArray *myArray;

- (void)generateMyRandomArray {
    _myArray = [[NSMutableArray alloc] init];
    for (int i=0; i<16; i++) {
        NSInteger r = [self randomNumber];
        [self validateIfNumberExist:r];
    }

    NSLog(@"my Array = %@", self.myArray); // this is resulted array between 1..4 each 4 times
    NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES];
    NSArray *result =[self.myArray sortedArrayUsingDescriptors:@[sort]];
    NSLog(@"Result Array = %@", result); //just to check 
}

- (void)validateIfNumberExist:(NSInteger)number {
    if ([self.myArray count] > 0) {
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF == %d", number];
        NSArray *resultArray = [self.myArray filteredArrayUsingPredicate:predicate];
        if ([resultArray count] < 4) {
             [self.myArray addObject:@(number)];
        } else {
            [self validateIfNumberExist:[self randomNumber]];
        }
    } else {
        [self.myArray addObject:@(number)];
    }
}

- (NSInteger)randomNumber {
    return 1 + arc4random_uniform(4);
}
Suhit Patil
  • 11,748
  • 3
  • 50
  • 60
  • haha :D thanks man... I don't know what you did there I just copy/paste the code and it works just perfect. – Chaudhry Talha Jan 15 '15 at 09:22
  • @TalhaCh great you liked what I did :-) – Suhit Patil Jan 15 '15 at 09:44
  • 1) Sorry, but this is a terribly inefficient solution. 2) @TalhaCh It's a bad idea to blindly copy and paste a solution you don't understand. Especially a solution that is far from ideal. What happens when your needs change? You won't have any idea how to change or fix the code. – rmaddy Jan 15 '15 at 17:38
  • @rmaddy: This is not the generic solution for all the situations but correctly satisfies the requirement asked in the question. If some changes need to be made, it can be easily done but I do agree that one should understand then use the solution. – Suhit Patil Jan 15 '15 at 17:44
  • @suhit I didn't say the answer was wrong, just that it's very inefficient (and overly complex for the task). But for only 16 values, the inefficiency isn't a big deal at runtime. – rmaddy Jan 15 '15 at 17:48
  • @rmaddy I do agree it's bit complex for this task compared to the solution given by Bair – Suhit Patil Jan 15 '15 at 17:55
  • I agree one should understand the code. I'm working on Apple Watch and all I know is this app didn't need changes. Deadline is short and if I come up with a problem I'll post it again. :) But for now this code works perfectly for me. – Chaudhry Talha Jan 15 '15 at 18:05