我正在尝试写一个卡洗牌器,我知道我想要洗牌的方法。但是,我无法用最好的面向对象的方式来编写它。
这个方法很常见,如下:
我的问题在于用最好的OOP方式来编写它。起初我想出了一个名为Card
的对象,其中包含一个套装值,一个数值和随机键值。然后我会有一个名为Deck
的类扩展HashSet
,我会将每张卡存储到HashSet
中,然后按键值对其进行排序。在我努力的地方,首先“生成”52 Card
个对象的最有效方法是什么,以及如何订购该集合。我会实现接口'SortedSet',如果是这样,我将如何编写比较器?
相当广泛的问题,更多基于OOP设计实践,但我希望这是一个非常流畅的基于对象的解决方案。
干杯,
添
编辑:
感谢大家的帮助。我的解决方案如下:
当创建和改组新牌组时,我循环穿过CardSuit Enum并创建牌,然后在该圈内,我通过CardValue Enum。这会创建卡片,然后我生成一个随机密钥并将它们放在TreeMap中。
由于密钥重复的可能性很小,如果最终套牌大小不是52,我会抛出一个新的InvalidDeckException。
感谢您的建议,我对此解决方案感到非常满意。
答案 0 :(得分:1)
rank
和value
字段。然后我初始化了所有52张卡枚举的可能性。所以是的,我有52个enum defs(并且所有可能的2张牌起手都有一个单独的枚举 - 有时候蛮力是最好的选择)
然后我创建了一个Deck
类,其中List
种类型为Enum<Card>
。
初始化Deck就像生成Enum的EnumSet
一样简单,并将该集传递给List。然后,您可以将shuffle
方法放在Deck
类上,并让它使用Deck列表。
这样做的好处是你的应用程序中只有52张牌 - 就像FlyWeight模式一样。
答案 1 :(得分:1)
使用TreeMap
,为每张卡生成一张地图中不存在的随机数,并将其作为卡的密钥插入地图中,完成。
地图现在按生成的随机数排序。
另见http://en.wikipedia.org/wiki/Shuffling#Shuffling_algorithms
请注意,这是一种迟钝的混淆方式,只需使用Collections.shuffle()
。
答案 2 :(得分:1)
<强> Card.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
}
}
Deal.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]
参考:
答案 3 :(得分:1)
我会将卡定义为持有套件的班级和数字值。卡不应该知道相关的随机数。
The Deck是一个包含卡片列表并具有随机播放方法的类,使用随机数字,可能不需要存储在某处。
答案 4 :(得分:1)
http://download.oracle.com/javase/6/docs/api/java/util/Collections.html#shuffle(java.util.List)
请参阅java.util.Collections util class中的shuffle方法的上述doc。
class Card {
private int number;
// other attributes
}
并简单地使用: -
Collections.shuffle(listOfCards);
答案 5 :(得分:0)
最简单的方法是为卡类型分配一个值属性并对其进行排序(面卡J,Q,K,A-> 11,12,13,14)。订购套装你必须选择一些任意的订单并组织成一个“包装”的卡片,其中包含每件套装的分类。由于套装永远不会改变,所以Pack总是有一个分类的每个俱乐部,心,钻石和黑桃。
生成卡片?每包显然必须定义4套。在给出套装的情况下,拥有一个CardFactory,为每件套装生成并返回一整套。工厂只会盲目地生成2-10和面部卡并返回有序集。
答案 6 :(得分:0)
您不应该进入与特定卡片不同的Card
类数据。特别是,套牌内的顺序和随机数不是卡的属性(无论卡片在哪里,卡都是相同的。)
卡片属性应该只是它的值和状态(显示/隐藏)。卡组可以用List实现。洗牌只是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());
}