private bool isHighCard(HandInfo hi, out FullRank fRank, out HandCard[] hcsRank, out HandCard[] hcsFill) { // Note: Any hand with 2+ cards and at least one wild card contains a pair. hcsRank = new HandCard[0]; List <HandCard> fillTamed; List <HandCard> fillPlain; Util.TakeFill(NumCardsInFinalHand, hi.CardsUnbound, out fillTamed, hi.CardsPlain.OrderByDescending(hc => hc.Value), out fillPlain); foreach (HandCard hc in fillTamed) { hc.TamedValue = TValue.Ace; } hcsFill = fillPlain.Reverse <HandCard>().Concat(fillTamed).ToArray(); TValue[] vals = fillTamed .Select(hc => hc.TamedValue) .Concat(fillPlain.Select(hc => hc.Value)) .ToArray(); fRank = new FullRank(SimpleRank.HighCard, vals); return(true); }
private bool isStraightOrStraightFlushN(HandInfo hi, out FullRank fRank, out HandCard[] hcsRank, out HandCard[] hcsFill, bool isFlushRequired, int n) { bool isStraight = false; bool isStraightFlush = false; TValue minVal = TValue.NoValue; // Suppress compiler warning TValue maxVal; IEnumerable <IGrouping <TValue, HandCard> > valueGroups = null; TSuit flushSuit = TSuit.NoSuit; // Note: The loop could be started at Max(hcsPlain.Value) + hi.UnboundCount() for (maxVal = TValue.Ace; maxVal >= (TValue)n; // TValue.Five maxVal = maxVal.Prev()) { minVal = maxVal.Prev(n - 1); valueGroups = hi.CardsPlain .Where(hc => (hc.Value >= minVal && hc.Value <= maxVal) || (minVal == TValue.LowAce && hc.Value == TValue.Ace)) .GroupBy(hc => hc.Value); isStraight = valueGroups.Count() >= n - hi.UnboundCount(); if (isStraight && isFlushRequired) { foreach (TSuit s in Card.Suits) { if (valueGroups.All(grp => grp.Any(hc => hc.Suit == s))) { flushSuit = s; isStraightFlush = true; break; } } } if (isStraight && (isStraightFlush || !isFlushRequired)) { break; } } if (!isStraight || (isFlushRequired && !isStraightFlush)) { setToNull(out fRank, out hcsRank, out hcsFill); return(false); } Func <HandCard, bool> pred = null; if (isFlushRequired) { pred = hc => hc.Suit == flushSuit; } IEnumerable <HandCard> hcsAvail = valueGroups.EnumerableChoice(pred); hcsRank = new HandCard[n]; hcsFill = new HandCard[NumCardsInFinalHand - n]; int index = 0; List <HandCard> hcsUnbound = new List <HandCard>(hi.CardsUnbound); // Need random access for (TValue val = minVal; val <= maxVal; val = val.Next()) { HandCard nextCard = hcsAvail.Where(hc => hc.Value == val).FirstOrDefault(); if (nextCard != null) { hcsRank[index] = nextCard; } else { Debug.Assert(hcsUnbound.Count > 0, "Error: Not enough cards to form straight"); IEnumerable <HandCard> hcDesired = hcsUnbound.Where(hc => hc.Value == val).Take(1); if (hcDesired.Count() > 0) { hcsRank[index] = hcDesired.ElementAt(0); hcsUnbound.Remove(hcsRank[index]); } else { hcsRank[index] = hcsUnbound[0]; hcsUnbound.RemoveAt(0); } hcsRank[index].TamedValue = val; if (isFlushRequired) { hcsRank[index].TamedSuit = flushSuit; } } index++; } fRank = new FullRank( isFlushRequired ? SimpleRank.StraightFlush5 : SimpleRank.Straight5, Enumerable.Range((int)minVal, ((int)maxVal - (int)minVal) + 1) .OrderByDescending(x => x) .Select(x => (TValue)x) .ToArray() ); return(true); }
private bool isKindN( HandInfo hi, out FullRank fRank, out HandCard[] hcsRank, out HandCard[] hcsFill, int n, int maxFillCount = int.MaxValue) { Contract.Requires(n >= 2 && n <= 5, String.Format("Error: Unrecognized n-of-a-kind: {0:d}", n)); bool hasKindN = (!hi.HasPlainCards() && hi.UnboundCount() >= n) || (hi.ValueGram.Values.Max() >= n - hi.UnboundCount()); if (!hasKindN) { setToNull(out fRank, out hcsRank, out hcsFill); return(false); } TValue kindVal; int numChosen; HandCard[] hcsChosen; var plainValues = hi.ValueGram.Keys; if (plainValues.Count() == 0) { kindVal = TValue.Ace; numChosen = 0; hcsChosen = new HandCard[0]; } else { kindVal = plainValues.Where(val => hi.ValueGram[val] >= n - hi.UnboundCount()).Max(); HandCard[] hcsAvail = hi.CardsPlain.Where(hc => hc.Value == kindVal).ToArray(); numChosen = Math.Min(n, hcsAvail.Count()); hcsChosen = hcsAvail.Take(numChosen).ToArray(); } int numTamed = Math.Min(n - numChosen, hi.UnboundCount()); HandCard[] hcsTamed = hi.CardsUnbound.Take(numTamed).ToArray(); foreach (HandCard hc in hcsTamed) { hc.TamedValue = kindVal; } List <HandCard> fillTamed; List <HandCard> fillPlain; Util.TakeFill(Math.Min(NumCardsInFinalHand - n, maxFillCount), hi.CardsUnbound.Except(hcsTamed).OrderByDescending(hc => hc.Value), out fillTamed, hi.CardsPlain.Except(hcsChosen).OrderByDescending(hc => hc.Value), out fillPlain); foreach (HandCard hc in fillTamed) { hc.TamedValue = TValue.Ace; } SimpleRank sRank; switch (n) { case 5: sRank = SimpleRank.Kind5; break; case 4: sRank = SimpleRank.Kind4; break; case 3: sRank = SimpleRank.Kind3; break; case 2: sRank = SimpleRank.Kind2; break; default: throw new ArgumentException("n"); } fRank = new FullRank(sRank, Util.SingletonEnumerable(kindVal) .Concat(fillTamed.Select(hc => hc.TamedValue)) .Concat(fillPlain.Select(hc => hc.Value)) ); hcsRank = hcsChosen.Concat(hcsTamed).ToArray(); hcsFill = fillTamed.Concat(fillPlain).ToArray(); return(true); }
private bool isFlushN(HandInfo hi, out FullRank fRank, out HandCard[] hcsRank, out HandCard[] hcsFill, int n) { Contract.Requires(n >= 4 && n <= 5, String.Format("Error: Unrecognized flush size: {0:d}", n)); bool hasFlushN = (!hi.HasPlainCards() && hi.UnboundCount() >= n) || (hi.SuitGram.Values.Max() >= n - hi.UnboundCount()); if (!hasFlushN) { setToNull(out fRank, out hcsRank, out hcsFill); return(false); } TSuit flushSuit; int numChosen = 0; IEnumerable <HandCard> hcsChosen; if (!hi.HasPlainCards()) { flushSuit = Card.Suits.First(); // Any suit will do numChosen = 0; hcsChosen = new HandCard[0]; } else { var sg = hi.SuitGram; // Note: suits can only have Length > 1 if the hand has >= 2 * numCardsInFullHand cards. TSuit[] candidateSuits = sg.Keys.Where(s => sg[s] >= n - hi.UnboundCount()).ToArray(); if (candidateSuits.Length == 1) { flushSuit = candidateSuits[0]; } else { // Determine which suit is best var cardSeqEnum = candidateSuits .Select(s => hi.CardsPlain .Where(hc => hc.Suit == s) .OrderByDescending(hc => hc.Value)); var cardSeqOrd = cardSeqEnum .OrderByDescending(hcs => (IEnumerable <HandCard>)hcs, new EnumerableComparer <HandCard>()); var cardSeq = cardSeqOrd.First(); flushSuit = cardSeq.First().Suit; } HandCard[] hcsAvail = hi.CardsPlain.Where(hc => hc.Suit == flushSuit).ToArray(); numChosen = Math.Min(n, hcsAvail.Count()); hcsChosen = hcsAvail.OrderByDescending(hc => hc.Value).Take(numChosen); } HandCard[] hcsTamed = hi.CardsUnbound.Take(n - numChosen).ToArray(); foreach (HandCard hcs in hcsTamed) { hcs.TamedValue = TValue.Ace; hcs.TamedSuit = flushSuit; } List <HandCard> fillTamed; List <HandCard> fillPlain; Util.TakeFill(NumCardsInFinalHand - n, hi.CardsUnbound.Except(hcsTamed), out fillTamed, hi.CardsPlain.Except(hcsChosen), out fillPlain); foreach (HandCard hcs in fillTamed) { hcs.TamedValue = TValue.Ace; } ; SimpleRank sRank; switch (n) { case 4: sRank = SimpleRank.Flush4; break; case 5: sRank = SimpleRank.Flush5; break; default: throw new ApplicationException(String.Format( String.Format("Error: Unrecognized flush size: {0:d}", n))); } ; fRank = new FullRank(sRank, hcsTamed.Select(hc => hc.TamedValue) .Concat(hcsChosen.Select(hc => hc.Value).OrderByDescending(v => v)) .Concat(fillTamed.Select(hc => hc.TamedValue)) .Concat(fillPlain.Select(hc => hc.Value).OrderByDescending(v => v))); hcsRank = hcsChosen.Concat(hcsTamed).ToArray(); hcsFill = fillTamed.Concat(fillPlain).ToArray(); return(true); }