将卡添加到不可变甲板的底部

时间:2016-08-09 22:48:37

标签: c# algorithm data-structures immutability

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

为了练习编码,我决定构建一个无法修改的ImmutableDeck。它的方法返回新的ImmutableDeck并使用out参数返回绘制的Card s。我在Eric Lippert的ImmutableStack上建模,创建了一个Empty Deck,使构造函数变得私密,并且有两个成员:&#34; Top Card&#34;和一个&#34 ;指针&#34;到下一个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现在是套牌中的最后一张卡,以及解决方案如何工作的解释。 / p>

3 个答案:

答案 0 :(得分:3)

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

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

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

解决问题的一个更简单的方法是:将其分解为三个较小的问题:

  • 插入顶部 - 您已经解决了这个问题。
  • 从顶部删除 - 您已经解决了这个问题。
  • 反转甲板。

如何实现反向?好吧,如果牌组是空的那么它已经被逆转了。如果它不是空的,则取出顶部卡片,将其插入空的甲板上,并继续这样做,直到它为空。

所以现在你可以做反向。插入底部是相反的,插入顶部,再次反转。

当然从底部移除也同样容易:反向,从顶部移除,再次反转。

答案 1 :(得分:1)

正如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;
}

注意:我不是百分百肯定会回复第一个电话的实例,但我认为这是有道理的,因为甲板的顶部没有&#39 ;改变。

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

答案 2 :(得分:0)

使用一个列表,该列表会自动将卡片放在卡座的底部。我有类似的东西,我使用List,这对我来说很完美。希望这可以帮助。