Last active
June 18, 2021 13:21
-
-
Save aalmada/fb474790e592145f9a998d963e2cfcc5 to your computer and use it in GitHub Desktop.
Cards deck implemented in C#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#nullable enable | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Diagnostics.CodeAnalysis; | |
namespace NetFabric | |
{ | |
public class Deck<T> | |
: IEnumerable<T> | |
{ | |
struct Card | |
{ | |
public T Value; | |
public bool Drawn; | |
} | |
readonly Card[] _cards; | |
public Deck(IReadOnlyCollection<T> cards) | |
{ | |
_cards = new Card[cards.Count]; | |
using var enumerator = cards.GetEnumerator(); | |
var span = _cards; | |
for (var index = 0; enumerator.MoveNext() && index < span.Length; index++) | |
span[index] = new Card { Value = enumerator.Current, Drawn = false }; | |
} | |
public bool TryDraw(out T value) | |
{ | |
var cards = _cards; | |
for (var index = 0; index < cards.Length; index++) | |
{ | |
ref var card = ref cards[index]; | |
if (card.Drawn) | |
continue; | |
card.Drawn = true; | |
value = card.Value; | |
return true; | |
} | |
value = default!; | |
return false; | |
} | |
public IEnumerable<T> Draw(int count) | |
{ | |
if (count <= 0) | |
yield break; | |
var cards = _cards; | |
// ReSharper disable once ForCanBeConvertedToForeach | |
for (var index = 0; index < cards.Length; index++) | |
{ | |
var card = cards[index]; // iterators cannot have by-reference locals | |
if (card.Drawn) | |
continue; | |
cards[index] = new Card { Value = card.Value, Drawn = true }; | |
yield return card.Value; | |
count--; | |
if (count == 0) | |
yield break; | |
} | |
} | |
public void Shuffle() | |
=> _cards.AsSpan().Shuffle(); | |
public void Shuffle(Random random) | |
=> _cards.AsSpan().Shuffle(random); | |
public void Reset() | |
{ | |
var cards = _cards; | |
for (var index = 0; index < cards.Length; index++) | |
{ | |
ref var card = ref cards[index]; | |
card.Drawn = false; | |
} | |
} | |
public Enumerator GetEnumerator() | |
=> new(this); | |
IEnumerator<T> IEnumerable<T>.GetEnumerator() | |
=> new DisposableEnumerator(this); | |
IEnumerator IEnumerable.GetEnumerator() | |
=> new DisposableEnumerator(this); | |
public struct Enumerator | |
{ | |
readonly Card[] _cards; | |
int _index; | |
internal Enumerator(in Deck<T> deck) | |
{ | |
_cards = deck._cards; | |
_index = -1; | |
} | |
public T Current | |
=> _cards[_index].Value; | |
public bool MoveNext() | |
{ | |
var cards = _cards; | |
while (++_index < cards.Length) | |
{ | |
var card = cards[_index]; | |
if (card.Drawn) | |
continue; | |
return true; | |
} | |
return false; | |
} | |
} | |
class DisposableEnumerator | |
: IEnumerator<T> | |
{ | |
readonly Card[] _cards; | |
int _index; | |
public DisposableEnumerator(in Deck<T> deck) | |
{ | |
_cards = deck._cards; | |
_index = -1; | |
} | |
public T Current | |
=> _cards[_index].Value; | |
object? IEnumerator.Current | |
=> _cards[_index].Value; | |
public bool MoveNext() | |
{ | |
var cards = _cards; | |
while (++_index < cards.Length) | |
{ | |
var card = cards[_index]; | |
if (card.Drawn) | |
continue; | |
return true; | |
} | |
return false; | |
} | |
public void Reset() | |
=> _index = -1; | |
public void Dispose() | |
{ } | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment