1

I have created a quiz which draws questions from a plist into an array and displays the question in a uilabel and the three possible answers in uibuttons. My question is how can I create a random order for the buttons so that the three answers don't always show up in the same order?

Any help would be most appreciated.

Jamie

Jamie Gordon
  • 61
  • 1
  • 8
  • how are you storing your options and the correct answer – Bharat Gulati Feb 04 '13 at 09:56
  • I am storing the options into my button like this `[btnA setTitle:[[questions objectAtIndex:r] objectForKey:@"A"] forState:UIControlStateNormal]; [btnB setTitle:[[questions objectAtIndex:r] objectForKey:@"B"] forState:UIControlStateNormal]; [btnC setTitle:[[questions objectAtIndex:r] objectForKey:@"C"] forState:UIControlStateNormal];` I then have my three buttons which give 0, 10 or 15 points based on the users answer - just like this `- (IBAction)answer1:(id)sender { [self setPoints:[self points] + 0]; progress.progress += 0.20f; }` – Jamie Gordon Feb 04 '13 at 09:57

4 Answers4

4

Going along with @Abizern's answer. It would be more efficient to have the fixed buttons and randomise the array. You could do something like this:

//NSMutableArray *questions = [[NSMutableArray alloc] initWithObjects:@"1", @"2", @"3", @"4", nil];

NSMutableArray *unorderedQuestions = [[NSMutableArray alloc] init];
for (int i=0; i < [questions count]; i++) {
    int lowerBound = 0;
    int upperBound = 100;
    int rndValue = lowerBound + arc4random() % (upperBound - lowerBound);
    [unorderedQuestions addObject:[[NSArray alloc] initWithObjects:[questions objectAtIndex:i], [NSString stringWithFormat:@"%i", rndValue], nil]];
}

NSArray* sortedArray = [unorderedQuestions sortedArrayUsingFunction:order context:NULL];
//or
// questions = [unorderedQuestions sortedArrayUsingFunction:order context:NULL];
NSLog(@"%@", sortedArray);

and put this function somewhere:

static NSInteger order (id a, id b, void* context) {
    NSString* catA = [a lastObject];
    NSString* catB = [b lastObject];
    return [catA caseInsensitiveCompare:catB];
}

This basically assigns a random number (between 0 and 100) to each question and sorts it by that number. You can then just make sortedArray global (or possibly just overwrite your questions array) and display objects sequentially and they will be shuffled.

[btnA setTitle:[[[questions objectAtIndex:r] objectAtIndex:0] objectForKey:@"A"] forState:UIControlStateNormal];

Judging by your code, you may need to amend a few lines: (but you could also create a currentQuestionsArray and assign it to [questions objectAtIndex:r] before the code above)

for (int i=0; i < [questions count]; i++) {
//to
for (int i=0; i < [[questions objectAtIndex:r] count]; i++) {`

and

[unorderedQuestions addObject:[[NSArray alloc] initWithObjects:[questions objectAtIndex:i], [NSString stringWithFormat:@"%i", rndValue], nil]];
//to
[unorderedQuestions addObject:[[NSArray alloc] initWithObjects:[[questions objectAtIndex:r] objectAtIndex:i], [NSString stringWithFormat:@"%i", rndValue], nil]];`

I think this is the most robust solution, as in the future you may have a different number of answers for a particular question and would not need to edit this to do so!

Patrick
  • 6,495
  • 6
  • 51
  • 78
2

Rather than go through recreating the buttons and positioning them, just have three buttons in fixed locations and assign the answers to them randomly.

How do you assign them randomly? you could either take elements out of the array in a random order and assign them, or, you could just shuffle the array yet always have the object at index 0 appear on the first button and the object at index 2 apear on the second button etc, which I think is easier.

You can see an implementation of array shuffling in this question What's the Best Way to Shuffle an NSMutableArray?

Community
  • 1
  • 1
Abizern
  • 146,289
  • 39
  • 203
  • 257
1

You can place the buttons anywhere e.g. by setting their center property with firstButton.center = newCenter;.
I assume you have created your buttons in Interface Builder. Therefore, you have already the 3 centers that only have to be permuted randomly. With 3 buttons that I call 1, 2 and 3, you have the following 6 possibilities: (123), (132), (213), (231), (312) and (321). Thus you have to select 1 of 6 possibilities randomly. The function arc4random() generates a random integer. To get one between 0 and x, one has to call arc4random() % (x+1). You can use the result to select the right permutation e.g. in the following code example:

Store first the 3 centers:

CGPoint center1 = myButton1.center;
CGPoint center2 = myButton2.center;
CGPoint center3 = myButton3.center;  

and generate new locations later:

int permutation = arc4random() % 6;
switch (permutation) {
    case 0:
        myButton1.center = center1;
        myButton2.center = center2;
        myButton3.center = center3;
        break;
    case 1:
        myButton1.center = center1;
        myButton2.center = center3;
        myButton3.center = center2;
        break;
    case 2:
        myButton1.center = center2;
        myButton2.center = center1;
        myButton3.center = center3;
        break;
    case 3:
        myButton1.center = center2;
        myButton2.center = center3;
        myButton3.center = center1;
        break;
    case 4:
        myButton1.center = center3;
        myButton2.center = center1;
        myButton3.center = center2;
        break;
    case 5:
        myButton1.center = center3;
        myButton2.center = center2;
        myButton3.center = center1;
        break;
    default:
        break;
}
Reinhard Männer
  • 14,022
  • 5
  • 54
  • 116
  • While your idea is reasonable, this is unmaintainable and doesn't scale. You don't need to move the buttons about, just the answers that are displayed on them. – Abizern Feb 04 '13 at 10:31
  • 1
    Scalability was not required. There were exactly 3 buttons. Moreover, we don't know if all buttons look the same. If not, repositioning them might be better than to change their properties. Thus I don't believe your downvoting is justified. – Reinhard Männer Feb 04 '13 at 10:36
0

First you need to calculate your all UIButtons means how many buttons you need to use there and then use for loop to create uibutton in radom order and use tag to perform action on each button.`

-(void)button:(id)sender {
int btnn = 0;
int spacex = 10;
int spacey=20;
int k=0;
saveBtn = [[NSMutableArray alloc] init];
for (int i=0; i<96; i++) {
    if (btnn>14) {
            spacey=spacey+32;
            spacex = 10;
            btnn = 0;
            }
        else {
            btnn++ ;
            k++;
            UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
            btn.frame = CGRectMake(spacex, spacey, 30.0, 32.0);
            [btn setShowsTouchWhenHighlighted:YES];
            int idx;
            idx = arc4random()%[arr count];
            NSString* titre1 = [arr objectAtIndex:idx];
            [btn setTitle: titre1 forState: UIControlStateNormal];
            [btn setBackgroundImage:[UIImage imageNamed:@"Orange.png"] forState:UIControlStateNormal];
            [btn setTitleColor: [UIColor blackColor] forState: UIControlStateNormal];
            [btn.titleLabel setFont:[UIFont fontWithName:@"TimesNewRomanPS-BoldMT" size:21.0]];
            spacex = spacex + 30;
            btn.tag=k;
            [btn addTarget:self action:@selector(aMethod:)forControlEvents:UIControlEventTouchUpInside];
            [saveBtn addObject:btn];
            [self.view addSubview:btn];
            }
    }

use the above method i hope it will work for you.if you have any query then let me know.Thanks

jamil
  • 2,419
  • 3
  • 37
  • 64