将牌添加到不可变牌组的底部
本文关键字:底部 添加 不可变 | 更新日期: 2023-09-27 18:01:49
Background:我创建了一个自定义的Card
结构体,其中Suit
和Value
属性由枚举表示,以模拟扑克牌。我创建了一个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,它对我来说非常有效。希望这能有所帮助。