0

背景:纸牌游戏;我想以一种干净的方式将牌组中的牌发给游戏中的每个玩家。

这就是我的想法:

public static CardGame.IGame DealAll(this CardGame.IGame objThis, CardGame.Card[] cards)
    {
        if (objThis.Players.Length > 0)
        {
            for (int i = 0; i < cards.Length; i++)
            {
                objThis.Deck.MoveTo(cards[i], objThis.CurrentPlayer.Hand);

                objThis.AdvancePlayer();
            }
        }

        return objThis;
    }

public static Card[] MoveTo(this Card[] objThis, Card card, Card[] cards)
    {
        List<Card> lstCards = cards.ToList();
        List<Card> lstThis = objThis.ToList();

        lstThis.Remove(card);
        lstCards.Add(card);

        objThis = lstThis.ToArray();
        cards = lstCards.ToArray();

        return cards;
    }

当然,您可以看到参考问题。使用 ref 关键字会导致一些看起来不太好看的代码,但这可能是不可避免的。有什么建议么?

我更喜欢一种足够灵活的解决方案来处理其他“传牌”情况(玩家将牌打到牌堆中,将牌从牌堆移到“垃圾”牌组等)。

4

3 回答 3

3

我认为,这对 . 来说是一个糟糕的情况Arrays,它通常不是为了重复添加和删除而设计的。此外,我不会将此作为扩展方法,因为它在您的应用程序中的几个选定位置之外没有相关性。

考虑只使用 List 并拥有一个负责移动的类方法。

public class CardDealer {
...
  private List<Card> _deck;

  // Put the card [c] into [hand], and remove it from the deck.
  public void Deal(List<Card> hand, Card c) {
    _deck.Remove(c);
    hand.Add(c);
  }
}

评论者建议一副牌可能更好地建模为一个队列,这是一个合理的观点,取决于你是否只能从牌组顶部拿牌。如果确实如此,请考虑以下情况:

public class CardDealer {
...
  private Queue<Card> _deck;

  // Put the top card of the deck into the specified hand.
  public void Deal(List<Card> hand) {
    // Deck is a Queue now. No need to specify which card to take.
    Card c = _deck.Dequeue(); 
    hand.Add(c);
  }
}
于 2009-03-15T22:40:04.990 回答
1

嗯,一个简单的方法是首先不使用数组。从一开始就使用列表,您不需要重新分配等 - 只需从牌组中移除并添加到手牌中。不过,您可能需要考虑将 aQueue<T>用于甲板。

更实用的方法是使用不可变集合和 ref 参数,但如果没有一些好的不可变集合类在你身后,这并不是非常实用。(它们可用,但未内置到框架中。)

你为什么将卡片数组传递给方法呢?它不应该只处理甲板上的所有东西吗?在这一点上更容易写:

foreach (Card card in deck)
{
    CurrentPlayer.Hand.Add(card);
    AdvancePlayer();
}
deck.Clear();

(顺便说一句,我不确定你为什么在这里使用扩展方法。这看起来更适合作为实例方法。)

于 2009-03-15T22:38:21.673 回答
0

也许是这样的?

interface ICardPile
{
    ICollection<Card> Cards
    {
        get;
    }
}

interface IOrderedCardPile : ICardPile // FIXME Better name.
{
}

class Deck : ICardPile
{
    private Stack<Card> _cards = new Stack<Card>();

    ICollection<Card> Cards
    {
        get
        {
            return _cards;
        }
    }

    public Deck()
    {
        // TODO Fill deck.
    }

    public void DealCardsTo(IEnumerable<ICardPile> piles, int cardCount)
    {
        for(int i = 0; i < cardCount; ++i)
        {
            foreach(var pile in piles)
                Cards.MoveSomeTo(piles, 1);
        }
    }
}

class Hand : IOrderedCardPile
{
    private HashSet<Card> _cards = new HashSet<Card>();

    ICollection<Card> Cards
    {
        get
        {
            return _cards;
        }
    }
}

// Extension methods
static void MoveSomeTo(this ICardPile pile, ICardPile other, int count)
{
    // Removes cards from the end of pile and puts them at the end of other.

    foreach(Card card in pile.Cards.Reverse().Take(count))
    {
        other.Add(card);
    }

    pile.Cards = pile.Cards.Take(count);
}

static void MoveCardTo(this IOrderedCardPile pile, ICardPile other, Card card)
{
    // Removes card from pile and puts it at the end of other.
    pile.Remove(card);
    other.Add(card);
}

// Examples
Deck deck;
DiscardPile discard;
var hands = new Hand[4];

deck.DealCardsTo(hands, 7);

// Discard all aces.
forach(var hand in hands)
{
    foreach(var card in hand.Cards.Where(card => card.Number == Card.SomeEnum.Ace))
        hand.MoveCardTo(discard, card);
}
于 2009-03-15T23:10:54.417 回答