Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

243 lines
5.5 KiB

#include <string.h>
#include "poker.h"
typedef unsigned short CARD_VALUE_BITS;
POKER_HAND_WEIGHT
ComputePokerHandWeight(HAND *poker_hand)
{
// We put all of the flags into a single structure so that we can
// initialize them easily.
struct
{
unsigned short values[NUM_CARD_VALUES + 1];
unsigned short suits[NUM_CARD_SUITS];
short flush;
CARD_VALUE_BITS flush_cards;
short straight;
short straight_len;
short quad;
short trip;
short high_pair;
short low_pair;
short high_cards[MAX_HAND_SIZE];
short high_card_count;
} flags;
register short s;
POKER_HAND_WEIGHT retval = 0;
ASSERT(poker_hand->count <= MAX_HAND_SIZE);
// Initialize the flag values
memset(&flags, 0, sizeof(flags));
// Walk the array of cards, setting suits and values (and watching
// for a flush)
for (s = 0; s < (short) poker_hand->count; s++)
{
flags.values[CARD_TO_VALUE(poker_hand->cards[s])]++;
if (MIN_FLUSH_LEN == ++flags.suits[CARD_TO_SUIT(poker_hand->cards[s])])
flags.flush = 1 + CARD_TO_SUIT(poker_hand->cards[s]);
}
// If we actually got a flush, we need to find the matching cards
// for later use
if (flags.flush)
{
for (s = 0; s < (short) poker_hand->count; s++)
{
if ((short) CARD_TO_SUIT(poker_hand->cards[s]) == flags.flush - 1)
{
flags.flush_cards |=
1 << CARD_TO_VALUE(poker_hand->cards[s]);
}
}
// Set the high ace bit if the low one is set
if (flags.flush_cards & 1)
flags.flush_cards |= 1 << NUM_CARD_VALUES;
}
// Copy the info for aces to the extra slot above the king
flags.values[NUM_CARD_VALUES] = flags.values[0];
// Walk the value array, setting flags as appropriate
for (s = NUM_CARD_VALUES; s >= 0; s--)
{
// Skip the pair/trip/quad computations when we reach the lower ace
if (s != 0)
{
switch(flags.values[s])
{
case 4:
flags.quad = s;
break;
case 3:
// If flag is already set, we treat this as the high pair
// (We don't have to worry about having two trips and a pair
// in 7 cards.)
if (flags.trip)
flags.high_pair = s;
else
flags.trip = s;
break;
case 2:
if (! flags.high_pair)
flags.high_pair = s;
else if (! flags.low_pair)
flags.low_pair = s;
else
flags.high_cards[flags.high_card_count++] = s;
break;
case 1:
flags.high_cards[flags.high_card_count++] = s;
break;
default:
ASSERT(flags.values[s] == 0);
break;
}
}
// Check for a straight (if we have enough cards to look and we
// haven't found one already)
if (poker_hand->count >= MIN_STRAIGHT_LEN && ! flags.straight)
{
if (flags.values[s])
{
if (++flags.straight_len == MIN_STRAIGHT_LEN)
flags.straight = s + MIN_STRAIGHT_LEN - 1;
}
else
flags.straight_len = 0;
}
} // End of value array traversal
// Compute the actual weight
if (flags.straight && flags.flush)
{
// We need to do special processing to determine if we have
// a straight flush (as opposed to a straight and a flush in
// different five-card combinations). This is an inefficient
// method of checking, but this case is so rare as to be almost
// insignificant.
CARD_VALUE_BITS tmp;
for (tmp = flags.flush_cards, s = MIN_STRAIGHT_LEN - 1;
tmp >= STRAIGHT_BITMASK && s <= NUM_CARD_VALUES;
tmp >>= 1, s++)
{
if ((tmp & STRAIGHT_BITMASK) == STRAIGHT_BITMASK)
{
// We have a straight flush! We set the value (but
// keep trying, in the event that there were six or
// seven in a row).
retval = PHF_STRAIGHT_FLUSH |
((POKER_HAND_WEIGHT) s << 24);
}
}
}
if (! retval)
{
if (flags.quad)
{
retval = PHF_FOUR_OF_A_KIND |
((POKER_HAND_WEIGHT) flags.quad << 24);
}
else if (flags.trip && flags.high_pair)
{
retval = PHF_FULL_HOUSE |
((POKER_HAND_WEIGHT) flags.trip << 24) |
((POKER_HAND_WEIGHT) flags.high_pair << 20);
}
else if (flags.flush)
{
short weight_slot;
short card_count;
short card_value;
retval = PHF_FLUSH;
// Walk the flush card bit mask, counting the first five
// cards we find.
for (weight_slot = 24, card_value = NUM_CARD_VALUES, card_count = 0;
card_count < MIN_FLUSH_LEN && card_value >= 0;
card_value--)
{
if (flags.flush_cards & (1 << card_value))
{
retval |= ((POKER_HAND_WEIGHT) card_value << weight_slot);
weight_slot -= 4;
card_count++;
}
}
ASSERT(card_count == MIN_FLUSH_LEN);
}
else if (flags.straight)
{
retval = PHF_STRAIGHT |
((POKER_HAND_WEIGHT) flags.straight << 24);
}
else if (flags.trip)
{
retval = PHF_THREE_OF_A_KIND |
((POKER_HAND_WEIGHT) flags.trip << 24);
}
else if (flags.low_pair)
{
retval = PHF_TWO_PAIRS |
((POKER_HAND_WEIGHT) flags.high_pair << 24) |
((POKER_HAND_WEIGHT) flags.low_pair << 20) |
((POKER_HAND_WEIGHT) flags.high_cards[0] << 16);
}
else if (flags.high_pair)
{
retval = PHF_ONE_PAIR |
((POKER_HAND_WEIGHT) flags.high_pair << 24) |
((POKER_HAND_WEIGHT) flags.high_cards[0] << 20) |
((POKER_HAND_WEIGHT) flags.high_cards[1] << 16) |
((POKER_HAND_WEIGHT) flags.high_cards[2] << 12);
}
else
{
retval = PHF_HIGH_CARD |
((POKER_HAND_WEIGHT) flags.high_cards[0] << 24) |
((POKER_HAND_WEIGHT) flags.high_cards[1] << 20) |
((POKER_HAND_WEIGHT) flags.high_cards[2] << 16) |
((POKER_HAND_WEIGHT) flags.high_cards[3] << 12) |
((POKER_HAND_WEIGHT) flags.high_cards[4] << 8);
}
}
ASSERT(retval > 0);
return retval;
}