public override MEquity[] Equity(string[] board, string[][] holeCards, string[] blockers, int draws) { if (draws != 0) { throw new ArgumentException("invalid draws: " + draws); } validateBoard(board); foreach (var hole in holeCards) { validateHoleCards(hole); } // cards not used by hands or board String[] deck = OmahaPoker.remdeck(holeCards, board, blockers); if (board.Length <= 1) { // monte carlo (random sample boards) return(equityImpl(new HEBoardSample(deck, board, 10000), holeCards)); } else { // all possible boards return(equityImpl(new HEBoardEnum(deck, board), holeCards)); } }
public int Compare(string c1, string c2) { int v = OmahaPoker.faceValueAH(c1) - OmahaPoker.faceValueAH(c2); if (v == 0) { v = OmahaPoker.suit(c1) - OmahaPoker.suit(c2); } return(polarity * v); }
/** * Return string representing current value of hand */ internal static String currentString(MEquity me) { String s = OmahaPoker.valueString(me.eqs[0].current); if (me.HiLo) { // s += " Hi: " + Poker.valueString(me.eqs[1].current); s += " / " + OmahaPoker.valueString(me.eqs[2].current); } return(s); }
/// <summary> /// Go through every possible 5 card hand and collect the unique hand values in order /// </summary> /// <returns></returns> internal static int[] highValues() { if (uniqueHighValues != null) { return(uniqueHighValues); } HashSet <int> uniqueValueSet = new HashSet <int>(); String[] hand = new String[5]; int valueCount = 0; for (int n0 = 0; n0 < deckArr.Length; n0++) { hand[0] = deckArr[n0]; for (int n1 = n0 + 1; n1 < deckArr.Length; n1++) { hand[1] = deckArr[n1]; for (int n2 = n1 + 1; n2 < deckArr.Length; n2++) { hand[2] = deckArr[n2]; for (int n3 = n2 + 1; n3 < deckArr.Length; n3++) { hand[3] = deckArr[n3]; for (int n4 = n3 + 1; n4 < deckArr.Length; n4++) { hand[4] = deckArr[n4]; uniqueValueSet.Add(OmahaPoker.Value(hand)); valueCount++; } } } } } int[] a = new int[uniqueValueSet.Count]; int i = 0; foreach (int v in uniqueValueSet) { a[i++] = v; } Array.Sort(a); uniqueHighValues = a; return(a); }
/// <summary> /// get normalised score of hand (i.e. hand value is 0-1), optionally /// inverted.bias is 0.5 to 1, representing how many values are less than /// 0.5, e.g. 0.9 means 90% of values are less than 0.5 /// </summary> /// <param name=""></param> /// <param name="value"></param> /// <param name=""></param> /// <param name="bias"></param> /// <returns></returns> protected static float score(int value, double bias) { if (bias < 0.5 || bias > 1.0) { throw new ArgumentException("invalid bias " + bias); } // get high value bool high; int highValue; switch (value & OmahaPoker.TYPE) { case OmahaPoker.HI_TYPE: high = true; highValue = value; break; case OmahaPoker.DS_LOW_TYPE: high = false; highValue = OmahaPoker.HI_TYPE | (OmahaPoker.MAX_RANK - (value & OmahaPoker.HAND)); break; default: // ace to five doesn't include str/fl // but then, no drawing games use ace to five values so doesn't matter throw new ArgumentException("can't get score of " + value.ToString("X4")); } int[] highValues = OmahaPoker.highValues(); int p = Array.BinarySearch(highValues, highValue); if (p < 0) { throw new ArgumentException("not a high value: " + highValue.ToString("X4")); } if (!high) { // invert score for deuce to seven low p = highValues.Length - 1 - p; } // raise score to some power to bias toward high values // note: for k=x^y, y=log(k)/log(x)... i think return((float)Math.Pow((1f * p) / (highValues.Length - 1f), Math.Log(0.5) / Math.Log(bias))); }
/// <summary> /// Summarise out probabilities for given number of picks from remaining cards /// </summary> /// <param name="remCards"></param> /// <param name="picks"></param> /// <param name="samples"></param> internal void summariseOuts(float remCards, float picks, float samples) { if (outcount != null) { // maximum number of times an out can appear (average if sampled) // prob of appearing once is picks/remCards, just multiply by samples // (n,k,s) = (k*s)/n // (52,1,52) = 1, (52,2,1326) = 51, (52,3,100000) = 5769 float max = (picks * samples) / remCards; //System.out.println(String.format("sum outs(%f,%f,%f) max=%f", remCards, picks, samples, max)); for (int n = 0; n < outcount.Count(); n++) { int count = outcount[n]; if (count > 0) { String card = OmahaPoker.indexToCard(n); float pc = (count * 100f) / max; outs.Add(new Out(card, pc)); } } outs.Sort(); outs.Reverse(); } }
public override int value(string[] hand) { return(OmahaPoker.afLowValue(hand)); }
/// <summary> /// get the best drawing hand for the given hand, number drawn and hand valuation. optionally returns score of all possible drawing hands. /// </summary> /// <param name="list"></param> /// <param name="hand"></param> /// <param name="drawn"></param> /// <param name="high"></param> /// <param name="blockers"></param> /// <returns></returns> public static String[] getDrawingHand(List <Draw> list, String[] hand, int drawn, bool high, String[] blockers) { if (hand.Length > 5) { throw new ArgumentException("invalid hand: " + (string.Join(", ", hand))); } // XXX really should take into account multiple draws // but thats only really a problem if you draw a greater number on a // later street (which is a bad strategy and almost unheard of) // e.g. draw 1, 1, 5 - obviously can't use final hand to predict any of them // related problem is that a later hand might contain blockers from a // reshuffle and so can't possibly occur on an earlier street // and you might not even have enough cards that aren't blocked, // i.e. bincoff(length(hand - blockers), 5 - drawn) needs to be >= 1 if (blockers != null && blockers.Length > 0) { String[] hand2 = ArrayUtil.sub(hand, blockers); if (hand2.Length != hand.Length) { // some of the cards were blocked // cheat and increase the draw amount (if necessary) drawn = Math.Max(5 - hand2.Length, drawn); hand = hand2; } } BigInteger combs = MathsUtil.binomialCoefficient(hand.Length, 5 - drawn); if ((int)combs <= 0) { throw new ArgumentException("invalid combs: " + combs); } // XXX if only 1 comb, just return hand? // high draw works best with around 0.9, low draw with 0.99 // generally, you can win in high with any top 10% hand, but low draw // pretty much needs 7-high (75432, 76432, 76542, etc) to win // XXX actually it probably depends if it's 2-7 single or triple draw double bias = high ? 0.9 : 0.99; OmahaValue value; if (high) { value = new HiValue(); } else { value = new DsLowValue(); } if (drawn < 0 || drawn > 5) { throw new ArgumentException("invalid drawn: " + drawn); } else if (drawn == 5) { // special case, no draw and no meaningful score return(new String[0]); } else if (drawn == 0) { // special case, nothing to test other than given hand if (list != null) { float s = score(value.value(hand), bias); list.Add(new Draw(hand, s)); } return(hand.ToArray()); } // drawing 1-4 // from players point of view, all other cards are possible (even the blockers) String[] deck = OmahaPoker.remdeck(null, hand); String[] drawnHand = new String[5]; int imax = MathsUtil.binomialCoefficientFast(hand.Length, 5 - drawn); int jmax = MathsUtil.binomialCoefficientFast(deck.Length, drawn); String[] maxDrawingHand = null; float maxScore = -1f; for (int i = 0; i < imax; i++) { ArrayUtil.Populate(drawnHand, null); // pick kept from hand MathsUtil.kCombination(5 - drawn, i, hand, drawnHand, 0); //System.out.println("drawnHand: " + Arrays.toString(drawnHand)); float score = 0; for (int j = 0; j < jmax; j++) { // pick drawn from deck MathsUtil.kCombination(drawn, j, deck, drawnHand, 5 - drawn); //System.out.println(" drawnHand: " + Arrays.toString(drawnHand)); int v = value.value(drawnHand); score += DrawPrediction.score(v, bias); } float averageScore = score / (1.0f * jmax); string[] drawingHand = drawnHand.Take(5 - drawn).ToArray(); if (list != null) { Array.Sort(drawingHand, Cmp.revCardCmp); list.Add(new Draw(drawingHand, averageScore)); } if (score > maxScore) { // copy new max hole cards maxDrawingHand = drawingHand; maxScore = score; } } if (list != null) { list.Sort(); list.Reverse(); } return(maxDrawingHand); }
/** * Update equities win, tie and win rank with given hand values for the * given cards. Return index of single winner (scoop), if any, or -1 */ private static int updateMEquities2(MEquity[] meqs, OmahaEquity.EquityType eqtype, int[] vals, String[] cards) { // find highest hand and number of times it occurs int max = 0, maxcount = 0; for (int i = 0; i < vals.Length; i++) { int v = vals[i]; if (v > max) { max = v; maxcount = 1; } else if (v == max) { maxcount++; } } int winner = -1; for (int i = 0; i < vals.Length; i++) { if (vals[i] == max) { // update the win/tied/rank count OmahaEquity e = meqs[i].getEquity(eqtype); if (maxcount == 1) { winner = i; e.woncount++; } else { e.tiedcount++; e.tiedwithcount += maxcount; } e.wonrankcount[OmahaPoker.rank(max)]++; // count the cards as outs if this turns losing hand into // win/tie or tying hand into win if (cards != null && e.current > 0 && (!(e.curwin || e.curtie) || (e.curtie && maxcount == 1))) { for (int c = 0; c < cards.Length; c++) { String card = cards[c]; int cardIndex = OmahaPoker.cardToIndex(card); e.outcount[cardIndex]++; } } // XXX experimental - String[][] mcards /* * if (mcards != null && e.current > 0 && (!e.curwin || * (e.curtie && maxcount == 1))) { for (int c = 0; c < * mcards[i].length; c++) { String card = mcards[i][c]; int * cardIndex = Poker.cardToIndex(card); e.outcount[cardIndex]++; * } } */ } } return(winner); }
public int Compare(String c1, String c2) { // highest first return(polarity * (OmahaPoker.faceValueAH(c2) - OmahaPoker.faceValueAH(c1))); }