# poker- how to compare hands

This topic is 4646 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

If you were making a poker game, what would be the best way to check one hand against the other hand if the game was texas hold'em? Assume that the cards are in an array A-2-3..Q-K(clubs)A-2-3..Q-K(spades)A-2-3..Q-K(diamonds)A-2-3..Q-K(heart). If there is a better way to structure the data for these comparisons, I'm open to suggestions. I've never made a card based game, so I want to make a game with the fastest response time possible. I want to make this a network game that will have a form of a ranking system for regular 10 man tables, but that's a long way from now..

##### Share on other sites
Check the cards present against possible hands, then assign a point value based on the rank of the hand that it compares to. Whoever has the higher point value winds.

##### Share on other sites
I guess I should have been more clear, I need to know how to figure out the what hand the person has as well. That is the part I would like to know about the most.

##### Share on other sites
Funnily enough I've been thinking about how you'd evaluate a poker hand recently too.

There are two separate things here (just to make sure we're all on the same page):

(Let's assume we're talking about Texas Holdem)

1) Evaluate a hand based on the cards in play - find out what it (currently) is - eg. Flush, High Card etc and rank it based on this (eg 100%=Royal Flush)
2) Evaluate a hand based on the possibility of improvement. For example you currently have 2 clubs in your hand and 2 clubs from the flop - what is the probability of improvment to a Flush etc

Number 2 can also be used to find out what 'the nuts' is - if you just gave it the community cards.

I haven't thought too much about number 2 yet - but I have some ideas on number 1. Which are you interested in?

##### Share on other sites
It should just randomly throw out cards, not have a percentage to hit a hand like a flush or a straight.

Example, have a multidimensioan array of size 52 for every card, representing all cards from each suit and if they are in use, or something.

So then you just deal to each player a card and continue clock-wise around the table until every player has 2 cards. Then, just discard a randomly generated card using the same method and not assigning it to a current player's ID, but instead assigning it to MUCK ID.

Works well and makes sure you don't have duplicates or rigging.

EDIT: This might become fairly inefficient if it generates a random int between 0 and 51, and keeps picking a number that has already been generated, so another card has to be picked.

##### Share on other sites
The 100%, I believe, was meant to indicate that a royal flush beats all other hands. It doesn't say anything about the probability of getting such a hand (which is, for reference, 4 / (52 choose 5)).

Honestly, I wouldn't worry about speed for the moment. You're unlikely to be doing anything very processor-intensive with the rest of the game as it is; this isn't exactly the latest 3D FPS. Work on making an accurate game first. Then run a profiler on your code to see what parts need to be optimized, if any. Only then should you really start worrying about speed. In the meantime, just don't make dumbassed algorithm decisions.

##### Share on other sites
Oh, I gotcha. Sorry for the misunderstanding.

##### Share on other sites
Here's what I'd do Each card has these identifiers when your calculating

int hand
int power

so if you have a Royal Flush you'd have a hand of 100.
If you have four of a kind you'd have a hand of 90
if you have a straight flush you'd have a hand of 80.

and so on (I don't know all the hands so just give them divisions of 10 and makes sure to do a "has no hand" at 0. then for power

If you have a Royal Flush (assuming all suits are the same) give power of 13.
If you have a four of a kind then Power=rank of card. (so 4 2s would get a power of 2 and 4 10s would get a power of 10, because a 4 10s beat a 4 2s)
For flushes and straights you take the high card.

Then you compare the hands, if you have the same hand you check the power.

This CAN fail you when the high cards are exactly the same, so maybe you should use power[5] so you can compare all five cards, in flushes but that's another story.

##### Share on other sites
Don't forget kickers!

After all, AAAKQ beats AAAQJ

sourceforge has a poker library that can handle all of the stuff for you if you'd like.

also, here's code I've written to do the same thing [albeit for Omaha Hi/Lo, but the high test is identical to Hold Em]:
//// omahasim.cc // // Simple brute force app to calculate winning percentages of hands in the//  poker game Omaha hi/lo.//#include <fstream>#include <iostream>#include <stdlib.h>#include <string.h>#ifdef	_WIN32	#include <time.h>#else	#include <sys/time.h>#endif#include <stdio.h>long	cmdlen=512;//int	logging=1;//char	*logname="omahasim.log";int	logging=0;char	*logname="";#include "vine.h"vine            *vinetocharvine(vine *inv){if (inv->type==CMD){return(inv->clone());}}#define		T	10#define		J	11#define		Q	12#define		K	13#define		A	14char	*cardletters[]={"","","2","3","4","5","6","7","8","9","T","J","Q","K","A"};enum	suits	{C,H,D,S};char	*suitletters[]={"c","h","d","s"};enum	hands	{KICKER,PAIR,TRIPS,QUADS,STRAIGHT,LOW};char	*handchar[]={"kicker","pair","trips","quads","straight","low"};#define		DEFAULTPLAYERS	9#define		DEFAULTDEALS	10#define		DEFAULTGAMES	1000unsigned short	deck[52];long		resultcounter[10];	// hands + flush + fh + strfl + 2p + lowint		players=DEFAULTPLAYERS;int		deals=DEFAULTDEALS;int		games=DEFAULTGAMES;char    *usage=" Usage: omahasim [-p {# of players (2-9)}] [-s {# of simulations}] [-g {# of games per simulation}]\n\n";void	initdeck		();void	resetcounter		();void	vinecat			(vine **);void	sorthands		(vine **);vine	*omahahigh		(struct omahahole *, struct community *);vine	*cardstohands		(vine **);vine	*cardstolowhands	(vine **);int	cmphands		(vine *, vine *);void	handkiller		(vine *);void	winner			(vine **);void	winnerlow		(vine **);void	parsecli		(int,char **);void		initdeck(){for (int x=0;x<52;x++){	deck[x]=0;}}void		resetcounter(){for (int x=0;x<10;x++){	resultcounter[x]=0;}}struct  card{        suits   suit;        short   rank;           // 2-14        card    (short inr, suits ins){                suit=ins;                rank=inr;		deck[ins*13+inr-2]=1;        }	card(){		suit=C;		rank=0;	}	~card(){		deck[suit*13+rank-2]=0;	}        vine    *cardtoa(){                char *tmp;                tmp=(char *)malloc(cmdlen);                bzero(tmp,cmdlen);                strcat(tmp,cardletters[rank]);                strcat(tmp,suitletters[suit]);                return(new vine(tmp));        }};struct	phand:	public	card{	hands		hand;	unsigned short	flushflag;	phand(hands inh,unsigned short inff,short inr,suits ins):card(inr,ins){		hand=inh;		flushflag=inff;	}	phand(hands inh,unsigned short inff,card *inc){		suit=inc->suit;		rank=inc->rank;		hand=inh;		flushflag=inff;	}	sout(){		vine *v=cardtoa();		cout << handchar[hand] << " ";		if (flushflag){			cout << "flush ";		}		v->sout();		v->nuke(&v);	}		};	card	*drawcard(){//// Deal a card from the deck and return it.//// WARNING: dealing from an empty deck will lead to inf-loop. //  Shouldn't be a problem for standard poker.//	suits	rs;	short	rr;	int	x;		while (1){		//		// NOTE: slight bug here. rand() sucks, and will produce decidedly unrandom results		//  should the suit be done seperately from the rank.		//		//		x=rand()%52;		rs=(suits)x/13;		rr=x%13;		//rs=(suits)rand()%4;		//rr=rand()%13;				if (!deck[rs*13+rr]){			return(new card(rr+2,rs));		}	}}struct	omahahole{	card	*h1;	card	*h2;	card 	*h3;	card	*h4;	omahahole(){		h1=drawcard();		h2=drawcard();		h3=drawcard();		h4=drawcard();	}	~omahahole(){		delete h1;		delete h2;		delete h3;		delete h4;	}	vine	*holetoa(){		vine	*v=0;		(h1->cardtoa())->bottom(&v);		(h2->cardtoa())->bottom(&v);		(h3->cardtoa())->bottom(&v);		(h4->cardtoa())->bottom(&v);		vinecat(&v);		return(v);	}};	struct	community{	card    *h1;        card    *h2;        card    *h3;        card    *h4;	card	*h5;        community(){                h1=drawcard();                h2=drawcard();                h3=drawcard();                h4=drawcard();		h5=drawcard();        }        ~community(){                delete h1;                delete h2;                delete h3;                delete h4;		delete h5;        }        vine    *holetoa(){                vine    *v=0;                (h1->cardtoa())->bottom(&v);                (h2->cardtoa())->bottom(&v);                (h3->cardtoa())->bottom(&v);                (h4->cardtoa())->bottom(&v);		(h5->cardtoa())->bottom(&v);                vinecat(&v);                return(v);        }};vine	*omahahigh(omahahole *inoh, community *inc){//// Send an omaha hand through the checker to determine player's best cards.//vine	*v,*max=0;card	*oh[4];card	*co[5];phand	*h;int	i[5];int	maxx[5];oh[0]=inoh->h1;oh[1]=inoh->h2;oh[2]=inoh->h3;oh[3]=inoh->h4;co[0]=inc->h1;co[1]=inc->h2;co[2]=inc->h3;co[3]=inc->h4;co[4]=inc->h5;for (i[0]=0;i[0]<3;i[0]++){	for (i[1]=i[0]+1;i[1]<4;i[1]++){		for (i[2]=0;i[2]<3;i[2]++){			for (i[3]=i[2]+1;i[3]<4;i[3]++){				for (i[4]=i[3]+1;i[4]<5;i[4]++){					v=0;					(new vine(CARD,oh[i[0]]))->bottom(&v);					(new vine(CARD,oh[i[1]]))->bottom(&v);					(new vine(CARD,co[i[2]]))->bottom(&v);					(new vine(CARD,co[i[3]]))->bottom(&v);					(new vine(CARD,co[i[4]]))->bottom(&v);					v=cardstohands(&v);					if (1==cmphands(v,max)){						handkiller(max);						max->nuke(&max);						max=v;									}else{						handkiller(v);						v->nuke(&v);					}				}			}		}		}}return(max);}vine	*omahalow(omahahole *inoh, community *inc){//// Send an omaha hand through the checker to determine player's best low cards.//vine    *v,*max=0;card    *oh[4];card    *co[5];phand   *h;int     i[5];int     maxx[5];vine	*om;oh[0]=inoh->h1;oh[1]=inoh->h2;oh[2]=inoh->h3;oh[3]=inoh->h4;co[0]=inc->h1;co[1]=inc->h2;co[2]=inc->h3;co[3]=inc->h4;co[4]=inc->h5;for (i[0]=0;i[0]<3;i[0]++){        for (i[1]=i[0]+1;i[1]<4;i[1]++){                for (i[2]=0;i[2]<3;i[2]++){                        for (i[3]=i[2]+1;i[3]<4;i[3]++){                                for (i[4]=i[3]+1;i[4]<5;i[4]++){                                        v=0;					om=max;                                        (new vine(CARD,oh[i[0]]))->bottom(&v);                                        (new vine(CARD,oh[i[1]]))->bottom(&v);                                        (new vine(CARD,co[i[2]]))->bottom(&v);                                        (new vine(CARD,co[i[3]]))->bottom(&v);                                        (new vine(CARD,co[i[4]]))->bottom(&v);                                        v=cardstolowhands(&v);					if (v){					if (!max){						max=v;					}else{                                        if (-1==cmphands(v,max)){						handkiller(max);                                                max->nuke(&max);                                                max=v;                                        }else{                                                handkiller(v);                                                v->nuke(&v);                                        }					}					if (om && !max){						cout << "max existed, then nulled.\n";					}					}                                }                        }                }        }}return(max);}void	result(vine *inhand){//// Take high hand and add result-counter//phand	*h;vine	*v;if (!inhand){	return;}h=(phand *)inhand->data;if (h->hand==STRAIGHT && h->flushflag){	resultcounter[7]++;	return;}if (h->flushflag){	resultcounter[5]++;	return;}if (h->hand==TRIPS){	for (v=inhand;v;v=v->next){		h=(phand *)v->data;		if (h->hand==PAIR){			// then it's a boat, not just trips.			resultcounter[6]++;			return;		}	}	resultcounter[TRIPS]++;	return;}if (h->hand==PAIR){	v=inhand->next->next;	h=(phand *)v->data;	if (h->hand==PAIR){		resultcounter[8]++;		return;	}	resultcounter[PAIR]++;	return;}if (h->hand==LOW){	resultcounter[9]++;	return;}resultcounter[h->hand]++;}void	printresults(){//// Print results of resultcounter//long	total;total=0;for (int x=0;x<9;x++){	total+=resultcounter[x];}cout 	<< "high only:  " << resultcounter[0] << "(" << ((float)resultcounter[0]/total)*100 << "%)\n"      	<< "1p:         " << resultcounter[1] << "(" << ((float)resultcounter[1]/total)*100 << "%)\n" 	<< "2p:         " << resultcounter[8] << "(" << ((float)resultcounter[8]/total)*100 << "%)\n"    	<< "trips:      " << resultcounter[2] << "(" << ((float)resultcounter[2]/total)*100 << "%)\n" 	<< "quads:      " << resultcounter[3] << "(" << ((float)resultcounter[3]/total)*100 << "%)\n" 	<< "straight:   " << resultcounter[4] << "(" << ((float)resultcounter[4]/total)*100 << "%)\n" 	<< "flush:      " << resultcounter[5] << "(" << ((float)resultcounter[5]/total)*100 << "%)\n" 	<< "full house: " << resultcounter[6] << "(" << ((float)resultcounter[6]/total)*100 << "%)\n"	<< "str flush:  " << resultcounter[7] << "(" << ((float)resultcounter[7]/total)*100 << "%)\n"	<< "low:        " << resultcounter[9] << "(" << ((float)resultcounter[9]/total)*100 << "%)\n";} 			vine	*cardstolowhands(vine **inv){//// convert vine of card to a vine of poker hands [low, assume 8 min]//int	lowtotal[8];vine    *v,*w;vine	*rtn=0;card    *c1,*c2;int	y;int 	x;for (x=0;x<8;x++){	lowtotal[x]=0;}if (!*inv){        return(0);}if ((*inv)->count()!=5){        return(0);}for (v=*inv;v;v=v->next){	c1=(card *)v->data;	if (c1->rank==A){		lowtotal[0]++;	}else{		if (c1->rank<=8){			lowtotal[c1->rank-1]++;		}else{			(*inv)->nuke(inv);               		 return(0);		}	}}y=0;for (x=0;x<8;x++){	y+=lowtotal[x];}if (y!=5){	(*inv)->nuke(inv);	return(0);}for (x=0;x<8;x++){	if (lowtotal[x]>1){		(*inv)->nuke(inv);		return(0);	}}for (v=*inv;v;v=v->next){	c1=(card *)v->data;	if (c1->rank==A){		c1->rank=1;	}	(new vine(HAND,new phand(LOW,0,c1)))->top(&rtn);	if (c1->rank==1){		c1->rank=A;	}}(*inv)->nuke(inv);sorthands(&rtn);return(rtn);}						vine	*cardstohands(vine **inv){//// convert vine of card to a vine of poker hands//vine	*v,*w;vine	*rtn=0;int	p=0;int	f=0;card	*c1,*c2;int	s[5];int	x;if (!*inv){	return(0);}if ((*inv)->count()!=5){	return(0);}// first, check for flushv=*inv;c1=(card *)v->data;for (v=(*inv)->next;v;v=v->next){	c2=(card *)v->data;	if (c2->suit==c1->suit){		f++;	}}if (f==4){	f=1;}else{	f=0;}// next, run through cardsfor (v=(*inv)->next;v;v=v->next){	p=0;	c1=(card *)v->data;	for (w=*inv;w;w=w->next){		if (w!=v){			c2=(card *)w->data;			if (c2->rank==c1->rank){				p++;			}		}	}	(new vine(HAND,new phand((hands)p,f,c1)))->top(&rtn);}// next check for straights.for (v=(*inv)->next;v;v=v->next){	for (x=0;x<5;x++){s[x]=0;}	s[0]=1;	c1=(card *)v->data;	for (w=*inv;w;w=w->next){                if (w!=v){			c2=(card *)w->data;			if (c1->rank==A){				if (c2->rank-1<5 && c2->rank-1>0){					s[c2->rank-1]++;				}			}else{				if (c2->rank-c1->rank<5 && c2->rank-c1->rank>0){					s[c2->rank-c1->rank]++;				}			}		}	}	if (s[0] && s[1] && s[2] && s[3] && s[4]){		(new vine(HAND,new phand(STRAIGHT,f,c1)))->top(&rtn);	}}(*inv)->nuke(inv);sorthands(&rtn);return(rtn);}void	sorthands(vine **inv){//// Sort hands according to hand//phand	*h1, *h2;vine	*v, *vv;int	flag;flag=1;//cout << "in sort\n";while(flag){	flag=0;	for (v=*inv;(v && !flag);v=v->next){		vv=v->next;		if (vv){			h1=(phand *)v->data;			h2=(phand *)vv->data;			if (h2->hand>h1->hand){				v->swapwith(vv,inv);				flag=1;			}else if (h2->hand==h1->hand && h2->flushflag==1 && h1->flushflag==0){				v->swapwith(vv,inv);                        	flag=1;			}else if (h2->hand==h1->hand && (h2->rank > h1->rank)){				v->swapwith(vv,inv);                        	flag=1;			}		}	}}}int	cmphands(vine *a,vine *b){//// compare hands//// 0 if equal, 1 if a, -1 if b//// Returns the "better" hand, so reverse for low tests.//  [and ensure both hands exist...]//phand	*h1,*h2,*ht;vine	*v,*vv;if (!b && !a){	return(0);}if (!b){	return(1);}if (!a){	return(-1);}h1=(phand *)a->data;h2=(phand *)b->data;//cout << "in cmphands\n";// Straight flushesif (h1->hand==STRAIGHT && h1->flushflag==1){	if (h2->hand!=STRAIGHT || h2->flushflag==0){		return(1);	}	if (h1->rank > h2->rank){		return(1);	}else if(h1->rank==h2->rank){		return(0);	}else{		return(-1);	}}if (h2->hand==STRAIGHT && h2->flushflag==1){        return(-1);}// Quadsif (h1->hand==QUADS){	if (h2->hand!=QUADS){		return(1);	}	if (h1->rank > h2->rank){		return(1);	}else{		return(-1);	}}if (h2->hand==QUADS){	return(-1);}// Flushesif (h1->flushflag==1){	if (h2->flushflag==1){		v=a;		vv=b;		while (v){			h1=(phand *)v->data;			h2=(phand *)vv->data;			if (h1->rank>h2->rank){				return(1);			}else if (h2->rank>h1->rank){				return(-1);			}						v=v->next;				vv=vv->next;		}		return(0);	}else if (h2->hand!=TRIPS){		return(1);	}else{		// possible full house beating the flush		for (v=b;v;v=v->next){			ht=(phand *)v->data;			if (ht->hand==PAIR){				return(-1);			}		}		// oops, no 2nd pair, flush beats trips.		return(1);	}}if (h2->flushflag==1){	if (h1->hand!=TRIPS){		return(-1);	}else{		// possible full house beating the flush                for (v=a;v;v=v->next){                        ht=(phand *)v->data;                        if (ht->hand==PAIR){                                return(1);                        }                }                // oops, no 2nd pair, flush beats trips.                return(-1);	}}// Straightsif (h1->hand==STRAIGHT){	if (h2->hand==STRAIGHT){		if (h1->rank>h2->rank){			return(1);		}else if (h1->rank==h2->rank){			return(0);		}else{			return(-1);		}	}else{		return(1);	}}if (h2->hand==STRAIGHT){	return(-1);}// Tripsif (h1->hand==TRIPS){	if (h2->hand!=TRIPS){		return(1);	}	v=a->next->next->next;	vv=b->next->next->next;	while(v){		h1=(phand *)v->data;                h2=(phand *)vv->data;		if (h1->hand==PAIR && h2->hand!=PAIR){			// full house beats trips.			return(1);		}		if (h1->hand!=PAIR && h2->hand==PAIR){			// full house beats trips.			return(-1);		}		if (h1->hand==PAIR && h2->hand==PAIR){			// check trip size of the boat.			if (((phand *)a->data)->rank > ((phand *)b->data)->rank){				// bigger boat wins.				return(1);			}			if (((phand *)a->data)->rank < ((phand *)b->data)->rank){                                // bigger boat wins.                                return(-1);                        }			// check the little size of the boat			if (h1->rank>h2->rank){				return(1);			}			if (h2->rank>h1->rank){				return(-1);			}			// and you can't split with boats.		}		// otherwise, just trips.		if (((phand *)a->data)->rank > ((phand *)b->data)->rank){                        return(1);                }                if (((phand *)a->data)->rank < ((phand *)b->data)->rank){                        return(-1);                }		// otherwise, even trips, check the kickers.		if (h1->rank>h2->rank){			return(1);		}		if (h1->rank<h2->rank){			return(-1);		}		// else, first kicker even		v=v->next;		vv=vv->next;	}	// else even kickers with the trips.	return(0);}if (h2->hand==TRIPS){	return(-1);}// pairsif (h1->hand==PAIR){	if (h2->hand!=PAIR){		return(1);	}	v=a->next->next;	vv=b->next->next;	while(v){                h1=(phand *)v->data;                h2=(phand *)vv->data;                if (h1->hand==PAIR && h2->hand!=PAIR){                        return(1);                }                if (h1->hand!=PAIR && h2->hand==PAIR){                        return(-1);                }                if (h1->hand==PAIR && h2->hand==PAIR){                        if (((phand *)a->data)->rank > ((phand *)b->data)->rank){                                return(1);                        }                        if (((phand *)a->data)->rank < ((phand *)b->data)->rank){                                return(-1);                        }                        if (h1->rank>h2->rank){                                return(1);                        }                        if (h2->rank>h1->rank){                                return(-1);                        }                }                // otherwise, just pair.                if (((phand *)a->data)->rank > ((phand *)b->data)->rank){                        return(1);                }                if (((phand *)a->data)->rank < ((phand *)b->data)->rank){                        return(-1);                }                if (h1->rank>h2->rank){                        return(1);                }                if (h1->rank<h2->rank){                        return(-1);                }                v=v->next;                vv=vv->next;        }	return(0);}if (h2->hand==PAIR){		return(-1);}// Only high card.v=a;vv=b;while(v){	h1=(phand *)v->data;        h2=(phand *)vv->data;	if (h1->rank>h2->rank){		return(1);	}	if (h1->rank<h2->rank){		return(-1);	}	v=v->next;	vv=vv->next;}return(0);}	void	handkiller(vine *inv){//// Delete hands out of vines//phand	*h;for (vine *v=inv;v;v=v->next){	if (v->type==HAND){		h=(phand *)v->data;		delete h;	}}}		void		vinecat(vine **inv){//// Concatenated cmd vines without newlines.//vine	*v;if (!*inv){	return;}for (v=*inv;v;v=v->next){	while(v->next && v->type==CMD && v->next->type==CMD && !strstr((char *)v->data,"\n") && cmdlen > strlen((char *)v->data) + strlen((char *)v->next->data)){		strcat((char *)v->data,(char *)v->next->data);		v->next->remove(inv);	}}}void	winner(vine **inv){//// Take vine *foo[9] and pair down the array to only winning hands.//vine	*v,*vv;int	x,y;int	rtn;for (x=0;x<9;x++){	for (y=0;y<9;y++){		if (inv[x]){			v=inv[x];			if (inv[y]){				vv=inv[y];				if (y!=x){					rtn=cmphands(v,vv);					if (rtn==1){						handkiller(vv);						inv[y]->nuke(&inv[y]);					}else if (rtn==-1){						handkiller(v);                                		inv[x]->nuke(&inv[x]);					}else{                                	}				}			}		}	}}}					void    winnerlow(vine **inv){//// Take vine *foo[9] and pair down the array to only winning hands.//vine    *v,*vv;int     x,y;int     rtn;for (x=0;x<9;x++){        for (y=0;y<9;y++){                if (inv[x]){                        v=inv[x];                        if (inv[y]){                                vv=inv[y];                                if (y!=x){                                        rtn=cmphands(v,vv);                                        if ((rtn<0 && v)||!vv){                                                handkiller(vv);                                                inv[y]->nuke(&inv[y]);                                        }else if (rtn==1){                                                handkiller(v);                                                inv[x]->nuke(&inv[x]);                                        }else{                                        }                                }                        }                }        }}}void	parsecli(int argc,char *argz[]){//// Parse through argv and set info.//int 	x;int	flag;flag=0;for (x=1;x<argc;x++){	if (argz[x]==strstr(argz[x],"-p")){		if (x+1!=argc){			players=atoi(argz[x+1]);			flag++;		}	}else if (argz[x]==strstr(argz[x],"-s")){		if (x+1!=argc){                        deals=atoi(argz[x+1]);			flag++;                }	}else if (argz[x]==strstr(argz[x],"-g")){                if (x+1!=argc){                        games=atoi(argz[x+1]);			flag++;                }	}}if (!flag && argc>1){	cout << usage;	exit(1);}if (players<2){ players=2; }if (players>9){ players=9; }if (deals<1){ deals=1; }if (games<1){ games=1; }}void	main(int argc, char *argz[]){//////omahahole	*oh[9];community	*co;int		rtn;vine		*v,*vv,*c;vine		*vh[9];int		t;float		w;float		lw;long		lp;int		z,zz;int		winnah;#ifdef	_WIN32	long    t;        time(&t);        srand(x);#else	srand(time(0));#endiffor (z=0;z<9;z++){	oh[z]=0;	vh[z]=0;}parsecli(argc,argz);cout << "Simulating "<< deals << " times.\n" << players-1 <<" opponents will play "<< games << " hands.\n\n";for (int x=0;x<deals;x++){	initdeck();	oh[0]=new omahahole();	c=(oh[0]->holetoa());	c->sout();	c->nuke(&c);	t=0;w=0;lw=0;lp=0;	for (int y=0;y<games;y++){		t++;		co=new community();		for (z=1;z<players;z++){			oh[z]=new omahahole();		}		for (z=0;z<players;z++){			vh[z]=omahahigh(oh[z],co);		}		result(vh[0]);		winner(vh);		zz=0;		if (vh[0]){ winnah=1; }else{ winnah=0; }		for (z=0;z<9;z++){			if (vh[z]){				zz++;				handkiller(vh[z]);				vh[z]->nuke(&vh[z]);			}		}		if (winnah){			w=w+1/zz;		}				for (z=0;z<players;z++){                        vh[z]=omahalow(oh[z],co);                }                result(vh[0]);                winnerlow(vh);		if (vh[0]){ winnah=1; }else{ winnah=0; }                zz=0;                for (z=0;z<9;z++){                        if (vh[z]){                                zz++;                                handkiller(vh[z]);                                vh[z]->nuke(&vh[z]);                        }                }		if (zz){			lp++;                	if (winnah){                        	lw=lw+1/zz;                	}		}		for (z=1;z<players;z++){			delete oh[z];		}		                delete co;				}	cout << "high wins: "<<w/t*100<<"%   low wins: "<<lw<<"("<<lw/t*100<<"% of total; "<<lw/lp*100<<"% of low; "<<lw/resultcounter[9]*100<<"% of participated) \n";	printresults();	cout << "\n";	resetcounter();	//cout << "vinecount: " << vinecount << "\n";	delete oh[0];}}

##### Share on other sites
To compare two hands:- In each hand, if all cards are the same, mark hand as a flush.- In each hand:  - Group matching cards. Represent each group as a pair (rank, number of cards).  - Sort the groups by number of cards, then by rank. If there are five groups:    - We know there are no matched cards. If the rank differs by 4 between first and last:      - mark hand as a straight.- If both hands are straight AND flush:  - Compare ranks of first group, and report the winner from that.- Elsif one hand is straight AND flush:  - That hand wins.(Otherwise, neither hand is a straight flush...)- Elsif both hands are straight OR flush: (must be exclusive or at this point)  - If one is flush and the other is straight, the flush wins.  - Else, compare groups from the beginning down (to handle flushes).- Elsif one hand is a straight OR flush (and thus the other isn't):  - If the non-straight/flush hand has two groups:    - It is four of a kind or full house, and wins.  - Otherwise, the other hand wins.(Otherwise, neither hand is a straight or a flush).- Compare group sizes from first group to last. If there is any mismatch:  - The hand with the larger group wins.- Otherwise, the hand types are the same; compare group ranks from first group to last.

[Edited by - Zahlman on March 8, 2005 10:26:39 PM]

##### Share on other sites
I have written extensive hand evaluation functions designed to be extremely efficient (for high speed monte-carlo's, complete enumerations, and so on) so listen up.

The idea here is to denote your ranks as powers of two.. duece = 1, three = 2, four = 4, five = 8, etc.. this allows you to use a bitwise 'or' operation to combine cards into bitmasks/hashes quite easily.

If you decimate the 7 cards a player has into 4 of these masks (A, B, C, and D.. one for each suit) then you have already greatly simplified the process of hand evaluation as you no longer need to sort the cards or anything.. also combine these 4 using bitwise 'or' into a 5th mask (E) representing all the ranks that appear in the hand.

Some helper functions/tables you will need include a bitwise population count ("how many bits are in this mask?") and a routine to seperate the lowest set bit from the rest of the mask (two outputs.. X and Y, X is the lowest set bit, and Y is the mask with that bit removed) .. These can be calculated using either lookup tables or bitwise manipulations. The tables are quite small (8192 entries) so its a pretty good option.

Also useful is a lookup table for straights. Straights are slow to evaluate without a lookup table. You can check for any straight using mask E, and then if needed, check for straight flushes using the other 4 masks (A, B, C, and D)

The population count of the masks A to D are usefull for finding flushes fast. If Count >= 5 then you have at least a flush.

The population count of the E mask is useful for deciding what types of pairish hands to look for.. if 7 bits are set then you know there arent any duplicate ranks.. if 6 bits are set then you know you need to find a single pair.. if 5 are set then the hand might be two pair or trips.. if 4 are set then it might be 2 pair (three pair really) a full house or quads.. if 3 are set then it might be a full house or quads.. if 2 are set then you definately got quads.. the technique for finding which pairs and so forth consist of several if statements combined with bitwise logic.

On to the most important thing.. ranking the hands high a low..

The 9 "primary" classifications of hands there are:

Straight Flush (8), Quads (7), Full House (6), Flush (5), Straight (4), Trips (3), Two Pair (2), One Pair (1), and No Pair (0).

There are nine of them. You can store this part of the evaluation in the upper 4 bits of the hand evaluation. This leaves the lower bits to store the remaining information necessary to discern precisely what the hand is, keeping in mind that we must be able to sort hands of the same primary type. (we can now already sort hands of different primary types)

There needs to be enough space left in the hand evaluation to store the one pair hands.. the one pair hands use the most space due to the amount of information you need to store.. the pair and 3 kickers. Each of these can be stored in 4 bits each by denoting the ranks as a value between 0 and 12 inclusive. This puts a limit on the evaluations at 20-bits (4-bits for primary, 16-bits for secondary), which luckily fits into a 32-bit integer and also semi-lucky is that each part aligns to a single hex digit.

It might seem like no pair and flush hands have 5 kickers, and they do, but we can use a trick to storing these hands just by using 13 bits of the 16 bits allocated to the secondary classification and simply store the bitmask of the 5 ranks.

Straight Flushes: (hex) 8000x
where x = the rank of the highest card in the straight

where x = the quaded rank and y = the kicker

Full house: (hex) 600xy
where x = the triped rank and y = the paired rank

Flush: (hex) 5xxxx
where x = the bitbask of the 5 cards that make up the flush

Straight: (hex) 4000x
where x = the rank of the highest card in the straight

Trips: (hex) 30xyz
where x = the triped rank, y and z are the kickers (high to low)

Two pair: (hex) 20xyz
where x = the highest pair, y = the second highest pair, and z = the kicker.

One pair: (hex) 1xyzw
where x = the paired rank, y, z, and w = the kickers (high to low)

No pair: (hex) 0xxxx
where x = the bitmask of the 5 ranks that make up the 5 kickers.

Now given an eval() function which returns said evaluation, you can simply compare the values to see which hand is better (or if they are tied).

Things to keep in mind: Lookup tables are you friend.. a lookup table to detect straights can simply store the hand evaluation for all legal straights and 0 otherwise (0 is not mapped to a legal hand in this system) .. as well a single lookup table for flushes and straight flushes is possible and those too can simply store the hand evaluation

- Rockoon (Joseph Koss)

##### Share on other sites
Hey AP - I found some code which took this/similar approach and had been hoping to step through it when I had the time/strength - your post should help a lot - thanks!

##### Share on other sites
You build a lut, where each entry has a number representing the number of hands it beats.

Simple.

From,
Nice coder

##### Share on other sites
Quote:
 Original post by stubbleHey AP - I found some code which took this/similar approach and had been hoping to step through it when I had the time/strength - your post should help a lot - thanks!

Well when you do finally get into the meat of it.. you will find that there is just a little bit of tedious, but simple, coding involved!

Some post-coding advice.. write a hold'em horse race simulator which pits two starting hands against each other and enumerates all possible outcomes and tabulate the results.. you can compare the results with the simulator at http://www.twodimes.net/poker/ which I am quite certain is flawless (it not only agrees with my own simulator, but several other peoples who I have come across over the past few years) .. consider the results of the twodimes.net simulator to be the standard with which to measure your own.

##### Share on other sites
http://www.azillionmonkeys.com/qed/gamealgorithms.html and 'A fast poker hand evaluation'

##### Share on other sites
I don't have anything to add to the whole evaluating hands dealt discussion, but I would like to recommend a method of handling card randomization/dealing that I used in an old poker sim I wrote a while back (it's method of evaluating the hands and picking a winner were rather clumsy and inefficient at the time).

What I did was to actually simulate the shuffling of the deck. I quickly slapped the following tidbit of code together as an example. This would be a perfect candidate to turn into a deck class that handled everything for you...

#include "stdafx.h"#include "stdlib.h"#include "iostream.h"#include "time.h"struct card{	int value;	int suit;};card deck[52];int cardsdealt = 0;void shuffle();void createdeck();void dealcard();void main(int argc, char* argv[]){	int x;    srand(static_cast<unsigned>(time(0)));	createdeck();	shuffle();	cout << "Hand one: ";	for(x = 0; x < 5; x++){		dealcard();		cout << " ";	}	cout << endl << "Hand two: ";	for(x = 0; x < 5; x++){		dealcard();		cout << " ";	}}void createdeck(){	int suit, card, index = 0;	for(suit = 0; suit<4; suit++){		for(card=0; card<13; card++){			deck[index].value = card;			deck[index].suit = suit;			index++;		}	}}void shuffle(){		int iterate, swap;	card holder;	for(iterate = 0; iterate<52; iterate++){		swap = rand()%52;		holder = deck[swap];		deck[swap] = deck[iterate];		deck[iterate] = holder;	}}void dealcard(){	char value[2];	char suit;	int temp;	//If cardsdealt>51, deck is empty	//Needs code to account for empty deck	switch(deck[cardsdealt].value){	case 0:		value[0] = 'A';		value[1] = 0;		break;	case 10:		value[0] = 'J';		value[1] = 0;		break;	case 11:		value[0] = 'Q';		value[1] = 0;		break;	case 12:		value[0] = 'K';		value[1] = 0;		break;	default:		temp = deck[cardsdealt].value + 1;		itoa(temp, value, 10);	}	switch(deck[cardsdealt].suit){	case 0:		suit = 'H';		break;	case 1:		suit = 'S';		break;	case 2:		suit = 'C';		break;	case 3:		suit = 'D';	}	cout << value << suit;	cardsdealt++;}

So you make 52 calls to rand(), and only 52 calls to rand, and you don't have to check if a card dealt is a duplicate or not.

##### Share on other sites
Quote:
 Original post by jRaskell*** Source Snippet Removed ***So you make 52 calls to rand(), and only 52 calls to rand, and you don't have to check if a card dealt is a duplicate or not.

Seems to me that this shuffle will not give a good random distribution. The effects of the problem are very small for a deck of 52 cards but are easily noticed in a deck of 3. A repeated test of this shuffle method on an ordered input deck will show that order matters.

A small modification to this shuffle routine is all thats needed.

While you select a swap card from the entire deck, it should be selecting a swap card from only the remaining unshuffled deck.

So change:

swap = rand() % 52

to

swap = iterate + rand() % (52 - iterate)

In english the shuffle becomes "The next card is chosen randomly from the cards that are left"

- Rockoon (Joseph Koss)

##### Share on other sites
See here for more about shuffling.

Of course, in C++ it is probably best to just make use of std::random_shuffle().

##### Share on other sites
Thanks for the link Zahlman. Interesting read. Good input as well on the randomness of my rather simple routine (to you too, AP). Easy modification as well.

##### Share on other sites
Well, realistically you should shuffle the deck once before each play and then throw out cards. You can randomly build a stack of cards and then just pop the ones off the top. That's exactly how I would do it; and it's fairly easy to write, and you don't have to worry about having duplicates (if there is only one card per stack).

##### Share on other sites

This topic is 4646 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628645
• Total Posts
2984028

• 9
• 9
• 9
• 10
• 21