Jacks or Better Program

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

Recommended Posts

I am reading the book Beginning C++ Game Programing. And from what I have learned so far I think I should be able to write this program. Just run into a little road block. I can make it deal to a hand from a deck and also discard cards and redraw cards. But analizing the hand is where I am having an issue. I kind of got an Idea of how to see if there is a flush but anything else seems a little hard lol. Anyone have any ideas how I can achieve my goal. (Analyzing a hand) Or any other advice would be greatly appreciated. Thanks!
/* Jacks Or Better */

#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;
#include &lt;ctime&gt;
#include &lt;cctype&gt;

using namespace std;

int main() {
//Creating Deck
string value[13] = { "A", "2", "3", "4", "5", "6", "7",
"8", "9", "T", "J", "Q", "K" };
string suite[4] = { "h", "s", "c", "d" };
vector&lt;string&gt; deck;
vector&lt;string&gt; hand;

for(int x = 0; x != 13; ++x) {
for(int i = 0; i != 4; ++i) {
deck.push_back(value[x] + suite);
}
}

//Shuffling Deck
srand(time(0));
for(int x = 0; x != 52; ++x){
int index1 = (rand() % 52);
int index2 = (rand() % 52);
string temp;
temp = deck[index1];
deck[index1] = deck[index2];
deck[index2] = temp;
}

//Drawing Cards from deck
const int CARDS_IN_HAND = 5;
for(int x = 0; x != CARDS_IN_HAND; ++x) {
hand.push_back(deck[0]);
deck.erase(deck.begin());
}

//Show Cards
for(int x = 0; x != 5; ++x) {
cout &lt;&lt; hand[x] &lt;&lt; " ";
}
cout &lt;&lt; endl;
cout &lt;&lt; endl;
for(int x = 0; x != 47; ++x) {
cout &lt;&lt; deck[x] &lt;&lt; " ";
if((x+1) % 5 == 0) {
cout &lt;&lt; endl;
}
}

cout &lt;&lt; "\n\nDo you want to keep? (y/n)" &lt;&lt; endl;
for(int x = 0; x!= CARDS_IN_HAND; ++x) {
cout &lt;&lt; "Card " &lt;&lt; x+1 &lt;&lt; ": "; cin &gt;&gt; discard[x];
cout &lt;&lt; "Card " &lt;&lt; x+1 &lt;&lt; ": "; cin &gt;&gt; discard[x];
}
hand[x] = deck[0];
deck.erase(deck.begin());
}
}

//Show new Hand
cout &lt;&lt; endl;
for(int x = 0; x != 5; ++x) {
cout &lt;&lt; hand[x] &lt;&lt; " ";
}

/*
bool pair = false; //pair pays nothing
bool jorb = false; //jacks or better pays 1x
bool twopair = false; //Two Pair pays 2x
bool threekind = false; //Three of a Kind pays 3x
bool straight = false; //Straight pays 4x
bool flush = false; //Flush pays 5x
bool fullhouse = false; //Full House pays 10x
bool straightflush = false; //Straight Flush pays 50x
bool royalflush = false;  //Royal Flush pays 100x

//Checks For Flush
if(hand[0][1] == hand[1][1], hand[0][1] == hand[2][1],
hand[0][1] == hand[3][1], hand[0][1] == hand[4][1]) {
flush == true;
}
//checks For Straight
//checks For Pair
hand.find(hand[0][0], 1)
*/

return 0;
}

[Edited by - Danikar on March 29, 2006 4:51:50 PM]

Share on other sites
For anything other than flush, your first step should be to sort the hand by rank. That way, you know that 2-, 3-, and 4-of-a-kinds (including in two pair and full house) will be consecutive, and that straights and straight flushes will be in order. Also, you don't need to check separately for royal flush (it's just an ace-high straight flush).

Share on other sites
Cool thanks,

for straight flush I figured I would jsut say

if(straight == true && flush == true) {
straightflush == true;
}

and the reason I have diffrent thing for royal flush is because I want it to pay out higher.

How do you do the code brackets thing? I type the tag I thought it was but I guess it didnt work.

I see other people use it, it looks like
Quote:
 this
but has a white background.

Thanks.

Share on other sites
FYI you forgot 4 of a kind which is right under Straight Flush.
It looks good. But something to sort them would work, the problem is, is that your average sorter does it by numbers or alphebets but not both. You could also have two sorters or something but I was thinking change J to 11, Q to 12, and K to 13. (and A to 14) Then when printing out on the screen change them back to J, Q, K and A. This way sorting is easier, as is seeing if they got straights with J, Q, K and A's.

Share on other sites
Post the code within [source] and [/source].

Share on other sites
you need an array that has a count of cards by rank(r).

you need an array that has a count of cards by suit(s).

you need to keep a value that is the lowest ranked card in the hand(l).

you need to keep a value that is the highest ranked card in the hand(h).

have an enum for ranks

enum rank_t{TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE,TEN,JACK,QUEEN,KING,ACE};

have an enum for suits

initialize the rank array(r) to zeros

initialize the suit array(s) to zeros

initialize the lowest ranked card to ACE

initialize the highest ranked card to TWO

go through each card in the hand.

increment the array value corresponding to each card's rank.

increment the array value coresponding to each card's suit.

if the rank of the current card is higher than the current high value, set a new current high value

if the rank of the current card is lower than the current low value, set a new current low value

once you are done doing all of this, start to analyze the resulting data:

check the suits array.

if a 5 is found, you have either a flush or a straight flush. you have no need to check the rank array, provided you have a single deck.

look at the highest ranked card minus the lowest ranked card. (h-l)==4, you have a straight flush, otherwise it is just a flush. telling whether or not a straight flush is a royal flush is trivial.

if it is NOT a flush, look at the rank array, and find the highest number.

if the highest number in the rank array is 4, you have four of a kind.

if the highest number in the rank array is 3, you either have a full house or three of a kind. search the rank array for a 2. if a 2 is found, it is a full house, otherwise it is three of a kind.

if the highest number in the rank array is a 2, you either have one or two pair. count the number of 2s in the rank array, and that's how many pairs you've got. if only one pair is present, make certain it is at least a JACK.

if the highest number in the rank array is a 1, the hand is either a straight or junk. if (h-l)==4, you have a straight. otherwise, you have junk.

NOW....

there is one exception of which you should be aware...

you can have a straight or straight-flush that numbers A-2-3-4-5. The above algorithm will not detect it as is, as it considers Ace to be high. you may simply decide to do a check specifically for it during straight and straight flush detection.

Share on other sites
Thanks, that is very detailed =)

I didn't think about enum for some reason. Thanks

Share on other sites
I made a console poker game a while back. I don't really remember how I did the hand checking now but I could dig it up if you want. Though, I was even more of a newb than I am now so I don't know how well I coded it but I think it worked fine. You probably have enough info from TANSTAAFL though. Goodluck getting it sorted out :)

Share on other sites
Yeah if u want to send that to me that would be cool. I always like looking over other peoples code.

Share on other sites
Tan that confuses the hell out of me. How does that prove they are flush if 5 is the highest? Could it not be you have, Ace, ace, Queen, Jack, and 10. And that 10 would make it a 5. Or maybe i just get the concept. It seems that you are doing a check high and low, but the low is really the high (ace) and ur high is really your low (two) Maybe it's the enum.. I have never heard of it.

Share on other sites
Quote:
 Original post by DanikarYeah if u want to send that to me that would be cool. I always like looking over other peoples code.

I PM'd it to ya. hope it helps.

Share on other sites
Quote:
 Original post by LothiaTan that confuses the hell out of me. How does that prove they are flush if 5 is the highest? Could it not be you have, Ace, ace, Queen, Jack, and 10. And that 10 would make it a 5. Or maybe i just get the concept. It seems that you are doing a check high and low, but the low is really the high (ace) and ur high is really your low (two) Maybe it's the enum.. I have never heard of it.

that's checking the SUITS array, not the RANKS array. if you get 5 cards of the same suit, it MUST be a flush or a straight flush, and the ranks array does not matter, as it will have no number higher than 1 in it, provided a single deck.

also, i set the initial value for the high value to the lowest value and the initial value for the low value to the highest value because it guarantees that it will be set to the correct value while the cards are being evaluated.

i'm going to be going home shortly, and I'll write up code that'll do this....

Share on other sites
Thank you Tan. That would be great to see the code, and now I actually get that part. I guess I was getting confused for something really trivial.

Share on other sites
It'll compile, but it hasn't been tested. Provided as-is, to be use by whomever for whatever. Corrections for deficiencies welcome.

enum rank_t{	RANK_TWO,	RANK_THREE,	RANK_FOUR,	RANK_FIVE,	RANK_SIX,	RANK_SEVEN,	RANK_EIGHT,	RANK_NINE,	RANK_TEN,	RANK_JACK,	RANK_QUEEN,	RANK_KING,	RANK_ACE,	RANK_COUNT,	RANK_FIRST=RANK_TWO};enum suit_t{	SUIT_CLUBS,	SUIT_HEARTS,	SUIT_SPADES,	SUIT_DIAMONDS,	SUIT_COUNT,	SUIT_FIRST=SUIT_CLUBS};enum handvalue_t{	HANDVALUE_INVALID,	HANDVALUE_JUNK,	HANDVALUE_ONEPAIR,	HANDVALUE_ONEPAIRJACKSORBETTER,	HANDVALUE_TWOPAIR,	HANDVALUE_THREEOFAKIND,	HANDVALUE_STRAIGHT,	HANDVALUE_FLUSH,	HANDVALUE_FULLHOUSE,	HANDVALUE_FOUROFAKIND,	HANDVALUE_STRAIGHTFLUSH,	HANDVALUE_ROYALFLUSH,};enum{	HAND_CARDCOUNT = 5};struct card_t{	rank_t rank;	suit_t suit;};struct hand_t{	card_t cards[HAND_CARDCOUNT];};handvalue_t getHandValue(const hand_t& theHand){	handvalue_t result=HANDVALUE_INVALID;		int cardRanks[RANK_COUNT]={0};	int cardSuits[SUIT_COUNT]={0};	rank_t rankHigh=RANK_TWO;	rank_t rankLow=RANK_ACE;	int validCards=0;	for(int cardIndex=0;cardIndex<HAND_CARDCOUNT;++cardIndex)	{		bool cardIsValid=false;		if((theHand.cards[cardIndex].rank<RANK_COUNT)&&(theHand.cards[cardIndex].suit<SUIT_COUNT))		{			bool foundDuplicate=false;			for(int otherCardIndex=cardIndex+1;otherCardIndex<HAND_CARDCOUNT;++otherCardIndex)			{				if((theHand.cards[cardIndex].rank==theHand.cards[otherCardIndex].rank)&&(theHand.cards[cardIndex].suit==theHand.cards[otherCardIndex].suit))				{					foundDuplicate=true;				}				if(!foundDuplicate)				{					cardIsValid=true;				}			}		}		if(cardIsValid)		{			validCards++;			cardRanks[theHand.cards[cardIndex].rank]++;			cardSuits[theHand.cards[cardIndex].suit]++;			if(theHand.cards[cardIndex].rank>rankHigh)			{				rankHigh=theHand.cards[cardIndex].rank;			}			if(theHand.cards[cardIndex].rank<rankLow)			{				rankLow=theHand.cards[cardIndex].rank;			}		}	}	if(HAND_CARDCOUNT==validCards)	{		for(int suitIndex=SUIT_FIRST;(result==HANDVALUE_INVALID)&&(suitIndex<SUIT_COUNT);++suitIndex)		{			if(HAND_CARDCOUNT==cardSuits[suitIndex])			{				result=HANDVALUE_FLUSH;			}		}		if(HANDVALUE_FLUSH==result)		{			if((HAND_CARDCOUNT-1)==(rankHigh-rankLow))			{				if(cardRanks[RANK_ACE])				{					result=HANDVALUE_ROYALFLUSH;				}				else				{					result=HANDVALUE_STRAIGHTFLUSH;				}			}			else if(cardRanks[RANK_TWO]&&cardRanks[RANK_THREE]&&cardRanks[RANK_FOUR]&&cardRanks[RANK_FIVE]&&cardRanks[RANK_ACE])			{				result=HANDVALUE_STRAIGHTFLUSH;			}		}		else		{			bool fourOfAKind=false;			bool threeOfAKind=false;			int pairCount=0;			bool jacksOrBetter=false;			for(int rankIndex=0;(!fourOfAKind)&&(rankIndex<RANK_COUNT);++rankIndex)			{				switch(cardRanks[rankIndex])				{				case 4:					{						fourOfAKind=true;					}break;				case 3:					{						threeOfAKind=true;					}break;				case 2:					{						pairCount++;						if(rankIndex>=RANK_JACK)						{							jacksOrBetter=true;						}					}break;				}			}			if(fourOfAKind)			{				result=HANDVALUE_FOUROFAKIND;			}			else if(threeOfAKind)			{				if(pairCount)				{					result=HANDVALUE_FULLHOUSE;				}				else				{					result=HANDVALUE_THREEOFAKIND;				}			}			else			{				switch(pairCount)				{				case 2:					{						result=HANDVALUE_TWOPAIR;					}break;				case 1:					{						if(jacksOrBetter)						{							result=HANDVALUE_ONEPAIRJACKSORBETTER;						}						else						{							result=HANDVALUE_ONEPAIR;						}					}break;				case 0:					{						if((HAND_CARDCOUNT-1)==(rankHigh-rankLow))						{							result=HANDVALUE_STRAIGHT;						}						else if(cardRanks[RANK_TWO]&&cardRanks[RANK_THREE]&&cardRanks[RANK_FOUR]&&cardRanks[RANK_FIVE]&&cardRanks[RANK_ACE])						{							result=HANDVALUE_STRAIGHT;						}						else						{							result=HANDVALUE_JUNK;						}					}break;				}			}		}	}	return(result);}

Share on other sites
just wondering why do you check if each card is valid first? wouldnt the deal function assure that the player is only handed valid cards?

Share on other sites
Always assume invalid input until you are certain otherwise...

Share on other sites
Can you explain what a enum is? It seems to me its a struct.

Share on other sites
Heres a little thing you should try which you might find interesting

for(char i = 3; i<7; i++)
cout << i;

whoa wasnt that cool? Now to make it easy for you

string typestr = string(char(3));

Share on other sites
Quote:
 Original post by LothiaCan you explain what a enum is? It seems to me its a struct.

enum types in C++

Share on other sites
here's another good enum description/tutorial cplusplus.com. I use this site whenever I want to look up anything related to c++.

Share on other sites
I suggest that you use a poker evaluation library such as pokersource rather than writing your own. At least look at the source -- it will help you out a lot. I started out writing my own evaluation code and after looking at the pokersource code, I decided to scrap mine and just use pokersource.