public override Hand newHand(Hand Hand)
        {
            var StraightCards = new List<Card>();
            Card PreviousCard = null;

            var Cards = Hand.getCards();
            Cards.Sort((Card1, Card2) => { return Card1.compareTo(Card2); });

            foreach (var Card in Cards) {
                if (PreviousCard is Card) {
                    if (Card.compareFaceValue(PreviousCard) == 0) {
                        continue;
                    } else if (PreviousCard.isAce() && Card.getFaceValue() == 5) { // Wheels are Straights too, you know
                        StraightCards.Add(Card);
                    } else if (PreviousCard.getFaceValue() - 1 == Card.getFaceValue()) {
                        StraightCards.Add(Card);
                    } else {
                        StraightCards = new List<Card> { Card };
                    }
                } else {
                    StraightCards.Add(Card);
                }

                PreviousCard = Card;
                if (StraightCards.Count == 5) {
                    return new Straight(StraightCards);
                }
            }

            return null;
        }
        public Hand identify(List<Card> Cards)
        {
            Cards.Sort((Card1, Card2) => { return Card1.compareTo(Card2); });
            Hand Hand = new Hand(Cards);

            HandSpecification[] SpecsInValueOrder = {
                new RoyalFlushSpecification(),
                new SteelWheelSpecification(),
                new StraightFlushSpecification(),
                new FourOfAKindSpecification(),
                new FullHouseSpecification(),
                new FlushSpecification(),
                new WheelSpecification(),
                new StraightSpecification(),
                new ThreeOfAKindSpecification(),
                new TwoPairSpecification(),
                new TwoOfAKindSpecification(),
            };

            foreach (HandSpecification Specification in SpecsInValueOrder) {
                if (Specification.isSatisfiedBy(Hand)) {
                    return Specification.newHand(Hand);
                }
            }

            return new HighCard(Cards);
        }
        public override Hand newHand(Hand hand)
        {
            var groupedByValue = hand.getCardsGroupedByValues();
            var highestValue = groupedByValue.First().Value;
            groupedByValue.Remove(groupedByValue.First().Key);
            var handCards = new List<Card>();

            if (highestValue.Count == numberOfCards) {
                handCards.AddRange(highestValue);
                handCards.AddRange(groupedByValue.First().Value.Take(1));
            } else {
                handCards.AddRange(highestValue.Take(1));

                while (groupedByValue.Count > 0 && handCards.Count < 5) {
                    var cardsOfValue = groupedByValue.First().Value;
                    groupedByValue.Remove(groupedByValue.First().Key);

                    if (cardsOfValue.Count == numberOfCards) {
                        handCards.AddRange(cardsOfValue);
                    }
                }
            }

            if (handCards.Count == 5) {
                return (Hand) Activator.CreateInstance(handClass, new object[] { handCards });
            } else {
                return null;
            }
        }
        public override bool isSatisfiedBy(Hand Hand)
        {
            var handIsARoyalFlush = (
                (Hand.getHighCard().getFaceValue() == Card.ACE) &&
                base.isSatisfiedBy(Hand)
            );

            return handIsARoyalFlush;
        }
        public override Hand newHand(Hand Hand)
        {
            var StraightFlush = base.newHand(Hand);

            if (StraightFlush is StraightFlush && StraightFlush.getHighCard().getFaceValue() == Card.ACE) {
                return new RoyalFlush(StraightFlush.getCards());
            }

            return null;
        }
        public override Hand newHand(Hand Hand)
        {
            var StraightFlush = base.newHand(Hand);

            if (StraightFlush is Hand && StraightFlush.isWheel()) {
                return new SteelWheel(StraightFlush.getCards());
            } else {
                return null;
            }
        }
        public override Hand newHand(Hand Hand)
        {
            var Straight = base.newHand(Hand);

            if (Straight is Hand && Straight.isWheel()) {
                return new Wheel(Straight.getCards());
            } else {
                return null;
            }
        }
        public override Hand newHand(Hand Hand)
        {
            var SpadesCards = new List<Card>();
            var HeartsCards = new List<Card>();
            var ClubsCards = new List<Card>();
            var DiamondsCards = new List<Card>();

            var Cards = Hand.getCards();
            Cards.Sort((Card1, Card2) => { return Card1.compareTo(Card2); });

            foreach (var Card in Cards) {
                switch (Card.getSuit()) {
                    case Suit.SPADES:
                        if (canAddCardTo(SpadesCards, Card)) {
                            SpadesCards.Add(Card);
                            if (SpadesCards.Count == 5) {
                                return new StraightFlush(SpadesCards);
                            }
                        }
                        break;

                    case Suit.HEARTS:
                        if (canAddCardTo(HeartsCards, Card)) {
                            HeartsCards.Add(Card);
                            if (HeartsCards.Count == 5) {
                                return new StraightFlush(HeartsCards);
                            }
                        }
                        break;

                    case Suit.CLUBS:
                        if (canAddCardTo(ClubsCards, Card)) {
                            ClubsCards.Add(Card);
                            if (ClubsCards.Count == 5) {
                                return new StraightFlush(ClubsCards);
                            }
                        }
                        break;

                    case Suit.DIAMONDS:
                        if (canAddCardTo(DiamondsCards, Card)) {
                            DiamondsCards.Add(Card);
                            if (DiamondsCards.Count == 5) {
                                return new StraightFlush(DiamondsCards);
                            }
                        }
                        break;
                }
            }

            return null;
        }
        public override bool isSatisfiedBy(Hand Hand)
        {
            int numPairsSeen = 0;
            var CardsGroupedByValues = Hand.getCardsGroupedByValues();
            foreach (var Cards in CardsGroupedByValues) {
                if (Cards.Value.Count == 2) {
                    numPairsSeen++;
                }
            }

            var canMakeTwoPair = (2 == numPairsSeen);
            return canMakeTwoPair;
        }
        public override bool isSatisfiedBy(Hand Hand)
        {
            var GroupedByValue = Hand.getCardsGroupedByValues();
            var faceValueCounts = new Dictionary<int, int>();

            foreach (KeyValuePair<int, List<Card>> cardsAndValue in GroupedByValue) {
                faceValueCounts.Add(cardsAndValue.Key, cardsAndValue.Value.Count);
            }

            int highestCount = 0;
            foreach (KeyValuePair<int, int> faceValueAndCount in faceValueCounts) {
                if (faceValueAndCount.Value > highestCount) {
                    highestCount = faceValueAndCount.Value;
                }
            }

            return highestCount == numberOfCards;
        }
        public override Hand newHand(Hand Hand)
        {
            var SpadesCards = new List<Card>();
            var HeartsCards = new List<Card>();
            var ClubsCards = new List<Card>();
            var DiamondsCards = new List<Card>();

            foreach (var Card in Hand.getCards()) {
                switch (Card.getSuit()) {
                    case Suit.SPADES:
                        SpadesCards.Add(Card);
                        if (SpadesCards.Count == 5) {
                            return new Flush(SpadesCards);
                        }
                        break;

                    case Suit.HEARTS:
                        HeartsCards.Add(Card);
                        if (HeartsCards.Count == 5) {
                            return new Flush(HeartsCards);
                        }
                        break;

                    case Suit.CLUBS:
                        ClubsCards.Add(Card);
                        if (ClubsCards.Count == 5) {
                            return new Flush(ClubsCards);
                        }
                        break;

                    case Suit.DIAMONDS:
                        DiamondsCards.Add(Card);
                        if (DiamondsCards.Count == 5) {
                            return new Flush(DiamondsCards);
                        }
                        break;
                }
            }

            return null;
        }
        public override Hand newHand(Hand hand)
        {
            var groupedByValue = hand.getCardsGroupedByValues();
            var handCards = groupedByValue.First().Value;
            groupedByValue.Remove(groupedByValue.First().Key);

            if (handCards.Count == numberOfCards) {
                handCards.Add(groupedByValue.First().Value.First());
                groupedByValue.Remove(groupedByValue.First().Key);
            } else {
                handCards.AddRange(
                    groupedByValue.Where(
                        cardsOfValue => {
                    return cardsOfValue.Value.Count == numberOfCards;
                }
                    ).First().Value
                );
            }

            int cardsLeftToAdd = 5 - handCards.Count;

            while (cardsLeftToAdd > 0 && groupedByValue.Count > 0) {
                var cardsOfValue = groupedByValue.First().Value;
                groupedByValue.Remove(groupedByValue.First().Key);

                while (cardsLeftToAdd > 0 && cardsOfValue.Count > 0) {
                    var nextCard = cardsOfValue.First();
                    cardsOfValue.Remove(nextCard);
                    handCards.Add(nextCard);
                    cardsLeftToAdd--;
                }
            }

            if (handCards.Count == 5) {
                return (Hand) Activator.CreateInstance(handClass, new object[] { handCards });
            } else {
                return null;
            }
        }
 public abstract Hand newHand(Hand Hand);
 public override Hand newHand(Hand Hand)
 {
     return new TwoPair(Hand.getCards());
 }
 public override bool isSatisfiedBy(Hand Hand)
 {
     return newHand(Hand) is Flush;
 }
 public abstract bool isSatisfiedBy(Hand Hand);
 public override bool isSatisfiedBy(Hand Hand)
 {
     return newHand(Hand) is Straight;
 }
 public override bool isSatisfiedBy(Hand Hand)
 {
     return base.isSatisfiedBy(Hand) && Hand.isWheel();
 }