C# 确定一张扑克牌与手齐平

C# 确定一张扑克牌与手齐平,c#,.net,optimization,C#,.net,Optimization,在卡片应用程序中,我使用0-51表示5张卡片的手 这套衣服是card/13 排名为card% 只有4种可能的套装(黑桃、红桃、梅花钻石) 如果五套衣服都一样,那就是同花顺。所有冲洗都具有相同的价值。黑桃和钻石一样 我知道你会说预优化是邪恶的,但我正在进行一些模拟,做了数百万次,这是最昂贵的一步。卡可以是字节,但int的计算速度似乎更快。我没有真正检查范围,但我把它放进去了,这样你就会知道有一个范围 有没有更有效的方法 public bool IsFlush(int[] quick) {

在卡片应用程序中,我使用0-51表示5张卡片的手

这套衣服是
card/13

排名为
card%

只有4种可能的套装(黑桃、红桃、梅花钻石)

如果五套衣服都一样,那就是同花顺。所有冲洗都具有相同的价值。黑桃和钻石一样

我知道你会说预优化是邪恶的,但我正在进行一些模拟,做了数百万次,这是最昂贵的一步。卡可以是字节,但int的计算速度似乎更快。我没有真正检查范围,但我把它放进去了,这样你就会知道有一个范围

有没有更有效的方法

public bool IsFlush(int[] quick)
{
    HashSet<int> suit = new HashSet<int>();
    suit.Add(quick[0] / 13);
    int thisQuick;
    for (int i = 1; i < quick.Length; i ++)
    {
        thisQuick = quick[i];
        if (thisQuick < 0 || thisQuick > 51)
            throw new IndexOutOfRangeException();
        if (suit.Add(thisQuick / 13))
            return false;
    }
    return true;
}
public bool IsFlush(int[]快速)
{
HashSet suit=新的HashSet();
suit.Add(快速[0]/13);
int thisQuick;
for(int i=1;i51)
抛出新的IndexOutOfRangeException();
如果(诉讼补充(thisQuick/13))
返回false;
}
返回true;
}

我会使用位域来存储有关卡的信息,它可能会更快,这样可以避免整数除法和模运算的开销

const Int32 SuitMask = 0x001100000;
const Int32 Spade    = 0x000000000;
const Int32 Heart    = 0x000100000;
const Int32 Diamond  = 0x001000000;
const Int32 Club     = 0x001100000;

public static Boolean AllCardsInHandOfSameSuit(Int32[] hand) {

    Int32 countSpades   = 0;
    Int32 countHeart    = 0;
    Int32 countDiamonds = 0;
    Int32 countClubs    = 0;

    foreach( Int32 card in hand ) {

        Int32 suit = card & SuitMask;
        switch( suit ) {
            case Spade:
                countSpades++;
                break;
            case Heart:
                countHearts++;
                break;
            case Diamond:
                countDiamonds++;
                break;
            case Club:
                countClubs++;
                break;
        }
    }

    // Your question is not worded clearly about whether or not you care about unique ranks, only unique suits:
    // I'm also unsure of your flush/hand rules, but just compare the counts as-required:
    Boolean allSameSuit = 
        ( countSpades   == 0 || countSpades   == hand.Length ) &&
        ( countHearts   == 0 || countHearts   == hand.Length ) &&
        ( countDiamonds == 0 || countDiamonds == hand.Length ) &&
        ( countClubs    == 0 || countClubs    == hand.Length );

    Boolean allDifferentSuit =
        countSpades   <= 1 &&
        countHearts   <= 1 &&
        countDiamonds <= 1 &&
        countClubs    <= 1;

}
例如:

Int32[] deck = new Int32[52];
for( Int32 i = 0; i < deck.Length; i++ ) {

    Int32 suit =
        i / 13 == 0 ? Spade :
        i / 13 == 1 ? Heart :
        i / 13 == 2 ? Diamond : Club;

    deck[i] = CreateCard( suit, i % 13 );
}

Int32[] hand = new Int32[4];
for( Int32 i = 0; i < hand.Length; i++ ) {
    hand[i] = deck[ GetRandomIndexPreviouslyUnused() ];
}
Int32[]deck=newint32[52];
对于(Int32 i=0;i
消除
哈希集
应该会加快速度:

public static bool IsFlush(int[] hand)
{
    int firstSuit = hand[0] / 13;
    for (int i = 1; i < hand.Length; i++)
    {
        int card = hand[i];
        if (card < 0 || card > 51)
            throw new IndexOutOfRangeException();
        if (firstSuit != (card / 13))
            return false;
    }
    return true;
}
公共静态bool IsFlush(int[]hand)
{
int firstSuit=hand[0]/13;
for(int i=1;i51)
抛出新的IndexOutOfRangeException();
如果(第一套!=(卡片/13))
返回false;
}
返回true;
}

我的测试(承认很差)显示性能提高了约20%。

本机“字”大小的整数总是比较小的单位(如
字节)快,因为处理器就是围绕这个单位大小构建的。对于x86,它是
Int32
对于x64,它是
Int64
。不幸的是,C不具有与C++不同的“<代码> FastInt <代码> >别名,因此如果你真的关心这个特定的微优化,那么你需要一个单独的X64代码路径。整数除法非常昂贵-我敢打赌这将比
Byte
vs
Int32
vs
Int64
消耗更多的挂钟时间。请注意,从本质上讲,哈希表并不完全便宜-因为它们必须分配足够大的bucket表并执行键哈希和相等检查。如果一副牌只有52张牌,我想你最好用一个简单的本机数组。@Dai我不明白你说的本机数组是什么意思?@Paparazzi,例如
int[]
你可以更疯狂地进行微优化,改为使用字节(8位给你的比你需要的更多)。您可以将
i/13
放入一个变量中,以便每次迭代只计算一次(内存更多,但计算速度更快)。但是,请确保在循环外部创建此变量,并在循环中重新赋值,以便只使用内存中的一个点。然后,对于齐平检查,迭代该手,当下一套西装与上一套西装不匹配时,返回false。最坏的情况是,你迭代了整手牌,最好的情况是,你只迭代了手中的两张牌。我会检查这个。规定了关于同花顺的规则。“如果五套衣服都是一样的,那就是同花顺。”如果是同花顺,那么所有的牌都必须有不同的等级。没错,你还必须进行等级检查。。。最好的情况仍然是只迭代两张牌(如果他们的套装不匹配,你甚至不需要检查等级)。@StephenPorter不,你不需要等级检查。在5张牌中,如果它们都是同一套牌,则表示同花顺(或同花顺)。不需要额外检查。如果你有一个同花顺,它不可能是一条船或四边形。我知道这是怎么回事,但现在重构卡将是一项工作。我只是想到这一点自己+1我得到了超过20%的分数。如果你假设你的牌组是完美的(例如,你不可能有相同等级的同一套牌(根据我们在另一个答案中的对话)),那么为什么不假设你的牌不可能少于0或超过51张呢?然后,您可以通过不检查IndexOutOfRange标准来节省CPU时间。我在我的基准测试中尝试了这一点,结果证明它对代码的运行时几乎没有影响。
public static bool IsFlush(int[] hand)
{
    int firstSuit = hand[0] / 13;
    for (int i = 1; i < hand.Length; i++)
    {
        int card = hand[i];
        if (card < 0 || card > 51)
            throw new IndexOutOfRangeException();
        if (firstSuit != (card / 13))
            return false;
    }
    return true;
}