/// <summary> /// Computes a preference matrix with preference probability based on maximum of pocket equity /// for given pairs (0 or 1). Pocket equity is given by PocketEquity class. /// </summary> public static double[,] ComputePreferenceMatrixPeMax(HePocketKind [] pockets) { int n = pockets.Length; double[] cardProbabs = PocketHelper.GetProbabDistr(pockets); double[,] ptMax = new double[n, n]; for (int i = 0; i < n; ++i) { HePocketKind p1 = pockets[i]; for (int j = 0; j <= i; ++j) { HePocketKind p2 = pockets[j]; PocketEquity.Result r = PocketEquity.CalculateFast(p1, p2); if (i == j || r.Equity == 0.5) { ptMax[i, j] = 0.5; } else { ptMax[i, j] = r.Equity > 0.5 ? 1 : 0; } ptMax[j, i] = 1 - ptMax[i, j]; } } return(ptMax); }
public static Result CalculateFast(HePocketKind p1, HePocketKind p2) { if (_lut == null) { LoadLut(); } Precalculated key = new Precalculated(); bool reverse = p1 > p2; if (reverse) { key.PocketKind1 = (byte)p2; key.PocketKind2 = (byte)p1; } else { key.PocketKind1 = (byte)p1; key.PocketKind2 = (byte)p2; } int i = Array.BinarySearch(_lut, key, _precalculatedComparer); Result r = new Result { Count = _lut[i].Count }; if (reverse) { r.Equity = 1 - _lut[i].Equity; } else { r.Equity = _lut[i].Equity; } return(r); }
public static HePocketKind[] GetAllPockets() { HePocketKind[] result = new HePocketKind[169]; for (int i = 0; i < 169; ++i) { result[i] = (HePocketKind)i; } return(result); }
public void Test_KindToString_StringToKind() { for (int p = 0; p < (int)HePocketKind.__Count; ++p) { HePocketKind kind = (HePocketKind)p; string kindString = HePocket.KindToString(kind); HePocketKind kind1 = HePocket.StringToKind(kindString); Assert.AreEqual(kind, kind1); } }
public void Test_HsSd_Pockets() { for (int p = 0; p < HePocket.Count; ++p) { HePocketKind pk = (HePocketKind)p; int[] hand = HePocket.KindToHand(pk); float[] hssd = HsSd.Calculate(hand, 1); Console.WriteLine("{0} {1:0.0000} {2:0.0000}", HePocket.KindToString(pk), hssd[0], hssd[1]); } }
public void Test_Constructor() { // No preflop bucketing by pocket Props p = new string[] { "SomeProp", "SomeVal" }; PreflopPocketCA pfca = new PreflopPocketCA(p, 4); Assert.IsNull(pfca.PocketKindToAbstrCard); // Do preflop bucketing by pocket p = new string[] { "Pockets3", "AA KK", "Pockets2", "QQ JJ TT", "Pockets1", "AKs AKo AQs", }; pfca = new PreflopPocketCA(p, 4); Assert.IsNotNull(pfca.PocketKindToAbstrCard); Assert.AreEqual((int)HePocketKind.__Count, pfca.PocketKindToAbstrCard.Length); for (int i = 0; i < (int)HePocketKind.__Count; ++i) { HePocketKind pk = (HePocketKind)i; switch (pk) { case HePocketKind._AA: case HePocketKind._KK: Assert.AreEqual(3, pfca.PocketKindToAbstrCard[i]); break; case HePocketKind._QQ: case HePocketKind._JJ: case HePocketKind._TT: Assert.AreEqual(2, pfca.PocketKindToAbstrCard[i]); break; case HePocketKind._AKs: case HePocketKind._AKo: case HePocketKind._AQs: Assert.AreEqual(1, pfca.PocketKindToAbstrCard[i]); break; default: Assert.AreEqual(0, pfca.PocketKindToAbstrCard[i], pk.ToString()); break; } } }
public double Equity(int[] range1, int[] range2) { HePocketKind [] prange1 = new HePocketKind[range1.Length]; HePocketKind [] prange2 = new HePocketKind[range2.Length]; for (int i = 0; i < range1.Length; ++i) { prange1[i] = (HePocketKind)range1[i]; } for (int i = 0; i < range2.Length; ++i) { prange2[i] = (HePocketKind)range2[i]; } PocketEquity.Result r = PocketEquity.CalculateFast(prange1, prange2); return(r.Equity); }
public void Test_CalculateFast_Array() { HePocketKind[] pockets1 = new HePocketKind[] { HePocketKind._55, HePocketKind._66 }; HePocketKind[] pockets2 = new HePocketKind[] { HePocketKind._76s, HePocketKind._76o }; PocketEquity.Result r = PocketEquity.CalculateFast(pockets1, pockets2); Assert.AreEqual(0.56058, r.Equity, 0.000005); Assert.AreEqual(246571776L / EnumAlgos.CountCombin(48,5), r.Count); pockets1 = new HePocketKind[] { HePocketKind._AKs, HePocketKind._AQs }; pockets2 = new HePocketKind[] { HePocketKind._88, HePocketKind._77 }; r = PocketEquity.CalculateFast(pockets1, pockets2); Assert.AreEqual(0.47681, r.Equity, 0.000005); Assert.AreEqual(164381184L / EnumAlgos.CountCombin(48, 5), r.Count); }
public void Print(TextWriter tw) { tw.WriteLine("{0}", Name); int[] totalCount = new int[_positions.Count]; for (int pos = 0; pos < _positions.Count; pos++) { foreach (Record r in _positions[pos]) { totalCount[pos] += r.count; } } tw.Write("Pos "); for (int pos = 0; pos < _positions.Count; pos++) { tw.Write(" {0}", pos); } tw.WriteLine(); tw.Write("Poc "); for (int pos = 0; pos < _positions.Count; pos++) { tw.Write(" Count Result Av,mb Freq"); } tw.WriteLine(); Record [] totalRecord = new Record[_positions.Count].Fill(i => new Record()); for (HePocketKind pocketKind = 0; pocketKind < HePocketKind.__Count; ++pocketKind) { Console.Write("{0,-3} ", pocketKind.ToString().Substring(1)); for (int pos = 0; pos < _positions.Count; pos++) { Record r = _positions[pos][(int)pocketKind]; totalRecord[pos].result += r.result; totalRecord[pos].count += r.count; PrintRecord(tw, totalCount[pos], r); } Console.WriteLine(); } Console.Write("ALL "); for (int pos = 0; pos < _positions.Count; pos++) { PrintRecord(tw, totalCount[pos], totalRecord[pos]); } Console.WriteLine(); }
/// <summary> /// Initializes a class from properties. /// For each preflop bucket it expects a a property in the following format: /// <para>name: "Pockets7", value: "AA KK QQ JJ TT 99 AKs"</para> /// <para>If there is no such properties at all, it is assumed that this CA does /// not use preflop pocket bucketizing. In this case the property PocketKindToAbstrCard returns null.</para> /// <para>If any such a property exists, than all other in range [1..bucketsCount-1] must be specified, /// otherwise an ArgumentException it thrown.</para> /// <para>All pockets unspecified in such properties go to bucket 0 (even if its property specifed explicitely).</para> /// </summary> public PreflopPocketCA(Props parameters, int bucketsCount) { bool isPreflopPocketBucketizingUsed = false; for (int b = bucketsCount - 1; b >= 0; --b) { string propName = "Pockets" + b.ToString(); string value = parameters.Get(propName); if (!string.IsNullOrEmpty(value)) { isPreflopPocketBucketizingUsed = true; break; } } if (!isPreflopPocketBucketizingUsed) { return; } PocketKindToAbstrCard = new int[(int)HePocketKind.__Count]; for (int b = bucketsCount - 1; b >= 0; --b) { string propName = "Pockets" + b.ToString(); string value = parameters.Get(propName); if (string.IsNullOrEmpty(value)) { if (b == 0) { // This can be left out. continue; } throw new ArgumentException(string.Format("Pockets{0} is not specified", b)); } string[] bucketKinds = value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (string kindString in bucketKinds) { HePocketKind kind = HePocket.StringToKind(kindString); PocketKindToAbstrCard[(int)kind] = b; } } }
static HePocket() { int[] rangePos = new int[(int)HePocketKind.__Count]; for (int p = 0; p < (int)HePocketKind.__Count; ++p) { HePocketKind kind = (HePocketKind)p; string name = kind.ToString(); string kindString = name.Substring(1); _kindToString[p] = kindString; _stringToKind.Add(kindString, kind); string c1 = name.Substring(1, 1); string c2 = name.Substring(2, 1); string type = name.Length == 4 ? name.Substring(3, 1) : ""; CardSet cs = new CardSet(); int rangeSize = 6; if (type == "s") { // Suited cs = StdDeck.Descriptor.GetCardSet(c1 + "c " + c2 + "c"); rangeSize = 4; } else if (type == "o") { // Offsuit cs = StdDeck.Descriptor.GetCardSet(c1 + "c " + c2 + "d"); rangeSize = 12; } else { // Pair cs = StdDeck.Descriptor.GetCardSet(c1 + "c " + c2 + "d"); rangeSize = 6; } _kindToSuitNormalizedCardset[p] = cs; _kindToHand[p] = StdDeck.Descriptor.GetIndexesAscending(cs).ToArray(); _cardSetToKind[cs] = kind; _kindToRange[(int)kind] = new CardSet[rangeSize]; } CardEnum.Combin(StdDeck.Descriptor, 2, CardSet.Empty, CardSet.Empty, AddPocket, rangePos); }
/// <summary> /// Computes a preference matrix with preference probability based on pocket equity /// given by PocketEquity class. /// </summary> public static double[,] ComputePreferenceMatrixPe(HePocketKind[] pockets) { int n = pockets.Length; double[] cardProbabs = PocketHelper.GetProbabDistr(pockets); double[,] ptEq = new double[n, n]; for (int i = 0; i < n; ++i) { HePocketKind p1 = pockets[i]; for (int j = 0; j <= i; ++j) { HePocketKind p2 = pockets[j]; PocketEquity.Result r = PocketEquity.CalculateFast(p1, p2); ptEq[i, j] = r.Equity; ptEq[j, i] = 1 - ptEq[i, j]; } } return(ptEq); }
private ChanceTree CreateCt(HePocketKind[] sbCards, HePocketKind[] bbCards) { int nodeCount = 1 + sbCards.Length + sbCards.Length * bbCards.Length; ChanceTree ct = new ChanceTree(nodeCount); ct.PlayersCount = 2; ct.Nodes[0].Probab = 1; ct.SetDepth(0, 0); int totalCombSB = 0; foreach (HePocketKind p in sbCards) { totalCombSB += HePocket.KindToRange(p).Length; } for (int c0 = 0; c0 < sbCards.Length; ++c0) { int sbNode = 1 + c0 * (bbCards.Length + 1); HePocketKind sbPocket = sbCards[c0]; ct.SetDepth(sbNode, 1); ct.Nodes[sbNode].Position = 0; ct.Nodes[sbNode].Probab = (double)HePocket.KindToRange(sbPocket).Length / totalCombSB; ct.Nodes[sbNode].Card = c0; double[] oppDealProbabCond = PocketHelper.GetProbabDistr(bbCards, HePocket.KindToCardSet(sbPocket)); for (int c1 = 0; c1 < bbCards.Length; ++c1) { int bbNode = sbNode + 1 + c1; ct.SetDepth(bbNode, 2); ct.Nodes[bbNode].Position = 1; ct.Nodes[bbNode].Probab = ct.Nodes[sbNode].Probab * oppDealProbabCond[c1]; ct.Nodes[bbNode].Card = c1; PocketEquity.Result pe = PocketEquity.CalculateFast(sbPocket, bbCards[c1]); var potShare = new double[] { pe.Equity, 1 - pe.Equity }; ct.Nodes[bbNode].SetPotShare(3, potShare); } } VerifyChanceTree.VerifyS(ct, 1e-5); return(ct); }
public static void PrintPreflopRanges(IChanceAbstraction ca) { List <HePocketKind>[] abstrRanges = new List <HePocketKind> [0]; int[] abstrRangesSizes = new int[0]; for (int p = 0; p < (int)HePocketKind.__Count; ++p) { HePocketKind kind = (HePocketKind)p; CardSet pocketCS = HePocket.KindToCardSet(kind); int [] pocketArr = StdDeck.Descriptor.GetIndexesAscending(pocketCS).ToArray(); int abstrCard = ca.GetAbstractCard(pocketArr, pocketArr.Length); if (abstrCard >= abstrRanges.Length) { Array.Resize(ref abstrRanges, abstrCard + 1); Array.Resize(ref abstrRangesSizes, abstrCard + 1); } if (abstrRanges[abstrCard] == null) { abstrRanges[abstrCard] = new List <HePocketKind>(); } abstrRanges[abstrCard].Add(kind); abstrRangesSizes[abstrCard] += HePocket.KindToRange(kind).Length; } Console.WriteLine("Preflop ranges of CA: {0}", ca.Name); int total = 0; for (int i = abstrRanges.Length - 1; i >= 0; --i) { Console.Write("{0,2} ({1,4}):", i, abstrRangesSizes[i]); foreach (HePocketKind k in abstrRanges[i]) { Console.Write(" {0}", HePocket.KindToString(k)); } Console.WriteLine(); total += abstrRangesSizes[i]; } Console.WriteLine("Total: {0}", total); }
public void Test_Pockets_Overall() { Console.WriteLine("Pocket hand strengths:"); int [] indexes = new int[2]; double weighedSumHs = 0; int sumCount = 0; for (int i = 0; i < (int)HePocketKind.__Count; ++i) { HePocketKind pk = (HePocketKind)i; int[] hand = HePocket.KindToHand(pk); double s = HandStrength.CalculateFast(hand); int count = HePocket.KindToRange(pk).Length; Console.WriteLine("{0} {1:0.0000} {2}", HePocket.KindToString(pk), s, count); weighedSumHs += s * count; sumCount += count; } Console.WriteLine("Weighed sum: {0:0.0000} {1}", weighedSumHs, sumCount); Assert.AreEqual(1326, sumCount); Assert.AreEqual(1326 * 0, 5, weighedSumHs, "Overall result must be 0.5 (tie)"); }
public void Test_CallKK() { string outDir = Path.Combine(_outDir, "call-KK"); Directory.CreateDirectory(outDir); HePocketKind[] sbPockets = new HePocketKind[] { HePocketKind._AA, HePocketKind._KK, HePocketKind._AKs }; HePocketKind[] bbPockets = new HePocketKind[] { HePocketKind._AA, HePocketKind._KK, HePocketKind._QQ, HePocketKind._AKs }; string xmlAt = Props.Global.Expand("${bds.DataDir}ai.pkr.holdem.learn/bigcards-pf-1.xml"); ActionTree at = XmlToActionTree.Convert(xmlAt); VisActionTree.Show(at, Path.Combine(outDir, "at.gv")); BigCardsPreflop bc = new BigCardsPreflop(); bc.Solve(at, sbPockets, bbPockets); Console.WriteLine("Game values: {0}, {1}", bc.GameValues[0], bc.GameValues[1]); VisChanceTree.Show(bc.Ct, Path.Combine(outDir, "ct.gv")); VisStrategyTree.Show(bc.Strategies[0], Path.Combine(outDir, "st-0.gv")); VisStrategyTree.Show(bc.Strategies[1], Path.Combine(outDir, "st-1.gv")); }
public void Update(GameRecord gameRecord) { for (int pos = 0; pos < gameRecord.Players.Count; ++pos) { GameRecord.Player player = gameRecord.Players[pos]; if (player.Name == _hero) { Allocate(pos); foreach (PokerAction action in gameRecord.Actions) { if (action.Kind == Ak.d && action.Position == pos) { CardSet pocket = StdDeck.Descriptor.GetCardSet(action.Cards); HePocketKind pocketKind = HePocket.CardSetToKind(pocket); _positions[pos][(int)pocketKind].count++; _positions[pos][(int)pocketKind].result += player.Result; } } break; } } }
private Bucket[] CreatePreflopBuckets(int preflopBucketsCount) { Bucket[] buckets = new Bucket[preflopBucketsCount].Fill(i => new Bucket()); int totalHands = 0; for (int i = 0; i < HePocket.Count; ++i) { HePocketKind pk = (HePocketKind)i; // Use all possible pockets for each pocket kind. This ensures // that they occur with the natural frequency in a typical case where // a bucket contain pocket kinds with different numbers of pockets (e.g. AA - 6, AKs - 4, AKo - 12). CardSet [] range = HePocket.KindToRange(pk); foreach (CardSet pocketCs in range) { McHand hand = new McHand(); int[] pocket = StdDeck.Descriptor.GetIndexesAscending(pocketCs).ToArray(); CardSet restCs = StdDeck.Descriptor.FullDeck; restCs.Remove(pocketCs); int[] rest = StdDeck.Descriptor.GetIndexesAscending(restCs).ToArray(); Debug.Assert(pocket.Length + rest.Length == 52); pocket.CopyTo(hand.Cards, 0); rest.CopyTo(hand.Cards, 2); hand.Length = 2; int abstrCard = Clusterizer.GetAbstractCard(hand.Cards, hand.Length); buckets[abstrCard].Hands.Add(hand); totalHands++; } } Debug.Assert(totalHands == 1326); if (IsVerbose) { Console.WriteLine("Preflop buckets created, buckets: {0}, hands: {1}", buckets.Length, totalHands); } return(buckets); }
public void Test_KindToRange_CardSetToKind_KindToSuiteNormalizedCardSet() { HashSet <CardSet> uniquePockets = new HashSet <CardSet>(); for (int p = 0; p < (int)HePocketKind.__Count; ++p) { HePocketKind kind = (HePocketKind)p; CardSet[] range = HePocket.KindToRange(kind); CardSet ncsExp = HePocket.KindToCardSet(kind); foreach (CardSet cs in range) { Assert.AreEqual(kind, HePocket.CardSetToKind(cs), "Each pocket from range must be of the expected kind."); NormSuit ns = new NormSuit(); CardSet ncs = ns.Convert(cs); Assert.AreEqual(ncsExp, ncs, "Card set from ranges must transform to same normalized card set"); // This will throw an exception if some pockets were duplicated. uniquePockets.Add(cs); } } Assert.AreEqual(1326, uniquePockets.Count); }
public void Test_HePockets() { double[] cardProbabs = new double[169]; for (int i = 0; i < 169; ++i) { cardProbabs[i] = HePocket.KindToRange((HePocketKind)i).Length / 1326.0; } double[,] ptEq = MultiplayerPocketProbability.ComputePreferenceMatrixPe(PocketHelper.GetAllPockets()); double[,] ptMax = MultiplayerPocketProbability.ComputePreferenceMatrixPeMax(PocketHelper.GetAllPockets()); double[][] resEq = new double[10][]; double[][] resMax = new double[10][]; for (int pc = 1; pc < 10; ++pc) { resEq[pc] = MultiplayerPocketProbability.Compute(pc, cardProbabs, ptEq); VerifyResult(169, resEq[pc]); resMax[pc] = MultiplayerPocketProbability.Compute(pc, cardProbabs, ptMax); VerifyResult(169, resMax[pc]); } Console.WriteLine(); Console.Write("{0,3} ", "Poc"); for (int pc = 1; pc < 10; ++pc) { Console.Write("{0,6} {1,6} ", pc.ToString() + " eq", pc.ToString() + " max"); } Console.WriteLine(); for (int i = 0; i < 169; ++i) { HePocketKind p = (HePocketKind)i; Console.Write("{0,3} ", HePocket.KindToString(p)); for (int pc = 1; pc < 10; ++pc) { Console.Write("{0,6:0.00} {1,6:0.00} ", resEq[pc][i] * 100, resMax[pc][i] * 100); } Console.WriteLine(); } }
public Entry01(HePocketKind pocketKind, CardSet board) { Key = GetKey((int)pocketKind, board); Hs = Sd3 = SdPlus1 = 0; }
public static Result Calculate(HePocketKind p1, HePocketKind p2) { CardSet[] csRange1 = HePocket.KindToRange(p1); CardSet[] csRange2 = HePocket.KindToRange(p2); return(CalculateNoVerify(csRange1, csRange2)); }
/// <summary> /// Returns a single suit-normalized cards set, e.g. AKs -> AcKc, AKo -> AcKd. /// </summary> public static CardSet KindToCardSet(HePocketKind pocketKind) { return(_kindToSuitNormalizedCardset[(int)pocketKind]); }
/// <summary> /// Converts a kind to a suit-normalized hand. /// </summary> public static int[] KindToHand(HePocketKind kind) { return(_kindToHand[(int)kind]); }
protected int GetPreflopAbstrCard(int[] hand) { HePocketKind pk = HePocket.HandToKind(hand); return(_pfPocketCa.PocketKindToAbstrCard[(int)pk]); }
public Entry(HePocketKind pocketKind, CardSet board) { key = GetKey((int)pocketKind, board); value = 0; }
public static CardSet [] KindToRange(HePocketKind kind) { return(_kindToRange[(int)kind]); }
/// <summary> /// Converts a kind to a regular string representation, for example KQs. /// </summary> public static string KindToString(HePocketKind kind) { return(_kindToString[(int)kind]); }
private static void MonteCarlo() { // Create new arrays for preflop values for (int pos = 0; pos < 2; ++pos) { _createPreflopValues.Walk(_neytiri, _neytiri.Positions[pos]); } DateTime start = DateTime.Now; for (int ourPos = 0; ourPos < _neytiri.Positions.Length; ++ourPos) { Console.WriteLine("Position {0}", ourPos); ActionTreeNode root = _neytiri.Positions[1 - ourPos]; List <ActionTreeNode> strategyPath = new List <ActionTreeNode>(100); strategyPath.Add(root); // Advance to the node where we get cards while (strategyPath[strategyPath.Count - 1].State.CurrentActor != ourPos) { strategyPath.Add(strategyPath[strategyPath.Count - 1].Children[0]); } for (HePocketKind pocketKind = 0; pocketKind < HePocketKind.__Count; ++pocketKind) { CardSet pocket = HePockets.PocketKindToCardSet(pocketKind); if (_pockets.Count > 0 && !_pockets.Contains(pocket)) { // Skip the pocket if command line specifies which pockets to include and it's not there. continue; } Console.Write("{0} ", pocketKind.ToString().Substring(1)); MonteCarloStrategyFinder.DoMonteCarlo(_neytiri, ourPos, pocket, 0, "", strategyPath, _cmdLine.mcCount); WalkTree <ActionTree, ActionTreeNode, int> copyValues = new WalkTree <ActionTree, ActionTreeNode, int> { OnNodeBegin = (t, n, s, d) => { if (n.State.Round > 0) { return(false); } n.PreflopValues[(int)pocketKind] = n.Value; return(true); } }; copyValues.Walk(_neytiri, root); } Console.WriteLine(); } DateTime finish = DateTime.Now; double sec = (finish - start).TotalSeconds; Console.WriteLine("Done {0} monte-carlo trials for every pocket in each position in {1:0.0} sec", _cmdLine.mcCount, sec); Console.WriteLine("Writing Neytiri strategy to {0} ...", _cmdLine.neytiri); _neytiri.XmlSerialize(_cmdLine.neytiri, new XmlWriterSettings { Indent = false }); }