简体   繁体   English

在确定21点游戏的Java代码中执行哪个类的方法时遇到问题。 非常基础,是编程新手

[英]Having an issue in determining which class to carry out method in java code for Blackjack game. Very basic, new to programming

I'm attempting to make a simple Blackjack game written in Java and consisting of a Blackjack (Tester), Card, Deck, Dealer, Player, and Game class. 我正在尝试制作一个简单的用Java编写的二十一点游戏,该游戏由二十一点(测试器),卡牌,牌组,发牌人,玩家和游戏类组成。

My code is still very much incomplete, but I'm having difficulty determining, once I've created a deck of cards, which class I should be dealing the cards in and how I should be storing the Card objects in both the player and the dealer's hand (arrayLists). 我的代码仍然很不完整,但是一旦创建了纸牌后,我就很难确定应该在哪个类别中处理纸牌以及如何将Card对象存储在播放器和游戏机中。经销商的手(arrayLists)。

For example, I thought I could solve the issue by using hand.add(deck.draw()); 例如,我认为我可以通过使用hand.add(deck.draw());解决问题。 to the player class, thereby adding the Card drawn from my array cards to the arraylist hand. 到玩家类,从而将从我的阵列卡中抽出的Card添加到arraylist手中。 However, in order to do this I have to create a deck object in my player class, which is then different than the deck object that I create in my Game class. 但是,为了做到这一点,我必须在我的玩家类中创建一个套牌对象,该对象不同于我在游戏类中创建的套牌对象。 However, if I draw the card in the Game class using deck.draw(), I'm unsure of how to take that value and store it in the arraylist hand within my Player class. 但是,如果我使用deck.draw()在Game类中绘制卡片,则不确定如何获取该值并将其存储在Player类中的arraylist手中。

Hopefully this is making sense! 希望这是有道理的!

Essentially, my question is if I use my deck.draw method in the Game class which returns a Card, how do I then take that Card and store it in my private arraylist hand in the Player class? 本质上,我的问题是,如果我在Game类中使用我的deck.draw方法返回一个Card,我该如何获取该Card并将其存储在Player类的私有arraylist中? Or is this the wrong approach entirely? 还是这完全是错误的方法?

Thank you for any guidance you can provide!!! 感谢您提供的任何指导!!!

First, seeing your code before your edit, I wanted to point out that I think you're doing pretty well for a new developer,keep at it! 首先,我想指出的是,在编辑之前先看一下代码,我想指出的是,对于新开发者来说,您做得还不错!

I think you simply should keep following the path you're on...you've used domain language to name you're model (Deck, Card, Dealer, etc) and you've got a good start in naming the behavior of those classes based on the model too (draw). 我认为您只是应该继续遵循自己所走的路...您已经使用域语言来命名自己的模型(甲板,卡,经销商等),并且在命名行为方面有了良好的开端。这些类也基于模型(绘制)。 Stick with this... 坚持下去...

Anyway, hope this helps below...it's pseudo-code (in this case, my way of saying I didn't write this on an IDE and I didn't validate the code...but it should be quite close) =) 无论如何,希望这对下面有帮助...它是伪代码(在这种情况下,我的说法是我没有在IDE上编写此代码,也没有验证代码...但是应该很接近)= )

Dealer should manage the Deck, so there should be an aggregate relationship there. 经销商应该管理平台,因此那里应该有一个总体关系。 Since the Dealer has the instance of the Deck (the Deck is backed by an array and its position is recorded by an int, no need for a Collection type) length of 52). 由于发牌人具有Deck的实例(Deck由数组支持,并且其位置由int记录,因此不需要Collection类型),长度为52)。 On construction, the 52 Card instances are added to the array. 在构建时,将52个Card实例添加到阵列。 The Deck indeed had draw, which increments the card position and returns the Card. 牌组确实有平局,这会增加卡的位置并返回卡。

//this interface will make sense a little later
public interface HandManager {

    Card draw();

}

public class Dealer implements HandManager {

    private Card[] deck;
    private int position;

    @Override
    public Card draw () {
         try {
             return deck[position];
         } catch (ArrayOutOfBoundsException ex) {
             //handle when you run out of cards in your deck...do you add another 52?
         } finally {
             position++;
         }
    }
}

The Dealer also has a draw method, that takes just a vararg on players (and deals he initial Hand to all players). 庄家也有一个抽奖方法,该方法只对玩家使用一个变数(并将初始手牌发给所有玩家)。

//also in Dealer
public void deal (Player... players) {
    for (Player p : players) {
        Hand hand = initializeHand(); //we'll get back to this in a bit
        p.addHand(hand);
    }
}

Meanwhile, the Player aggregates the Hand....they own and decide what they want to do with it. 同时,玩家汇总手牌...。他们拥有并决定他们要如何处理。 The Hand shouldn't really be a simple array because it should be able to easily grow, so a List or Set should do (a Set is probably more appropriate in theory...but because you probably don't need to enforce uniqueness here, there isn't need for that overhead really). Hand不应真正是一个简单的数组,因为它应该能够轻松地增长,所以List或Set应该可以做到(Set在理论上可能更合适...但是因为您可能不需要在此处强制唯一性,实际上并不需要这些开销)。 But...to future proof it, so you can change it to a Set later if you want, you should program to the Collection interface (you should always try to program against the highest super class if you can, better for code maintenance). 但是...为了将来进行验证,因此,如果需要,可以稍后将其更改为Set,应该对Collection接口进行编程(如果可能的话,应始终尝试针对最高的超类进行编程,以更好地进行代码维护) 。

public class Player {
    private Hand hand;

    //can be named "setHand" if you only want to support one Hand per player, named 
    //like this because it might be a fun exercise to enable n hands per player later
    public void addHand (Hand hand) {
        this.hand = hand;
    }
}

public interface Hand { 公共接口Hand {

/**
 * Returns the cards currently in the hand.
 *
 * Changes to the returned array are <b>NOT</b> reflected in the hand.
 */
public Card[] getCards();

public void hit();

public void split();

public void fold();

} }

Anyway, player acts on Hand, decides to hit, split, fold, etc. The neat thing here is that, in theory, a Player can mange n hands this way ;) Anyway...here is where some magic comes in which will keep your code cleaner: the 'communication' between Player and Dealer happen through the Hand instance. 无论如何,玩家在牌局上行动,决定击中,分裂,弃牌等。在这里,整洁的事情是,从理论上讲,玩家可以用这种方式管理n手;)无论如何……这是一些神奇的地方保持代码清洁:玩家和发牌人之间的“交流”通过Hand实例进行。 This allows Player to call the shots, but more importantly, allows your applications orchestration to focus not on passing commands from player to dealer and card from dealer to player...but the aspect it needs to: managing the turn based play and knowing when to end the game. 这允许播放器做主,但更重要的是,允许您的应用程序编排不着重于从播放器向发牌人传递命令以及从发牌者向发牌人传递卡片...而是需要的方面:管理基于回合的比赛并知道何时结束游戏。

public class ManagedHand implements Hand {

    private Collection<Card> cards;
    private HandManager manager;

    public Hand (HandManager manager, Card[] cards) {
        this.manager = manager;
        cards = Arrays.asList(cards); //to make this a set, simply pass this into a HashSet constructor =)
    }

    /**
     * Returns the cards currently in the hand.
     *
     * Changes to the returned array are <b>NOT</b> reflected in the hand.
     */
    public Card[] getCards() {
        //bonus lesson: look up "defensive copy"
        return cards.toArray(new Card[cards.size()]);
    }

    @Override
    public void hit() {
        if (isBust()) {
            throw new BustException("Need to wait for next hand!");
        }
        //***RIGHT HERE, Dealer (the HandManager) gives the card on draw request****
        cards.add(manager.draw());
    }

    @Override
    public void split() {
        if (isBust()) {
            throw new BustException("Need to wait for next hand!");
        }
        //do split...beyond demo code scope =)
    }

    @Override
    public void fold() {
        //clean up, take money/car/happiness
    }

    @Override
    public String toString() {
        //pretty-print the current hand
    }

}


//the initializeHand method is Dealer that I promised
public Hand initializeHand() {
    Card[] initialHand = new Card[INIT_HAND_SIZE];
    for (int i =0; i<INIT_HAND_SIZE; i++) {
        initialHand[i] = draw();
    }

    //****Dealer registers itself as a HandManager to the Hand**********
    return new ManagedHand(this, initialHand);
}

Since Dealer instantiates (creates) Hand, it had the opportunity to register a listener (itself, in this case) for Player actions on the Hand. 由于发牌者实例化(创建)手牌,因此它有机会为该手牌上的玩家动作注册侦听器(在本例中为自身)。 Since the Player is given the instance of Hand, take action on the Hand...the Hand does the validation itself (ie checks if itself isn't bust before requesting more cards) in this implementation (just because it would be a more complex example to have Dealer do it) and the manager is "notified" when more cards are needed. 由于给了玩家Hand的实例,因此在Hand上采取行动... Hand在此实现中自行进行验证(即,在请求更多卡牌之前检查自身是否没破门)(因为这样做会更复杂)例如让交易商这样做),并且在需要更多卡时会“通知”经理。

Side note: This could have been built out a little more, but in general, it kinda-sorta follows what is called the Observer Pattern . 旁注:本可以增加一些,但通常来说,它有点类似于观察者模式 It might not be a perfect match for this pattern...but you should check it out...and read all about design patterns. 这可能不是这种模式的完美匹配...但是您应该检查一下...并阅读有关设计模式的所有信息。 Learning these early in your career, you'll quickly become a rockstar. 在您职业生涯的早期学习这些知识,您将很快成为摇滚明星。

One approach would be to have a function in the Player class called something like AddCard 一种方法是在Player类中具有一个名为AddCard类的函数。

public class Player
{
    private ArrayList<Card> hand;

    public Player()
    {
        hand = new ArrayList<Card>();
    }

    public void AddCard(Card aCard)
    {
        hand.Add(aCard);
    }
}

Since the cards in a player's hand have no inherent order to them, I think it makes more sense to use some kind of Set (such as a HashSet to store them) than an ordered structure like an ArrayList . 由于玩家手中的纸牌没有固有顺序,因此我认为使用某种Set (例如HashSet来存储它们)比像ArrayList这样的有序结构更有意义。 I might write something like this. 我可能会写这样的东西。 You'll see I've assumed that the draw method of the Deck class returns null if there are no cards left. 您将看到,我假设如果没有卡片,则Deck类的draw方法将返回null。

public class Player {
    private Set<Card> hand;
    private String name;

    public Player(String name) {
        this.name = name;
        this.hand = new HashSet<Card>();
    }

    public boolean takeCard(Deck toTakeFrom) {
        Card drawn = toTakeFrom.draw();
        if (drawn != null) {
            hand.add(drawn);
            return true;
        } else {
            System.out.format("Sorry, %s, no cards remain in the deck.%n", name);
            return false;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM