概念难度 c++ 扑克牌

Posted

技术标签:

【中文标题】概念难度 c++ 扑克牌【英文标题】:Conceptual Difficulty c++ Deck of Cards 【发布时间】:2016-06-30 15:43:59 【问题描述】:

我知道关于这个永恒的实现有很多问题,但作为一个新的 OOP 程序员,我正在努力掌握必要的概念来建立任何基础。

我是否在一个数组中构建了一个实际的随机牌组,可以作为任何纸牌游戏的纸牌牌组?或者我是通过创建 4 个花色然后创建 13 个不同的面来“复制”一个随机的扑克牌套牌吗?我见过多种实现,但我不太明白他们在做什么。 int deck[]; 是我计划存放卡片的地方。当创建纸牌类的实例时,我会填充该纸牌数组吗?

我的 main 只调用了 print 函数(我还没有写)

//Texas holdem build
//Will attempt using Classes and inheritance
//Full build for up to 6 players

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

int main()


    DeckOfCards deck;

    deck.printDeck();

    return(0);

标题

* deckOfCards.h
 *
 *  Created on: Jun 28, 2016
 *      Author: TAmend
 */

#ifndef DECKOFCARDS_H_
#define DECKOFCARDS_H_

class DeckOfCards


    public:
        DeckOfCards();
        void printDeck() const;
        void shuffle();

    private:
        int currentCard;
        int deck[];

;

#endif /* DECKOFCARDS_H_ */

【问题讨论】:

为了学习和说话作为OOP设计。 Deck of Cards 将是 52 objects 的容器,而不仅仅是 ints。因此,另一个小结构/类将代表card。那张卡(类)有什么?它有一套西装(4 个中的 1 个)、一个值(1/13)和一个脸(1/13)。然后在你的Deck of cards 类中,会有一个函数将那个小类(卡片)的 52 个对象填充到它自己的私有成员容器中,确保卡片中没有重复。 【参考方案1】:

好吧,拥有一个 Card classstruct 和一个充当专用容器的 DeckOfCards 类是正确的方法(正如 @Thomas' answer 中提到的那样):

struct Card

  enum Suit_Type 
      Diamonds,
      Hearts,
      Spades,
      Clubs,
   suit;
  enum Value_Type 
      Two = 2, // <<<<<<<<< Note starts at 2
      Three ,
      // Four, Five, Six, aso. ...
      Ten ,
      Jack ,
      Queen ,
      King ,
      Ace , // <<<<<<<<< Note has the highest value here
   value;
  void printCard();
;

 void Card::printCard() 
      switch(suit) 
      case Hearts:
          std::cout << "♥";
          break;
      case Diamonds:
          std::cout << "♦";
          break;
      case Clubs:
          std::cout << "♣";
          break;
      case Spades:
          std::cout << "♠";
          break;
      
      if(value < Jack) 
         std::cout << (int)value;
      
      else 
          switch(value) 
          case Jack:
              std::cout << 'J';
              break;
          case Queen:
              std::cout << 'Q';
              break;
          case King:
              std::cout << 'K';
              break;
          case Ace:
              std::cout << 'A';
              break;
          
      
  

如前所述,应该在Card 上实现一些比较运算符,以使游戏玩法的实现更容易:

  bool operator<(const Card& lhs, const Card& rhs) 
       return (lhs.suite < rhs.suite) &&
              (lhs.value < rhs.value);
  

  bool operator>(const Card& lhs, const Card& rhs) 
       return (lhs.suite > rhs.suite) &&
              (lhs.value > rhs.value);
  

请注意,从语义角度来看,相等测试的实现没有多大意义,除非您想同时使用多个 DeckOfCards

Cards 在特定游戏中的行为方式可能完全委托给 Strategy Pattern 类。


DeckOfCards 可以从适当的初始化列表中初始化:

class DeckOfCards 
     DeckOfCards() : cards_(
          Diamonds, Two  ,
         // ...
          Diamonds, Ace  ,
          Hearts, Two  ,
         // ...
          Hearts, Ace  ,
          Spades, Two  ,
         // ...
  Spades, Ace  , // !!! Extremely important !!!
          Clubs, Two  ,
         // ...
          Clubs, Ace  ,
     ) 

     void printDeck();
     void shuffle();

private:
     std::array<Card,52> cards_;
;

那么其他功能就可以这么简单实现了:

void DeckOfCards::printDeck() 
    bool first = true;
    for(auto card : cards_) 
         if(!first) 
             std::cout << ", ";
         
         card.printCard();
         first = false;
    
    std::cout << std::endl;


void DeckOfCards::shuffle() 
    std::random_device rd;
    std::mt19937 g(rd());

    std::shuffle(cards_.begin(), cards_.end(), g);
;

我不是 100% 确定你想用 DeckOfCards 中的 currentCard 成员实现什么,但我想你不希望这成为下一个 Card 的偏移量DeckOfCards,因此您可以简单地将其用作cards_ 数组的索引,以分发对底层Card 实例的引用,然后将其递增:

 const Card& getNextCard(bool& cardsAvailable) 
      cardsAvailable = true;
      if(currentCard < 52) 
          return cards_[currentCard++];
      
      // Reset the deck
      cardsAvailable = false;
      currentCard = 0;
      shuffle();
 

去找彩蛋

【讨论】:

我从来没有听说过叫“cross”的球杆。此外,王牌的价值取决于游戏。在某些游戏中,所有的面卡都具有相同的价值。 @RobK THX 对于洞察力,我不是母语人士,而是从翻译网站获得的。嗯,当然值的顺序取决于实际玩的游戏,但大多数纸牌游戏都使用这种顺序(套件中的小修正)。 在大多数地方你使用Deck,但是类被定义为DeckOfCards。我猜这只是复制/粘贴错误。 @JamesAdkison 是的,我错过了将 Deck 更改为 DeckOfCards 的原始答案。希望我现在抓住了所有发生的事情。 我很确定现在还不是复活节,但是 +1【参考方案2】:

我以前回答过这些,所以我会再回答一次。

恕我直言,有两个对象:卡片的容器和卡片。不要混合它们。

让我们从一张卡片开始。一张牌有花色和价值:

struct Card

  Suit_Type suit;
  Value_Type value;
;

容器可以是任何东西,例如std::vectorstd::list,或者我最喜欢的std::deque。 ;-)

typedef std::vector<Card> Deck_Of_Cards;

您可以制作自己的容器,但对于大多数使用卡片的任务来说,没有必要。首选现有的容器数据结构。

Card 结构中的类型而言,这是一个偏好问题。您可以对Suit_Type 使用枚举、字符串或其他任何内容。与Value_Type 类似。

为了使卡片更有用,您应该在Card 结构中实现以下方法:

    构造函数、赋值运算符、析构函数。 等式和排序运算符(例如 == 和 流插入和提取(例如 >> 和

同时查看函数std::random_shuffle

【讨论】:

“这些我已经回答过了,所以我再回答一次。”那这不是骗人的吗? 我之前没有给出完整的答案,只是建议。 :-) 好吧,那你现在可以试着给出一个完整的答案(顺便说一句,由于 一副牌 中的牌数通常是固定的,我宁愿推荐std::array&lt;&gt;作为内部容器类型)。 std::random_shuffle 已弃用。只需使用std::shuffle @πάντα ῥεῖ 对于只有 52 个元素的套牌,它们永远不会增长/收缩我想说这实际上并不重要 - 性能方面。【参考方案3】:

好的,只是为了说得非常清楚,你的甲板类将充当一个“容器”类。这意味着它将持有一堆卡片类型的卡片;不是int。

最后,你用来存储卡片的数组看起来像 卡片组[];而不是 int 甲板 [];这将允许您将您喜欢的任何属性添加到每个单独的卡中。

您可以在构造时或之前随机化 Card 类的每个属性,然后将随机值传入。

为了帮助你理解:

class Card

public:
    Card(int value): value(value) 
    int Getvalue() return value; 
private:
    int value;
;



class DeckOfCards


public:
 //   DeckOfCards();
 //   void printDeck() const;
  //  void shuffle();
    void createDeck()
    
        for(int i = 0; i < deck_size; i++)    //Implementation of createDeck
            deck[i] = new Card(rand()%10-1);//whatever val you want to generate
    

private:
 //   int currentCard;
  //  Card deck[];

;

通过这种方式,您可以随时获取卡片,并添加您想要的任何属性,例如西装。

注意:向量比原始数组更可取,但不要只删除 DeckOfCards 类,因为如果这样做,那么将 shuffledeck 函数或 printdeck 函数存储在哪里?等等...而是简单地用向量替换成员数组。

【讨论】:

“一个向量会更好......” 事实上,std::array&lt;Card,52&gt; 将是正确的内部标准容器类型。在这种情况下不需要动态内存分配。 @πάνταῥεῖ 同意 100% 不清楚应该是什么类型的纸牌游戏/套牌,这就是为什么我省略了套装属性。另外,是的,一个普通的数组,从堆栈中分配它的成员就可以了,但是如果你想删除一个元素怎么办,同样不清楚它是什么类型的游戏/套牌。您可以使用标准阵列,这完全取决于您希望如何管理从阵列中移除每张卡(如果有的话)。【参考方案4】:

这真的取决于你想用你的一副牌实现什么,你想如何使用它。在某些情况下,一个简单的int[] 将完全满足您的需求。在其他情况下,您将需要完整的卡片和甲板类以及其他助手类。其他答案中给出的纸牌和套牌实现(无意中?)专门用于某些纸牌游戏,而对其他人完全不可用。不要问你能拥有什么,问问你自己你需要什么。 Do the simplest thing that could possibly work.

(实际上这个问题过于宽泛/基于意见,可能更适合于programmers.stackexchange.com)

【讨论】:

以上是关于概念难度 c++ 扑克牌的主要内容,如果未能解决你的问题,请参考以下文章

华为OD机试真题 C++ 实现整理扑克牌2022.11 Q4 新题

华为机试真题 C++ 实现斗地主之顺子

leetcode刷题42.扑克牌中的顺子——Java版

美团后端笔试2022.08.13

华为OD机试真题 JS 实现整理扑克牌2022.11 Q4 新题

棋牌平台搭建教程-德州扑克算法详解