用C ++实现卡片组

时间:2011-03-10 09:39:45

标签: c++ oop pointers

所以我试图创建一副牌,我仍然是C ++和指针的新手,所以我有几个问题

所以我有Card课程getRankgetSuit,以及两个Card对象的比较。 他们的方式我设置牌组的等级为1-13,套装为1-4。所以这是一个简单的比较,比较一张卡的等级+套装与另一张卡的等级+套装。

所以我初始化并声明了这两个数组:

char Rank[13] = {1,...13};
char Suit[4] = ...

我的方法是这样的:

char* getSuit(){ return Suit; }
char* getRank(){ return Rank; }
int Comp(Card *card) {
    if (rank+suit < card->rank+card->suit)
        return 1;
    else if...
    else ...
}

我的问题是,拥有一个char数组是一个坏主意,因为我只存储整数? 后来我计划将这些数字转换为输出“Three Spade”,这就是我使用char的原因。

我的另一个问题是,我的get方法看起来是否合适? get方法,它会返回整个数组还是数组的索引,这就是我想要的。我使用' - &gt;'正确?

我仍处于绘图过程中,这就是为什么我只有代码片段

8 个答案:

答案 0 :(得分:2)

->将获得LHS引用的对象的RHS元素的值。所以,只要您处理LHS上的指针,这是正确的。

你可以看看使用Enums for suit。

我建议再次查看你的逻辑评估,因为@littleadv已经说过了。

答案 1 :(得分:1)

以下是一些供您考虑的草稿,可能会在其上构建您的课程:

class Card
{
public:
   // TODO: provide suitable constructor...

   enum Suit {Hearts, Diamonds, Clubs, Spades};
   enum Rank {A, K, Q, J, _10, _9, _8, _7, _6, _5, _4, _3, _2};

   Suit getSuit() { return suit; }
   Rank getRank() { return rank; }

   // TODO: implement setters, etc...

   bool operator==(const Card& c) const
   {
      return rank == c.rank && suit == c.suit;
   }

private:
   Suit suit;
   Rank rank;
};

所以我建议你使用枚举并使用精确的比较标准来比较两张牌 同样,您可以实现运算符&gt;和运算符&lt;根据你的游戏规则和逻辑。

你明白了......

答案 2 :(得分:0)

这是一个坏主意,因为这是浪费空间。您只需要存储一个号码,而不是所有号码。

此外,您可以实现==运算符,而不是编写一组方法来执行此操作,使用起来会更自然。

顺便说一下:你的逻辑 - 排名+西装是比较的标准吗?西装4的等级9比西装2的等级10好?我不确定你在模拟什么游戏,但通常排名先于套装......但这取决于实际要求,当然,只是说....

重新提出有关使用->get方法的问题 - 查看编译器错误。是的,在get方法中,您返回数组。但是如果你停止使用数组,只存储你需要的东西 - 那么这些方法就可以了。

如果您想因任何原因返回字符串 - 您可以将存储的整数索引映射到某个静态数组中的正确字符串,这样就不会在类的不同实例中存储冗余字符串。

答案 3 :(得分:0)

通过这个比较过程,你最终将拥有相同的牌......我猜错了...... 编辑:在视觉工作室中还有一个二十一点入门套件,你可以看看。

答案 4 :(得分:0)

您开始使用工作代码逐步构建课程。从一个只有getSuitgetRank方法的简单类开始。编写一个测试它的小应用程序,例如:

int main() {
    Card card(10, 4);

    if (card.getSuit() != 4) {
        std::cout << "Wrong suit!" << std::endl;
    }

    return 0;
}

通过为您实现的每个功能编写这样的小测试,您可以确保工作正常。此外,如果您考虑首先如何使用课程,您将更好地理解实施。

关于实际实施,其中大部分取决于课堂上的教学内容。一个简单的考虑因素是使用enum来表示等级和套装。

答案 5 :(得分:0)

这种受歧视的联盟最好用ML家族的语言处理。

例如在OCaml中:

type suit = Hearts | Diamonds | Clubs | Spades
type rank = Ace | King | Queen | Jack | Num of int
type card = rank * suit

是的我知道,海报要求C ++回答......

答案 6 :(得分:0)

一张牌是一个不好的候选人 - 它没有行为,因此没有方法。因此最好将其建模为结构。卡是不可变的(除非你作弊),所以指示const成员数据:

enum Suit {Hearts, Diamonds, Clubs, Spades};
enum Rank {A, K, Q, J, _10, _9, _8, _7, _6, _5, _4, _3, _2};

struct Card
{
    Card(Suit suit, Rank rank) : suit(suit), rank(rank) {}

    const Suit suit;
    const Rank rank;
};

如果你可以使用语法card.first而不是card.suit,你可以使用标准对免费获得:

#include <utility>
typedef const std::pair<Suit, Rank> Card;

Card aceOfSpades(Spades, A);

奖金:你也可以合理地==和&lt;运营商免费。

答案 7 :(得分:0)

使用界面

它为学生提供了一种简单的方法,可以在他们编写的代码中使用卡而无需访问 卡的内部,无法创建特定的卡,也不知道卡是如何 实现。这个过程从卡接口的代码开始,我们称之为ICard接口。

public interface ICard extends Comparable
{
public static final int SPADES = 0;
public static final int HEARTS = 1;
public static final int DIAMONDS = 2;
public static final int CLUBS = 3;
public int getSuit();
public int getRank();
}

接口指定卡的行为,但不提供有关卡的信息 实现。一旦他们知道getSuit()返回类似ICard.HEARTS的值,那就是 getRank()返回1(ace)到13(king)范围内的值,学生可以从中编写代码 规格。例如,这里的代码用于检查卡阵列是否已排序。我们没有 知道它是如何分类的(例如,所有的A在两个之前出现或者做所有的黑桃来 在心灵之前?),但我们可以确定数组是否已排序。 1以大写字母I开头的接口名称,后跟大写名称,是一个常见的命名 面向对象编程中的约定,使用多种语言,而不仅仅是Java。

public boolean isSorted(ICard[] list){
for(int k=1; k < list.length; k++){
if (list[k-1].compareTo(list[k]) > 0){
return false;
}
}
return true;
}

从这个简单的ICard界面开始,我们可以向学生提出多种选择 用于测试和审查从Java语法到解决问题的概念的问题 关于一张,两张或许多卡片。这里包含一些简单的例子, 网站上提供了更多内容。在回答这些问题时,学生必须 了解界面,因为没有实现。学生专注于 行为而不是实例变量和其他实现细节,例如 如何创建一个字符串来表示黑桃的王牌。 ICard学习/代码问题

  1. 编写函数isRed,如果其ICard参数为红色(heart或 钻石)并且否则返回false。 public boolean isRed(ICard card){...}

  2. 一对是同一等级的两张牌(例如,两个国王或两个八个)。写功能 isPair如果其两个ICard参数表示一对并返回false,则返回true 除此以外。 public boolean isPair(ICard a,ICard b){...}

  3. 在扑克牌中,同花顺是一手牌,其中所有牌都有相同的牌(例如,五个心, 或者五张牌的五个俱乐部)。编写函数isFlush,如果返回则返回true 卡数组是刷新,否则返回false。 public boolean isFlush(ICard [] hand){...}

  4. 在二十一点或21中,一手牌的价值是牌的总数,其中是千斤顶,皇后和 国王(11,12和13,分别由getRank()返回)每个计为10,和a ace计为1或10,以较好者为准。总共超过21岁是一个半身像;破产是不好的。 写函数handTotal,返回手的总值。 public int handTotal(ICard [] hand){...} 从接口到实现 ICard接口提供了足够的信息来编写卡片代码, 但是没有办法创建一系列卡片,例如,甚至一个卡片 卡来测试上面写的函数(如isPair和handTotal)。哪里 卡来自哪里?在大多数现实世界的例子中,卡片来自甲板。好 设计一个模拟甲板的类 - 它基本上是用于创建和获取卡的工厂。 为了简单起见,并鼓励学习一些标准的Java接口,这个类 Deck将实现java.util.Iterator接口。例如,存储所有 从卡片到ArrayList变量的卡片,我们可以使用以下代码:

    甲板d =新甲板(); ArrayList cards = new ArrayList(); while(d.hasNext()){ ICard卡=(ICard)d.next(); 的System.out.println(卡); cards.add(卡); } System.out.println(&#34;处理的牌数=&#34; + cards.size());

  5. 此代码段输出的最后几行可能如下所示。他们将是不同的 每一次,因为这里开发的Deck类通过迭代对其处理的卡进行洗牌。 ... 黑桃王牌 俱乐部的杰克 六个黑桃 十颗心 十个黑桃 发卡数量= 52 如果我们按如下方式更改循环后的行,则输出也会发生变化。

    Collections.sort(cards);
    for(int k=0; k < cards.size(); k++){
    System.out.println(cards.get(k));
    }
    

    System.out.println(&#34;处理的牌数=&#34; + cards.size()); 输出显示从Deck类返回的卡如何实现Comparable接口。 ... 九个俱乐部 十个俱乐部 俱乐部的杰克 俱乐部女王 俱乐部之王 发卡数量= 52 Deck类的完整代码如下所示。方法hasNext(),next()和 实现Iterator接口的类需要remove()。下面的代码 显示了如何构造Card类型的对象。

    public class Deck implements Iterator{
    private ArrayList myCardList;
    private int myIndex;
    public Deck(){
    myCardList = new ArrayList();
    for(int suit = ICard.SPADES; suit <= ICard.CLUBS; suit++){
    for (int rank = 1; rank <= 13; rank++){
    myCardList.add(new Card(suit,rank));
    }
    }
    shuffle();
    }
    private void shuffle(){
    Collections.shuffle(myCardList);
    myIndex = 0;
    }
    public boolean hasNext() {
    return myIndex < myCardList.size();
    }
    public Object next() {
    ICard card = (ICard) myCardList.get(myIndex);
    myIndex++;
    return card;
    }
    public void remove() {
    throw new UnsupportedOperationException();
    }
    }
    

    Deck对象存储52张卡片 - 这些卡片可以从Deck获得 对象通过迭代,但Deck对象不能重新洗牌和重复使用。 相反,必须创建一个新的Deck对象来处理新卡。这保持不变 事情很简单,并提供了一个易于理解的类的例子 实现Iterator接口。方法remove()是可选的--- for 调用此方法的Deck类会抛出异常。 甲板研究/代码问题

    1. 在构造函数中调用shuffle方法之前,描述了它的顺序 存储在myCardList中的对象。

    2. 描述如果更改实例变量myCardList,每个Deck方法如何更改 例如,一组Card对象, private ICard [] myCardList; myCardList的哪个选择更好?为什么呢?

    3. 编写定义Deck对象的客户端代码,并创建一个包含13个ICard对象的数组 代表从甲板处理的黑桃。通过检查处理的每个对象来完成 并且只存储铁锹卡。

    4. 编写下面指定的假设Hand类构造函数的主体

      private ArrayList myCards; / **

      • 从d交易numCards卡,存储在myCards
      • (假设d中至少留有numCards卡) * / public Hand(Deck d,int numCards){ }
    5. 从甲板到卡片 我们最初关注的是使用ICard接口而不是担心如何使用 卡已实施。然而,在某些时候,需要有一个 实现。不容易争辩说Card对象应该是由。创建的 甲板课。这是我们在这里使用的方法。 Card类是私有类 在甲板课堂内宣布。实际上没有充分的理由在其中宣布它 Deck(Deck.java文件)。但是,通过宣布它是私有的,我们就做到了 任何代码class2都不可能;它可以很容易地被宣布为非公共类 Deck类以外的方法来构造Card对象。这有助于实现我们的最初目标。 客户端程序可以从Deck获取卡,但不能创建卡。自甲板供应以来 ICARD对象,一旦从卡片中获得卡片,就无法更换卡片。 ICard interfaced不支持修改卡片。

      如上所述,Deck类中定义的私有Card类不支持 修改,因为它的私有状态实例变量是最终的,但这是额外的 因为没有客户端代码访问私人卡类,所以可能不需要保护。 2通常在另一个类中声明的类通常引用封闭对象的状态。在这 case嵌套类Card被声明为私有静态类,因此它不能引用私有非静态状态 在Deck对象中。 Card类可以引用静态Deck状态,但此代码中没有。 Card类可在网站上找到;自实施以来,我们不在此处 与我们关于设计的讨论没有直接关系。 细心的读者可能会声称我们的原始目标尚未实现。客户端代码可以作弊 例如,通过创建一个Deck对象然后从该对象处理卡片直到空格 (或任何其他卡)被处理。在Deck类的当前设计中,这是真的。但是,我们 可以创建单个Deck对象,与Random类的单个实例相同 用于海洋生物学案例研究。 Singleton对象通常通过声明来创建 构造者,以便他们私下。在这种情况下,Deck构造函数将从public更改为 私人的。客户端代码通过调用公共getInstance()方法获取Deck 返回存储在Deck类中的私有静态Deck对象。 getInstance方法 在第一次调用getInstance时创建此私有对象。