背景:纸牌游戏;我想以一种干净的方式将卡牌从牌组中交给每个玩家。
这就是我的想法:
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关键字会导致一些看起来不太好看的代码,但它可能是不可避免的。有什么建议吗?
我更喜欢一种足够灵活的解决方案,可以处理其他“卡片传递”情况(玩家将牌打到堆中,将牌从堆中移到“垃圾”牌组等)。
答案 0 :(得分: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);
}
}
答案 1 :(得分:1)
嗯,一个简单的方法是首先不使用数组。从一开始就使用列表,您不需要重新分配等 - 只需从卡座中移除并添加到手中。您可能想考虑使用Queue<T>
作为套牌。
使用不可变集合和ref参数的功能更多,但如果没有一些好的不可变集合类,那么这种方法并不十分实用。 (它们可用,但没有内置到框架中。)
为什么要将卡片组传递给方法呢?它不应该只是处理甲板上的所有东西吗?此时写起来更容易:
foreach (Card card in deck)
{
CurrentPlayer.Hand.Add(card);
AdvancePlayer();
}
deck.Clear();
(我不确定你为什么在这里使用扩展方法,顺便说一句。这看起来像是一个更合适的实例方法。)
答案 2 :(得分: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);
}