快速唯一整数生成

时间:2014-08-03 01:38:53

标签: c# optimization statistics

背景

我正在写一个Cribbage统计计算器。首先,我计算了每张可能的5张牌的分值,然后对wikipedia进行了检查,直到我的数字与他们的数字相同为止。

现在我计算每一对双手(你的手和婴儿床),大约2.3万亿组合,所以优化是关键。

代码

所有卡都被分配了0到51之间的数字。Hand构造函数的长度为int[],并假设最后一张卡是启动卡。既然已经完成了所有的点计算代码,我想优化手牌号码生成过程。

现在我有:

private static IEnumerable<Tuple<int[], int[]>> GetTwoHands()
{
    bool[] avail = new bool[52];
    for (int i = 0; i < 52; i++)
    {
        avail[i] = true;
    }

    // hand 1 cards
    for (int i = 0; i < 52; i++)
    {
        avail[i] = false;
        for (int j = i + 1; j < 52; j++)
        {
            avail[j] = false;
            for (int k = j + 1; k < 52; k++)
            {
                avail[k] = false;
                for (int l = k + 1; l < 52; l++)
                {
                    avail[l] = false;

                    // hand 2 (crib) cards
                    for (int i2 = 0; i2 < 52; i2++)
                    {
                        if (!avail[i2])
                        {
                            continue;
                        }

                        avail[i2] = false;
                        for (int j2 = i2 + 1; j2 < 52; j2++)
                        {
                            if (!avail[j2])
                            {
                                continue;
                            }

                            avail[j2] = false;
                            for (int k2 = j2 + 1; k2 < 52; k2++)
                            {
                                if (!avail[k2])
                                {
                                    continue;
                                }

                                avail[k2] = false;

                                for (int l2 = k2 + 1; l2 < 52; l2++)
                                {
                                    if (!avail[l2])
                                    {
                                        continue;
                                    }

                                    avail[l2] = false;

                                    // shared starter card
                                    for (int m = 0; m < 52; m++)
                                    {
                                        if (!avail[m])
                                        {
                                            continue;
                                        }

                                        yield return Tuple.Create(new int[] { i, j, k, l, m }, new int[] { i2, j2, k2, l2, m });
                                    }

                                    avail[l2] = true;
                                }

                                avail[k2] = true;
                            }

                            avail[j2] = true;
                        }

                        avail[i2] = true;
                    }

                    avail[l] = true;
                }

                avail[k] = true;
            }

            avail[j] = true;
        }

        avail[i] = true;
    }
}

其中il是第一手牌的号码,i2l2是第二个号码, m是入门卡的卡号。显然手中不能有重复的卡片,所以对于秒针,我确保每个卡号都不在手中。

我使用C#的IEnumerable<T>.AsParallel().ForAll(action)来使用我的所有处理器内核,因此Hand(int[])在操作中发生,而不是同步的GetTwoHands()

问题

  • 有没有办法在不牺牲性能的情况下清理所有这些循环?我怀疑,虽然没有经过测试,但由于所有的函数调用,递归会降低它的速度。
  • 是否有更快的算法来生成这些数字?

1 个答案:

答案 0 :(得分:1)

我很晚才进来,但是因为我从7岁开始玩Cribbage(我52岁),我可能会有所帮助。

看起来在其他帖子中有一些递归的暗示。当你谈论大数字时,你也可能是迭代和战略性的。

我知道它可以发布URI,但是......它会节省很多时间。

如果你去http://www.cribbagematch.com/,你可以从2000年创建的Cribbage软件包中找到Tim Schempp的皇家婴儿床重启,目前处于测试阶段。有一个电子邮件地址可以联系到他。前几天我和他说话,他说他用ca.重新测试他的代码。他做出改变的1k游戏。

短篇小说长篇大论是他在2000年整理了几个文档,这些文档为你正在研究的统计数据以及基础算法提供了很多见解。他在2000年使用过。只是准备好看很多西格玛。两份PDF文档大约只有40多页。问他一份副本,因为他已经分享了很多年了。他的一些作品跑了好几天(记得,这是14年前的事了)。

如果您想要播放的数字不符合所提供的信息,那么就足以向您展示如何进行一些自己的特殊计算。例如投掷后,单人牌的四张牌手可以像这样分解:

  • 4张不同的卡................ 715
  • 1对,2种不同.............. 858
  • 2对................................ 78
  • 3种,1 diff .............. 156
  • 4种...................... 13

  • 总计................................. 1&#39; 820总组合

那么为什么蛮力和过滤器重复?

e.g。在玩家与玩家的游戏过程中,共有18个&#39; 395六张牌组合(一个玩家),3&#39; 274&375组合4张牌。 Tim指出The Play(4x4)的组合数量在1&#802;平方的1%之内。

如果您在方法论上更具战略性,我认为您会发现其中有超过2.3T的独特序列:您是否正在考虑处理同花顺?如果没有,那么你不需要担心52张牌,只有13张,有4次出现。将52改为13,看看这些数字是如何变得可管理的。如果你正在生成一个计算器,你仍然可以考虑刷新,这方面的数学计算要简单得多,而不是将其拖到你正在进行的计算的中间。

如果不出意外:查看Martin Broadhurst的网站(它的同名)并查看&#34; Combinatorial Algorithms&#34; (它在C中非常甜蜜)这将大大减少你的数字 - 使得管理所有各种组合/排列/等成为可能。您将使用几个不同的来获取所需的数据。它还可以让您的生活更轻松,确保您使用正确的算法。其中大多数允许您指定映射到字符,因此您可以替换&#34; T&#34;为了使对齐更容易,因为所有将显示的将是单个字符。

即使您使用Martin的库,也可以在不简化流程的情况下制作出一整套数据。

我不想责备你做家庭作业 - 我真的很好奇为什么你会产生如此多的原始Cribbage数据(它不常作为休闲运动)

我很久以前就已经碰到了很多论文(在500多个课程中,或在会议上介绍了Cribbage),他们只是在战略上产生了手中的东西。与随机投掷,与人工神经网络。他们正在关注游戏的一小部分(有时,代码是不对的!)。对于那个级别的课程,我很惊讶他们能够偷偷溜过他们的赞助商。 (如果只有他们知道的话。)即使对The Play应用人工神经网络也会更有趣,更复杂,而且非常有趣。

最后一个想法 - 这是大多数人都不会想到的东西 - 除了保留你手中的积分之外的东西:

&#34;您是经销商,已发卡(随机)&lt; 1&gt;,&lt; 2&gt;,&lt; 3&gt;,&lt; 4&gt;,&lt; 5&gt;&lt; 5&gt;&lt; 6&gt; ;。你需要5分才能盯住,pone需要7分。因为pone会打第一张牌并且会先计算他们的手牌,那么这六张牌的最佳投掷/保持策略是什么?&#34; (然后提供分析,看看你是否可以自己提出一两条规则)。

怎么样:&#34;如果你是经销商并有19分的得分手,那么你的婴儿床中你有19分的几率是多少?&#34;这些是让游戏变得有趣的见解类型。