为了账号安全,请及时绑定邮箱和手机立即绑定

在 Java 中对扑克手牌进行分类

在 Java 中对扑克手牌进行分类

鸿蒙传说 2024-01-05 15:05:15
我目前正在研究一个对玩家的手进行分类的 CS 项目。我解决了项目的前半部分,打印出牌组、洗牌牌组以及玩家 1、玩家 2 和剩余牌组的手牌。当我必须评估手牌时,问题就出现了。我的代码必须以某种方式评估手牌的分类,并打印出玩家 1 或玩家 2 是否获胜。到目前为止我已经上了三门课: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()));                       }}我认为它会起作用是因为 Deck 类扩展自 Card 类,我可以使用 getRank 方法来比较每手牌,但我不确定如何构造条件。任何帮助是极大的赞赏。谢谢。
查看完整描述

3 回答

?
慕村225694

TA贡献1880条经验 获得超4个赞

不想为你做作业...

这是个问题:

class Deck extends Card

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

class Deck {
    List<Card> cards;
}

是一个更好的选择。

另外,以下代码对牌组没有任何作用:

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

它会洗牌牌组的副本,使牌组保持不变。

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

另外,制作西装enum

另外,card_rank完全删除 - 它没有任何意义。相反,int rank;向 Card 添加一个字段,或者更好地使排名成为enum

首先修复这些问题,然后通过编写一个方法来重新解决问题,该方法传递一个具有 List 的 Hand (一个新类),以及一个通过评估该手牌是否是同花而返回 HandType (另一个枚举)的方法,否则有四种,否则...一直到高牌 - 从最高到最低。


查看完整回答
反对 回复 2024-01-05
?
大话西游666

TA贡献1817条经验 获得超14个赞

  1. 为了对游戏进行建模,首先要识别CardDeck等实体(大多数情况下您已经完成了)。我会添加更多内容,例如PlayerEvaluator(如下所述)等。

  2. 排名和花色不是字符串/整数,但它们是预定义的(在游戏的生命周期中不会改变)卡牌中可能的变化。始终使用领域词汇来获得最佳模型。每张卡牌属于一种花色和一种等级。(将 Rank 和 Suit 视为枚举,这将避免未知值在运行时破坏代码。

  3. 不给出 Card 中的套件和等级的设置方法是必要的(它们组合形成 Card 的标识)

  4. 全牌组(初始化时)由花色和等级的叉积形成。意思是牌组有(包含)多张牌。请记住,卡牌在牌组之外(在玩家手中时)也可以是活的,因此它不是组合。从 Card 继承 Deck 是绝对错误的。它翻译为陈述Deck 是一种 Card,这是不正确的。牌组将收集卡片。使用继承,会导致违反里氏替换原则(SOLID之一)。

  5. 为了对 Deck 进行建模,请考虑以下事实:Deck 不包含重复的牌,Deck 一旦形成就不会改变其顺序(除非洗牌)。这是 Set 和 List 之间的棘手选择,我会选择带有添加编程约束的 List 以避免重复(仅在初始化时才需要完成)。

  6. 但是,最好不要将 Modeling Deck 作为 java 集合,而是让类 Deck 包含合适选择的 java 集合,并且通过定义所需的 API(从领域角度来看)如 shuffle、getTopCard() 等,Deck 类作为包装器工作。这称为对象适配器设计模式。这使得我们的设计平台(实现)独立。

  7. 您需要对更多的类进行建模,例如Player持有CardInHand等。

  8. 关于评估手中的卡片,最好将其建模为单独的类,因为其不同的关注点和规则可以独立于其他类而改变。

  9. 扑克游戏是学习面向对象编程的最佳作业。


查看完整回答
反对 回复 2024-01-05
?
holdtom

TA贡献1805条经验 获得超10个赞

看来你的类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);

    }

现在 aHand是从 a 中取出的一组五张牌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;

}

请注意,常数是从最低到最高排列的。此外,牌的排列方式必须能够在出现平局的情况下,您可以比较牌来确定获胜者。


我建议你将相同等级的卡牌分组;如果您有五个不同的组,它仍然可以是同花或顺子。


另一种方法是声明Handfor every 的子类HandType,但我认为这样做不会获得太多好处。


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;

    }

}



查看完整回答
反对 回复 2024-01-05
  • 3 回答
  • 0 关注
  • 107 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信