比较手牌中的牌位

时间:2017-05-24 21:24:07

标签: c++ poker

我有一份两部分的家庭作业。第一部分是在为Deck类创建对象时创建一个包含52个卡对象的向量的程序。我做了这个,让甲板首先给每张卡片1-4号套装,2-14张卡片。然后它将数字更改为字符串,以便它可以输出卡片的形式为"黑桃王牌,两个心脏"现在我想弄清楚如何让它画五张牌并评估它

对,两对,三种,四种,满屋。

不确定我的字符串是否可以这样做,或者我是否必须更改整个代码才能以不同的方式执行此操作。这是代码。

编辑:此外,main.cpp作为模板提供,我们被迫围绕它进行构建,所以即使有更好的方法,我们也必须以这种形式进行构建>。

editedit:这是我们给出的一个提示"提示:创建一个地图,其中每个对存储一个唯一的等级和手中等级出现的次数。您还可以使用count_if函数来确定集合中有多少对或三对。"但说实话,我并没有真正得到他希望我们在这里做的事情......

//main.cpp 

#include <iostream>
#include "Deck.h"

using namespace std; 



int main()
{
    Deck deck;                  // created the object called 'deck'
    deck.shuffleCards();        // puts cards in the deck and shuffles them
    while (not deck.empty())    // if the deck isn't empty loop will continue
    {
        cout << deck.draw().toString() << endl;    // first it draws a card from the deck                                                                                                                                                           
    }                                              // of the form '000' and then puts those three
                                                   // numbers into the toString function which 
}                                                  // converts them into a string of words
                                                   // in the form 'Card' of 'Suit'. Keeps drawing
                                                   // cards run out. 

这是函数

#include "Deck.h"

// Constructor for cards that are created

inline Card::Card(int s, int r)
{
    suit = s;
    rank = r;
};

// This function turns three int 'Cards' into three word
// strings that get returned when you call the function.

std::string Card::toString() 
{

    std::string oldS = std::to_string(suit); // this creates a string called oldS(uit) 
                                             // and changes the int into a string
    std::string oldR = std::to_string(rank); // this creates a string called oldR(ank) 
                                             // and changes the int into a string

    std::string SR = oldS + oldR;       // turns the two strings into one 
                                        // and puts them into a new string
    std::string newS;
    std::string newR;                   // These will be the new suit and rank 

    // this code turns the numbers (which are already strings) into words.
    // 'substr' lets you search any length of the string. We have a string of
    // two to three numbers but we need to analyze the first character and the
    // second / third seperately. With 'substr' you can do this. 

    if(SR.substr(0, 1) == "1") // if starting at character 0 and reading one character
        newS = "Hearts";       // is equal to '1' then make 'newS' equal to ' Hearts'
    if(SR.substr(0, 1) == "2")
        newS = "Diamonds";
    if(SR.substr(0, 1) == "3")
        newS = "Spades";
    if(SR.substr(0, 1) == "4")
        newS = "Clubs";

    if(SR.substr(1, 2) == "2") // if starting at character 1 and reading 2 characters
        newR = "Two";          // is equal to '2' then make 'newR' equal to 'Three'
    if(SR.substr(1, 2) == "3")
        newR = "Three";
    if(SR.substr(1, 2) == "4")
        newR = "Four";
    if(SR.substr(1, 2) == "5")
        newR = "Five";
    if(SR.substr(1, 2) == "6")
        newR = "Six";
    if(SR.substr(1, 2) == "7")
        newR = "Seven";
    if(SR.substr(1, 2) == "8")
        newR = "Eight";
    if(SR.substr(1, 2) == "9")
        newR = "Nine";
    if(SR.substr(1, 2) == "10")
        newR = "Ten";
    if(SR.substr(1, 2) == "11")
        newR = "Jack";
    if(SR.substr(1, 2) == "12")
        newR = "Queen";
    if(SR.substr(1, 2) == "13")
        newR = "King";
    if(SR.substr(1, 2) == "14")
        newR = "Ace";

    SR = newR + " of " + newS; // this string had the numbers in it but now we can  
                               // reassign it the string 'Card of suit'

    return SR; // returns the string which is outputted to the console when you call
               // the 'toString' function
};

// This function draws top object of the vector then pops it from 
// the vector and returns it to the call. It is of return type 'Card'.

Card Deck::draw() 
    {
        int a = Cards.size(); 
        int b = a - 1;        // -1 because the vector has 52 cards but you 
        Cards.pop_back();     // want to access [0] - [51] not [52]
        return Cards[b];
    };

// This is the function that creates the cards in the vector.
// It uses two loops and assigns a number to 'a' and 'b'. The first number is 
// in the range 1 - 4 and the second is 2 - 14. It then creates an object using 
// 'a' and 'b' which is then pushed back onto the vector. All vector objects have
// the same name as of now (but not the same data). Shuffles the objects at the end.

void Deck::shuffleCards()
{
    int a;
    int b;
    for(a = 1; a < 5; a++) // 1 - 4
    {
        for(b = 2; b < 15; b++ ) // 2 - 14
        {
            Card newCard(a, b);
            Cards.push_back(newCard);
        }
    }

    std:: mt19937 seed(rd());                        // this creates the seed
    std::shuffle(Cards.begin(), Cards.end(), seed);  // this shuffles the deck with the 
};                                                   // random seed 

// This function checks if the deck is empty 
// if it is not it will return false and when it is empty 
// it will return true which breaks the loop in main.cpp

bool Deck::empty()
{
    if(Cards.size() < 1)
        return true;
    else 
        return false;
};

// This function will reset the deck if called. It will purge 
// the vector and then repopulate it with the original contents.
// but will not shuffle them. 

void Deck::reset()
{
    Cards.clear();
    int a;
    int b;
    for(a = 1; a < 5; a++)
    {
        for(b = 2; b < 15; b++ )
        {
            Card newCard(a, b);
            Cards.push_back(newCard);
        }
    }
};

和标题

#ifndef DECK_H
#define DECK_H
#include <vector> 
#include <string> 
#include <random>
#include <algorithm>

class Card
{
public:
    inline Card(int s, int r);
    int rank;
    int suit;
    std::string toString();
};

class Deck 
{
private:
    std::vector<Card> Cards;
    std::random_device rd;
public:
    void shuffleCards();
    void reset();
    Card draw();
    bool empty();
};

class Hand
{
    public: 
        std::vector<std::string> Hand;
        void fillHand()
        {
            Deck deck;
            std::string C1 = deck.draw().toString();
            std::string C2 = deck.draw().toString();
            std::string C3 = deck.draw().toString();
            std::string C4 = deck.draw().toString();
            std::string C5 = deck.draw().toString();
            Hand.push_back(C1);
            Hand.push_back(C2);
            Hand.push_back(C3);
            Hand.push_back(C4);
            Hand.push_back(C5);
        }
};
#endif

提前谢谢你:D

此时我基本上是从手类创建一个新对象,用5张随机牌填充手牌,每张卡片中都有一张#34;西装卡片的字符串&#34;。因为我只需要担心&#34;卡&#34;我应该更改代码以丢弃&#34;&#34;和&#34;适合&#34;?最终我们还需要使用西装,这就是为什么我不想那样做。

3 个答案:

答案 0 :(得分:3)

字符串对玩家只有重要意义,对于计算机而言,只比int解决方案浪费内存。

那就是说,我建议你使用枚举:

enum Suit {Hearts, Clubs, Spades, Diamonds};
enum Rank {Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen King, Ace};

请注意,枚举从0开始,如果没有其他内容,则添加1,因此它们处于完美的顺序,只是碰巧它们更好地表示为int。

使用to_string方法:

string toString(const Suit){
    switch(Suit){
        case Hearts:
        return "Hearts";
et cetera

class Card
{
public:
Card(const Suit suit, const Rank rank); //<--- why did you declare this inline? arguments should be const
string toString() const;
Rank rank() const;
Suit suit() const;

private: // <-- encapsule. A card should not be able to change those values
Rank _rank;
Suit _suit;
};

此类卡是完美的容器。没有必要将其更改为字符串,至少在您不想打印时不会。

现在有趣的部分:

首先,我要让Hand成为Deck(“创建手”)返回的东西,或者让它成为一个唯一的构造函数的Deck。应始终使用五张卡来实例化一只手,这应该是唯一可能的状态。甲板应始终是一个独立的对象。

我给Hand一张卡片。不需要字符串。让一切变得更轻松。

作为辅助方法,我将添加一个方法来创建一个计算每个等级的多重性的向量。从那里,您可以轻松获得一个计算有多少双打,三元组和四元组的向量。如果你有,那你就完成了。所以这样:

enum HandValue {HighCard, Pair, ThreeOfAKind, FourOfAKind, FullHouse };

class Hand //note that I omitted some methods that are not relevant for the answer
{
private:
    vector<Card> cards;
    vector<unsigned int> multiplicityOfRank() const;
    vector<unsigned int> components() const; //<-- uses multiplicityOfRank
public:
    Hand(Deck& deck); // <-- will reduce deck by five cards. Note that a reference is used.
    HandValue evaluate() const; // <-- uses components
}

组件可能像位置0存储双打数量,位置1是三元组,位置2是四元组

这有帮助吗?还有问题吗?

(顺便说一下,如果名称空间很明显,我个人不想编写名称空间 - 你知道using关键字,就像using std::vector;一样吗?不要像{1}}那样使用using namespace std;但是,给定的主,std太大,不能排除名称冲突。)

答案 1 :(得分:2)

Re:&#34;如果您更改代码以丢弃&#39;&#39;并且&#39;适合&#39;?&#34;

我没有理由这样做。你有一个toString()方法,它将为输出生成一个显示字符串,我喜欢示例代码不是将字符串结果存储在类成员中。

你的.suit和.rank会员可以用来评估一张卡是否是所谓的套装之一(一对,两对,三种,四种,满屋)。不要与字符串表示进行比较 - 因为这是一种不太直接的比较,效率较低,并且如果可能更新字符串表示的真实情况,例如错误,则容易出错。提供西班牙语本地化。

我认为大部分工作都是在这里完成的。您对卡片的评估应该非常简单。也许为Hand添加一种新方法,检查你已经推入手牌的牌中的牌组。

答案 2 :(得分:-1)

正如另一个答案中所建议的那样,我会专注于使用枚举而不是字符串。您有一个非常有限的潜在价值清单。我首先要设置以下typedef:

enum class Suit {Hearts, Clubs, Spades, Diamonds};
constexpr static auto num_ranks = 13;  // must be consistent with below
enum class Rank {Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace};
enum class PokerHand {Nada, Pair, TwoPair, ThreeOfKind, FullHouse, FourOfKind};

using Card = const struct {
    Suit suit;
    Rank rank;
};

using PlayerHand = std::array<Card, 5>;

设置完这个机器后,我们现在可以继续推出我们的解决方案:

PokerHand determineHand(const PlayerHand& player_hand) {
    std::vector<int> rank_count(num_ranks);

    for (auto& card : player_hand) {
        ++rank_count[static_cast<int>(card.rank)];
    }

    auto count_rank_counts = [&] (int count) {
        return std::count(rank_count.begin(), rank_count.end(), count);
    };

    if (count_rank_counts(4)) return PokerHand::FourOfKind;

    if (count_rank_counts(3)) {
        if (count_rank_counts(2)) return PokerHand::FullHouse;
        else return PokerHand::ThreeOfKind;
    }

    if (count_rank_counts(2) == 2) return PokerHand::TwoPair;
    if (count_rank_counts(2) == 1) return PokerHand::Pair;

    return PokerHand::Nada;
}

几个关键点。 static_cast可能看起来有点奇怪,但实际上这是合法的,因为枚举类的支持类型没有明确声明它是int,除非int不够大。然后我们设置一个函数来计算某个排名发生的次数。我知道它有点奇怪,因为它是计数的数量。但它确实如此。然后我们只需检查手从最高到最低。不是很有效但很容易理解。

实例:http://coliru.stacked-crooked.com/a/a0db9e552cdfbcf5