【问题标题】:Generating a Deck of Cards生成一副牌
【发布时间】:2008-10-24 17:00:31
【问题描述】:

我正在尝试制作一个简单的二十一点程序。可悲的是,我在生成一副纸牌时遇到了问题。

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<char> deck;
    char suit[] = {'h','d','c','s'};
    char card[] = {'2','3','4','5','6','7','8','9','10','J','Q','K','A'};
    for (int j=0; j<13; j++) {
        for (int i=0; i<4; i++) {
            deck.push_back(card[j] suit[i]);
        }       
    }

    return 0;
}

我知道我的问题始于我试图将值“10”分配给一个字符。显然我无法编译它,但我敢肯定,当我尝试将卡片值分配给矢量卡组时,我也会得到一个错误,因为我使用了变量类型“char”。知道使用什么样的变量类型似乎让我很生气。另外,'deck.push_back(card[j] suit[i]);'是组合卡片和花色的正确代码,还是必须在卡片 [j] 和花色 [i] 之间添加一些东西?如果你们中的任何人能引导我朝着正确的方向前进,我将不胜感激。另外作为一个小注解,这是家庭作业的一部分,所以请不要只给我整个代码块。感谢您的帮助。

【问题讨论】:

  • 你的教授会认为你这周的作业很出色:)
  • 那么……你最后做了什么?

标签: c++


【解决方案1】:

我认为您要使用的是枚举。它将使您的代码更清晰并解决您的问题。

enum SUIT { HEART, CLUB, DIAMOND, SPADE }; 
enum VALUE { ONE, TWO, THREE, ..., TEN, JACK, QUEEN, KING};

【讨论】:

    【解决方案2】:

    尝试创建以花色和卡片为成员的卡片类,并将其设置为向量类型。喜欢

    public class Card {
     public:
      Card(char suit, char card);
      char suit, card;
    };
    
    int main() {
        vector<Card> deck;
        char suit[] = {'h','d','c','s'};
        char card[] = {'2','3','4','5','6','7','8','9','T','J','Q','K','A'};
        for (int j=0; j<13; j++) {
            for (int i=0; i<4; i++) {
                    deck.push_back(new Card(card[j],suit[i]));
            }               
        }
        return 0;
    }
    

    在花色和卡片中也使用枚举而不是字符会更清楚。

    【讨论】:

    • 我认为你仍然会遇到 char 数组中的 '10' 的问题。
    • 想想适合和等级的枚举。
    • 使用 sizeof(card) 和 sizeof(suit) 代替幻数 13 和 4。
    • 如果你使用 Enums 表示面和花色,你如何填充牌组?据我所知,你不能遍历枚举,也不能通过它们的值来查找枚举?
    • 应该是vector 牌组;如果你在向量中推新卡。
    【解决方案3】:

    你建模它的方式实际上取决于你想要做什么。

    您是否正在创建一个实际的游戏,而数据结构只需要支持游戏玩法?

    如果是这样,我会创建一个卡片类,其中包含用于花色的枚举字段和用于面值的数字类型(值 1 - 13)。

    另一方面,如果您正在构建分析应用程序或 AI 播放器,那么模型可能会有所不同。

    几年前,我编写了一个模拟器来计算各种德州扑克场景中的概率,我希望它能够真正快速地计算数字。我从一个非常简单的模型开始(卡片类、套装枚举等),但经过大量分析和优化后,我最终得到了按位表示。

    每张牌都是一个 16 位的值,其中 13 个高位表示面值,2 个低位表示花色,bit[2] 是一个特殊的标志位(仅用于A2345 顺子中可能出现 A 的情况)。

    这里有几个例子:

    0000000000001001  <----  Two of hearts
    0100000000000011  <----  King of spades
    1000000000000110  <----  Ace of diamonds
    
    ^^^^^^^^^^^^^            ("face-value" bits)
                 ^           ("low-ace" flag)
                  ^^         ("suit" bits)
    

    您可以想象,在这样的设计中,寻找对子、三人组和顺子(同花稍难一点)是多么容易。

    我不会详细介绍所有特定的操作,但只要说这种模型支持每秒数百万次操作就足够了……

    当然,请记住,我实际上并不是在提倡您在简单的游戏实现中使用这样的设计。我最终选择这个设计的唯一原因是因为我需要进行大规模的统计模拟。

    因此,请仔细考虑您要如何建模:

    • 每张卡片
    • 玩家的手
    • 整个甲板
    • 牌桌状态...包括所有玩家手牌(包括已拆分初始手牌的玩家),可能是六副牌鞋、弃牌堆等

    整个应用程序模型以及应用程序的总体目标将在很大程度上决定最合适的数据结构类型。

    玩得开心!!!

    【讨论】:

      【解决方案4】:

      使用“T”而不是 10。

      【讨论】:

        【解决方案5】:

        您是否尝试过将 J 替换为 11、Q 替换为 12 以及 K 替换为 13?然后你可以使用integers 而不是characters。稍后将 11-13 替换为相应的字母。

        【讨论】:

        • 您可以使用 stdint.h 中的 uint8_t 作为整数类型,并且您的结构与使用 char 的大小相同。
        【解决方案6】:

        首先,deck[0] 是一个字符,但您正在尝试将“2h”塞入其中。 (目前,我们将忽略您的做法是错误的。)

        基本上,您需要将牌组设为vector&lt;std::string&gt;。将 card 设为 const char*s 数组,并将元素转换为字符串。

        然后使用:

        deck.push_back(std::string(card[j]) + suit[i]);
        

        【讨论】:

        • 我认为这是一个很好的方法,使用字符串而不是字符。
        【解决方案7】:

        正如其他人所提到的,您可以使用“T”表示十,使用 J、Q 和 K 表示数字。 至于 push_back.. 由于 deck 是一个字符向量,因此您只能将一个字符作为参数传递给 push_back。将牌面值(1...9、T、J、Q、K)和它的套牌同时传递是行不通的。

        我个人会创建一个小结构来表示一张卡片,带有一个 Value 和一个 Suite 属性。然后,你可以让你的牌组成为 Cards 的向量。

        已编辑:修复最后一个单词,因为矢量(小于)卡片(大于)被渲染为矢量(无)。

        【讨论】:

          【解决方案8】:

          这可能无法编译,但这是我会(并且已经使用过)的方法。您将要使用整数来表示您的卡片,但您可以在一个类中轻松地抽象它。我会写给你的。

          class Card
          {
          public:
              enum ESuit
              {
                  kSuit_Heart,
                  kSuit_Club,
                  kSuit_Diamond,
                  kSuit_Spade,
                  kSuit_Count
              };
          
              enum ERank
              {
                  kRank_Ace,
                  kRank_Two,
                  kRank_Three,
                  kRank_Four,
                  kRank_Five,
                  kRank_Six,
                  kRank_Seven,
                  kRank_Eight,
                  kRank_Nine,
                  kRank_Ten,
                  kRank_Jack,
                  kRank_Queen,
                  kRank_King,
                  kRank_Count
              };
          
              static int const skNumCards = kSuit_Count * kRank_Count;
          
              Card( int cardIndex )
              : mSuit( static_cast<ESuit>( cardIndex / kRank_Count ) )
              , mRank( static_cast<ERank>( cardIndex % kRank_Count ) )
              {}
          
              ESuit GetSuit() const { return mSuit );
              ERank GetRank() const { return mRank );
          
          private:
              ESuit mSuit;
              ERank mRank;
          }
          

          现在很容易添加到这个类中以获得你想要的一切。 要生成列表,如下所示。

          rstl::vector<Card> mCards;
          mCards.reserve( Card::skNumCards );
          
          for ( int cardValue = 0; cardValue < Card::skNumCards; ++cardValue )
          {
              mCards.push_back( Card( cardValue ) );
          }
          

          你需要洗牌吗?

          #include <algorithm>
          std::random_shuffle( mCards.begin(), mCards.end() );
          

          看看第一张卡的价值如何?

          if ( mCards[0].GetSuit() == Card::kRank_Club && mCards[0].GetRank() == Card::kRank_Ace )
          {
              std::cout << "ACE OF CLUBS!" << std::endl;
          }
          

          我没有编译任何这些,但它应该很接近。

          【讨论】:

            【解决方案9】:

            由于这是一个二十一点程序,您将添加和比较卡片的价值。

            在这种情况下,您可以通过为卡片指定 int 值 (1-13) 而不是 char 值,从而为自己节省一些额外的编程和痛苦。

            【讨论】:

            • 除了在二十一点中,几张不同的牌具有相同的自然值,而一张牌有两个值。
            • 是的,但你会遇到同样的问题 chars,并且可以简化检查条件如下: 1:默认值 1 (Ace) 是 11,除非你的总数已经更大大于 21,则为 1。 2:如果卡片的值大于 10,则使其等于 10,否则使用它自己的值。
            【解决方案10】:

            当我创建my C++ Deck of cards class 时,我遇到了一些自己的问题。首先,我试图将my PHP deck of cards class 转换为 C++,但运气不佳。我决定坐下来,把它写在纸上。我决定使用面向对象的设置,主要是因为我觉得它最容易用于扩展。我使用对象 CardDeck,因此,例如,如果您想在二十一点游戏的 Shoe 中放入 10 个套牌,您可以创建 10 个套牌,这很简单,因为我决定让所有东西都自成一体。事实上,它是如此独立,要创建你的鞋子,代码是:

            #include "AnubisCards.cpp"
            
            int main() {
            
                Deck *shoe = new Deck(10);
            
            }
            

            但是,这是为了简单起见,在只需要一副牌的小型游戏中并非完全必要。

            无论如何,是通过创建一个包含 52 个 Card 对象的数组来生成套牌的。套牌很简单,因为你知道你有4套每套13张牌,你也知道你有2,3,4,5 ,6,7,8,9,10,Jack,Queen,King,Ace 在每一种花色中。这些永远不会改变。所以我使用了两个循环,一个用于Suit,另一个用于Value

            原来是这样的:

            for(int suit = 1; suit <= 4; suit++){
                for(int card = 1; card <= 13; card++){
                    // Add card to array
                }
            }
            

            现在,您会注意到,在每一个循环中,我都使用了一个整数值。原因很简单,卡片就是数字。 4套。 13 个值。甚至是二十一点游戏中的数值。面值,直到你击中面卡,这是数值 10,直到你击中数值 1 或 11 的 Ace。一切都是数字。因此,您不仅可以使用这些数字来分配卡片的价值,还可以分配卡片的花色以及数字序列中的数字。

            一个想法是在 Card 类中存储一个地图,其中包含卡片的字符或字符串名称,其中 1、2、3... 是每个卡片的索引。

            【讨论】:

              【解决方案11】:

              我会同意罗斯的使用整数的建议。大多数纸牌游戏都会涉及到一些数学知识,因此这是一种更好的表现形式。

              在输出时转换为“A”或“ACE”等。

              【讨论】:

                【解决方案12】:

                由于这是 C++ 的作业,我猜你应该使用类。 否则使用枚举,如果这是 C 使用结构或其他东西。

                对于某些游戏,除了积分值之外,您还需要为卡片存储某种等级,这取决于当前的游戏模式。

                我从来没有做过纯 C,但我的意思是这样的:

                typedef struct struct_card {
                  unsigned short int suit:2;
                  unsigned short int card:4;
                //  unsigned short int valu:4;
                } card;
                
                int main() {
                  card a_card;
                  card std_deck[52];
                  const unsigned short int rummy_value[13] = {1,2,3,4,5,6,7,8,9,10,10,10,10};
                  const char *std_card_name[13] = {"Ace","Two","Three","Four","Five","Six",
                    "Seven","Eight","Nine","Ten","Jack","Queen","King"};
                  const char *std_suit_name[4] = {"Spades","Clubs","Hearts","Diamonds"};
                
                  int j, k, i=0;
                  for(j=0; j<4; j++){
                    for(k=0; k<13; k++){
                      a_card.suit=j; a_card.card=k;
                      std_deck[i++] = a_card;
                    }
                  }
                
                  //check our work
                  printf("In a game of rummy:\n");
                  for(i=0;i<52;i++){
                    printf("  %-5s of %-8s is worth %2d points.\n",
                        std_card_name[std_deck[i].card],
                        std_suit_name[std_deck[i].suit],
                        rummy_value[std_deck[i].card]);
                  }
                
                  //a different kind of game.
                  enum round_mode {SHEILD_TRUMP, FLOWER_TRUMP, BELL_TRUMP, ACORN_TRUMP, BOCK, GEISS} mode;
                  const card jass_deck[36]={
                    {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},
                    {1,1},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},
                    {2,2},{2,1},{2,2},{2,3},{2,4},{2,5},{2,6},{2,7},{2,8},
                    {3,3},{3,1},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{3,8},
                  };
                #define JASS_V {11,0,0,0,0,10,2,3,4}
                  const unsigned short int jass_value[9] = JASS_V;
                #define JASS_TRUMP_V {11,0,0,0,14,10,20,3,4}
                  const unsigned short int jass_trump_value[9] = JASS_TRUMP_V;
                #define JASS_BOCK_V {11,0,0,8,0,10,2,3,4}
                  const unsigned short int jass_bock_value[9] = JASS_BOCK_V;
                #define JASS_GEISS_V {0,11,0,8,0,10,2,3,4}
                  const unsigned short int jass_geiss_value[9] = JASS_GEISS_V;
                  const char *jass_card_name[9] = {"Ace","Six","Seven","Eight","Nine","Banner",
                    "Under","Ober","King"};
                  const char *jass_suit_name[4] = {"Sheilds","Flowers","Bells","Acorns"};
                  const unsigned short int jass_all_value[6][4][9] = {
                    { JASS_TRUMP_V, JASS_V, JASS_V, JASS_V },
                    { JASS_V, JASS_TRUMP_V, JASS_V, JASS_V },
                    { JASS_V, JASS_V, JASS_TRUMP_V, JASS_V },
                    { JASS_V, JASS_V, JASS_V, JASS_TRUMP_V },
                    { JASS_BOCK_V, JASS_BOCK_V, JASS_BOCK_V, JASS_BOCK_V },
                    { JASS_GEISS_V, JASS_GEISS_V, JASS_GEISS_V, JASS_GEISS_V }
                  };
                
                  //check our work 2: work goes on summer vacation
                  printf("In a game of jass with trump (Sheilds | Flowers | Bells | Acorns) | Bock | Geiss\n");
                  for(i=0;i<36;i++){
                    printf("  %-6s of %-7s is worth %8d%10d%8d%9d%8d%8d\n",
                        jass_card_name[jass_deck[i].card],
                        jass_suit_name[jass_deck[i].suit],
                        jass_all_value[SHEILD_TRUMP][jass_deck[i].suit][jass_deck[i].card],
                        jass_all_value[FLOWER_TRUMP][jass_deck[i].suit][jass_deck[i].card],
                        jass_all_value[BELL_TRUMP][jass_deck[i].suit][jass_deck[i].card],
                        jass_all_value[ACORN_TRUMP][jass_deck[i].suit][jass_deck[i].card],
                        jass_all_value[BOCK][jass_deck[i].suit][jass_deck[i].card],
                        jass_all_value[GEISS][jass_deck[i].suit][jass_deck[i].card]);
                  }
                  return 0;
                }
                

                输出如下:

                In a game of rummy:
                  Ace   of Spades   is worth  1 points.
                  Two   of Spades   is worth  2 points.
                  Three of Spades   is worth  3 points.
                  Four  of Spades   is worth  4 points.
                  Five  of Spades   is worth  5 points.
                ...
                  Nine  of Diamonds is worth  9 points.
                  Ten   of Diamonds is worth 10 points.
                  Jack  of Diamonds is worth 10 points.
                  Queen of Diamonds is worth 10 points.
                  King  of Diamonds is worth 10 points.
                In a game of jass with trump (Sheilds | Flowers | Bells | Acorns) | Bock | Geiss
                  Ace    of Sheilds is worth       11        11      11       11      11       0
                  Six    of Sheilds is worth        0         0       0        0       0      11
                  Seven  of Sheilds is worth        0         0       0        0       0       0
                  Eight  of Sheilds is worth        0         0       0        0       8       8
                  Nine   of Sheilds is worth       14         0       0        0       0       0
                  Banner of Sheilds is worth       10        10      10       10      10      10
                ...
                  Under  of Acorns  is worth        2         2       2       20       2       2
                  Ober   of Acorns  is worth        3         3       3        3       3       3
                  King   of Acorns  is worth        4         4       4        4       4       4
                

                二十一点很无聊。 这段代码可以编译。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-06-07
                  • 1970-01-01
                  • 2020-06-10
                  • 2020-08-25
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多