Poker StraightFlush and FourofaKind

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>

using namespace std;

string r[13] ={
      "Two","Three","Four",
      "Five", "Six","Seven","Eight", "Nine",
      "Ten","Jack", "Queen", "King", "Ace"
};

string s[4] = {"Spades","Hearts","Clubs","Diamonds"};

class Card{
private:
  string rank;
  string suit;
  int value;

public:
  void set_rank(string r){rank = r;};
  void set_suit(string s){suit = s;};
  void set_value(int v){value = v;};

  string get_rank(){ return rank; };
  string get_suit(){ return suit; };
  int get_value(){ return value; };

  void display(){
      cout <<" - "<< rank << " of "<< suit << endl;
  }
}; 


//a is hand 
//s is suit
// pseudocode
bool StraightFlush(vector <Card> &d){
	
	if(a[1]suit = a[2]suit, ...)
		if(a[1]=a[0]+1, ...)
			cout<<"congrats, straight flush";
				return true;
	
	
	
		return false;
}

bool FourofaKind(vector <Card> &d){
	
	
	
}


Need help with StraightFluhs and FourofaKind functions
the hand is an array but cards are from class

Last edited on
Are you playing 5-card poker or 7-card poker?

If 5-card, then a flush means all 5 are in the same suit. If 7-card, then 5 of the 7 have to be in the same suit.

For straight flush, in 5-card poker the cards must all have successive ranks as well as a flush. For 7-card poker, there must be a flush AND the cards in the flush must have successive ranks.

To figure out which ranks are in your hand, create and array int eachRank[13 = {0}; For each card in your hand, increment eachRank[<rank of card>]. At the end, if any array element contains '4' you have 4-of-a-kind. If 5-successive ranks contain a non-zero value you have a straight. You can do the same thing with an array of 4 to determine whether you have a flush.

When you are doing 7-card poker, straight flush becomes trickier because you need to make sure that the same 5 cards in the straight are the same 5 cards in the flush.
It is 5 card. But i have trouble understanding.
if(a[1]suit = a[2]suit, ...)
if(a[1]=a[0]+1, ...)

these be assignments. comparison for equality is ==
if (x == y) //is x = y?


if (x = y) //legal, but it says: x = y. Is y not zero?

sort the hand by value and by suit.
if the first suit and last suit are the same, is a flush.
if you can iterate across it and each value is 1 more than the previous value, its a straight. (hmm, is it true that if [0] and [4] are exactly 5 apart, its a straight?)
if both, its a straight flush.
if both and the first value is a 10, its a royal flush.
don't forget to handle jokers or designated wilds if you have.
Last edited on
sort the hand by value and by suit.
if the first suit and last suit are the same, is a flush.
if you can iterate across it and each value is 1 more than the previous value, its a straight. (hmm, is it true that if [0] and [4] are exactly 5 apart, its a straight?)


This implies 2 separate sorts.

First sort by suits. Check for a flush.

Next sort by rank. Check for a straight.

I you sort by both (sort by suit, sort by rank within a suit), you cannot determine whether you have a straight. for instance:

Spades 4, Hearts Jack, Clubs 3,  Clubs 10, Diamonds 8


is not a straight even though value[0] is 4 less than value[4]
yes, it implies 2 sorts. Iteration is actually cheaper, but sorting 2x is simpler code, if I am right.
i think we can afford to sort 5 items a couple of times, inefficient as it may be

I think you can iterate once and solve both questions in O(n). There are a lot of ways to solve this one. if your deck of cards were laid out the right way, you may be able to sort them by deck position instead and solve both at once. if it were a-kS a-kh a-kC a-kd layout, sorted by deck order, its a flush if the max and min card are in the same block, and a straight if max - min = 5, right?
Last edited on
I agree about the cheap sorting. Your first post was a little bit ambiguous about whether you were talking about 2 sorts (once by value, once by suit) or a 2-level nested sort (by value and then by suite within each value, or vice versa). I just wanted to point out pitfalls of the 2-level sort.

I think you can iterate once and solve both questions in O(n). There are a lot of ways to solve this one. if your deck of cards were laid out the right way, you may be able to sort them by deck position instead and solve both at once. if it were a-kS a-kh a-kC a-kd layout, sorted by deck order, its a flush if the max and min card are in the same block, and a straight if max - min = 5, right?

First of all, a nitpick: I think you mean it's a straight if max - min = 4. Simple off-by-one mistake we've all made.

But beyond that, I am a little bit confused, and I don't think the check for straights is as simple as you suggest. I think this is what you are saying:

The deck of cards is represented by integer values 0 - 51. Each suit is represented by 13 values mapping to ranks 2 - Ace:
    Spades:   0 - 12
    Hearts:   13 - 25
    Clubs:    26 - 38
    Diamonds: 39 - 51

If your hand has values 16, 18, 19, 20, 23, you would have a flush in hearts because all the values are between 13 and 25. (Incidentally, you can quickly determine this by dividing (integer division) each value by 13, and the result is the same for all cards.)

If my assumption so far is correct, then I don't understand how you use this for a quick check for a straight. Say you have 2S, 3d, 4C, 5C and 6h (I believe that's values 0, 40, 28, 29 and 17). This is a straight, however max - min == 40 and (max%13) - (min%13) == 1. From this layout, you cannot easily determine what ranks you have. You really need to sort the cards by rank and then make sure you have 5 consecutive values. This means that not only max - min == 4, but none of the ranks match.

The way I suggested above (array of ranks containing counts for each) will allow you for checks of straights as well as 2-, 3- and 4-of-a-kind.
the cards are in the same position in blocks the way I laid it out.
so your 2s are a fixed number apart.. if 2s is 2, then 2h is 13+2, 2c is 26+2, and so on. just like your modulo for flush, you can convert a deck position back to its pure face value and then subtract. and yes, its 4. I seem to have said 5 at least twice :( My thinking is known to be faulty. it may require actual iteration or 2 distinct sorts. There may not be a cute solution... that above does not actually work and I see now -- 2,2,2,3,6 of whatever suits would return true but isnt a straight... so scratch that idea.
Last edited on
I see. But how would all this in code form? That was a lot of info to read.
1. Sort the cards by suit. If sorted[0].suit == sorted[4].suit, you have a flush.

2. Sort the cards by rank. If for all i in 0...4 if (sorted[i].rank + 1 == sorted[i + 1].rank) then you have a straight.

3. If you have both a straight and a flush, then you have a straigh flush.

4. While cards are still sorted by rank, if sorted[0].rank == sorted[3].rank or sorted[1].rank == sorted[4].rank, then you have a 4-of-a-kind.

You don't need to sort to check for a flush. Just check if all cards have the same suit as the first card.

Don't forget the special case of a straight that starts with an ace: A-2-3-4-5.

After you sort by rank, count up how many cards of a kind you have. Something like:
1
2
3
4
5
6
7
8
9
10
11
12
13
vector<int> numOfAKind(5);  // e.g., numOfAKind[2] is how many pairs in the hand.
int lastIdx = 0;  // index where last run of equal-ranked cards started
for (i=1; i<5; ++i) {
    if (hand[i].rank == hand[lastIdx].rank) {
       // They're the same, keep going
    } else {
        // This one isn't the same
        int numTheSame = i - lastIdx;  // You saw this many that were the same
        numOfAKind[numTheSame]++; // increment that slot
        lastIdx = i;
    }
}
numOfAKind[5-lastIdx]++;  // Do the last run 

Assuming that you already computed whether it's a straight and whether it's a flush
you can now determine the hand.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (isFlush && isStraight && hand[4].rank == ace) {
    // royal flush
} else if (isFlush && isStraight) {
    // straight-flush
} else if (numOfAKind[4]) {
    // 4 of a kind
} else if (numOfAKind[3] && numOfAKind[2]) {
    // full house
} else if (flush) {
    // flush
} else if (straight} {
    // straight
} else if (numOfAKind[3]) {
    // 3 of a kind
} else if (numOfAKind[2] == 2) {
    // 2 pair
} else if (numOfAKind[2]) {
   // 1 pair
} else {
   // high card
}

This will let you rank a hand, but how do you compare two hands? You need to know what kind of hand they have, but you also need something to break a tie. I think this can always be done with a single card:
1
2
3
4
5
enum HandKind {Card, Pair, TwoPair, ThreeOfAKind, Straight, Flush, FullHouse, FourOfAKind, StraightFlush}; // royal flush is just the highest straight-flush
struct HandRank {
    HandKind kind;
    Card tieBreaker;  // In case there's a tie
};


Now things are falling into place. The code above can go into a method that returns a HandRank. You'll have to add code to set the tiebreaker. Add a < operator to compare HandRanks: first by kind and then by tiebreaker card. When you're done you should be able to do things like:
1
2
3
4
5
6
7
8
9
HandRank rank1 = rank(Player1.hand);
HandRank rank2 = rank(Player2.hand);
cout << "Player1 has " << rank1 << '\n';
cout << "Player2 has " << rank2 << '\n';
if (rank1 < rank2) {  // HandRank::operator<()
    cout << "Player 2 wins\n";
} else {
    cout << "Player 1 wins\n";
}
Last edited on
Topic archived. No new replies allowed.