Could someone walk me through a deck of cards problem?

Pages: 12
Okay, I believe that I fixed most of the errors again... The header is starting to get organized.
So as you mentioned, I need two loops for my deal function, which is obviously a crucial function. So you'll see that I started those loops, but they don't quite make sense the way I have them. I want to deal until the hand is five cards, then loop through each of the six players. Then pass to add_card_to_hand.

Then I started with the comparison functions, for comparing hands. Thanks for the freebie, I'm using similar functions for the others, but what's the best way to do the find_high_rank()
function, because this will be crucial in the others.

card_games.h
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#ifndef HEADER_H
#define HEADER_H
#include <string>
#include <iostream>
#include <vector>

using namespace std;

class Card{
	public:
		Card(int value, char suit) : value(value), suit(suit) {}
	private:
		int value;
		char suit;
	};
class Deck {
	public:
		void createDeck();
		void shuffleDeck();
		Card draw();
		Deck();
		void Print() const;
	private:
		vector<Card> deck;
};
enum hand_kind
    {   HIGH_CARD,
        ONE_PAIR,
        TWO_PAIR,
        THREE_OF_A_KIND,
        STRAIGHT, 
        FLUSH,
        FULL_HOUSE,
        FOUR_OF_A_KIND,
        STRAIGHT_FLUSH,        
    };
class Hand 
{   vector<Card>    m_hand;
    hand_kind       m_kind;
    int             m_high_rank;
    
    bool is_straight_flush ();
    bool is_four();
    bool is_full_house(); 
    bool is_flush ();
    bool is_straight ();
    bool is_three();
    bool is_same_rank (int rank);
    bool is_two_pair ();
    int find_high_rank () const;
    int how_many (int rank) const;
public:
    Hand ();
    void add_card_to_hand (const Card & card);
    hand_kind classify_hand ();

    bool operator < (const Hand & rhs) const;
    
    friend ostream & operator << (ostream & os, const Hand & hand);
};
class Player: public Hand {
	
	int player_chips;
	bool folded;
	public:
	Player (int starting_chips);
	int make_bet ();
};
class StudPoker{
public:
	vector <Player> m_players;
	int m_pot;
	void deal(vector <Player> m_players);
	};

#endif // HEADER_H 


functions.cpp

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "card_games.h"
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>

using namespace std;

Deck::Deck() {
	createDeck();
}

void Deck::createDeck() {
	deck.clear();
	static const char suits[] = {'C','D','H','S'};
	for (int suit=0; suit < 4; suit++)
		for (int val=1; val <=13; val++)
			deck.push_back(Card(val,suits[suit]));
}

Card Deck::draw()
{
	int RandIndex=rand() % deck.size();
	Card draw=deck[RandIndex];
	deck.erase(deck.begin()+RandIndex);
	return draw;

}

/*void Deck::Print () const{ //for debugging purposes
	Card tempcard;
	for (unsigned i = 0; i < deck.size(); i++)
	{
		tempcard = deck[i];
		tempcard.Print();
	}	
}
 */
void StudPoker::deal(vector <Player> m_players) {
	int hand = 0; 
	//draw card to hand
	for (i = 0; i < hand.size(); i++)
	{
		deck.draw()
	}
	//players loop
	for (i = 0; i < 6; i++)
	{
		vector <Player> m_players;
		Player[draw].add_card_to_hand();
	}
}
void Hand::add_card_to_hand(const Card & card) {

	deck.push_back(cards_in_hand(val,suits[suit]));
}

int Player::make_bet(){
	int bet;
	cout << "Your chips: " << player_chips;
	cout << "Place bet (enter 0 to fold): ";
	cin >> bet;
	
	return bet;
}

bool Hand::is_straight_flush () 
{   if (! (is_flush () && is_straight()))
        return false;  // Not flush and not straight
    m_high_rank = find_high_rank();
    return true;        
}

bool Hand::is_four()
{
	if (! (is_four()))
		return false;
	m_high_rank = find_high_rank();
}
bool Hand::is_full_house()
{
	if (! (is_three() && is_two_pair()))
		return false;
	m_high_rank = find_high_rank();
}

bool Hand::is_flush()
{
	if (! (is_flush()))
		return false;
	m_high_rank = find_high_rank();
}

bool Hand::is_straight()
{
	if (! (is_straight()))
		return false;
	m_high_rank = find_high_rank();
	return true;
}

bool Hand::is_three()
{
	if (! (is_three()))
		return false;
	m_high_rank = find_high_rank();
	return true;
}

bool Hand::is_two_pair()
{
	if (! (is_two_pair()))
		return false;
	m_high_rank = find_high_rank();
	return true;
}

int Hand::find_high_rank() const 
{
	//not sure how to check cards for high rank. a bunch of cases?
}


So again, main issues are my deal function, add_card_to_hand and setting up the find_high_rank() function for checking.

I'm sure you'll find some other things to fix, and I really appreciate your help on this and I especially appreciate your patience as I struggle through this.
card_games.h
------------------
Line 11: Card needs a default constructor (and an implementation of it).

functions.cpp
----------------
StudPoker::deal() needs work.
1) No need to pass m_players in as an argument. m_players is a member of StudPoker.
2) You declare m_plays again at line 49.
3) The two loops should be nested. MAX_CARDS should be the outer loop.
4) Line 42: hand.size(). That's the number of cards current in the hand, if hand were a vector. It's not, it's an int (line 40). The loop limit here should be i<5.
4) Line 44: When you draw a card, you have to put it somewhere.
1
2
3
4
5
6
7
8
9
10
11
12
13
void StudPoker::Deal ()
{   Card        card;

    cout << "Dealing..." << endl;
    for (int i=0; i<MAX_CARDS; i++)
    {   for (int j=0; j<m_num_players; j++)
        {   card = m_deck.Draw();
            m_player[j].add_card (card);
        }
        // Accept bets after one card dealt to each player.
        betting_round();  
    }    
}


what's the best way to do the find_high_rank()

Here's a starter:
1
2
3
4
5
6
7
8
//  Return the value of the highest card
int Hand::find_high_rank () const 
{   int high_rank = 0;

    for (unsigned i=0; i<m_hand.size(); i++)
        high_rank = max(high_rank, m_hand[i].get_rank());
    return high_rank;
}

Note: This only returns the highest card in the hand. This won't work for situations like full house where you want the higher thresome, or two pair where you want the higher pair. Note that two pair could have the same higher pair, then the lower pair determines. e.g. KK55, KK99.

functions.cpp
-----------------

Lines 74-76,89,96,104,112: These are recursive. i.e. is_four calls itself. Will cause an endless loop and stack overflow.

Line 82: A full house is a threesome and a pair, not a threesome and two pair.

StudPoker needs a method to input the number of players.

main.cpp
-----------
main() needs to call StudPoker's function to determine the number of players.






Last edited on
Okay, I'm working on these fixes. For this function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

void StudPoker::Deal ()
{   Card card;
    cout << "Dealing..." << endl;
    for (int i=0; i<MAX_CARDS; i++)
    {   for (int j=0; j<m_num_players; j++)
        {   card = m_deck.Draw();
            m_players[j].add_card (card);
        }
        // Accept bets after one card dealt to each player.
        betting_round();  
    }    
}


What would be the member of add_card, because I'm getting the 'no member named add_card, but I'm not sure what type of member this is, since it's the card itself.

Then basically, the same question for m_deck, but maybe you were just naming this different then what I have, would this just be my deck function?

Then in find_high_rank(), get_rank is just getting the value of the card correct?

I'll continue working on everything you listed above. Thanks!
Line 8 should be:
 
  m_players[j].add_card_to_hand (card);

Note: Since Player inherits from Hand, we can call public functions in Hand by referencing an instance of Player.

the same question for m_deck, but maybe you were just naming this different then what I have

Yes, that is your member variable deck. I tend to use the m_ prefix to indicate a variable is a member of a class.

Then in find_high_rank(), get_rank is just getting the value of the card correct?

Yes. Since rank (value) is a private member of Card, we need a getter function to get the rank of the card.

I hope you're starting to understand how these five classes fit together. Each of the classes represents a distinct object. The member variables of each class are attributes of that object and the member functions of each class represent actions that an instance of that class can preform.

I know your assignment stated to use inheritance. We do have an example of inheitance (Player inherits Hand). It's not clear to me if the intent of the assignment was for the StudPoker class to inherit some other class. To my way of thinking, there is not really a good example of inheritance between any of these classses. e.g. Even though we have Player inheriting from Hand, a Player "has a" Hand implying composition rather than inheritance, but inheritance does work in this situation. The StudPoker class "could" inherit Deck, but StudPoker "has a" Deck implying composition makes more sense, and not StudPoker "is a" Deck (inheritance).

Last edited on
Yeah, I am starting to understand how the classes fit together, and how each member variable can be used within the class. You have been hugely helpful. As you mentioned, I do need to use inheritance, which is used once, but right now I just want to get the program working, since it's due Friday evening. I may lose quite a few points, since there is also supposed to be a DrawPoker class that allows the player to draw cards, then replace them with a few new one's, etc. But right now, I'll just take what I can get.

Again, thanks and I'll ask another question here...

1
2
3
4
5
6
7
8
9
10
11
12
void StudPoker::Deal ()
{   Card card;
    cout << "Dealing..." << endl;
    for (int i=0; i<MAX_CARDS; i++)
    {   for (int j=0; j<m_num_players; j++)
        {   card = m_deck.Draw();
            m_players[j].add_card_to_hand (card);
        }
        // Accept bets after one card dealt to each player.
        betting_round();  
    }    
}


What type is the declaration in my class for the m_deck()? Because wouldn't we be calling the deck itself. So this needs to be under the StudPoker class, but call a member of the Deck Class? Or just declare m_deck() and pass in deck?

 
void m_deck(const Deck & deck) //something like this? 


Then can this statement remain the same
 
card = m.deck.Draw();


Thanks for all your help, hopefully I can finish everything, even after the deadline. Just for the practice.
Last edited on
What type is the declaration in my class for the m_deck()?

You're confusing a variable and a function again. The () imply a call of a function by that name. m_deck is an instance of the Deck class (i.e. a variable). It should be a member of your StudPoker class.

1
2
3
class StudPoker
{    Deck  m_deck;
...


m_deck's constructor (which populates the deck) get called automatically which is when the StudPoker class gets instantiated (your game variable in main.cpp).

Now that you mention DrawPoker, the requirement for inheritance becomes clear. That would imply a PokerGsme base class. StudPoker and DrawPoker become classes derived from the PokerGame class. Both StudPoker and DrawPoker satisfy "is a " PokerGame (inheritance).
Last edited on
Okay, yeah I keep getting confused with the instance of the Deck/Card as you mentioned.
As you mentioned, the DrawPoker and StudPoker inherent from PokerGame, this is also why the required main.cpp just has calls to the game the player chooses.

So if I want to get the number of players. Here is the function I created, but again, I'm trying to figure out how I can essentially populate the players vector with the input m_players.

1
2
3
4
5
6
int StudPoker::get_players() {
	cout << "Enter number of players (2-6): ";
	cin >> m_players;
	return m_players;
	
}


Then another question related to calling a function from a function. How can I call the betting_round() function from within Deal.

And within the betting_round function, which I figure we need to pass m_players so the round only goes until each player has bet. But again, I'm passing a vector, which obviously gives me errors. Then in my class it just says, m_players is not a type. Calling make_bet() doesn't give me any errors, that's why I'm a bit confused about calling betting_round().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void StudPoker::Deal ()
{   Card card;
    cout << "Dealing..." << endl;
    for (int i=0; i<MAX_CARDS; i++)
    {   for (int j=0; j<m_num_players; j++)
        {   card = m_deck.Draw();
            m_players[j].add_card_to_hand (card);
        }
        // Accept bets after one card dealt to each player.
        betting_round();  
    }    
}
void StudPoker::betting_round(m_players) {
	for (int i = 0; i < m_players; i++)
	{
		make_bet();
	}

}

class:
 
void betting_round(m_players);


Then as you mentioned, my checking functions for high card, pair, etc. are recursive, so I'll work on these.

Would doing this fix the recursion issue?

1
2
3
4
5
6
7
8
9
10
11
12
bool Hand::is_straight() {
    int current_rank = m_hand.begin()->value;
    for(std::vector<Card>::const_iterator it = m_hand.begin(),++it;
        it != m_hand.end();
        ++it) {
        if(it->value + 1 != current_rank) {
             return false; // No straight
        }
        current_rank = it->value;
    }
    return true;
}


Thanks!
Last edited on
As you mentioned, the DrawPoker and StudPoker inherent from PokerGame

This is the first time you've mentioned DrawPoker. Not knowing that you were to write a DrawPoker class also, I was puzzled why StudPoker was supposed to use inheritance. Now the requirement makes sense.

So if I want to get the number of players. Here is the function I created

I'm going to suggest a change in naming here. I would suggest you change m_players to m_num_players. You're already using m_players as the name of your vector (line 71 above).

get_players can be a void function. Since you're doing a cin directly to m_num_players, there is no reason for get_players() to return anything. I'd also suggest that get_players() range check it's input, but that a minor point.

'm trying to figure out how I can essentially populate the players vector with the input m_players.

Use a loop and push the required number of Player objects onto the m_players vector.

How can I call the betting_round() function from within Deal.

Just call it. Line 10 of Deal() is just fine.

Line 13 however, you don't need to pass m_players in. Since betting_round is a member function of StudPoker, betting_round has access to all data members of StudPoker including m_num_players and the m_players vector.

Line 16: Here you want to do two things:
1) You want to refer to the make_bet() function of a player
2) You want to increment the pot by the amount of the players bet.
m_pot += m_players[i].make_bet();
Note that make_bet() should return the amount of the players bet so that the pot can be incremented.




Yeah, sorry I didn't mention it before (the drawpoker and studpoker). Would the header file just be something like:

1
2
3
4
5
6
7
8
class Poker {
//include everything except whats in the StudPoker class
};
Class StudPoker: Poker {
};
Class DrawPoker: Poker {
};
//with our current memebers in StudPoker, then make everything for draw poker. 


So how do the following functions look now:
On this line, is Player incorrect? I'm getting the expected expression before ( and ].
 
m_players.push_back(Player(m_num_players[]));


functions:

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
void StudPoker::get_players() {
	cout << "Enter number of players (2-6): ";
	cin >> m_num_players;
	for (int i = 0; i < m_num_players; i++){
		m_players.push_back(Player(m_num_players[]));
	}
	
	
}
 
void StudPoker::Deal ()
{   Card card;
    cout << "Dealing..." << endl;
    for (int i=0; i<MAX_CARDS; i++)
    {   for (int j=0; j<m_num_players; j++)
        {   card = m_deck.Draw();
            m_players[j].add_card_to_hand (card);
        }
        // Accept bets after one card dealt to each player.
        betting_round(); 
    }    
}
void StudPoker::betting_round() {
	for (int i = 0; i < m_num_players; i++)
	{
		Player make_bet();
		m_pot += m_players[i].make_bet();
	}

}
void Hand::add_card_to_hand(const Card & card) {

	deck.push_back(m_cards_in_hand(val,suits[suit]));
}

int Player::make_bet(){
	int bet;
	cout << "Your chips: " << player_chips;
	cout << "Place bet (enter 0 to fold): ";
	cin >> bet;
	
	return bet;
}


Then my add_card_hand needs some work I think, pretty much everything is 'not declared in this scope'

Also, I edited my previous post, but I think you were already answering it. It's about handling the card checking.

With something like this:

1
2
3
4
5
6
7
8
9
10
11
12
bool Hand::is_straight() {
    int current_rank = m_hand.begin()->value;
    for(std::vector<Card>::const_iterator it = m_hand.begin(),++it;
        it != m_hand.end();
        ++it) {
        if(it->value + 1 != current_rank) {
             return false; // No straight
        }
        current_rank = it->value;
    }
    return true;
}
Last edited on
Regarding the poker class, lines 4 and 6 need the keyword public before Poker.

What goes in Poker would be functions and variables that are common to both DrawPoker and StudPoker. e,g, get_num_players() would belong in Poker. Deal() would belong in both DrawPoker and StudPoker classes (but not Poker) since the code would be different for the two different games.

is Player incorrect?

Yes.
functions.cpp
--------------
line 5: Not sure what your constructor for Player looks like now. The last one you posted (big post above), Player takes one int which is the starting chip count. I see no implementation for that constructor. The push_back part is okay.

Line 11: Deal() looks fine.

Line 26: Delete this. The syntax is bogus. You're trying to define an instance of Player, but it looks like a function call with the ().

Line 27: Looks good.

Line 33: It is simply:
cards_in_hand.push_back (card);
What you have makes no sense.

Line 41: You need to decrement player_chips by the amount of the bet.

pretty much everything is 'not declared in this scope'

That's usually a symptom of the implementation function name not matching the declaration function name, or the function name wasn't declared at all.

You're on the right track with is_straight(). although you have a few problems:
1) Keep in mind though that cards are added to the hand in random order. Cards could be 52314.
2) Line 3: You have an extraneous ++it in your for statement.







Last edited on
Okay, so with get_players():
1
2
3
4
5
6
7
void StudPoker::get_players() {
	cout << "Enter number of players (2-6): ";
	cin >> m_num_players;
	for (int i = 0; i < m_num_players; i++){
		m_players.push_back(Player(m_num_players[]));
	}
}


Not sure what your constructor...
It looks like this:
1
2
3
4
5
6
7
class Player: public Hand {
	int player_chips;
	bool folded;
	public:
	Player (int starting_chips);
	int make_bet ();
};


but should I just insert, like we did in Card:
 
Player();


Then would:
 
m_players.push_back(Player(m_num_players[]));

make sense (work)?

Then onto add_card_to_hand:
1
2
3
4
void Hand::add_card_to_hand(const Card & card) {

	cards_in_hand.push_back (card);
}


I didn't declare cards_in_hand in my Hand class, as I'm not sure what type this should be. It's kind of a vector for hand isn't it?

Then how does this look:
1
2
3
4
5
6
7
8
9
bool Hand::is_straight() {
    int current_rank = m_hand.begin()->value;
    for(std::vector<Card>::const_iterator it = m_hand.begin();
        it != m_hand.end(); ++it) {
        if(it->value + 1 != current_rank) {
             return false; // No straight
        }
        current_rank = it->value;
    }


Just getting a message under
1
2
3
4
5
int current_rank = m_hand.begin()->value;
//
if(it->value + 1 != current_rank) {
//
current_rank = it->value;


saying 'within this context'

Then as far as the Poker Parent class goes, as you mentioned, the members would go under Poker, for stuff relevant to both. Would I basically copy and paste the Card, Deck, Hand and Player classes into Poker, sort of a nested class (if that's a thing). Or a long list of all the public members, that are shared to DrawPoker and StudPoker.

Thanks so much. Appreciate all the help as always!
Last edited on
m_players.push_back(Player(m_num_players[]));
Look at the constructor for Player. What does it take? It takes an int (starting chip count). It doesn't take an array of num_players (which BTW, is not an array).
Should be:
m_players.push_back(Player(500)); // Each player starts with 500 chips

I didn't declare cards_in_hand in my Hand class

In you last full code post, it was m_hand.

Regarding is_straight(), your for statement looks better. My #1 comment from before regarding random order still applies.

Just getting a message under

Post the full message.

Would I basically copy and paste the Card, Deck, Hand and Player classes into Poker

No. Those classes stay exactly as you have them.

You can move the m_players and m_deck to be protected members of Poker since you want those members to be inherited by both StudPoker and DrawPoker.







Last edited on
Okay, fixed m_players. Here is is the full message. Not sure what it's referring too though:

functions.cpp:109:40: error: within this context

referring to this line and not giving any more information.
 
int current_rank = m_hand.begin()->value;

then under
 
if(it->value + 1 != current_rank) {

it's the exact same message, but I think fixing the first one should fix this.

Yeah, I understand what you are saying about random order. Would another loop to organize the cards coming in, be needed?

I think I'll worry about the inheritance stuff later since we seem to be fairly close as far as getting it to run... That part shouldn't be much of a problem, I'd imagine, just moving members around and ensuring the Stud and Draw use Poker properly.
Last edited on
Androidguy... would I be wrong in assuming you are taking cs with Rooker at OSU lol? Don't worry... your secret is safe with me.
You would be correct haha. I don't think asking about the assignment on here would be against any rules though. Just asking for help. Next assignment will be tough too...
Yeah, I understand what you are saying about random order. Would another loop to organize the cards coming in, be needed?

I'd use std::sort to sort the vector of cards.
http://www.cplusplus.com/reference/algorithm/sort/
Note that you will want to provide your own comparison function, since you want to compare on rank (value) only.

As for the errors you're getting, I'd have to see more code.
The 'within this context' errors are all within this function:

1
2
3
4
5
6
7
8
9
10
11
bool Hand::is_straight() {
    int current_rank = m_hand.begin()->value; //'within this context' error on this line
    for(std::vector<Card>::const_iterator it = m_hand.begin();
        it != m_hand.end(); ++it) {
        if(it->value + 1 != current_rank) { //'within this context' error on this line
             return false; // No straight
        }
        current_rank = it->value; //'within this context' error on this line
    }
    return true;
}


I'll start looking at sort. Thanks!
Note that value is a private member of Card so that means you can't reference it directly from Hand.

The following compiles for me:
1
2
3
4
5
6
7
8
9
10
11
bool Hand::is_straight() 
{   int current_rank = m_hand.begin()->get_rank(); //'within this context' error on this line
    for(std::vector<Card>::const_iterator it = m_hand.begin();
        it != m_hand.end(); ++it) {
        if(it->get_rank() + 1 != current_rank) { //'within this context' error on this line
             return false; // No straight
        }
        current_rank = it->value; //'within this context' error on this line
    }
    return true;
}


I don't know if you have a getter function in Card for rank (aka value). If you don't have one, you will need one. Note that in my code I called the getter get_rank()as opposed to get_value(). A little more descriptive of the purpose than "value".
Topic archived. No new replies allowed.
Pages: 12