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;
}
source to share
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.
source to share
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() ];
}
source to share