面向对象编程设计纸牌游戏类

5
设计以下类时,应用哪种设计模式最好?
- Deck - addCard, deal, shuffle, getTopCard, removeTopCard, removeAllCards - Hand - addCard, removeCard, getCard,removeAllCards - DiscardPile - addCard, getTopCard, removeTopCard, removeAllCards - MeldPile - addCard, removeAllCards
(MeldPile保存桌子上的所有合并项)
对我来说,getTopCard和removeTopCard只是getCard和removeCard的包装器,因为它只获取卡片的顶部位置,然后将其传递给getCard或removeCard。
我应该使用组合?策略模式?还是只需创建另一个名为CardPile的类,并将其用作上述类的基类?如果您可以提供示例代码,则不胜感激。

3
最好的方法是开始编写游戏规则,让你的设计自然而然地发展。如果你有一个具体的问题,例如“我正在尝试实现这样一条规则:如果一个玩家出牌,另一个玩家必须弃牌,我应该使用什么模式?”那么这个问题是可以回答的。 - Garrett Hall
1
+1 是指“让你的设计自然演化”。 - radarbob
小心将“自然发生”的类变成亚原子粒子基类。类层次结构可能会变得过于深入,出现不必要的通用处理。如果您的“自然设计演进”需要更普遍的基础来派生新功能,则随时可以进行重构。 - radarbob
这是作业还是面试题? - gonzobrains
1个回答

6

我认为您可以使用以下类似的单一牌堆类来实现您想要的功能,它本质上是对 Stack 的封装。我不明白为什么任何特定的牌堆/堆叠/手牌不想要大部分甚至全部相同的方法。

class Deck {
    private Stack<Card> cards = new Stack<Card>();

    public Deck() { }

    public Deck(int numberOfCards) {
        for (int i=0; i<numberOfCards; i++) {
            cards.push(CardFactory.createCard(i));
        }
    }

    private void shuffle() {
        Collections.shuffle(this.cards);
    }

    public void sort() {
        Collections.sort(this.cards);
    }

    public void removeAllCards() {
        this.cards.removeAllElements();
    }

    public void removeCard(Card c) {
        int i = this.cards.search(c);
        this.cards.remove(i);            
    }

    public Card getCard(Card c) {
        int i = this.cards.search(c);
        return this.cards.get(i);
    }

    public Card getTopCard() {
        return this.cards.pop();
    }

    public Card getNthCard(int i) {
        return this.cards.get(i);
    }

    public Card addCard(Card c) {
        this.cards.push(c);
    }

}

我认为唯一真正的问题在于deal()方法,以及这是否应该是Deck的职责?个人认为不是,这让我想到可能需要Player类和Dealer类来扩展Player,并实现处理牌堆的逻辑。

class Player() {
    protected String name;
    protected Deck hand = new Deck();

    public void addCard(Card c) {
        this.hand.addCard(c);
    }

    // .....
}

class Dealer() extends Player {
    private Deck deck;

    public Dealer(int deckSize) {
        this.deck = new Deck(deckSize);
    }

    public void deal(Player[] players, int numberOfCards) {
        for (player in players) {
            for (int i=0; i<numberOfCards; i++) {
                player.addCard(this.deck.getTopCard());
            } 
        }
    }

    // .....
}

我并不真正理解什么是合并堆,或者它的作用听起来有点像魔法风云会(MtG),它属于玩家吗?例如一个类似于魔法风云会的游戏(从我简短的游戏经验中),玩家会有一副牌、一手牌、元素力量打出的牌和怪物打出的部分,我认为所有这些都可以是“牌堆”,尽管您可能希望创建一个基础类“Deck”,它不实现shuffle()等方法,并将其用作“较小的牌堆”。 - T I
我同意你关于发牌方法的看法,它不应该作为一副牌的一部分,因为发牌是庄家的行为。一个合并堆是一个玩家放在桌子上的一组牌(三张相同的牌、四张相同的牌和顺子)。我只是无法决定要实现什么,因为大多数开源纸牌游戏使用不同的类来处理牌堆、手牌和弃牌堆,而其他人则创建了一个CardPile并将其用作基类。 - Zack
我建议先使用一个单一的 CardPile 基类,该类将封装添加和删除卡片的功能。你可以从中继承出 Deck(可洗牌和“魔法创建”),MeldPile(具有自己的卡片规则)和 Hand(可以设置最大允许的卡片数量和丢弃规则)。更重要的是,我认为最好先开始一些东西,避免“模式病”,如果需要的话再进行重构/优化代码。 - T I

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接