1

我正在尝试编写洗牌器,并且我知道我希望洗牌的方法。但是,我不知道编写它的最佳面向对象方式。

该方法是一种比较常见的方法,如下所示:

  • 为每个分配一个随机数值,介于 0 和 2,147,483,647 之间
  • 如果有重复的键值(非常不可能),扔掉套牌,然后重新开始。
  • 将卡片存放在一组中
  • 按每张卡片键值对集合进行排序

我的问题在于最好的 OOP 方式来写这个。起初我想出了一个名为 的对象Card,其中包含一个花色值、一个数字值和随机键值。然后我会有一个名为Deck扩展 a的类HashSet,我会将每张卡片存储到 中HashSet,然后按键值对其进行排序。我挣扎的地方是,首先“生成” 52 个对象的最有效方法是什么Card,以及如何订购集合。我会实现接口“SortedSet”吗?如果是,我将如何编写比较器?

相当广泛的问题,更多基于 OOP 设计实践,但我希望这是一个非常流畅且基于对象的解决方案

干杯,

蒂姆。

编辑:

感谢大家的帮助。我的解决方案如下:

  • 2 个枚举(CardValues、CardSuits),包含 4 个花色和 13 个可能的值
  • Card 类,将 CardValue 和 CardSuit 作为构造函数参数。
  • 扩展 TreeMap 的 Deck 类

当创建和洗牌新牌组时,我循环遍历 CardSuit 枚举并创建卡片,然后在该循​​环中,我遍历 CardValue 枚举。这将创建卡片,然后我生成一个随机密钥并将它们放入 TreeMap。

由于按键重复的可能性很小,如果最终的牌组大小不是 52,我会抛出一个新的 InvalidDeckException。

感谢您的建议,我对这个解决方案更满意。

4

7 回答 7

1

我写了一些扑克分析的东西。我为所有卡片类型创建了一个枚举,带有rankvalue字段。然后我初始化了所有 52 个卡枚举的可能性。所以是的,我有 52 个枚举定义(以及所有可能的 2 张起手牌的单独枚举——有时蛮力是最好的选择)

然后,我创建了一个Deck具有 a类型ListEnum<Card>类。

初始化 Deck 就像生成一个EnumSetEnum 并将该集合传递给 List 一样简单。然后,您可以将您的shuffle方法放在Deck类上,并让它使用 Deck 的列表。

这样做的好处是你的应用程序中只有 52 张卡片——就像 FlyWeight 模式。

于 2011-09-15T15:41:27.883 回答
1

使用TreeMap, 为每张卡片生成一个地图中不存在的随机数,并将其插入地图中作为卡片的密钥,完成。

地图现在按生成的随机数排序。

另请参阅http://en.wikipedia.org/wiki/Shuffling#Shuffling_algorithms

请注意,这是一种迟缓的洗牌方式,只需使用Collections.shuffle().

于 2011-09-15T15:42:57.023 回答
1

卡.java

import java.util.*;

public class Card {
    public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX,
        SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE }

    public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }

    private final Rank rank;
    private final Suit suit;
    private Card(Rank rank, Suit suit) {
        this.rank = rank;
        this.suit = suit;
    }

    public Rank rank() { return rank; }
    public Suit suit() { return suit; }
    public String toString() { return rank + " of " + suit; }

    private static final List<Card> protoDeck = new ArrayList<Card>();

    // Initialize prototype deck
    static {
        for (Suit suit : Suit.values())
            for (Rank rank : Rank.values())
                protoDeck.add(new Card(rank, suit));
    }

    public static ArrayList<Card> newDeck() {
        return new ArrayList<Card>(protoDeck); // Return copy of prototype deck
    }
}

交易.java

import java.util.*;

public class Deal {
    public static void main(String args[]) {
        int numHands = Integer.parseInt(args[0]);
        int cardsPerHand = Integer.parseInt(args[1]);
        List<Card> deck  = Card.newDeck();
        Collections.shuffle(deck);
        for (int i=0; i < numHands; i++)
            System.out.println(deal(deck, cardsPerHand));
    }

    public static ArrayList<Card> deal(List<Card> deck, int n) {
         int deckSize = deck.size();
         List<Card> handView = deck.subList(deckSize-n, deckSize);
         ArrayList<Card> hand = new ArrayList<Card>(handView);
         handView.clear();
         return hand;
     }
}

输出:

 $ java Deal 4 5
    [FOUR of HEARTS, NINE of DIAMONDS, QUEEN of SPADES, ACE of SPADES, NINE of SPADES]
    [DEUCE of HEARTS, EIGHT of SPADES, JACK of DIAMONDS, TEN of CLUBS, SEVEN of SPADES]
    [FIVE of HEARTS, FOUR of DIAMONDS, SIX of DIAMONDS, NINE of CLUBS, JACK of CLUBS]
    [SEVEN of HEARTS, SIX of CLUBS, DEUCE of DIAMONDS, THREE of SPADES, EIGHT of CLUBS]

参考

于 2011-09-15T15:46:23.213 回答
1

我会将 Card 定义为包含 Suite 和数字值的类。卡片不应该知道相关的随机数。

Deck 是一个包含卡片列表并具有 shuffle 方法的类,通过使用可能不需要存储在某处的随机数。

于 2011-09-15T15:47:06.620 回答
1

http://download.oracle.com/javase/6/docs/api/java/util/Collections.html#shuffle(java.util.List )

有关 java.util.Collections util 类中的 shuffle 方法,请参见上述文档。

 class Card {

private int number;
// other attributes

}

并简单地使用: -

Collections.shuffle(listOfCards);
于 2011-09-15T16:14:06.937 回答
0

最简单的事情就是为卡片类型分配一个值属性并对其进行排序 (face card J,Q,K,A->11,12,13, 14) 。订购西装,您必须选择一些任意顺序并组织成一个“卡片包”,其中每个西装都有一套排序。由于花色永远不会改变,因此包总是有一组排序好的梅花、红心、钻石和黑桃。

生成卡片?每包显然必须定义 4 套西装。有一个 CardFactory,它为每个花色生成并返回一套完整的花色,给定花色。工厂只会盲目地生成 2-10 和面卡并返回排序后的集合。

于 2011-09-15T15:43:50.173 回答
0

你不应该进入Card不是特定卡的类数据。特别是,一副牌内的顺序和随机数不是牌的属性(牌无论在牌的哪个位置都是一样的)。

卡片属性应该只是它的值和状态(显示/隐藏)。该套牌可以用一个列表来实现。洗牌只是Deck的一种方法。

对于洗牌,有几种选择:

1)您自己列出随机数并排序;随机数列表中的每一个变化都会在卡片列表中重现。问题是您不能使用 List() 已经可用的排序方法

2)您添加一个包含卡片和随机数的中间类(我们称之为 ShufCard),并且:

a) 卡片组是这些中间对象的列表。

b) 对于洗牌,您创建一个包含牌组内容的时间列表,洗牌,然后从时间列表中检索卡片以维持其顺序。就像是:

 List<ShufCard> list = new ArrayList<ShufCard>();
 for (Card card : Deck.cards) {
   list.add(new ShufCard(Card, Random.getNumber());
 }

 list.sort();
 Deck.cards.clear();

 for (ShufCard shCard : list) {
   Deck.cards.add(shCard.getCard());
 }
于 2011-09-15T15:52:00.027 回答