为甲板中的卡分配值

发布于 2025-01-17 21:04:57 字数 2800 浏览 2 评论 0原文

我正在为我的第一届编程课程构建二十一点游戏。除了我在这堂课上的含量外,我的编程经验还为零。我们的主要项目是使用Java构建和运行二十一点程序。

我已经建造了甲板,洗了它并打了一张卡。我站在站着的地方仍在为被拉的卡分配一个值。我不确定如何实施。谁能为我提供任何方向?任何帮助将不胜感激!

以下是我的卡和甲板课:

public class Card
{
    private int suit;
    private int rank;   
    private int value;
    private String [] suits = {"Spades", "Hearts", "Clubs", "Diamonds"};
    private String [] ranks = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};

    public Card (int cardSuit, int cardRank)
    {
        suit = cardSuit;
        rank = cardRank;
    }

    public int getSuit()
    {
        return suit;
    }

    public int getRank()
    {
        return rank;
    }

    public String toString()
    {
        return ranks[rank] + " of " + suits[suit];
    }
}

import java.util.ArrayList;
import java.util.*;

public class Deck
{   
    private ArrayList<Card> deck;
    private int suitCounter;
    private int rankCounter;
    private int randomIndex;
    private Card card;
    private ArrayList<Card> temp;
    private Card removeCard;

    public Deck()    //building deck with 52 cards
    {
        deck = new ArrayList<Card>();
        
        for(suitCounter = 0; suitCounter < 4; suitCounter++)
        {
            for(rankCounter = 0; rankCounter < 13; rankCounter++)
            {
                deck.add(new Card(suitCounter, rankCounter));
            }
        }
    } 
    
    public void shuffle()    //shuffling the deck
    {
        Collections.shuffle(deck);
    }

    public Card deal()      //picking the first card out of the deck
    {
        card = deck.get(0);
        return card;
    }

    public void remove()     //removing the dealt card from the deck and putting it in a new  temporary deck
    {
        temp = new ArrayList<Card>();

        removeCard = deck.remove(0);
        temp.add(removeCard);
    }   
    
    public String toString()      //display the choosen card
    {
        return "Card: " + card;
    }
}
 

迄今为止,我还没有带有主要方法的官方二十一点类。我希望能够建造甲板,处理卡并获得价值,然后我开始构建主要方法。但是,这是我必须帮助知道我是否用价值打印出卡的内容。

public class Game
{
    public static void main(String[] args)
    {   
        Deck playingDeck = new Deck();      //creating deck object
        playingDeck.shuffle();              //shuffling deck
        playingDeck.deal();                 //dealing card 1 of player's hand
        playingDeck.remove();               //removing card 1 from deck 
        System.out.println(playingDeck);    //printing out card 1 
        playingDeck.deal();                 //dealing card 2 of player's hand
        playingDeck.remove();               //removing card 2 from deck 
        System.out.println(playingDeck);    //printing out card 2 
    }

先感谢您!

I am working on building a blackjack game for my first programming class. I have zero programming experience other than the bit I've had in this class. Our major project is to build and run a blackjack program using java.

I have built my deck, shuffled it and dealt a card. Where I am at a stand still is assigning a value to the card that was pulled. I am not sure how to implement this. Can anyone provide any direction for me? Any help would be greatly appreciated!

Below are my Card and Deck class:

public class Card
{
    private int suit;
    private int rank;   
    private int value;
    private String [] suits = {"Spades", "Hearts", "Clubs", "Diamonds"};
    private String [] ranks = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};

    public Card (int cardSuit, int cardRank)
    {
        suit = cardSuit;
        rank = cardRank;
    }

    public int getSuit()
    {
        return suit;
    }

    public int getRank()
    {
        return rank;
    }

    public String toString()
    {
        return ranks[rank] + " of " + suits[suit];
    }
}

import java.util.ArrayList;
import java.util.*;

public class Deck
{   
    private ArrayList<Card> deck;
    private int suitCounter;
    private int rankCounter;
    private int randomIndex;
    private Card card;
    private ArrayList<Card> temp;
    private Card removeCard;

    public Deck()    //building deck with 52 cards
    {
        deck = new ArrayList<Card>();
        
        for(suitCounter = 0; suitCounter < 4; suitCounter++)
        {
            for(rankCounter = 0; rankCounter < 13; rankCounter++)
            {
                deck.add(new Card(suitCounter, rankCounter));
            }
        }
    } 
    
    public void shuffle()    //shuffling the deck
    {
        Collections.shuffle(deck);
    }

    public Card deal()      //picking the first card out of the deck
    {
        card = deck.get(0);
        return card;
    }

    public void remove()     //removing the dealt card from the deck and putting it in a new  temporary deck
    {
        temp = new ArrayList<Card>();

        removeCard = deck.remove(0);
        temp.add(removeCard);
    }   
    
    public String toString()      //display the choosen card
    {
        return "Card: " + card;
    }
}
 

I do not have an official blackjackgame class with a main method as of yet. My hope was to get the deck built, deal a card and get the value and then I'd start building the main method. But here is what I have to help to know if I printed out the card with a value or not.

public class Game
{
    public static void main(String[] args)
    {   
        Deck playingDeck = new Deck();      //creating deck object
        playingDeck.shuffle();              //shuffling deck
        playingDeck.deal();                 //dealing card 1 of player's hand
        playingDeck.remove();               //removing card 1 from deck 
        System.out.println(playingDeck);    //printing out card 1 
        playingDeck.deal();                 //dealing card 2 of player's hand
        playingDeck.remove();               //removing card 2 from deck 
        System.out.println(playingDeck);    //printing out card 2 
    }

Thank you in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

逆夏时光 2025-01-24 21:04:58

一些问题

虽然您通常走在正确的轨道上,但您的实现有一些您应该重新考虑的设计决策。
这就是为什么你很难为抽到的牌赋值的部分原因。在您的设计中,一张牌具有 value 属性,但如果您考虑一下,BlackJack 中的牌的价值取决于其等级并且仅取决于其等级。此外,它不会随着时间的推移而改变,这就是为什么您应该密切关注该值与排名耦合。对于等级和花色,要考虑的另一件事是,只有一组有限的允许且定义良好的值,该值远小于 intString 的值范围code> 可能会这样,所以我建议你使用 enum 来键入这些值。始终记住枚举只是特殊的类,因此它们也可以具有属性。

下面我将如何实现 RankSuit

Rank.java

public enum Rank {
    // the value is determined only by rank so assign the value here!
    TWO(2, "2"),
    THREE(3, "3"),
    FOUR(4, "4"),
    FIVE(5, "5"),
    SIX(6, "6"),
    SEVEN(7, "7"),
    EIGHT(8, "8"),
    NINE(9, "9"),
    TEN(10, "10"),
    JACK(10, "J"),
    QUEEN(10, "Q"),
    KING(10, "K"),
    ACE(11, "A");

    private final int value;
    private final String display;

    /**
     * Each rank has a value and a String which determines how the rank is displayed in the console.
     * @param value value assigned to a rank
     * @param display String displayed to represent this rank
     */
    Rank(int value, String display) {
        this.value = value;
        this.display = display;
    }

    public int getValue() {
        return value;
    }

    public String getDisplay() {
        return display;
    }

    @Override
    public String toString() {
        return display;
    }
}

Suit.java

public enum Suit {
    SPADES("Spades"),
    HEARTS("Hearts"),
    CLUBS("Clubs"),
    DIAMONDS("Diamonds");

    // display value in console
    private final String display;

    /**
     * Suit of a card
     * @param display display value for a suit
     */
    Suit(String display) {
        this.display = display;
    }

    public String getDisplay() {
        return display;
    }

    @Override
    public String toString() {
        return display;
    }
}

这对于 Card 类有一些很好的好处。一张牌只需要一个花色和一个等级,仅此而已。有了它的排名,它现在也会自动分配一个值。您实现该卡的问题在于,您在每张卡中都有一个包含等级和花色的所有可能值的数组。再次,想想现实世界。一张牌当然不包含可能的等级和花色的所有值,而仅具有一个等级和一个花色。您的类 Card 是现实世界卡的某种简化模型,因此它应该具有现实世界卡的属性。以这种方式设计还可以帮助您掌握程序,因为您的设计将更容易理解。

这是我的卡的实现。

Card.java

public class Card {
    // value of a card is not going to change, so we can make it final
    private final Suit suit;
    private final Rank rank;

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

    public Suit getSuit() {
        return suit;
    }

    public Rank getRank() {
        return rank;
    }

    @Override
    public String toString() {
        // prints e.g. "2-Hearts"
        return rank.toString() + "-" + suit.toString();
    }
}

现在,让我们转到 Deck 类。这场战争实际上是你精心设计的,因为套牌只是纸牌的集合。但是您的方法 deal() 有一个问题,它会阻止您知道抽出了哪张牌。在您的实现中,您只需删除牌组顶部的卡牌,但不会将其归还,因此您实际上只是从内存中擦除了一张卡牌,它就会丢失并且无法在游戏中播放。默认情况下,ArrayListremove() 方法确实返回删除的值,因此请使用它。
另外,这可能有点吹毛求疵,但我认为你应该将 deal() 重命名为 drawTop(),因为在现实世界中,交易涉及首先绘制一张牌,然后将其交给一名玩家,然后接受该牌并将其放入手中。

这是我的 Deck 实现。由于我之前所做的更改,需要进行一些更改,但这本质上是经过上述更改的您的套牌。

Deck.java

import java.util.ArrayList;
import java.util.*;

public class Deck {
    private final ArrayList<Card> deck;

    /**
     * Building deck with 52 cards
     *
     * Try to use Java Doc syntax to like this to comment on methods.
     * These comments will be shown in IDEs and an HTML page can be auto-generated from them.
     */
    public Deck(){
        // get all possible value from the enums for Suit and Ranks
        var allSuits = Suit.values();
        var allRanks = Rank.values();
        // You can provide an initial capacity for how many card you are going to have
        // this will avoid unnecessary resizing of the array but that is not that important here
        this.deck = new ArrayList<Card>(allSuits.length * allRanks.length);
        // These are for-each loop that loop over all possible suits and ranks
        for (var suit : allSuits) {
            for (var rank : allRanks) {
                // add one card for each suit-rank combination
                deck.add(new Card(suit, rank));
            }
        }
    }

    /**
     * Shuffle the deck.
     */
    public void shuffle()    //shuffling the deck
    {
        Collections.shuffle(deck);
    }

    public Card drawTop()      //picking the first card out of the deck
    {
        // check if Deck is empty or not!
        if(this.isEmpty()) return null;
        // remove removes the card and returns the removed card
        return deck.remove(0);
    }

    /**
     * Checks if deck is empty i. e. no cards left in the deck.
     * @return true, if no cards are left in deck, false otherwise
     */
    public boolean isEmpty(){
        return deck.isEmpty();
    }

    /**
     * Gets number of remaining cards in the deck. This is helpful for debugging purposes.
     * @return number of remaining cards in the deck
     */
    public int getNoRemainingCars(){
        return deck.size();
    }

    @Override
    public String toString() {
        return deck.toString();
    }
}

您现在可以调用 var topCard = new Deck().drawTop() ,它将从牌堆顶部移除一张牌,并且该牌将存储在topCard中。您只需调用 System.out.println(topCard) 或使用 topCard.getRank() 和 topCard.getSuit() 即可查看哪个卡被抽了。请记住,通过等级,您还将获得卡的价值。

请参阅此 main 方法,了解如何与所有这些类进行交互。

public static void main(String[] args) {
        // create the deck with all 52 cards
        var deck = new Deck();
        // print the deck
        System.out.printf("Newly created deck: %s\n", deck);
        // shuffle the cards
        deck.shuffle();
        System.out.printf("Shuffled deck: %s\n", deck);
        // remove the first card
        var dealtCard = deck.drawTop();
        // print the car that was dealt
        System.out.printf("Removed card: %s\n", dealtCard);
        // print info about that card
        System.out.printf("The card that was removed from the deck is the %s of %s\n", dealtCard.getRank(), dealtCard.getSuit());
        // print deck again to show that the card is no longer in the deck
        System.out.printf("The deck after a card was removed: %s\n", deck);
}

预期输出:

Newly created deck: [2-Spades, 3-Spades, 4-Spades, 5-Spades, 6-Spades, 7-Spades, 8-Spades, 9-Spades, 10-Spades, J-Spades, Q-Spades, K-Spades, A-Spades, 2-Hearts, 3-Hearts, 4-Hearts, 5-Hearts, 6-Hearts, 7-Hearts, 8-Hearts, 9-Hearts, 10-Hearts, J-Hearts, Q-Hearts, K-Hearts, A-Hearts, 2-Clubs, 3-Clubs, 4-Clubs, 5-Clubs, 6-Clubs, 7-Clubs, 8-Clubs, 9-Clubs, 10-Clubs, J-Clubs, Q-Clubs, K-Clubs, A-Clubs, 2-Diamonds, 3-Diamonds, 4-Diamonds, 5-Diamonds, 6-Diamonds, 7-Diamonds, 8-Diamonds, 9-Diamonds, 10-Diamonds, J-Diamonds, Q-Diamonds, K-Diamonds, A-Diamonds]
Shuffled deck: [6-Diamonds, 9-Hearts, Q-Diamonds, 2-Hearts, 7-Hearts, A-Clubs, J-Clubs, A-Hearts, 3-Clubs, 4-Hearts, 3-Hearts, Q-Clubs, 9-Clubs, 6-Hearts, K-Clubs, 8-Clubs, 2-Diamonds, J-Hearts, J-Spades, 4-Diamonds, A-Spades, 7-Clubs, 3-Diamonds, 4-Clubs, Q-Spades, 5-Spades, 5-Hearts, 10-Clubs, 2-Spades, 5-Clubs, K-Hearts, K-Diamonds, 4-Spades, A-Diamonds, 6-Spades, 9-Spades, 3-Spades, 10-Spades, 7-Diamonds, K-Spades, J-Diamonds, 7-Spades, 6-Clubs, 5-Diamonds, 8-Spades, 10-Diamonds, 9-Diamonds, Q-Hearts, 10-Hearts, 8-Hearts, 2-Clubs, 8-Diamonds]
Removed card: 6-Diamonds
The card that was removed from the deck is the 6 of Diamonds
The deck after a card was removed: [9-Hearts, Q-Diamonds, 2-Hearts, 7-Hearts, A-Clubs, J-Clubs, A-Hearts, 3-Clubs, 4-Hearts, 3-Hearts, Q-Clubs, 9-Clubs, 6-Hearts, K-Clubs, 8-Clubs, 2-Diamonds, J-Hearts, J-Spades, 4-Diamonds, A-Spades, 7-Clubs, 3-Diamonds, 4-Clubs, Q-Spades, 5-Spades, 5-Hearts, 10-Clubs, 2-Spades, 5-Clubs, K-Hearts, K-Diamonds, 4-Spades, A-Diamonds, 6-Spades, 9-Spades, 3-Spades, 10-Spades, 7-Diamonds, K-Spades, J-Diamonds, 7-Spades, 6-Clubs, 5-Diamonds, 8-Spades, 10-Diamonds, 9-Diamonds, Q-Hearts, 10-Hearts, 8-Hearts, 2-Clubs, 8-Diamonds]

后续步骤

现在,这就是您的第一个问题。但是,由于您是初学者并且需要一些指导,所以我决定为您提供一些关于下一步该做什么以及如何做到的指导:)我知道需要考虑的内容很多,但我相信您会明白你的头围绕着它。在接下来的几节中,我将向您展示您实际上可以从牌堆中抽牌并将其发给玩家。

前几句话我提到过

在现实世界中发牌需要首先抓一张牌,然后将其交给玩家,然后玩家接受该牌并将其放入手中

这句话中的名词应该是你的下一个类,动词应该是你的下一个方法。所以那就是:

    • 卡片集合
    • 能够从手牌中添加和删除牌
  • Player
    • 能够接受卡片并将其放入他/她的手中
    • 应该有一个Hand,它又是Card的集合
  • (对于句子中的发牌部分)
    • 荷官是一名玩家,拥有额外的属性和能力
    • 需要一副牌组,他/她可以将牌发给玩家
    • 能够从牌组中抽取一张牌并将其发给玩家

手牌

手牌是一组牌(我使用的是 Java 数据结构 HashSet 此处)并且所有卡有一个总价值,因此这应该是属性。另外,Hand 应该允许添加和删除卡片,这将是我们的方法。添加和删​​除时,我们需要相应地调整手牌的总价值

Hand.java

mport java.util.HashSet;
import java.util.Set;

public class Hand {
    private final Set<Card> cards;
    private int totalValue;

    public Hand() {
        this.cards = new HashSet<>();
        this.totalValue = 0;
    }

    /**
     * Add a card to the hand
     * @param card card to be added
     */
    public void addCard(Card card){
        // add card to hand
        cards.add(card);
        // increase total value by value of the card
        totalValue += card.getRank().getValue();
    }

    public void removeCard(Suit suits, Rank rank){
        var searchedCard = new Card(suits, rank);
        // call other remove method which does the actual removal
        removeCard(searchedCard);
    }

    public void removeCard(Card card){
        // remove card if it is present
        cards.remove(card);
        // remove card from total value
        totalValue -= card.getRank().getValue();
    }

    @Override
    public String toString() {
        return "Hand{" +
                "cards=" + cards +
                ", totalValue=" + totalValue +
                '}';
    }
}

Player

让我们继续讨论播放器。玩家将有一个名称和一个手牌。此外,他/她(顺便说一句,如果您想分配一张牌,性别也是可能的)应该有能力接受一张牌,并在发牌给他们时将其放入手中。玩家还将拥有其他能力,例如决定是否接受另一张卡牌以及其他东西,但这取决于您是否可以扩展,我将只关注如何接受/接收卡牌。

Player.java

public class Player {
    // protected is a necessary access qualifier so subclasses of Player (Croupier will also have the property name and hand without specifically stating that, see Croupier.java) 
    protected String name;
    protected Hand hand;

    public Player(String name) {
        this.name = name;
        this.hand = new Hand();
        System.out.printf("Player %s has joined the game.\n", name);
    }

    /**
     * Receive a card and add it to the hand
     * @param card card to be received
     */
    public void receiveCard(Card card){
        // add card to hand
        hand.addCard(card);
    }

    @Override
    public String toString() {
        return "Player{" +
                "name='" + name + '\'' +
                ", hand=" + hand +
                '}';
    }

    public String getName() {
        return name;
    }
}

荷官

现在变得很有趣,因为荷官是一个拥有玩家所有能力和属性的玩家,但他/她还拥有更多的能力和属性。为了反映这一点,在 Java 中我们使用了一个名为 继承 的功能。因此,Croupier 拥有 Player 所拥有的一切,甚至更多,因此它扩展了 Player。继承将允许我们简单地定义它,并且我们不必为 Croupier 再次重新实现我们为 Player 所做的一切。因此,我们只需要关注荷官的额外属性和能力,即他/她获得一副牌,他/她可以洗牌并向玩家发牌。要洗牌,我们只需使用 Deckshuffle() 方法。为了发牌,我们使用DeckdrawTop()方法从牌堆中抽一张牌(并返回该牌)和receiveCard()我们将抽到的牌传递给的 Player 方法。这样,牌组最上面的牌就会被移除并添加到玩家的手上。所有这些都发生在 dealCardTo() 方法中。

Croupier.java

/**
 * Croupier extends Player as he/she is also a Player and should have the same possibilities as a player, but also has additional functionality.
 * Google for Java inheritence for more information
 */
public class Croupier extends Player{
    private final Deck deck;

    public Croupier(String name, Deck deck) {
        // call constructor of superclass player
        super(name);
        this.deck = deck;
    }

    public void dealCardTo(Player player){
        // get one card of the deck
        var cardToDeal = deck.drawTop();
        // deal the card to the player
        player.receiveCard(cardToDeal);
        System.out.printf("%s is dealing a card to %s.\n", name, player.getName());
    }

    // this is just for demo purposes
    public String showDeck(){
        return deck.toString();
    }

    public void shuffleCards(){
        deck.shuffle();
        System.out.printf("Croupier %s has shuffled the cards.\n", name);
    }

    @Override
    public String toString() {
        return "Croupier{" +
                "name='" + name + '\'' +
                ", hand=" + hand +
                ", deck=" + deck +
                '}';
    }
}

将它们放在一起

现在我们已经拥有了向玩家发牌的所有必要功能,因此这里有一个简单的示例来说明我们如何做到这一点。

Application.java

public class Application {
    public static void main(String[] args) {               
        System.out.println("""
                +-------------------------------------------------------------------
                | Example: Create players, a deck and deal 1 card to each player
                +-------------------------------------------------------------------
                """);
        // create two players, and the croupier
        var john = new Player("John");
        System.out.println(john);
        var elton = new Player("Elton");
        System.out.println(elton);
        // create a croupier; a groupie is a player and deals cards, so give him a new deck of cards
        var croupierTom = new Croupier("Tom", new Deck());
        System.out.println(croupierTom);
        // a list of all players
        var allPlayers = new ArrayList<Player>();
        allPlayers.add(john);
        allPlayers.add(elton);
        // remember a croupier is also a player because it is a subclass
        allPlayers.add(croupierTom);
        // let the croupier shuffle the cards
        croupierTom.shuffleCards();
        // tell croupier to deal one card to each player (including himself)
        for (var player : allPlayers) {
            croupierTom.dealCardTo(player);
        }
        // now let's see who got which cards
        for (var player : allPlayers) {
            System.out.println(player);
        }
    }
}

预期输出:

+-------------------------------------------------------------------
| Example: Create players, a deck and deal 1 card to each player
+-------------------------------------------------------------------

Player John has joined the game.
Player{name='John', hand=Hand{cards=[], totalValue=0}}
Player Elton has joined the game.
Player{name='Elton', hand=Hand{cards=[], totalValue=0}}
Player Tom has joined the game.
Croupier{name='Tom', hand=Hand{cards=[], totalValue=0}, deck=[2-Spades, 3-Spades, 4-Spades, 5-Spades, 6-Spades, 7-Spades, 8-Spades, 9-Spades, 10-Spades, J-Spades, Q-Spades, K-Spades, A-Spades, 2-Hearts, 3-Hearts, 4-Hearts, 5-Hearts, 6-Hearts, 7-Hearts, 8-Hearts, 9-Hearts, 10-Hearts, J-Hearts, Q-Hearts, K-Hearts, A-Hearts, 2-Clubs, 3-Clubs, 4-Clubs, 5-Clubs, 6-Clubs, 7-Clubs, 8-Clubs, 9-Clubs, 10-Clubs, J-Clubs, Q-Clubs, K-Clubs, A-Clubs, 2-Diamonds, 3-Diamonds, 4-Diamonds, 5-Diamonds, 6-Diamonds, 7-Diamonds, 8-Diamonds, 9-Diamonds, 10-Diamonds, J-Diamonds, Q-Diamonds, K-Diamonds, A-Diamonds]}
Croupier Tom has shuffled the cards.
Tom is dealing a card to John.
Tom is dealing a card to Elton.
Tom is dealing a card to Tom.
Player{name='John', hand=Hand{cards=[7-Spades], totalValue=7}}
Player{name='Elton', hand=Hand{cards=[4-Diamonds], totalValue=4}}
Croupier{name='Tom', hand=Hand{cards=[2-Spades], totalValue=2}, deck=[8-Hearts, 5-Hearts, 9-Hearts, 3-Spades, Q-Hearts, 8-Clubs, 2-Diamonds, 6-Diamonds, 10-Hearts, 2-Hearts, 8-Spades, Q-Clubs, 2-Clubs, Q-Spades, 5-Diamonds, 5-Clubs, 7-Clubs, 4-Hearts, K-Spades, 3-Hearts, 9-Clubs, K-Clubs, Q-Diamonds, A-Clubs, 10-Spades, 4-Clubs, A-Spades, J-Diamonds, 10-Diamonds, 7-Diamonds, J-Hearts, A-Hearts, 5-Spades, A-Diamonds, 4-Spades, 7-Hearts, 6-Hearts, J-Clubs, 9-Diamonds, 6-Spades, J-Spades, 8-Diamonds, 10-Clubs, 6-Clubs, 3-Diamonds, K-Diamonds, 3-Clubs, 9-Spades, K-Hearts]}

请记住,通过洗牌,您的结果可能会略有不同,但每个玩家(包括荷官)手中都应该有一张牌,并且牌组中应该将所有这些牌都从其中移除。

接下来该怎么办?

现在这应该给你一个很好的骨架来实现游戏的其余部分。还有很多事情要做。接下来可能应该创建一个代表 BlackJack 游戏的 Game 类。再次从现实世界开始,并记住您的设计应该是现实世界的模型。始终考虑实例具有的能力(=方法)和属性(=属性)。一个游戏肯定会有一群玩家、一个荷官和开始游戏的能力。想想游戏开始时会发生什么:荷官必须发牌(我们已经知道如何做到这一点),但它不会只是一张,并且涉及的玩家将做出是否发牌的决定。他们想再拿一张卡。您需要执行二十一点的规则以及获胜条件来确定获胜者。您还可以为玩家实施一些赌注等等。

我希望这能帮助您了解可以开始什么、如何开始以及下一步做什么:) 快乐编码:)

免责声明:我的设计不是黄金标准或类似的东西,它只是一种可能的设计,可能还有其他(更好的)设计。但我认为这是一种相对简单但足够强大的方法。

Some issues

Although you are generally on the right track, your implementation has some design decisions that you should reconsider.
This is part of the reason why you find it hard to assign a value to the card that is drawn. In your design a card has a value attribute but if you think about it, a card's value in BlackJack is determined by its rank and its rank only. Additionally, it will not be changing over time, that is why you should keep the value closely coupled to the rank. Another thing to consider for both, ranks and suits, is there is only a limited set of allowed and well-defined values which is far smaller than the range of values an int or String could take so I would propose you use an enum to type those values. Always keep in mind enums are just special classes so they can have attributes as well.

Here how I would implement Rank and Suit.

Rank.java

public enum Rank {
    // the value is determined only by rank so assign the value here!
    TWO(2, "2"),
    THREE(3, "3"),
    FOUR(4, "4"),
    FIVE(5, "5"),
    SIX(6, "6"),
    SEVEN(7, "7"),
    EIGHT(8, "8"),
    NINE(9, "9"),
    TEN(10, "10"),
    JACK(10, "J"),
    QUEEN(10, "Q"),
    KING(10, "K"),
    ACE(11, "A");

    private final int value;
    private final String display;

    /**
     * Each rank has a value and a String which determines how the rank is displayed in the console.
     * @param value value assigned to a rank
     * @param display String displayed to represent this rank
     */
    Rank(int value, String display) {
        this.value = value;
        this.display = display;
    }

    public int getValue() {
        return value;
    }

    public String getDisplay() {
        return display;
    }

    @Override
    public String toString() {
        return display;
    }
}

Suit.java

public enum Suit {
    SPADES("Spades"),
    HEARTS("Hearts"),
    CLUBS("Clubs"),
    DIAMONDS("Diamonds");

    // display value in console
    private final String display;

    /**
     * Suit of a card
     * @param display display value for a suit
     */
    Suit(String display) {
        this.display = display;
    }

    public String getDisplay() {
        return display;
    }

    @Override
    public String toString() {
        return display;
    }
}

This has some nice benefits for the Card class. A card only needs a Suit and a Rank and that's it. With it's rank it will automatically have a value assigned as well now. The problem with your implementation of the card is that you had an array of all possible values for ranks and suits in every card. Again, think of the real world. A card certainly does not hold all values of possible ranks and suits, but only has one rank and one suit. Your class Card is a somewhat simplified model of the real-world card so it should have the properties of a real-world card. Designing it this way will also help you staying on top of your program because your design will be easier to comprehend.

Here my implementation of the card.

Card.java

public class Card {
    // value of a card is not going to change, so we can make it final
    private final Suit suit;
    private final Rank rank;

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

    public Suit getSuit() {
        return suit;
    }

    public Rank getRank() {
        return rank;
    }

    @Override
    public String toString() {
        // prints e.g. "2-Hearts"
        return rank.toString() + "-" + suit.toString();
    }
}

Now, let's move on to the Deck class. This war actually quite well designed by you as a deck is just a collection of cards. But there is a issue with your method deal() which hinders you from knowing which card was drawn. In your implementation you just remove the card on the top of the deck but you don't return it, so you're essentially just wiping a card from memory and it is lost and cannot be played in the game. The remove() method of an ArrayList does return the removed value by default so use that.
Also, that's maybe splitting hairs, but I think you should rename deal() to drawTop() as dealing in the real-world involves first drawing a card then giving it to a player, who then accepts that card and puts it in his hand.

This is my Deck implementation. There are some changes required due to the previous changes I've made but this is essentially your Deck with the change described above.

Deck.java

import java.util.ArrayList;
import java.util.*;

public class Deck {
    private final ArrayList<Card> deck;

    /**
     * Building deck with 52 cards
     *
     * Try to use Java Doc syntax to like this to comment on methods.
     * These comments will be shown in IDEs and an HTML page can be auto-generated from them.
     */
    public Deck(){
        // get all possible value from the enums for Suit and Ranks
        var allSuits = Suit.values();
        var allRanks = Rank.values();
        // You can provide an initial capacity for how many card you are going to have
        // this will avoid unnecessary resizing of the array but that is not that important here
        this.deck = new ArrayList<Card>(allSuits.length * allRanks.length);
        // These are for-each loop that loop over all possible suits and ranks
        for (var suit : allSuits) {
            for (var rank : allRanks) {
                // add one card for each suit-rank combination
                deck.add(new Card(suit, rank));
            }
        }
    }

    /**
     * Shuffle the deck.
     */
    public void shuffle()    //shuffling the deck
    {
        Collections.shuffle(deck);
    }

    public Card drawTop()      //picking the first card out of the deck
    {
        // check if Deck is empty or not!
        if(this.isEmpty()) return null;
        // remove removes the card and returns the removed card
        return deck.remove(0);
    }

    /**
     * Checks if deck is empty i. e. no cards left in the deck.
     * @return true, if no cards are left in deck, false otherwise
     */
    public boolean isEmpty(){
        return deck.isEmpty();
    }

    /**
     * Gets number of remaining cards in the deck. This is helpful for debugging purposes.
     * @return number of remaining cards in the deck
     */
    public int getNoRemainingCars(){
        return deck.size();
    }

    @Override
    public String toString() {
        return deck.toString();
    }
}

You are now able to call var topCard = new Deck().drawTop() and it will remove a card from the top of the deck and this card will be stored in topCard. You can just simply call System.out.println(topCard) or use topCard.getRank() and topCard.getSuit() to see which card was drawn. Remember with the rank you also will get the value of the card.

See this main method on how you can now interact with all those classes.

public static void main(String[] args) {
        // create the deck with all 52 cards
        var deck = new Deck();
        // print the deck
        System.out.printf("Newly created deck: %s\n", deck);
        // shuffle the cards
        deck.shuffle();
        System.out.printf("Shuffled deck: %s\n", deck);
        // remove the first card
        var dealtCard = deck.drawTop();
        // print the car that was dealt
        System.out.printf("Removed card: %s\n", dealtCard);
        // print info about that card
        System.out.printf("The card that was removed from the deck is the %s of %s\n", dealtCard.getRank(), dealtCard.getSuit());
        // print deck again to show that the card is no longer in the deck
        System.out.printf("The deck after a card was removed: %s\n", deck);
}

Expected output:

Newly created deck: [2-Spades, 3-Spades, 4-Spades, 5-Spades, 6-Spades, 7-Spades, 8-Spades, 9-Spades, 10-Spades, J-Spades, Q-Spades, K-Spades, A-Spades, 2-Hearts, 3-Hearts, 4-Hearts, 5-Hearts, 6-Hearts, 7-Hearts, 8-Hearts, 9-Hearts, 10-Hearts, J-Hearts, Q-Hearts, K-Hearts, A-Hearts, 2-Clubs, 3-Clubs, 4-Clubs, 5-Clubs, 6-Clubs, 7-Clubs, 8-Clubs, 9-Clubs, 10-Clubs, J-Clubs, Q-Clubs, K-Clubs, A-Clubs, 2-Diamonds, 3-Diamonds, 4-Diamonds, 5-Diamonds, 6-Diamonds, 7-Diamonds, 8-Diamonds, 9-Diamonds, 10-Diamonds, J-Diamonds, Q-Diamonds, K-Diamonds, A-Diamonds]
Shuffled deck: [6-Diamonds, 9-Hearts, Q-Diamonds, 2-Hearts, 7-Hearts, A-Clubs, J-Clubs, A-Hearts, 3-Clubs, 4-Hearts, 3-Hearts, Q-Clubs, 9-Clubs, 6-Hearts, K-Clubs, 8-Clubs, 2-Diamonds, J-Hearts, J-Spades, 4-Diamonds, A-Spades, 7-Clubs, 3-Diamonds, 4-Clubs, Q-Spades, 5-Spades, 5-Hearts, 10-Clubs, 2-Spades, 5-Clubs, K-Hearts, K-Diamonds, 4-Spades, A-Diamonds, 6-Spades, 9-Spades, 3-Spades, 10-Spades, 7-Diamonds, K-Spades, J-Diamonds, 7-Spades, 6-Clubs, 5-Diamonds, 8-Spades, 10-Diamonds, 9-Diamonds, Q-Hearts, 10-Hearts, 8-Hearts, 2-Clubs, 8-Diamonds]
Removed card: 6-Diamonds
The card that was removed from the deck is the 6 of Diamonds
The deck after a card was removed: [9-Hearts, Q-Diamonds, 2-Hearts, 7-Hearts, A-Clubs, J-Clubs, A-Hearts, 3-Clubs, 4-Hearts, 3-Hearts, Q-Clubs, 9-Clubs, 6-Hearts, K-Clubs, 8-Clubs, 2-Diamonds, J-Hearts, J-Spades, 4-Diamonds, A-Spades, 7-Clubs, 3-Diamonds, 4-Clubs, Q-Spades, 5-Spades, 5-Hearts, 10-Clubs, 2-Spades, 5-Clubs, K-Hearts, K-Diamonds, 4-Spades, A-Diamonds, 6-Spades, 9-Spades, 3-Spades, 10-Spades, 7-Diamonds, K-Spades, J-Diamonds, 7-Spades, 6-Clubs, 5-Diamonds, 8-Spades, 10-Diamonds, 9-Diamonds, Q-Hearts, 10-Hearts, 8-Hearts, 2-Clubs, 8-Diamonds]

The next steps

Now, this is it as far as your first question goes. But as you are a beginner and you wanted some pointers I've decided to give you some pointers on what to do next and how you could do it :) I know it's quite a lot to take in, but I am sure you will get your head around it. In the next few sections, I will show you can you can actually draw cards from the deck and deal them to players.

A few sentences ago I mentioned

dealing in the real-world involves first drawing a card then giving it to a player, who then accepts that card and puts it in his hand

The nouns in this sentence should be your next classes and the verbs should be your next methods. So that would be:

  • Hand
    • a collection of cards
    • ability to add and remove cards from the hand
  • Player
    • ability to accecpt a card an put it into his/ her hand
    • should have a Hand which is again a collection of Cards
  • Croupier (for the dealing cards part in the sentence)
    • Croupier is a player and has additional properties and abilities
    • needs a Deck of cards which he/ she can deal to players
    • ability to draw a card from the Deck and deal it to a player

Hand

A hand is a set of cards (I am using the Java data structure HashSet here) and there is a total value of all cards, so this should be the attributes. Additionally a Hand should allow to add and remove cards to it, this will be our methods. When adding and removing we need to adjust the total value of the hand accordingly.

Hand.java

mport java.util.HashSet;
import java.util.Set;

public class Hand {
    private final Set<Card> cards;
    private int totalValue;

    public Hand() {
        this.cards = new HashSet<>();
        this.totalValue = 0;
    }

    /**
     * Add a card to the hand
     * @param card card to be added
     */
    public void addCard(Card card){
        // add card to hand
        cards.add(card);
        // increase total value by value of the card
        totalValue += card.getRank().getValue();
    }

    public void removeCard(Suit suits, Rank rank){
        var searchedCard = new Card(suits, rank);
        // call other remove method which does the actual removal
        removeCard(searchedCard);
    }

    public void removeCard(Card card){
        // remove card if it is present
        cards.remove(card);
        // remove card from total value
        totalValue -= card.getRank().getValue();
    }

    @Override
    public String toString() {
        return "Hand{" +
                "cards=" + cards +
                ", totalValue=" + totalValue +
                '}';
    }
}

Player

Let's move on to the player. A player will have a name and a Hand. Additionally he/ she (a gender is also be possible if you want to assign one btw) should have the ability to accept a card and put it in their hand when a card is dealt to them. A player will also have other abilities like making a decision whether to take on another card or not and other stuff, but that is up to you to extend on that, I will just focus on how accepting/ receiving a card.

Player.java

public class Player {
    // protected is a necessary access qualifier so subclasses of Player (Croupier will also have the property name and hand without specifically stating that, see Croupier.java) 
    protected String name;
    protected Hand hand;

    public Player(String name) {
        this.name = name;
        this.hand = new Hand();
        System.out.printf("Player %s has joined the game.\n", name);
    }

    /**
     * Receive a card and add it to the hand
     * @param card card to be received
     */
    public void receiveCard(Card card){
        // add card to hand
        hand.addCard(card);
    }

    @Override
    public String toString() {
        return "Player{" +
                "name='" + name + '\'' +
                ", hand=" + hand +
                '}';
    }

    public String getName() {
        return name;
    }
}

Croupier

Now it gets interesting as a croupier is a player with all the abilities and properties of a player but he/ she also has more abilities and properties. To reflect that in Java we use a feature called inheritance. So a Croupier has everything a Player has and more so it extends the Player. Inheritance will allow us to simply define that and we don't have to re-implement everything we have done for the Player again for the Croupier. So we only need to focus on the additional properties and abilities of a Croupier i. e. he/ she gets a deck of cards which he/ she can shuffle and deal to players. To shuffle we just use the shuffle() method of the Deck. To deal a card we use the drawTop() method of the Deckto draw a card from the deck (and get that card returned) and the receiveCard() method of the Player which we pass that drawn card to. This way the top card from the deck will be removed and added to the hand of the player. All this happens in the dealCardTo() method.

Croupier.java

/**
 * Croupier extends Player as he/she is also a Player and should have the same possibilities as a player, but also has additional functionality.
 * Google for Java inheritence for more information
 */
public class Croupier extends Player{
    private final Deck deck;

    public Croupier(String name, Deck deck) {
        // call constructor of superclass player
        super(name);
        this.deck = deck;
    }

    public void dealCardTo(Player player){
        // get one card of the deck
        var cardToDeal = deck.drawTop();
        // deal the card to the player
        player.receiveCard(cardToDeal);
        System.out.printf("%s is dealing a card to %s.\n", name, player.getName());
    }

    // this is just for demo purposes
    public String showDeck(){
        return deck.toString();
    }

    public void shuffleCards(){
        deck.shuffle();
        System.out.printf("Croupier %s has shuffled the cards.\n", name);
    }

    @Override
    public String toString() {
        return "Croupier{" +
                "name='" + name + '\'' +
                ", hand=" + hand +
                ", deck=" + deck +
                '}';
    }
}

Putting it all together

Now we have all necessary features to deal cards to players so here an quick example of how we would do that.

Application.java

public class Application {
    public static void main(String[] args) {               
        System.out.println("""
                +-------------------------------------------------------------------
                | Example: Create players, a deck and deal 1 card to each player
                +-------------------------------------------------------------------
                """);
        // create two players, and the croupier
        var john = new Player("John");
        System.out.println(john);
        var elton = new Player("Elton");
        System.out.println(elton);
        // create a croupier; a groupie is a player and deals cards, so give him a new deck of cards
        var croupierTom = new Croupier("Tom", new Deck());
        System.out.println(croupierTom);
        // a list of all players
        var allPlayers = new ArrayList<Player>();
        allPlayers.add(john);
        allPlayers.add(elton);
        // remember a croupier is also a player because it is a subclass
        allPlayers.add(croupierTom);
        // let the croupier shuffle the cards
        croupierTom.shuffleCards();
        // tell croupier to deal one card to each player (including himself)
        for (var player : allPlayers) {
            croupierTom.dealCardTo(player);
        }
        // now let's see who got which cards
        for (var player : allPlayers) {
            System.out.println(player);
        }
    }
}

Expected output:

+-------------------------------------------------------------------
| Example: Create players, a deck and deal 1 card to each player
+-------------------------------------------------------------------

Player John has joined the game.
Player{name='John', hand=Hand{cards=[], totalValue=0}}
Player Elton has joined the game.
Player{name='Elton', hand=Hand{cards=[], totalValue=0}}
Player Tom has joined the game.
Croupier{name='Tom', hand=Hand{cards=[], totalValue=0}, deck=[2-Spades, 3-Spades, 4-Spades, 5-Spades, 6-Spades, 7-Spades, 8-Spades, 9-Spades, 10-Spades, J-Spades, Q-Spades, K-Spades, A-Spades, 2-Hearts, 3-Hearts, 4-Hearts, 5-Hearts, 6-Hearts, 7-Hearts, 8-Hearts, 9-Hearts, 10-Hearts, J-Hearts, Q-Hearts, K-Hearts, A-Hearts, 2-Clubs, 3-Clubs, 4-Clubs, 5-Clubs, 6-Clubs, 7-Clubs, 8-Clubs, 9-Clubs, 10-Clubs, J-Clubs, Q-Clubs, K-Clubs, A-Clubs, 2-Diamonds, 3-Diamonds, 4-Diamonds, 5-Diamonds, 6-Diamonds, 7-Diamonds, 8-Diamonds, 9-Diamonds, 10-Diamonds, J-Diamonds, Q-Diamonds, K-Diamonds, A-Diamonds]}
Croupier Tom has shuffled the cards.
Tom is dealing a card to John.
Tom is dealing a card to Elton.
Tom is dealing a card to Tom.
Player{name='John', hand=Hand{cards=[7-Spades], totalValue=7}}
Player{name='Elton', hand=Hand{cards=[4-Diamonds], totalValue=4}}
Croupier{name='Tom', hand=Hand{cards=[2-Spades], totalValue=2}, deck=[8-Hearts, 5-Hearts, 9-Hearts, 3-Spades, Q-Hearts, 8-Clubs, 2-Diamonds, 6-Diamonds, 10-Hearts, 2-Hearts, 8-Spades, Q-Clubs, 2-Clubs, Q-Spades, 5-Diamonds, 5-Clubs, 7-Clubs, 4-Hearts, K-Spades, 3-Hearts, 9-Clubs, K-Clubs, Q-Diamonds, A-Clubs, 10-Spades, 4-Clubs, A-Spades, J-Diamonds, 10-Diamonds, 7-Diamonds, J-Hearts, A-Hearts, 5-Spades, A-Diamonds, 4-Spades, 7-Hearts, 6-Hearts, J-Clubs, 9-Diamonds, 6-Spades, J-Spades, 8-Diamonds, 10-Clubs, 6-Clubs, 3-Diamonds, K-Diamonds, 3-Clubs, 9-Spades, K-Hearts]}

Keep in mind that through shuffling your results will probably be slightly different but each player (including the croupier) should have one card in his/ her hand and the deck should have all those cards removed from it.

What to do next?

Now that should give you a good skeleton to implement the rest of the game. There is still a lot to do. The next thing should probably be to create a Game class which represents one game of BlackJack. Again start from the real-world and keep in mind that your design should be a model of that. Always think in terms of abilities (= methods) and properties (= attributes) an instance has. A Game will certainly have a collection of players, a croupier and the ability to start the game. Think about what should happen on the start of the game: The croupier will have to deal cards (we've seen how to do that already) but it won't be just one and there will be decisions being made by the players involved whether they would like to take on another card. And you will need to implement the rules of BlackJack as well as win conditions to determine a winner. You could also implement some stakes for the players and so on and so on.

I hope this has helped you understand what and how you can start and what to do next :) Happy coding :)

Disclaimer: My design is not a gold standard or anything like this, it's just one possible design, there might be other (better) designs. But it's one relatively simple yet powerful enough approach I think.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文