在Java中对扑克手进行分类



我目前正在做一个CS项目,对玩家的手进行分类。我解决了项目的前半部分,打印出牌组、洗牌牌组以及玩家1、玩家2和剩余牌组的手。当我必须评估手部时,问题就出现了。我的代码必须以某种方式评估手是哪种分类,并打印出player1还是player2获胜。到目前为止,我有三门课:

public class Card {
static String[] card_suit = {"hearts", "diamonds", "clubs", "spades"};
static int[] card_rank = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};// 11 is Jack, 12 is Queen, 13 is King and 14 is Ace 
public int[] getRank() {
return card_rank;
}
public String[] getSuit() {
return card_suit;
}
}
public class Driver {
public static void main(String[] args) {
Card card = new Card();
Deck deck = new Deck();
deck.getDeck();
System.out.print("ORIGINAL DECK: ");
deck.printDeck();
deck.shuffleDeck();
System.out.print("SHUFFLED DECK: ");
deck.printDeck();
System.out.println();

System.out.print("PLAYER ONE: ");
System.out.println(java.util.Arrays.toString(deck.playerOneHands()));
System.out.print("PLAYER TWO: ");
System.out.println(java.util.Arrays.toString(deck.playerTwoHands()));
System.out.print("REMAINING DECK: ");
System.out.println(java.util.Arrays.toString(deck.remainingDeckCards()));               
}
}
import java.util.Arrays;
import java.util.Collections;
public class Deck extends Card {
Card card = new Card();
private String[] deck_card = new String[52];
public String[] getDeck() {
int i = 0;
for(int s = 0; s < 4; s++) {
for(int r = 0; r < 13; r++) {
deck_card[i]=(card_suit[s] + " of " + card_rank[r]);
i++;
}
}
return deck_card;
}
public void printDeck() {
System.out.println (java.util.Arrays.toString (deck_card));
}
public void shuffleDeck() {
Collections.shuffle(Arrays.asList(deck_card));
}
public String[] playerOneHands() {
String [] firsthand = new String[5];
for(int a = 0; a < 5; a++) {
firsthand[a] = deck_card[a];
}
return firsthand;
}
public String[] playerTwoHands() {
String[] secondhand = new String[5];
for(int a = 0; a < 5; a++) {
secondhand[a] = deck_card[a+5];
}
return secondhand;
}
public String[] remainingDeckCards() {
String[] remainDeck = new String[42];
for(int a = 0; a < 42; a++){
remainDeck[a] = deck_card[a+10];
}
return remainDeck;
}
}

我认为它会起作用,因为Deck类是从Card类扩展而来的,我可以使用getRank方法来比较每只手,但我不确定如何构造条件词。

非常感谢您的帮助。谢谢

  1. 要对游戏建模,首先要识别实体,如CardDeck等(大多数情况下您已经完成)。我想再添加一些,如播放器评估器(解释如下)等
  2. 等级和套装不是string/int,但它们是预先定义的(在游戏寿命内不会改变),可能是卡牌中的变体。始终使用领域词汇表获得最佳模型。每张卡属于一套套装和一个等级。(考虑将Rank和Suit作为枚举,这样可以避免未知值在运行时破坏代码
  3. 不给出Card中组号和秩的集合方法是必不可少的(它们在组合中形成Card的身份)
  4. 全套(初始化时)由套装和等级的交叉乘积形成。意味着牌组有(包含)多张牌。记住卡牌也可以在牌组之外(当玩家手中时)是有生命的,因此它不是合成的。从卡牌继承牌组是绝对错误的。它翻译成语句甲板是一种卡片,这是不正确的。甲板将收集卡片。使用继承,将导致违反利斯科夫的替代原则(一个固体)
  5. 为了模拟牌组,考虑到牌组不包含重复的牌,牌组在形成后不会改变顺序(除非洗牌)。在Set和List之间进行这种棘手的选择,我会选择添加了程序约束的List,以避免重复(只需要在初始化时进行)
  6. 但是,与其将Deck建模为java集合,不如让Deck类包含适当选择的java集合,并且Deck类通过定义所需的API(从域的角度来看)(如shuffle、getTopCard()等)作为包装器工作。这被称为对象适配器设计模式。这使得我们的设计平台(实现)独立
  7. 您需要为更多的类建模,如Player持有CardInHand
  8. 关于评估手中的卡,最好将其建模为单独的类,因为它的不同关注点和规则可以独立于其他类进行更改
  9. 扑克游戏是学习面向对象编程的最佳作业

不想为你做作业。。。

这是一个问题:

class Deck extends Card

牌组不是一张牌的子类型。一副牌,所以:

class Deck {
List<Card> cards;
}

是一个更好的选择。

此外,以下代码对甲板没有任何作用:

public void shuffleDeck() {
Collections.shuffle(Arrays.asList(deck_card));
}

它打乱了副本的牌组,使牌组保持原样。

此外,您不应该在循环中构建字符串。相反,在Card和Deck上实现(重写)toString()方法。

另外,将西装做成enum

此外,完全删除card_rank—它没有任何作用。相反,在Card中添加一个int rank;字段,或者更好地将秩设为enum

首先解决这些问题,然后通过编写一个方法来重新攻击这个问题,该方法传递了一个具有List的Hand(一个新类)和一个返回HandType(另一个枚举)的方法,该方法通过评估该Hand是否为直齐平,否则为四类,否则。。。一直到高牌——从最高到最低。

Card似乎只有静态字段;我会更改它,使Card的实例将代表来自Deck的单个卡。我也会使套房成为enum类型。您还可以为数字和A添加整数常量。该类可以实现Comparable<Card>:

public class Card implements Comparable<Card> {
public enum Suite {CLUBS, DIAMONDS, HEARTS, SPADES};
public static final int JACK = 11;
public static final int QUEEN = 12;
public static final int KING = 13;
public static final int ACE = 14;
public final Suite suite;
public final int rank;
public Card(Suite suite, int rank) {
if (suite == null) {
throw new IllegalArgumentException("Suite cannot be null");
}
if (rank < 2 || rank > 14) {
throw new IllegalArgumentException(
"Value must be between 2 and 14");
}
this.suite = suite;
this.rank = rank;
}
public Suite getSuite() {
return suite;
}
public int getRank() {
return rank;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
if (rank >= 2 && rank <= 10) {
buf.append(rank);
} else {
switch (rank) {
case JACK:
buf.append("jack");
break;
case QUEEN:
buf.append("queen");
break;
case KING:
buf.append("king");
break;
case ACE:
buf.append("ace");
break;
}
}
buf.append(" of ");
buf.append(suite.toString().toLowerCase());
return buf.toString();
}
@Override
public int compareTo(Card other) {
if (rank > other.rank) {
return 1;
} else if (rank < other.rank) {
return -1;
} else {
return suite.compareTo(other.suite);
}
}
}

注意,Card也可以有两个子类:一个用于数字,一个用于图形。

Deck是52张卡片的集合。它是通过将每张卡添加到列表中来初始化的。一个人可以shuffle一副牌,也可以take一副牌:

public class Deck {
private final List<Card> cards = new ArrayList<>();
public Deck() {
for (Card.Suite suite: Card.Suite.values()) {
for (int i = 2; i <= 14; ++i) {
cards.add(new Card(suite,i));
}
}
}
public void shuffle() {
Collections.shuffle(cards);
}
public boolean isEmpty() {
return cards.isEmpty();
}
public Card take() {
if (cards.isEmpty()) {
throw new IllegalStateException("Deck is empty");
}
return cards.remove(0);
}
}

你可以洗牌并从牌组中取出5张牌,如下所示:

Deck deck = new Deck();
deck.shuffle();
for (int i = 0; i < 5; ++i) {
Card card = deck.take();
System.out.println(card);
}

现在,Hand是从Deck中取出的一组五张牌。我们可以将Hand声明为实现Comparable<Hand>,这样我们就可以知道两只手中哪只手的值最高:

public class Hand implements Comparable<Hand> {
private final Card[] cards = new Card[5];
public Hand(Deck deck) {
for (int i = 0; i < 5; ++i) {
cards[i] = deck.take();
}
Arrays.sort(cards);
}
@Override
public int compareTo(Hand other) {
...
}
}

现在有趣的部分来了:您必须将手类型标识为以下类型之一(枚举类型):

public enum HandType {
SINGLE, PAIR, TWO_PAIRS, THREE, STRAIGHT, FLUSH, FULL_HOUSE, FOUR,
STRAIGHT_FLUSH, ROYAL_FLUSH;
}

请注意,常数是从最低到最高排列的。此外,必须对牌进行排列,以便在平局的情况下,您可以比较牌来确定获胜者。

我建议你制作一组等级相同的牌;在你有五个不同的组的情况下,它仍然可以是齐平的或直的。

另一种方法是为每个HandType声明一个Hand的子类,但我认为这样做不会有多大好处。

public class Hand implements Comparable<Hand> {
public enum HandType {
SINGLE, PAIR, TWO_PAIRS, THREE, STRAIGHT, FLUSH, FULL_HOUSE, FOUR,
STRAIGHT_FLUSH, ROYAL_FLUSH;
}
private final Card[] cards = new Card[5];
private final int[] groupSize;
private final HandType type;
public Hand(Deck deck) {
for (int i = 0; i < 5; ++i) {
cards[i] = deck.take();
}
groupSize = group(cards);
type = identifyType(groupSize, cards);
}
@Override
public int compareTo(Hand other) {
int r = type.compareTo(other.type);
if (r != 0) {
return r;
}
for (int i = cards.length; --i >= 0; ) {
int r1 = cards[i].getRank();
int r2 = other.cards[i].getRank();
if (r1 < r2) {
return -1;
} else if (r1 > r2) {
return 1;
}
}
return 0;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(type);
buf.append(": ");
buf.append(cards[0]);
for (int i = 1; i < 5; ++i) {
buf.append(", ");
buf.append(cards[i]);
}
return buf.toString();
}
private static int[] group(Card[] cards) {
Arrays.sort(cards);
List<List<Card>> groups = new ArrayList<>();
int val = -1; // invalid rank
List<Card> currentGroup = null;
for (Card card: cards) {
if (val == card.getRank()) {
currentGroup.add(card);
} else {
if (currentGroup != null) {
groups.add(currentGroup);
}
currentGroup = new ArrayList<>();
currentGroup.add(card);
val = card.getRank();
}
}
if (currentGroup != null) {
groups.add(currentGroup);
}
// identify groups of cards of same value
// sort groups by size and highest card
Collections.sort(groups, (List<Card> group1, List<Card> group2) -> {
int s1 = group1.size();
int s2 = group2.size();
if (s1 < s2) {
return -1;
} else if (s1 > s2) {
return 1;
} else {
return group1.get(s1-1).compareTo(group2.get(s2-1));
}
});
int[] groupSize = new int[groups.size()];
int g = 0;
int i = 0;
for (List<Card> group: groups) {
groupSize[g++] = group.size();
for (Card card: group) {
cards[i++] = card;
}
}
assert sum(groupSize) == 5;
return groupSize;
}
private static HandType identifyType(int[] groupSize, Card[] cards) {
switch (groupSize.length) {
case 2:
// can be a full house or four cards
if (groupSize[0] == 1) {
return HandType.FOUR;
} else if (groupSize[0] == 2) {
return HandType.FULL_HOUSE;
} else {
assert false;
return null;
}
case 3:
if (groupSize[0] == 1) {
// three cards or double pair
if (groupSize[1] == 1) {
return HandType.THREE;
} else {
assert groupSize[1] == 2 && groupSize[2] == 2;
return HandType.TWO_PAIRS;
}
} else {
assert false;
return null;
}
case 4:
// one pair
return HandType.PAIR;
case 5:
// all different values: check for flush
Card prev = cards[0];
boolean sameSuite = true;
boolean straight = true;
for (int i = 1; i < 5; ++i) {
Card card = cards[i];
straight &= card.getRank() == prev.getRank()+1;
sameSuite &= card.getSuite() == prev.getSuite();
}
if (sameSuite) {
if (straight) {
if (cards[4].getRank() == Card.ACE) {
return HandType.ROYAL_FLUSH;
}
return HandType.STRAIGHT_FLUSH;
} else {
return HandType.FLUSH;
}
} else {
if (straight) {
return HandType.STRAIGHT;
} else {
return HandType.SINGLE;
}
}
default:
assert false;
return null;
}
}
private static int sum(int[] groupSize) {
int sum = 0;
for (int s: groupSize) {
sum += s;
}
return sum;
}
}

最新更新