将牌添加到不可变牌组的底部

本文关键字:底部 添加 不可变 | 更新日期: 2023-09-27 18:01:49

Background:我创建了一个自定义的Card结构体,其中SuitValue属性由枚举表示,以模拟扑克牌。我创建了一个Deck类,其中包含卡片,并有几个操作它们的选项。它将卡片存储为Queue<Card>,因为这样最符合逻辑,并且使大多数实现更容易。

为了练习编码,我决定构建一个不能修改的ImmutableDeck。它的方法返回新的ImmutableDeck s,并使用out参数返回绘制的Card s。我模仿了Eric Lippert的ImmutableStack,创建了一个Empty Deck,使构造函数私有,并有两个成员:"Top Card"和一个指向下一个ImmutableDeck的"指针"。

public class ImmutableDeck
{
    static readonly EmptyDeck Empty = new EmptyDeck ();
    readonly Card top;
    readonly ImmutableDeck next;
    ImmutableDeck ()
    {
    }
    ImmutableDeck (Card top, ImmutableDeck next)
    {
        this.top = top;
        this.next = next;
    }
    public int Count => 1 + next.Count;
    public bool IsEmpty => this == Empty;
    public Card Top => top;
    public Card Bottom ()
    {
        var temp = next;
        while (!temp.next.IsEmpty)
        {
            temp = temp.next;
        }
        return temp.Top;
    }
    public ImmutableDeck DrawCard (out Card c)
    {
        c = top;
        return next;
    }
    public ImmutableDeck PutCardOnTop (Card c)
    {
        return new ImmutableDeck (c, this);
    }
    public ImmutableDeck PutCardOnBottom (Card c)
    {
        throw new NotImplementedException ("PutCardOnBottom");
    }

    public class EmptyDeck : ImmutableDeck
    {
        public new int Count
        {
            get;
        } = 0;
        public new bool IsEmpty
        {
            get;
        } = true;
        public new Card Top
        {
            get
            {
                throw new Deck.DeckEmptyException ();
            }
        }
        public new Card Bottom ()
        {
            throw new Deck.DeckEmptyException ();
        }
        public new ImmutableDeck DrawCard (out Card c)
        {
            throw new Deck.DeckEmptyException ();
        }
        public new ImmutableDeck PutCardOnTop (Card c)
        {
            return new ImmutableDeck (c, this);
        }
        public new ImmutableDeck PutCardOnBottom (Card c)
        {
            return new ImmutableDeck (c, this);
        }
    }
}

问题:显然,这些牌组可以通过在空牌组上的牌组上的牌组来构建。它相当强大。但我正在努力实现一种允许将Card添加到底部的方法。到目前为止,我所想到的是,我需要跟随next指针通过链,直到我到达结束(空),但我不确定下一步是什么。

一个好的解决方案将提供工作代码,正确返回一个新的ImmutableDeck实例,其中Card传递的现在是牌堆中的最后一张牌,以及解决方案如何工作的解释。

将牌添加到不可变牌组的底部

首先,如果您对具有对两端廉价访问的不可变队列式数据结构感兴趣,请阅读我关于不可变队列的文章。

https://blogs.msdn.microsoft.com/ericlippert/2008/01/22/immutability-in-c-part-10-a-double-ended-queue/

deque通常比堆栈和队列复杂得多,但却是非常有趣的数据结构。

解决你的问题的一个更简单的方法是:把它分解成三个小问题:

  • 插入到顶部——你已经解决了这个问题。
  • 从顶部删除——你已经解决了这个问题。
  • 翻转甲板

如何实现反向?如果一副牌是空的,那么它就已经反转了。如果它不是空的,然后移除顶部的牌,将它插入到一个空的牌组,并继续这样做,直到它是空的。

现在你可以反向操作了。插入到底部是反向的,插入到顶部,再反向。

当然从底部移除也很简单:反转,从顶部移除,再反转

正如Leandro所说,有多种方法可以做到这一点。这是我的(使用您已经拥有的相同类)。我能看到的唯一问题是,它要求您为next字段分配一个值,这在您的实现中是只读的。我明白为什么会这样(你不能修改另一张卡下的内容,然后再把那张卡拿出来),但在这种情况下,我确信它是可以做到的,而不改变这个字段。

Public ImmutableDeck PutCardOnBottom (Card c)
{
    if (!this.next.IsEmpty)
        this.next.PutCardOnBottom(c);
    else
        this.next = new ImmutableDeck(c, ImmutableDeck.Empty);
    return this;
}

注释:我不是100%确定返回第一个调用的实例,但我认为这是有意义的,因为甲板的顶部没有改变。

其他注意事项:我能看到的唯一问题是(除了我之前注意到的),如果你有一个真的大牌组,你会遇到StackOverflowException。我本可以用类似于Bottom方法的实现方式来完成它,但我认为52张牌不会是一个问题,我喜欢递归函数:)

使用一个列表,它会自动将牌放在你的牌堆的底部。我也有类似的东西,我使用List,它对我来说非常有效。希望这能有所帮助。