/// <summary> /// Returns a probability distribution assuming that only given pockets can be dealt /// and one pocket is already dealt. /// The distribution is bases on pockets count only. /// For example, for (AA, 72o) the distribution will be (6/18, 12/18). /// </summary> /// <param name="pockets"></param> /// <returns></returns> public static double[] GetProbabDistr(HePocketKind[] pockets, CardSet dealtPocket) { int n = pockets.Count(); double[] result = new double[n]; int totalPockets = 0; for (int c = 0; c < pockets.Length; ++c) { CardSet[] range = HePocket.KindToRange(pockets[c]); int count = 0; foreach (CardSet cs in range) { if (!cs.IsIntersectingWith(dealtPocket)) { count++; } } result[c] = count; totalPockets += count; } for (int c = 0; c < pockets.Length; ++c) { result[c] /= totalPockets; } return(result); }
public void Test_CreateCt() { int oppCount = 2; var pockets = PocketHelper.GetAllPockets(); //var pockets = new HePocketKind[] { HePocketKind._AA, HePocketKind._76s, HePocketKind._72o }; var pocketDist = PocketHelper.GetProbabDistr(pockets); double[,] ptPeMax = MultiplayerPocketProbability.ComputePreferenceMatrixPeMax(pockets); string xmlAt = Props.Global.Expand("${bds.DataDir}ai.pkr.holdem.learn/nlpf-1.xml"); ActionTree at = XmlToActionTree.Convert(xmlAt); string[] actionLabels = CreateActionLabels(at, 0); Dictionary <string, int> actionLabelToId = new Dictionary <string, int>(); for (int i = 0; i < actionLabels.Length; ++i) { actionLabelToId.Add(actionLabels[i], i); } double[] oppDist = MultiplayerPocketProbability.Compute(oppCount, pocketDist, ptPeMax); ChanceTree ct = PreflopStrategy.CreateCt(pockets, oppDist); //GameDefinition gd = XmlSerializerExt.Deserialize<GameDefinition>(Props.Global.Expand("${bds.DataDir}ai.pkr.metastrategy/${0}", "kuhn.gamedef.xml")); //at = CreateActionTreeByGameDef.Create(gd); //ct = CreateChanceTreeByGameDef.Create(gd); VisChanceTree.Show(ct, Path.Combine(_outDir, "ct.gv")); VisActionTree.Show(at, Path.Combine(_outDir, "at.gv")); StrategyTree[] st = SolveAndVerifyVerifySolution(at, ct, 0.001, false); double[,] fs = FlattenStrategy(st[0], 0, pockets.Length, actionLabelToId); Console.WriteLine("Result for opponent count: {0}", oppCount); Console.Write("{0,4}", oppCount); foreach (string al in actionLabels) { Console.Write("{0,20}", al); } Console.WriteLine(); int raiseCount = 0; for (int c = 0; c < pockets.Length; ++c) { Console.Write("{0,4}", HePocket.KindToString(pockets[c])); for (int j = 0; j < actionLabels.Length; ++j) { Console.Write("{0,20}", Math.Round(fs[c, j] * 100, 0)); } if (fs[c, actionLabels.Length - 1] > 0.9) { raiseCount += HePocket.KindToRange(pockets[c]).Length; } Console.WriteLine(); } Console.WriteLine("Raise count: {0}", raiseCount); }
static HeRules() { _cards = new string[HePocket.Count]; for (int p = 0; p < HePocket.Count; ++p) { _cards[p] = HePocket.KindToString((HePocketKind)p); _cardCounts[p] = HePocket.KindToRange((HePocketKind)p).Length; } }
private static void PrintPockets(PocketData[] pockets, bool printCenters) { for (int i = 0; i < pockets.Length; ++i) { Console.Write("{0,3} ", HePocket.KindToString((HePocketKind)i)); pockets[i].Print(Console.Out, printCenters); Console.WriteLine(); } }
public void Test_HandToToKind() { DeckDescriptor deck = StdDeck.Descriptor; Assert.AreEqual(HePocketKind._AQo, HePocket.HandToKind(deck.GetIndexes("Ac Qd"))); Assert.AreEqual(HePocketKind._AQo, HePocket.HandToKind(deck.GetIndexes("As Qc"))); Assert.AreEqual(HePocketKind._22, HePocket.HandToKind(deck.GetIndexes("2s 2c"))); Assert.AreEqual(HePocketKind._32s, HePocket.HandToKind(deck.GetIndexes("2s 3s"))); Assert.AreEqual(HePocketKind._32s, HePocket.HandToKind(deck.GetIndexes("3c 2c"))); }
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_CardSetToKind() { Assert.AreEqual(169, (int)HePocketKind.__Count); DeckDescriptor deck = StdDeck.Descriptor; Assert.AreEqual(HePocketKind._AQo, HePocket.CardSetToKind(deck.GetCardSet("Ac Qd"))); Assert.AreEqual(HePocketKind._AQo, HePocket.CardSetToKind(deck.GetCardSet("As Qc"))); Assert.AreEqual(HePocketKind._22, HePocket.CardSetToKind(deck.GetCardSet("2s 2c"))); Assert.AreEqual(HePocketKind._32s, HePocket.CardSetToKind(deck.GetCardSet("2s 3s"))); Assert.AreEqual(HePocketKind._32s, HePocket.CardSetToKind(deck.GetCardSet("3c 2c"))); }
public void Test_KindToHand() { DeckDescriptor deck = StdDeck.Descriptor; int[] hand = HePocket.KindToHand(HePocketKind._AA); Assert.AreEqual(deck.GetIndexes("Ac Ad").ToArray(), hand); hand = HePocket.KindToHand(HePocketKind._KQo); Assert.AreEqual(deck.GetIndexes("Kc Qd").ToArray(), hand); hand = HePocket.KindToHand(HePocketKind._54s); Assert.AreEqual(deck.GetIndexes("4c 5c").ToArray(), hand); }
private static unsafe double[][] SolveKMeans(PocketData[] pockets) { Kml.Init(null); Kml.Parameters kmParams = new Kml.Parameters(); kmParams.SetDefaultTerm(); kmParams.dim = _cmdLine.Dim; kmParams.term_st_a = _cmdLine.Stages; kmParams.term_st_b = kmParams.term_st_c = kmParams.term_st_d = 0; kmParams.seed = 1; kmParams.k = _cmdLine.K; kmParams.n = _cmdLine.UsePocketCounts ? 1326: 169; kmParams.Allocate(); Console.WriteLine("Data passed to kml:"); int p = 0; for (int pocket = 0; pocket < pockets.Length; ++pocket) { int count = _cmdLine.UsePocketCounts ? HePocket.KindToRange((HePocketKind)pocket).Length : 1; for (int i = 0; i < count; ++i) { for (int d = 0; d < _cmdLine.Dim; ++d) { double value = pockets[pocket].Value[d]; *kmParams.GetPoint(p, d) = value; Console.Write(value.ToString(CultureInfo.InvariantCulture) + " "); } Console.WriteLine(); ++p; } } Console.WriteLine(); Debug.Assert(!_cmdLine.UsePocketCounts || p == 1326); Kml.KML_Hybrid(&kmParams); double[][] centers = new double[_cmdLine.K][].Fill(i => new double[_cmdLine.Dim]); for (int c = 0; c < kmParams.k; ++c) { for (int d = 0; d < kmParams.dim; ++d) { centers[c][d] = *kmParams.GetCenter(c, d); } } kmParams.Free(); return(centers); }
public static float[] CalculateFast(int[] hand, int handLength, SdKind sdKind) { Debug.Assert(handLength >= 0 && handLength <= 7); if (handLength == 7) { // SdKind.SdPlus1 will throw an exception, this is exactly what we want. return(Calculate(hand, handLength, sdKind == SdKind.SdPlus1 ? 4 : 3)); } if (_lut2 == null) { LoadLuts(); } float[] hssd = new float[2]; int round = HeHelper.HandSizeToRound[handLength]; CardSet pocket = StdDeck.Descriptor.GetCardSet(hand, 0, 2); CardSet board = StdDeck.Descriptor.GetCardSet(hand, 2, handLength - 2); NormSuit se = new NormSuit(); CardSet sePocket = se.Convert(pocket); CardSet seBoard = se.Convert(board); if (round == 2) { Entry2 keyEntry = new Entry2(HePocket.CardSetToKind(sePocket), seBoard); int idx = Array.BinarySearch(_lut2, keyEntry); if (idx < 0) { ThrowNoEntryException(sePocket, seBoard); } hssd[0] = _lut2[idx].Hs; // For turn, there is no difference between SD kinds. hssd[1] = _lut2[idx].SdPlus1; } else { Entry01 keyEntry = new Entry01(HePocket.CardSetToKind(sePocket), seBoard); int idx = Array.BinarySearch(_lut01[round], keyEntry); if (idx < 0) { ThrowNoEntryException(sePocket, seBoard); } // For turn, there is no difference between SD kinds. hssd[0] = _lut01[round][idx].Hs; hssd[1] = sdKind == SdKind.SdPlus1 ? _lut01[round][idx].SdPlus1 : _lut01[round][idx].Sd3; } return(hssd); }
private static void PrintBuckets(PocketData[] pockets) { for (int b = _cmdLine.K - 1; b >= 0; --b) { Console.Write("{0,3}: ", b); for (int i = 0; i < pockets.Length; ++i) { if (pockets[i].Center == b) { Console.Write("{0} ", HePocket.KindToString((HePocketKind)i)); } } Console.WriteLine(); } }
/// <summary> /// Precalculate and store tables. If the output already exists, will not overwrite. /// <remarks>Long-running. </remarks> /// </summary> /// <param name="round">Round (0, 1 or 2).</param> public static void Precalculate(int round) { DateTime startTime = DateTime.Now; string lutPath = GetLutPath(round); if (File.Exists(lutPath)) { // Do not ovewriting an existing file to save time. Console.WriteLine("LUT file {0} already exist, exiting. Delete the file to recalculate.", lutPath); return; } int POCKETS_COUNT = (int)HePocketKind.__Count; //POCKETS_COUNT = 1; // Test PrecalculationContext context = new PrecalculationContext { Round = round }; int[] listSize = new int[] { 169, 1361802, 15111642 }; context.list = round < 2 ? (object)new List <Entry01>(listSize[round]) : (object)new List <Entry2>(listSize[round]); Console.WriteLine("Calculating for round {0}: ", round); int boardSize = HeHelper.RoundToHandSize[round] - 2; for (int p = 0; p < POCKETS_COUNT; ++p) { context.pocketKind = (HePocketKind)p; context.pocket = HePocket.KindToCardSet((HePocketKind)p); context.pocketSei.Reset(); context.pocketSei.Convert(context.pocket); Console.Write("{0} ", HePocket.KindToString((HePocketKind)p)); CardEnum.Combin(StdDeck.Descriptor, boardSize, CardSet.Empty, context.pocket, OnPrecalculateBoard, context); } Console.WriteLine(); Debug.Assert(EnumAlgos.CountCombin(50, boardSize) * POCKETS_COUNT == context.count); if (round < 2) { WriteTable((List <Entry01>)context.list, lutPath); } else { WriteTable((List <Entry2>)context.list, lutPath); } Console.WriteLine("LUT file {0} written, calculated in {1:0.0} s", lutPath, (DateTime.Now - startTime).TotalSeconds); }
public void Test_KindToCardset() { Assert.AreEqual(169, (int)HePocketKind.__Count); DeckDescriptor deck = StdDeck.Descriptor; Assert.AreEqual(deck.GetCardSet("Ac Ad"), HePocket.KindToCardSet(HePocketKind._AA)); Assert.AreEqual(deck.GetCardSet("Ac Kd"), HePocket.KindToCardSet(HePocketKind._AKo)); Assert.AreEqual(deck.GetCardSet("Ac Kc"), HePocket.KindToCardSet(HePocketKind._AKs)); Assert.AreEqual(deck.GetCardSet("7c 2d"), HePocket.KindToCardSet(HePocketKind._72o)); Assert.AreEqual(deck.GetCardSet("7c 5c"), HePocket.KindToCardSet(HePocketKind._75s)); //for (int i = 0; i < 169; ++i) //{ // HePocketKind pk = (HePocketKind)i; // Console.WriteLine("{0,-4}: {1}", pk, HePocket.KindToCardSet(pk)); //} }
/// <summary> /// Returns a probability distribution assuming that only given pockets can be dealt. /// The distribution is bases on pockets count only. /// For example, for (AA, 72o) the distribution will be (6/18, 12/18). /// </summary> /// <param name="pockets"></param> /// <returns></returns> public static double[] GetProbabDistr(HePocketKind[] pockets) { int n = pockets.Count(); double[] result = new double[n]; int totalPockets = 0; for (int c = 0; c < pockets.Length; ++c) { int count = HePocket.KindToRange(pockets[c]).Length; result[c] = count; totalPockets += count; } for (int c = 0; c < pockets.Length; ++c) { result[c] /= totalPockets; } return(result); }
public void Benchmark_CardSetToKind() { CardSet[] pockets = CardEnum.Combin(StdDeck.Descriptor, 2, CardSet.Empty, CardSet.Empty); int repetitions = 100; DateTime startTime = DateTime.Now; int checksum = 0; for (int r = 0; r < repetitions; ++r) { for (int p = 0; p < pockets.Length; ++p) { checksum += (int)HePocket.CardSetToKind(pockets[p]); } } double runTime = (DateTime.Now - startTime).TotalSeconds; Console.WriteLine("Cardset to kind: count: {0:#,#}, {1:#,#} r/s, checksum: {2}", repetitions * pockets.Length, repetitions * pockets.Length / runTime, checksum); startTime = DateTime.Now; CardSet checksum1 = CardSet.Empty; NormSuit ns = new NormSuit(); for (int r = 0; r < repetitions; ++r) { for (int p = 0; p < pockets.Length; ++p) { checksum1 |= ns.Convert(pockets[p]); ns.Reset(); } } runTime = (DateTime.Now - startTime).TotalSeconds; Console.WriteLine("To compare performance:"); Console.WriteLine("Normalize suit : count: {0:#,#}, {1:#,#} r/s, checksum: {2}", repetitions * pockets.Length, repetitions * pockets.Length / runTime, checksum1.bits); }
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 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)"); }
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); }
static List <Entry> Precalculate(int boardSize) { int POCKETS_COUNT = (int)HePocketKind.__Count; //POCKETS_COUNT = 1; // Test PrecalculationContext context = new PrecalculationContext(); int[] listSize = new int[] { 169, -1, -1, 1361802, 15111642 }; context.list = new List <Entry>(listSize[boardSize]); for (int p = 0; p < POCKETS_COUNT; ++p) { context.pocketKind = (HePocketKind)p; context.pocket = HePocket.KindToCardSet((HePocketKind)p); context.pocketSei.Reset(); context.pocketSei.Convert(context.pocket); Console.WriteLine("Calculating for board size {0}, pocket {1}", boardSize, context.pocket); CardEnum.Combin(StdDeck.Descriptor, boardSize, CardSet.Empty, context.pocket, OnPrecalculateBoard, context); } Debug.Assert(EnumAlgos.CountCombin(50, boardSize) * POCKETS_COUNT == context.count); return(context.list); }
/// <summary> /// A heuristic to correct opponent probabilies based on the card dealt to the hero. /// </summary> private static double[] CorrectOpponentProbab(HePocketKind[] pockets, int heroCard, double[] dealProbab, double[] oppCardProbab) { int n = pockets.Length; // Calculate card distribution for opponents with condition that the hero received heroCard. double[] oppDealProbabCond = PocketHelper.GetProbabDistr(pockets, HePocket.KindToCardSet(pockets[heroCard])); // Calculate a corrected probability of opponent cards. double[] corrOppProbab = new double[n]; double sum = 0; for (int i = 0; i < n; ++i) { double condCoeff = oppDealProbabCond[i] / dealProbab[i]; corrOppProbab[i] = oppCardProbab[i] * condCoeff; sum += corrOppProbab[i]; } // Normalize the probability of opponent cards. for (int i = 0; i < n; ++i) { corrOppProbab[i] /= sum; } return(corrOppProbab); }
private static float CalculateFast(CardSet pocket, CardSet board, int handLength) { if (_luts[1] == null) { LoadPrecalculationTables(); } int round = HeHelper.HandSizeToRound[handLength]; Entry[] lookup = _luts[round]; NormSuit se = new NormSuit(); CardSet sePocket = se.Convert(pocket); CardSet seBoard = se.Convert(board); Entry keyEntry = new Entry(HePocket.CardSetToKind(sePocket), seBoard); int idx = Array.BinarySearch <Entry>(lookup, keyEntry); if (idx < 0) { throw new ApplicationException(String.Format("No entry in lookup table for pocket {{{0}}} board {{{1}}}", sePocket, seBoard)); } return(lookup[idx].value); }
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(); } }
protected int GetPreflopAbstrCard(int[] hand) { HePocketKind pk = HePocket.HandToKind(hand); return(_pfPocketCa.PocketKindToAbstrCard[(int)pk]); }