// from http://www.azillionmonkeys.com/qed/poker.zip
// shamelessly copied from azillionmonkeys. getting millions of evals per second!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>

#define CLUB_SUIT              (1)
#define DIAMOND_SUIT           (2)
#define HEART_SUIT             (4)
#define SPADE_SUIT             (8)

#define RANK_SHL              (27)
#define SUBR_SHL              (13)
#define SUBR_SHLMASK          ((1<<SUBR_SHL)-1)

#define STRAIGHT_FLUSH_SCORE  (8 << RANK_SHL)
#define FOUR_KIND_SCORE       (7 << RANK_SHL)
#define FULL_HOUSE_SCORE      (6 << RANK_SHL)
#define FLUSH_SCORE           (5 << RANK_SHL)
#define STRAIGHT_SCORE        (4 << RANK_SHL)
#define THREE_KIND_SCORE      (3 << RANK_SHL)
#define TWO_PAIR_SCORE        (2 << RANK_SHL)
#define TWO_KIND_SCORE        (1 << RANK_SHL)

#define ONE_PAIR_SCORE        (TWO_KIND_SCORE)

typedef uint8_t u8;
typedef int8_t s8;
typedef uint32_t u32;
typedef int32_t s32;

typedef struct { int32_t len; u8 entry[52]; } CardPileType;

static char *handstrs[16] = { "high card", "one pair", "two pair", "three of a kind", "straight", "flush", "full house", "four of a kind", "straight flush", "err", "err", "err", "err", "err", "err", "err" };
static char *kickerstrs[16] = { "", "kickers", "kicker", "kickers", "high", "high", "full of", "kicker", "high", "err", "err", "err", "err", "err", "err", "err" };

static u32 CardValue[52] = {
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 
};

static u32 CardSuit[52] = {
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
	8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
};

int32_t cardstr(char *cardstr,uint8_t card)
{
    int32_t suit; char *cardc = "A234567890JQK",suitc[4] = { 'C', 'D', 'H', 'S' };
    suit = card / 13;
    card %= 13;
    if ( card == 9 )
        sprintf(cardstr,"10%c",suitc[suit]);
    else sprintf(cardstr,"%c%c",cardc[card],suitc[suit]);
    return(card);
}

static u32 CardSuitIdx[52] = {
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
};

static u32 CardMask[52] = {
	1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
	1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
	1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
	1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000
};

static u32 FiveCardDrawScoreFast (u32 c0, u32 c1, u32 c2, u32 c3, u32 c4, u32 u)
{
    u32 y,z,m1,m2,m3,m4;
	// Test for single suitedness
	u = u & (u - 1);
	// Build masks of 1, 2, 3, and 4 of a kind.
	m1  = c0 | c1;
	m2  = c1 & c0;

	m2 |= c2 & m1;
	m1 |= c2;

	m2 |= c3 & m1;
	m1 |= c3;

	m2 |= c4 & m1;
	m1 |= c4;

	if (m2 == 0) {                   // No pairs?
		// Is the mask a sequence of 1 bits?
		z  = m1 & (m1 - 1);
		z ^= m1;
		y  = (z << 5) - z;
		// Deal with the bicycle/wheel 5,4,3,2,Ace straight
		if  (m1 == 0x100F) {
			if (u != 0) return STRAIGHT_SCORE + 0xF;
			return STRAIGHT_FLUSH_SCORE + 0xF;
		}
		if (y == m1) {
			if (u != 0) return STRAIGHT_SCORE + m1;
			return STRAIGHT_FLUSH_SCORE + m1;
		}
		if (u != 0) return m1;	// Nothing
		return FLUSH_SCORE + m1;
	}
	/*
	// m1 = c0 | ... | c4
	// m2 = (c0 & c1) | ((c0|c1) & c2) | ((c0|c1|c2) & c3) | ((c0|c1|c2|c3) & c4)
	// m3 = mask of 3 or 4 of a kind.
	// m4 = mask of 4 of a kind.
	*/
	m1  = c0 | c1;
	m2  = c1 & c0;

	m3  = c2 & m2;
	m2 |= c2 & m1;
	m1 |= c2;

	m4  = c3 & m3;
	m3 |= c3 & m2;
	m2 |= c3 & m1;
	m1 |= c3;

	m4 |= c4 & m3;
	m3 |= c4 & m2;
	m2 |= c4 & m1;
	m1 |= c4;

	m1 &= ~m2;
	if (m3 == 0) {
		if ((m2 & (m2 - 1)) == 0)
			return TWO_KIND_SCORE + (m2 << SUBR_SHL) + m1;
		return TWO_PAIR_SCORE + (m2 << SUBR_SHL) + m1;
	}
	m2 &= ~m3;
	if (m4 == 0) {
		if (m2 == 0)
			return THREE_KIND_SCORE + (m3 << SUBR_SHL) + m1;
		return FULL_HOUSE_SCORE + (m3 << SUBR_SHL) + m2;
	}
	return FOUR_KIND_SCORE + (m4 << SUBR_SHL) + m1;
}

static u32 FiveCardDrawScore (const u8 * h)
{
    u32 c0, c1, c2, c3, c4,u;
	// Make suits powers of two.
	u  = CardSuit[h[0]];
	u |= CardSuit[h[1]];
	u |= CardSuit[h[2]];
	u |= CardSuit[h[3]];
	u |= CardSuit[h[4]];
	// Make cards powers of two.
	c0 = CardMask[h[0]];
	c1 = CardMask[h[1]];
	c2 = CardMask[h[2]];
	c3 = CardMask[h[3]];
	c4 = CardMask[h[4]];
	return FiveCardDrawScoreFast (c0, c1, c2, c3, c4, u);
}

static u32 SevenCardDrawFlush (const u8 * h, const u32 c[7])
{
    static s32 LG2TAB[9] = {-1, 0, 1, -1, 2, -1, -1, -1, 3};
    u32 i,t,f[4]; s32 cc[4],s;
	// Make suits powers of two.
    // There is at most one flush in a 7 card hand.  So up to 4 masks arecreated, each being the set of cards in one particular suit.
    // As themasks are created a maximum countdown from 4 is tracked.
#if 0
	s = (((((u32 *) h)[1])) * 5) & 0x00C0C0C0;
	i = (((((u32 *) h)[0])) * 5) & 0xC0C0C0C0;
	s = ((s * (1 + 64 + 4096)) >> 8) & 0x3F00;
	i = ((i * (1 + 64 + 4096 + 262144)) >> 24) | s;
#endif

	f[0]  = f[1]  = f[2]  = f[3]  = 0;
	cc[0] = cc[1] = cc[2] = cc[3] = 4;

	i = CardSuitIdx[h[0]];
	f[i]  = c[0]; cc[i]--;

	i = CardSuitIdx[h[1]];
	f[i] |= c[1]; cc[i]--;

	i = CardSuitIdx[h[2]];
	f[i] |= c[2]; cc[i]--;

	i = CardSuitIdx[h[3]];
	f[i] |= c[3]; cc[i]--;

	i = CardSuitIdx[h[4]];
	f[i] |= c[4]; cc[i]--;

	i = CardSuitIdx[h[5]];
	f[i] |= c[5]; cc[i]--;

	i = CardSuitIdx[h[6]];
	f[i] |= c[6]; cc[i]--;

	// If any of the counts goes below 0, then that suit has at least 5 cards in it.

	if (((cc[0] | cc[1]) | (cc[2] | cc[3])) < 0) {

		// Map the negative count (of which there is at most 1) to the suit index.

		s = (((cc[0] & 8) | (cc[1] & 16)) | ((cc[2] & 32) | (cc[3] & 64))) >> 3;
		s = LG2TAB[s];

		// Work out the top 5 cards, so that the proper flush is also known ...

		t = f[s];
		while (cc[s] < -1) {
			t &= t - 1;			// Rip off last bit.
			cc[s]++;
		}

		// ... but also keep the low part so that all straight flushes can still be tested for.

		return f[s] | (t << SUBR_SHL);
	}
	// 0 -> indicates there is no flush in the hand.
	return 0;
}

#define SevenCardDrawFlushScore(f) (FLUSH_SCORE + ((f) >> SUBR_SHL))

u32 SevenCardDrawScore (const u8 * h)
{
    u32 c[7],f, t, s, u, v,m1, m2, m3, m4;
	c[0] = CardMask[h[0]];
	c[1] = CardMask[h[1]];
	c[2] = CardMask[h[2]];
	c[3] = CardMask[h[3]];
	c[4] = CardMask[h[4]];
	c[5] = CardMask[h[5]];
	c[6] = CardMask[h[6]];
	// Work out flush mask always, since its only redundant in the case of a full house or 4 of a kind.
	f = SevenCardDrawFlush (h, c);
	// t is the full card mask
	t = ((c[0] | c[1]) | (c[2] | c[3])) | (c[4] | c[5] | c[6]);
	// If 7 cards are found in a row ...
	s  = t & (t - 1);
	v  = s ^ t;
	u  = (v << 7) - 1;
	u &= ~(u >> 7);
	// ... then work out the possible straight flush/bicycle, straight, and flush possibilities.
	if ((u & t) == u) {
		if (f) {
			// Intersect the flush mask with the straight mask to try to figure out if we have a straight flush.
			s  = f & u;
			u  = s & (s - 1);
			u ^= s;
			u  = (u << 7) - 1;
			u &= ~(u >> 5);
			t  = u >> 1;
 			v  = u >> 2;
			if ((u & s) == u) return STRAIGHT_FLUSH_SCORE + u;
			if ((t & s) == t) return STRAIGHT_FLUSH_SCORE + t;
			if ((v & s) == v) return STRAIGHT_FLUSH_SCORE + v;
			// Deal with possible bicycle/wheel 5,4,3,2,Ace straight flush
			if ((0x100F & f) == 0x100F)
				return STRAIGHT_FLUSH_SCORE + 0xF;
			return SevenCardDrawFlushScore (f);
		}
		u &= ~(u >> 5);
		return STRAIGHT_SCORE + u;
	}
	// If at most 6 cards are found in a row ...
	u  = (v << 6) - 1;
	u &= ~(u >> 6);
	if ((u & t) != u) {
		u  = s & (s - 1);
		u ^= s;
		u  = (u << 6) - 1;
		u &= ~(u >> 6);
	}
	// ... then work out the possible straight flush/bicycle, straight, and flush possibilities.
	if ((u & t) == u) {
		if (f) {
			s  = f & u;
			u  = s & (s - 1);
			u ^= s;
			u  = (u << 6) - 1;
			u &= ~(u >> 5);
			t  = u >> 1;
			if ((u & s) == u) return STRAIGHT_FLUSH_SCORE + u;
			if ((t & s) == t) return STRAIGHT_FLUSH_SCORE + t;
			// Deal with possible bicycle/wheel 5,4,3,2,Ace straight flush
			if ((0x100F & f) == 0x100F)
				return STRAIGHT_FLUSH_SCORE + 0xF;
			return SevenCardDrawFlushScore (f);
		}
		u &= ~(u >> 5);
		return STRAIGHT_SCORE + u;
	}
	// If at most 5 cards are found in a row ...
	u  = (v << 5) - 1;
	u &= ~(u >> 5);
	if ((u & t) != u) {
		v  = s;
		s  = s & (s - 1);
		v ^= s;
		u  = (v << 5) - 1;
		u &= ~(u >> 5);
		if ((u & t) != u) {
			u  = s & (s - 1);
			s ^= u;
			u  = (s << 5) - 1;
			u &= ~(u >> 5);
		}
	}
	// ... then work out the possible straight flush/bicycle, straight, and flush possibilities.
	if ((u & t) == u) {
		if (f) {
			s  = f & u;
			u  = s & (s - 1);
			u ^= s;
			u  = (u << 5) - 1;
			u &= ~(u >> 5);
			if ((u & s) == u) {
				return STRAIGHT_FLUSH_SCORE + u;
			}
			// Deal with possible bicycle/wheel 5,4,3,2,Ace straight flush
			if ((0x100F & f) == 0x100F)
				return STRAIGHT_FLUSH_SCORE + 0xF;
			return SevenCardDrawFlushScore (f);
		}
		u &= ~(u >> 5);
		return STRAIGHT_SCORE + u;
	}
	// Deal with the bicycle/wheel 5,4,3,2,Ace straight
	if ((0x100F & t) == 0x100F) {
		if (f)
        {
			if ((0x100F & f) == 0x100F)
				return STRAIGHT_FLUSH_SCORE + 0xF;
			return SevenCardDrawFlushScore (f);
		}
		return STRAIGHT_SCORE + 0xF;
	}
	/*
	// m1 = c0 | ... | c4
	// m2 = (c0 & c1) | ((c0|c1) & c2) | ((c0|c1|c2) & c3) | ((c0|c1|c2|c3) & c4)
	// m3 = mask of 3 or 4 of a kind.
	// m4 = mask of 4 of a kind.
	*/

	m1  = c[0] | c[1];
	m2  = c[1] & c[0];

	m3  = c[2] & m2;
	m2 |= c[2] & m1;
	m1 |= c[2];

	m4  = c[3] & m3;
	m3 |= c[3] & m2;
	m2 |= c[3] & m1;
	m1 |= c[3];

	m4 |= c[4] & m3;
	m3 |= c[4] & m2;
	m2 |= c[4] & m1;
	m1 |= c[4];

	m4 |= c[5] & m3;
	m3 |= c[5] & m2;
	m2 |= c[5] & m1;
	m1 |= c[5];

	m4 |= c[6] & m3;
	m3 |= c[6] & m2;
	m2 |= c[6] & m1;
	m1 |= c[6];
	// Make sure the m1 is just the mask of singleton cards.
	m1 &= ~m2;
	// No 3 or 4 of a kinds.
	if (m3 == 0) {
		if (f) {
			return SevenCardDrawFlushScore (f);
		}
		if (m2) {
			s = m2 & (m2 - 1);
			if (s == 0) {
				t = m1 & (m1 - 1);
				t &= (t - 1);
				return TWO_KIND_SCORE + (m2 << SUBR_SHL) + t;
			}
			v = m1;
			t = s & (s - 1);
			if (t) {
				v |= m2 ^ s;
				m2 = s;
			} else {
				v &= (v - 1);
			}
			v &= (v - 1);
			return TWO_PAIR_SCORE + (m2 << SUBR_SHL) + v;
		}
		// Nothing -- just remove the two low cards.
		m1 &= (m1 - 1);
		m1 &= (m1 - 1);
		return m1;
	}
	// 4 of a kind.
	if (m4) {
		m1 |= (m2 & ~m4);
		while ((m2 = (m1 & (m1 - 1))) != 0) {
			m1 = m2;
		}
		return FOUR_KIND_SCORE + (m4 << SUBR_SHL) + m1;
	}
	// 3 of a kind, but no other pair in the hand
	if ((m2 & ~m3) == 0) {
		t = m3 & (m3 - 1);
		// Two 3 of a kinds => Full House
		if (t)
			return FULL_HOUSE_SCORE + (t << SUBR_SHL) + (m3 ^ t);
		if (f)
			return SevenCardDrawFlushScore (f);
		// Just remove the two low cards, and score this as 3 of a kind.
		m1 &= (m1 - 1);
		m1 &= (m1 - 1);
		return THREE_KIND_SCORE + (m3 << SUBR_SHL) + m1;
	}
	// 3 of a kind and a seperate 2 of a kind (full house.)
	m2 &= ~m3;
	t = m2 & (m2 - 1);
	// If there are two 2 pairs in the hand, then pick the higher pair
	if (!t) t = m2;
	return FULL_HOUSE_SCORE + (m3 << SUBR_SHL) + t;
}

// Just a brute force 7 card draw ranking by picking each of the possible two cards to be skipped, and finding the score which is highest amongst the 21 possible 5 card sub-hands.
u32 SevenCardDrawScoreSlow (const u8 * h) {
s32 i, j, k;
u32 r, m;
u8 h2[5];

	m = 0;
	for (i=0; i < 6; i++) {
		for (k=0; k < i; k++) {
			h2[k] = h[k];
		}
		for (j=i+1; j < 7; j++) {
			for (k=i+1; k < j; k++) {
				h2[k-1] = h[k];
			}
			for (k=j+1; k < 7; k++) {
				h2[k-2] = h[k];
			}
			r = FiveCardDrawScore (h2);
			if (r > m) m = r;
		}
	}
	return m;
}

// A correctly distributed (ignoring the problem of using "rand() % x") reshuffling of your cards.
static void Shuffle (CardPileType * c)
{
    int32_t i, j, k; u8 t;
	for (i = 0; i < (c->len - 1); i++)
    {
		k = (RAND_MAX / (c->len - i)) * (c->len - i);
		do {
			j = rand ();
		} while (j >= k);
		j = i + (j % (c->len - i));
		t = c->entry[i];
		c->entry[i] = c->entry[j];
		c->entry[j] = t;
	}
}

static int32_t Deal (CardPileType * h, CardPileType * d, int32_t n)
{
    int32_t i;
	for (i=0; i < n && d->len > 0; i++)
    {
		d->len--;
		h->entry[ h->len ] = d->entry[ d->len ];
		h->len++;
	}
	return i;
}

static void InitDeck (CardPileType * deck)
{
    u8 i;
	deck->len = 52;
	for (i=0; i < 52; i++) deck->entry[i] = i;
}

static void DisplayCard (u8 c, char out[])
{
    // char suitdisp[9] = { 0, 5, 4, 0, 3, 0, 0, 0, 6 };
    static char suitdisp[9] = { 0, 'c', 'd', 0, 'h', 0, 0, 0, 's' };
    char s[4];
	s[0] = "        1    "[CardValue[c]];
	s[1] = "234567890JQKA"[CardValue[c]];
	s[2] = suitdisp[CardSuit[c]];
	s[3] = '\0';
    strcat (out, " ");
    strcat (out, s);
}

void DisplayHand5 (const CardPileType * h) {
    char out[128];
    int i;
    
	out[0] = '\0';
	for (i=0; i < 5; i++) DisplayCard (h->entry[i], out);
	sprintf (out + strlen (out), " => %08X\n", (int)FiveCardDrawScore (&h->entry[0]));
	printf ("%s", out);
}

void set_cardstr(char *cardstr,uint32_t c)
{
    /*static char suitdisp[9] = { 0, 'c', 'd', 0, 'h', 0, 0, 0, 's' };
	cardstr[0] = "        1    "[CardValue[c % 13]];
	cardstr[1] = "234567890JQKA"[CardValue[c % 13]];
	cardstr[2] = suitdisp[CardSuit[c]];
	cardstr[3] = '\0';*/

     int32_t i,j=0;
    c >>= 1;
     for (i=12; i>=0; i--)
        if ( ((1 << i) & c) != 0 )
        {
            cardstr[j++] = "        1    "[i];
            cardstr[j++] = "234567890JQKA"[i];
            cardstr[j++] = ' ';
        }
    cardstr[j++] = 0;
}

uint32_t set_handstr(char *handstr,uint8_t cards[7],int32_t verbose)
{
    char cardstr[32],cardstr2[32],*kickerstr,*str; uint32_t score,i;
    handstr[0] = 0;
    if ( cards == 0 )
    {
        handstr[0] = 0;
        printf("set_handstr: null cards??\n");
        return(0);
    }
    for (i=0; i<7; i++)
        if ( cards[i] < 0 || cards[i] >= 52 )
        {
            //printf("illegal card[%d] %d\n",i,cards[i]);
            return(0);
        }
   	score = SevenCardDrawScore (&cards[0]);
    set_cardstr(cardstr,(score>>SUBR_SHL) & SUBR_SHLMASK);
    set_cardstr(cardstr2,score & SUBR_SHLMASK);
    kickerstr = kickerstrs[(score>>RANK_SHL)&15];
    str = handstrs[(score>>RANK_SHL)&15];
    if ( verbose != 0 )
    {
        if ( strcmp(kickerstr,"high") == 0 )
            sprintf(handstr,"%c%c high %s",cardstr2[0],cardstr2[1],str);
        else if ( strcmp(str,"full house") == 0 )
            sprintf(handstr,"%c%c full of %c%c",cardstr[0],cardstr[1],cardstr2[0],cardstr2[1]);
        else if ( strcmp(str,"three of a kind") == 0 )
            sprintf(handstr,"set of %c%c with kickers %c%c %c%c",cardstr[0],cardstr[1],cardstr2[0],cardstr2[1],cardstr2[3],cardstr2[4]);
        else if ( strcmp(str,"two pair") == 0 )
            sprintf(handstr,"two pair %c%c and %c%c with %c%c kicker",cardstr[0],cardstr[1],cardstr[3],cardstr[4],cardstr2[0],cardstr2[1]);
        else if ( strcmp(str,"one pair") == 0 )
            sprintf(handstr,"pair of %c%c with %c%c kicker",cardstr[0],cardstr[1],cardstr2[0],cardstr2[1]);
        else sprintf(handstr,"%s %s %s %s",str,cardstr,kickerstr,cardstr2);
    }
    else
    {
        if ( strcmp(kickerstr,"high") == 0 )
            sprintf(handstr,"%c%c high %s",cardstr2[0],cardstr2[1],str);
        else if ( strcmp(str,"full house") == 0 )
            sprintf(handstr,"fullhouse %c%c %c%c",cardstr[0],cardstr[1],cardstr2[0],cardstr2[1]);
        else if ( strcmp(str,"three of a kind") == 0 )
            sprintf(handstr,"trip %c%c",cardstr[0],cardstr[1]);
        else if ( strcmp(str,"two pair") == 0 )
            sprintf(handstr,"two pairs %c%c %c%c",cardstr[0],cardstr[1],cardstr[3],cardstr[4]);
        else if ( strcmp(str,"one pair") == 0 )
            sprintf(handstr,"pair %c%c",cardstr[0],cardstr[1]);
        else sprintf(handstr,"%s",cardstr2);
    }
    return(score);
}

void DisplayHand7(char *handstr,uint8_t *cards)
{
    uint32_t x,y; int32_t i; char out[512];
	out[0] = '\0';
	for (i=0; i<7; i++)
        DisplayCard (cards[i], out);
	x = SevenCardDrawScore (cards);
	y = SevenCardDrawScoreSlow (cards);
    set_handstr(handstr,cards,1);
	if ( x != y )
        fprintf(stderr,"Error slow score %08x vs fast score %08x???\n",y,x);
     sprintf (out + strlen (out), " => %08x %6d %6d ->   (%s)",x,(x>>SUBR_SHL)&SUBR_SHLMASK,x&SUBR_SHLMASK,handstr);
    printf("%s\n",out);
}

void poker_test()
{
    char *_mbstr(double n);
    CardPileType Deck,Hands[1000]; uint32_t c,starttime,score; uint64_t total,counter; char handstr[512]; uint8_t *cards;
    //srand (0);
	InitDeck (&Deck);
	Shuffle (&Deck);
	for (c=0; c<(sizeof(Hands)/sizeof(*Hands)); c++)
    {
		Deal (&Hands[c],&Deck,7);
		DisplayHand7(handstr,Hands[c].entry);
		Deal (&Deck,&Hands[c],7);
		Shuffle(&Deck);
	}
    starttime = (uint32_t)time(NULL);
#ifndef _WIN32
    while ( (uint32_t)time(NULL) == starttime )
        usleep(100);
    total = counter = 0;
    while ( (uint32_t)time(NULL) < starttime+11 )
    {
        for (c=0; c<1000; c++,counter++)
        {
            cards = Hands[c % (sizeof(Hands)/sizeof(*Hands))].entry;
            score = SevenCardDrawScore(cards);
            total += score;
        }
    }
    char *mbstr(char *str,double val);
    char str[65]; printf("counter.%llu %s in 10 seconds: ave score %llx\n",(long long)counter,mbstr(str,counter),(long long)(total/counter));
#endif
}