Identify a hand held flash card

In the card application, I use 0-51 to represent the card 5 cards.

Suit card / 13


Rank card %


There are only 4 possible suits (shovel, heart, club diamond)

If all five suits are the same, it's a flush. All flushes have the same value. Spades are the same as diamonds.

I know you will say that pre-optimization is evil, but I am running some simulations doing it a million times and this is the most expensive step. The map may be byte, but the computation seems to be faster with int. I don't really check the range, but I put it so that you know a range exists.

Is there a more efficient way?

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;
}

      

+3


source to share


2 answers


Eliminating HashSet

should speed things up a bit:

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;
}

      



My (though meager) testing shows a 20% improvement in performance.

+2


source


I would use bit-fields to store card information, it might be faster so you can avoid the cost of integer division and modulo operations.

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;

}

      

To create values ​​for maps:



public static Int32 CreateCard(Int32 suit, Int32 rank) {

    return suit | ( rank & 0x0000 );
}

      

For example:

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() ];
}

      

+2


source







All Articles