从甲板上抽一张牌进行扑克的蒙特卡罗模拟

时间:2013-09-28 10:31:47

标签: objective-c random montecarlo poker

目前我正在开发一个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次)! 目前,整个过程是缓慢的,我需要真正优化它。 我有一些想法:

  • 更快的随机数生成器
  • 将套牌的整个高级别表示(Objective-C类包括一张播放卡的NSArray)和卡片(Objective-C Class)更改为普通C-Arrays和结构中的表示
  • 将套牌和牌的整个表示更改为按位级别并在那里做所有事情

你怎么看? 你有其他想法吗?
你知道一个更适合(更快)的随机数发生器吗?

提前致谢!

3 个答案:

答案 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调用一次,结果是每次抽奖的摊销常数时间。这应该避免由于识别已绘制的值和拒绝而导致的任何开销。如果你想在重新洗牌之前避免处理整个牌组,你可以添加一个重置方法。