【问题标题】:Is it possible to have only 2 of the same numbers come out of arc4random()? [duplicate]是否有可能只有 2 个相同的数字来自 arc4random()? [复制]
【发布时间】:2014-10-16 20:40:48
【问题描述】:

我正在制作一个简单的记忆游戏应用程序,我想让它随机放置图片。所以我使用的是arc4random() %4。我有 4 张图片,每张图片需要 2 张才能显示总共 8 张。但是当我执行 arc4random() 时,每张图片都超过 2 张。

这是我的代码 这是我的 .M 文件

#import "GameViewController.h"

@interface GameViewController ()

@end

@implementation GameViewController

-(void)Card1SelectedType{

    switch (card1Type) {
        case 0:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"cell phone.jpeg"];
            [card1 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card1];

        }
            break;
            case 1:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"Dinasore.jpeg"];
            [card1 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card1];

        }
            break;
        case 2:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"jump Rope.jpeg"];
            [card1 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card1];

        }
            break;
            case 3:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"monkey.jpeg"];
            [card1 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card1];

        }
            break;

        default:
            break;
    }

}
-(void)Card2SelectedType{

    switch (card2Type) {
        case 0:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"cell phone.jpeg"];
            [card2 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card2];

        }
            break;
        case 1:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"Dinasore.jpeg"];
            [card2 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card2];

        }
            break;
        case 2:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"jump Rope.jpeg"];
            [card2 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card2];

        }
            break;
        case 3:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"monkey.jpeg"];
            [card2 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card2];

        }
            break;

        default:
            break;
    }

}
-(void)Card3SelectedType;{
    switch (card3Type) {
        case 0:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"cell phone.jpeg"];
            [card3 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card3];

        }
            break;
        case 1:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"Dinasore.jpeg"];
            [card1 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card3];

        }
            break;
        case 2:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"jump Rope.jpeg"];
            [card3 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card3];

        }
            break;
        case 3:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"monkey.jpeg"];
            [card3 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card3];

        }
            break;

        default:
            break;
    }

}
-(void)Card4SelectedType{
    switch (card4Type) {
        case 0:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"cell phone.jpeg"];
            [card4 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card4];

        }
            break;
        case 1:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"Dinasore.jpeg"];
            [card4 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card4];

        }
            break;
        case 2:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"jump Rope.jpeg"];
            [card4 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card4];

        }
            break;
        case 3:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"monkey.jpeg"];
            [card4 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card4];

        }
            break;

        default:
            break;
    }

}
-(void)Card5SelcetedType{
    switch (card5Type) {
        case 0:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"cell phone.jpeg"];
            [card5 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card5];

        }
            break;
        case 1:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"Dinasore.jpeg"];
            [card5 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card5];

        }
            break;
        case 2:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"jump Rope.jpeg"];
            [card5 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card5];

        }
            break;
        case 3:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"monkey.jpeg"];
            [card5 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card5];

        }
            break;

        default:
            break;
    }

}
-(void)Card6SelectedType{
    switch (card6Type) {
        case 0:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"cell phone.jpeg"];
            [card6 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card6];

        }
            break;
        case 1:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"Dinasore.jpeg"];
            [card6 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card6];

        }
            break;
        case 2:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"jump Rope.jpeg"];
            [card6 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card6];

        }
            break;
        case 3:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"monkey.jpeg"];
            [card6 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card6];

        }
            break;

        default:
            break;
    }

}
-(void)Card7SelectedType{
    switch (card7Type) {
        case 0:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"cell phone.jpeg"];
            [card7 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card7];

        }
            break;
        case 1:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"Dinasore.jpeg"];
            [card7 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card7];

        }
            break;
        case 2:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"jump Rope.jpeg"];
            [card7 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card7];

        }
            break;
        case 3:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"monkey.jpeg"];
            [card7 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card7];

        }
            break;

        default:
            break;
    }

}
-(void)Card8SelectedType{
    switch (card8Type) {
        case 0:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"cell phone.jpeg"];
            [card8 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card8];

        }
            break;
        case 1:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"Dinasore.jpeg"];
            [card8 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card8];

        }
            break;
        case 2:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"jump Rope.jpeg"];
            [card8 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card8];

        }
            break;
        case 3:
        {
            UIImage *ButtonImage = [UIImage imageNamed:@"monkey.jpeg"];
            [card8 setImage:ButtonImage forState:UIControlStateNormal];
            [self.view addSubview:card8];

        }
            break;

        default:
            break;
    }

}


- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    card1Selected.hidden = YES;
    card2Selected.hidden = YES;
    card3Selected.hidden = YES;
    card4Selected.hidden = YES;
    card5Selected.hidden = YES;
    card6Selected.hidden = YES;
    card7Selected.hidden = YES;
    card8Selected.hidden = YES;

    card1Type = arc4random() %4;
    card2Type = arc4random() %4;
    card3Type = arc4random() %4;
    card4Type = arc4random() %4;
    card6Type = arc4random() %4;
    card7Type = arc4random() %4;
    card8Type = arc4random() %4;


    [self Card1SelectedType];
    [self Card2SelectedType];
    [self Card3SelectedType];
    [self Card4SelectedType];
    [self Card5SelcetedType];
    [self Card6SelectedType];
    [self Card7SelectedType];
    [self Card8SelectedType];







    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

这是在我的 .h 文件中

![#import <UIKit/UIKit.h>

int card1Type;
int card2Type;
int card3Type;
int card4Type;
int card5Type;
int card6Type;
int card7Type;
int card8Type;



@interface GameViewController : UIViewController
{
    IBOutlet UIButton *card1;
    IBOutlet UIButton *card2;
    IBOutlet UIButton *card3;
    IBOutlet UIButton *card4;
    IBOutlet UIButton *card5;
    IBOutlet UIButton *card6;
    IBOutlet UIButton *card7;
    IBOutlet UIButton *card8;
    IBOutlet UIImageView *card1Selected;
    IBOutlet UIImageView *card2Selected;
    IBOutlet UIImageView *card3Selected;
    IBOutlet UIImageView *card4Selected;
    IBOutlet UIImageView *card5Selected;
    IBOutlet UIImageView *card6Selected;
    IBOutlet UIImageView *card7Selected;
    IBOutlet UIImageView *card8Selected;




}

-(void)Card1SelectedType;
-(void)Card2SelectedType;
-(void)Card3SelectedType;
-(void)Card4SelectedType;
-(void)Card5SelcetedType;
-(void)Card6SelectedType;
-(void)Card7SelectedType;
-(void)Card8SelectedType;



@end][1]

【问题讨论】:

标签: ios objective-c random arc4random


【解决方案1】:

解决这个问题的方法很简单,随机排列一个数组。在这种情况下,数组表示一个固定的值集合,很像一副扑克牌/扑克牌。洗牌不会添加或移除任何牌 - 例如即使经过一百万次洗牌,也有 4 个(并且只有 4 个)A,每种花色一个。

所使用的算法在其他几个问题中进行了讨论,例如Re-arrange NSArray/MSMutableArray in random order,(正确的)提出的解决方案通常实现Fisher-Yates Shuffle。包装解决方案,产生一个整洁的功能:

-(void)shuffleArray: (NSMutableArray*)arr {
  NSUInteger count = [arr count];
  for (NSUInteger i = 0; i < count; ++i) {
     int nElements = count - i;
     // See JeremyP's comment
     int n = arc4random_uniform(nElements) + 1;
     [ar exchangeObjectAtIndex:i withObjectAtIndex:n];
  }
}

(也可以编写这样的 shuffle 以直接针对普通 C 数组工作,在这种情况下就足够了。)

现在,考虑最初具有值 [0, 0, 1, 1, 2, 2, 3, 3] 的数组,其中每个数字恰好出现两次并代表一个图像。它可能像这样创建:

-(NSMutableArray*)createCardTypeDeck: {
    NSMutableArray *cardTypes = [NSMutableArray arrayWithCapacity:8];
    for (int i = 0; i < 4; i++) {
        // Add the same number twice, for a total 8 objects added
        [cardTypes addObject:[NSNumber numberWithInteger:i]];
        [cardTypes addObject:[NSNumber numberWithInteger:i]];
    }
    return cardTypes;
}

最后,让我们把它们放在一起删除一些不必要的复制粘贴方法;这可以进一步完善,但我希望它显示出足够的变化而不会“太复杂”。

// Take in /a/ card and the type, so it will work for all cards;
// don't add the card to the view here. Note there is no hard-coding of
// card1..card8 and thus there is NO NEED to duplicate this method 8 times!
-(void)updateCard: (UIButton*) card, cardType: (int) cardType ({
    // The imageName and UIImage creation could be further extracted but
    // this should be sufficient to show how much common code (and copy'n'paste)
    // can be eliminated - resulting in shorter and more readable code.
    NSString *imageName;
    switch (cardType) {
        case 0:
            imageName = @"cell phone.jpeg";
            break;
        case 1:
            imageName = @"Dinasore.jpeg";
            break;
        case 2:
            // .. etc
            break;
        default:
            image = nil; // but really an error of some sort
            break;
    }
    UIImage *image = [UIImage imageNamed:imageName];
    [card setImage:image forState:UIControlStateNormal];
}

现在我们也可以对卡片进行一般处理,只要我们将它们视为一个数组。

-(void)viewDidLoad
{
    // Create card/cardType deck, values   -> [0, 0, 1, 1, 2, 2, 3, 3]
    NSMutableArray *cardTypes = [self createCardTypeDeck];
    // Shuffle the card types, result e.g. -> [2, 1, 0, 3, 2, 3, 0, 1]
    [self shuffleArray: cardTypes];

    // At least we only use the names once now
    NSArray *cards = [NSArray arrayWithObjects:
                                card1, card2, card3, card4,
                                card5, card6, card7, card8, nil];

    // For each card, assign it an image and otherwise finish adding it
    for (int i = 0; i < 8; i++) {
        // Get now shuffled cardType and this index
        // (We know that only values 0..3 will appear and each will appear
        //  exactly twice - as only those values, and that multiplicity,
        //  have been added to the original array before shuffling.)
        int cardType = [[cardTypes objectAtIndex:i] intValue];
        // Get the card to apply the changes to, and do so
        UIButton* card = [cards objectAtIndex:i];
        [self updateCard:card withType:cardType];
        // Then add the card view
        [self.view addSubview:card];
    }

    [super viewDidLoad];
}

YMMV。错误是免费的。玩得开心。

【讨论】:

  • 一个小批评,不要使用 arc4random() % n 来获取 0 和 n 之间的数字,因为它会有 modulo bias 。请改用arc4random_uniform()
  • @JeremyP 感谢您的反馈。我已经更新了答案 - 留下评论,因为它也被引用了!
猜你喜欢
  • 1970-01-01
  • 2021-03-19
  • 2011-01-29
  • 1970-01-01
  • 2021-09-17
  • 2015-04-14
  • 2019-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多