目前我正在开发一个iOS应用程序,我需要从卡片中抽取随机卡片。目前我的代码看起来像这样:
- (PlayingCard*) drawRandomCard
{
PlayingCard * randomCard = nil;
NSUInteger index = arc4random_uniform(self.cards.count);
randomCard = self.cards[index]; //self.cards is an NSArray of PlayingCard's
while (randomCard.isUsed) {
index = arc4random_uniform(self.cards.count);
randomCard = self.cards[index];
}
randomCard.used = YES;
return randomCard;
}
这种方法被大量调用(一次蒙特卡罗模拟的时间为50'000 - 1'000'000次)! 目前,整个过程是缓慢的,我需要真正优化它。 我有一些想法:
你怎么看?
你有其他想法吗?
你知道一个更适合(更快)的随机数发生器吗?
提前致谢!
答案 0 :(得分:2)
随机查看循环中的完整套牌
while (randomCard.isUsed) {
并且不仅仅是那些仍处于游戏中的游戏,当你到达游戏结束时,你会得到很多重试。使用最后一张卡(编号52)给出&gt; 25次失误。横向整个牌组平均总共超过<600>次失误。
除此之外,您还需要重新设置套牌才能再次使用它。我想你有一个方法可以通过循环遍历所有卡来重置牌组,然后进行used = NO
。即使您只需要处理一张卡,这也会在套牌上提供 52次操作。
通过这个简单的解决方案可以避免这两个问题。
将所有卡存储在阵列中。然后将一端用于尚未处理的卡片,另一端用于已经处理的卡片:
<---------------------- not yet dealt ---------------------->
[ ah 2h 3h 4h 5h 6h 7h 8h 9h 10h jh qh kh ad 2d ..... jk qk kk ]
^
dealt
cards
随机选择尚未发牌
卡范围内的卡片(7h):[ ah 2h 3h 4h 5h 6h 7h 8h 9h 10h jh qh kh ad 2d ..... jk qk kk ]
^^
用最后一个尚未发出的东西切换它,并将发出的卡片指针移到左边的位置。
<-------------------- not yet dealt --------------------->
[ ah 2h 3h 4h 5h 6h kk 8h 9h 10h jh qh kh ad 2d ..... jk qk 7h ]
^
dealt
cards
根据需要重复:
<------------------ not yet dealt ----------------->
[ ah 2h qk 4h 5h 6h kk 8h 9h 10h jh jk kh ad 2d ..... qh 3h 7h ]
^
dealt
cards
当你需要一个新牌组时,只需将已发牌指针移回到最后,牌组即可供新用途使用。
<----------------------- not yet dealt ---------------------->
[ ah 2h qk 4h 5h 6h kk 8h 9h 10h jh jk kh ad 2d ..... qh 3h 7h ]
^
dealt
cards
套牌的新顺序只会增加随机性......
答案 1 :(得分:0)
我假设您多次调用此方法从卡片中绘制卡片,将绘制卡片的used
属性设置为YES
,以便不再绘制它。
您可以从卡片中取出卡片并将其放在usedCards
数组中,而不是设置属性,从而为您节省可能永无止境的while
循环。
另一种方法是最初对牌组进行洗牌,然后从阵列的开头或末尾抽出牌。
答案 2 :(得分:0)
保持指向最后一张牌的静态索引(最初设置为-1)。每次调用该方法时,都要使索引模self.cards.count
前进,如果结果为零,则对该套牌进行洗牌。然后在索引处返回卡片。由于像Fisher-Yates / Knuth这样的体面改组是Theta(self.cards.count
)但是只从self.cards.count
调用一次,结果是每次抽奖的摊销常数时间。这应该避免由于识别已绘制的值和拒绝而导致的任何开销。如果你想在重新洗牌之前避免处理整个牌组,你可以添加一个重置方法。