将卡片添加到不可变卡片组的底部
Adding Cards to the bottom of an immutable Deck
背景: 我创建了一个自定义 Card
结构,其中 Suit
和 Value
属性由枚举表示以模拟扑克牌。我创建了一个 Deck
class,其中包含卡片并有多个操作选项。它将卡片存储为 Queue<Card>
因为这最合乎逻辑并且使大多数实现变得容易。
为了练习编码,我决定构建一个无法修改的 ImmutableDeck
。它的方法 return 新 ImmutableDeck
s 并使用 out
参数来 return 绘制 Card
s。我以 Eric Lippert 的 ImmutableStack
为模型,创建了一个 Empty
Deck,将构造函数设为私有,并有两个成员:"Top Card" 和下一个 [=16] 的 "pointer" =].
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
指针,直到到达终点(空),但我不确定接下来的步骤是什么。
一个好的解决方案将提供正确的工作代码 returns 一个新的 ImmutableDeck
实例,其中传入的 Card
现在是牌组中的最后一张牌以及对解决方案如何工作。
正如 Leandro 所说,有多种方法可以做到这一点。这是我的(使用您已有的 class)。我能看到的唯一问题是它要求您为 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% 确定 return 第一次调用的实例,但我认为自甲板顶部以来这是有意义的没变。
其他注意事项:我能看到的唯一问题(除了我之前提到的)是,如果你有 really big deck,你会遇到一个WhosebugException
。我本可以用与您实施 Bottom
方法类似的方式完成它,但我认为 52 张卡片组不会成为问题,而且我喜欢递归函数:)
首先,如果您对可以廉价访问两端的不可变队列式数据结构感兴趣,请阅读我关于不可变双端队列的文章。
双端队列通常比堆栈和队列复杂得多,但却是非常有趣的数据结构。
您问题的更简单解决方案是:将其分解为三个较小的问题:
- 插入顶部 -- 您已经解决了这个问题。
- 从顶部删除 -- 您已经解决了这个问题。
- 反转一副牌。
如何实现逆向?好吧,如果一副牌是空的,那么它已经被颠倒了。如果它不是空的,则取出最上面的牌,将其插入空的牌组中,并继续这样做直到它是空的。
所以现在你可以反向操作了。插到下面是反的,插到上面,再反。
当然,从底部移除也同样简单:反转,从顶部移除,再反转。
使用一个列表,该列表会自动将卡片放在牌组底部。我有类似的东西,我使用了 List,这对我来说很完美。希望这可以帮助。
背景: 我创建了一个自定义 Card
结构,其中 Suit
和 Value
属性由枚举表示以模拟扑克牌。我创建了一个 Deck
class,其中包含卡片并有多个操作选项。它将卡片存储为 Queue<Card>
因为这最合乎逻辑并且使大多数实现变得容易。
为了练习编码,我决定构建一个无法修改的 ImmutableDeck
。它的方法 return 新 ImmutableDeck
s 并使用 out
参数来 return 绘制 Card
s。我以 Eric Lippert 的 ImmutableStack
为模型,创建了一个 Empty
Deck,将构造函数设为私有,并有两个成员:"Top Card" 和下一个 [=16] 的 "pointer" =].
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
指针,直到到达终点(空),但我不确定接下来的步骤是什么。
一个好的解决方案将提供正确的工作代码 returns 一个新的 ImmutableDeck
实例,其中传入的 Card
现在是牌组中的最后一张牌以及对解决方案如何工作。
正如 Leandro 所说,有多种方法可以做到这一点。这是我的(使用您已有的 class)。我能看到的唯一问题是它要求您为 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% 确定 return 第一次调用的实例,但我认为自甲板顶部以来这是有意义的没变。
其他注意事项:我能看到的唯一问题(除了我之前提到的)是,如果你有 really big deck,你会遇到一个WhosebugException
。我本可以用与您实施 Bottom
方法类似的方式完成它,但我认为 52 张卡片组不会成为问题,而且我喜欢递归函数:)
首先,如果您对可以廉价访问两端的不可变队列式数据结构感兴趣,请阅读我关于不可变双端队列的文章。
双端队列通常比堆栈和队列复杂得多,但却是非常有趣的数据结构。
您问题的更简单解决方案是:将其分解为三个较小的问题:
- 插入顶部 -- 您已经解决了这个问题。
- 从顶部删除 -- 您已经解决了这个问题。
- 反转一副牌。
如何实现逆向?好吧,如果一副牌是空的,那么它已经被颠倒了。如果它不是空的,则取出最上面的牌,将其插入空的牌组中,并继续这样做直到它是空的。
所以现在你可以反向操作了。插到下面是反的,插到上面,再反。
当然,从底部移除也同样简单:反转,从顶部移除,再反转。
使用一个列表,该列表会自动将卡片放在牌组底部。我有类似的东西,我使用了 List,这对我来说很完美。希望这可以帮助。