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だと思います。また、アプリケーションで選択したいくつかの場所以外には関連性がないため、これを拡張メソッドにはしません。

代わりにリストに固執し、移動を担当するクラスメソッドを持つことを検討してください。

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

簡単な方法の 1 つは、そもそも配列を使用しないことです。最初からリストを使用し、再割り当てなどの必要はありません。デッキから削除して手札に追加するだけです。Queue<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 に答える