/// <summary> /// 1. Selects a starting suit /// 2. Converts a pattern of one suite 4 times, setting the pattern first to the starting suite, /// then to next suit, etc. /// </summary> /// <param name="pattern"></param> private void TestConvertOneSuite(UInt32 pattern) { NormSuit sn = new NormSuit(); for (int s1 = 0; s1 < 4; ++s1) { // Console.WriteLine("Starting suite {0}", s1); CardSet orig = new CardSet(); orig.bits = (ulong)pattern << 16 * (s1 % 4); Assert.AreEqual(FromSuits(0, 0, 0, pattern), sn.Convert(orig)); orig.bits = (ulong)pattern << 16 * ((s1 + 1) % 4); Assert.AreEqual(FromSuits(0, 0, pattern, 0), sn.Convert(orig)); // Test copy constructor. NormSuit sn2 = new NormSuit(sn); orig.bits = (ulong)pattern << 16 * ((s1 + 2) % 4); Assert.AreEqual(FromSuits(0, pattern, 0, 0), sn2.Convert(orig)); orig.bits = (ulong)pattern << 16 * ((s1 + 3) % 4); Assert.AreEqual(FromSuits(pattern, 0, 0, 0), sn2.Convert(orig)); // Test both reset and recreate. if (s1 % 2 == 0) { sn.Reset(); } else { sn = new NormSuit(); } } }
static void OnPrecalculateBoard(ref CardSet board, PrecalculationContext d) { NormSuit sei = new NormSuit(d.pocketSei); CardSet seBoard = sei.Convert(board); Entry keyEntry = new Entry(d.pocketKind, seBoard); // Actually there is no BinarySearch necessary, because a key will be either present in the table // or go to the end (greater than the rest). // It's left here just to verify the algorithm. int idx = d.list.BinarySearch(keyEntry); if (idx < 0) { if (d.list.Count > 0 && d.list[d.list.Count - 1].key >= keyEntry.key) { throw new ApplicationException( "Algorithm error, new value must be greater than all existing values."); } List <int> pocketIdxs = StdDeck.Descriptor.GetIndexesAscending(d.pocket); List <int> boardIdxs = StdDeck.Descriptor.GetIndexesAscending(seBoard); int[] hand = new int[pocketIdxs.Count + boardIdxs.Count]; int h = 0; for (int i = 0; i < pocketIdxs.Count; ++i) { hand[h++] = pocketIdxs[i]; } for (int i = 0; i < boardIdxs.Count; ++i) { hand[h++] = boardIdxs[i]; } keyEntry.value = Calculate(hand); d.list.Add(keyEntry); } d.count++; }
// Create ranges for each pocket kind. // Also puts non-se pockets to _cardSetToKind private static void AddPocket(ref CardSet pocket, int [] rangePos) { NormSuit ns = new NormSuit(); CardSet snPocket = ns.Convert(pocket); // The suit-normalized pocket is already added, we can use its kind. int kindIndex = (int)_cardSetToKind[snPocket]; if (!_cardSetToKind.ContainsKey(pocket)) { _cardSetToKind.Add(pocket, (HePocketKind)kindIndex); } _kindToRange[kindIndex][rangePos[kindIndex]] = pocket; rangePos[kindIndex]++; }
public void Benchmark_Convert() { int repetitions = 40000000; CardSet cs1 = FromSuits(0, 0x1, 0, 0); CardSet cs2 = FromSuits(0x1, 0, 0, 0); CardSet cs3 = FromSuits(0, 0, 0x1, 0); CardSet cs4 = FromSuits(0, 0, 0, 0x1); NormSuit sn = new NormSuit(); DateTime startTime = DateTime.Now; for (int i = 0; i < repetitions; ++i) { CardSet result; result = sn.Convert(cs1); result = sn.Convert(cs2); result = sn.Convert(cs3); result = sn.Convert(cs4); } double time = (DateTime.Now - startTime).TotalSeconds; Console.WriteLine("Single card: conversions {0:###,###,###}, time {1} s, {2:###,###,###} conv/s", repetitions * 4, time, repetitions * 4 / time); cs1 = FromSuits(0, 0xFFFF, 0, 0); cs2 = FromSuits(0xFFFF, 0, 0, 0); cs3 = FromSuits(0, 0, 0xFFFF, 0); cs4 = FromSuits(0, 0, 0, 0xFFFF); sn = new NormSuit(); startTime = DateTime.Now; for (int i = 0; i < repetitions; ++i) { CardSet result; result = sn.Convert(cs1); result = sn.Convert(cs2); result = sn.Convert(cs3); result = sn.Convert(cs4); } time = (DateTime.Now - startTime).TotalSeconds; Console.WriteLine("Full suite: conversions {0:###,###,###}, time {1} s, {2:###,###,###} conv/s", repetitions * 4, time, repetitions * 4 / time); }
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); }
public static float CalculateFast(CardSet board) { NormSuit ns = new NormSuit(); Entry searchEntry = new Entry(); searchEntry.CardSet = ns.Convert(board).bits; int round = HeHelper.HandSizeToRound[board.CountCards() + 2]; Entry [] lut = _luts[round - 1]; int idx = Array.BinarySearch(lut, searchEntry); if (idx < 0) { throw new ApplicationException(string.Format("Cannot find LUT entry for board: '{0}'", StdDeck.Descriptor.GetCardNames(board))); } return(lut[idx].Ahvo); }
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); }
public void Benchmark_CopyFrom() { int repetitions = 40000000; NormSuit sn = new NormSuit(); NormSuit sn1 = new NormSuit(); DateTime startTime = DateTime.Now; for (int i = 0; i < repetitions; ++i) { sn1.CopyFrom(sn); } double time = (DateTime.Now - startTime).TotalSeconds; Console.WriteLine("Repetitions {0:###.###.###}, time {1} s, {2:###,###,###,###} copy/s", repetitions, time, repetitions / time); }
public void Test_CountSuits() { // Total 16 combinations Assert.AreEqual(0, NormSuit.CountSuits(FromSuits(0, 0, 0, 0))); Assert.AreEqual(1, NormSuit.CountSuits(FromSuits(0, 0, 0, 1))); Assert.AreEqual(1, NormSuit.CountSuits(FromSuits(0, 0, 1, 0))); Assert.AreEqual(1, NormSuit.CountSuits(FromSuits(0, 1, 0, 0))); Assert.AreEqual(1, NormSuit.CountSuits(FromSuits(1, 0, 0, 0))); Assert.AreEqual(2, NormSuit.CountSuits(FromSuits(0, 0, 1, 1))); Assert.AreEqual(2, NormSuit.CountSuits(FromSuits(0, 1, 0, 1))); Assert.AreEqual(2, NormSuit.CountSuits(FromSuits(1, 0, 0, 1))); Assert.AreEqual(2, NormSuit.CountSuits(FromSuits(0, 1, 1, 0))); Assert.AreEqual(2, NormSuit.CountSuits(FromSuits(1, 0, 1, 0))); Assert.AreEqual(2, NormSuit.CountSuits(FromSuits(1, 1, 0, 0))); Assert.AreEqual(3, NormSuit.CountSuits(FromSuits(0, 1, 1, 1))); Assert.AreEqual(3, NormSuit.CountSuits(FromSuits(1, 0, 1, 1))); Assert.AreEqual(3, NormSuit.CountSuits(FromSuits(1, 1, 0, 1))); Assert.AreEqual(3, NormSuit.CountSuits(FromSuits(1, 1, 1, 0))); Assert.AreEqual(4, NormSuit.CountSuits(FromSuits(1, 1, 1, 1))); }
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 static Result CalculateNoVerify(CardSet[] csRange1, CardSet[] csRange2) { UInt64 totalValue = 0; uint count = 0; NormSuit ns = new NormSuit(); Dictionary <CardSet, UInt32> knonwValues = new Dictionary <CardSet, UInt32>(); foreach (CardSet cs1 in csRange1) { foreach (CardSet cs2 in csRange2) { if (cs1.IsIntersectingWith(cs2)) { continue; } CardSet union = ns.Convert(cs1); union.UnionWith(ns.Convert(cs2)); ns.Reset(); Debug.Assert(union.CountCards() == 4); UInt32 knownValue; if (!knonwValues.TryGetValue(union, out knownValue)) { int[] h1 = StdDeck.Descriptor.GetIndexesAscending(cs1).ToArray(); int[] h2 = StdDeck.Descriptor.GetIndexesAscending(cs2).ToArray(); knownValue = CalculateMatchupValue(h1, h2); knonwValues.Add(union, knownValue); } totalValue += knownValue; count++; } } Result r = new Result(); r.Equity = (float)totalValue / count / _boardsCount / 2; r.Count = count; return(r); }
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); }
/// <summary> /// Generates all possible hands containing given suites, /// normalizes and verifies them. /// </summary> private void TestPermutations(uint s3, uint s2, uint s1, uint s0) { uint[] arr = new uint[] { s0, s1, s2, s3 }; Array.Sort(arr); CardSet expected = FromSuits(arr[0], arr[1], arr[2], arr[3]); List <List <int> > perms = EnumAlgos.GetPermut(4); for (int i = 0; i < perms.Count; ++i) { // Console.WriteLine("Permutation: {0}", i); NormSuit sn = new NormSuit(); CardSet orig = FromSuits(arr[perms[i][0]], arr[perms[i][1]], arr[perms[i][2]], arr[perms[i][3]]); CardSet converted = sn.Convert(orig); Assert.AreEqual(expected, converted); // Make sure result is consistent. converted = sn.Convert(orig); Assert.AreEqual(expected, converted); // Make sure self is converted to self with a new normalizers // (because it is already sorted). NormSuit sn2 = new NormSuit(); converted = sn2.Convert(converted); Assert.AreEqual(expected, converted); } }
public void Test_Convert() { // Do generic testing with 1 suit in card set. TestConvertOneSuite(0xFFFF); TestConvertOneSuite(0x8001); // Do some more complex testing manually. NormSuit sn = new NormSuit(); Assert.AreEqual(FromSuits(0, 0, 0x8001, 0x8001), sn.Convert(FromSuits(0x8001, 0, 0, 0x8001))); sn = new NormSuit(); Assert.AreEqual(FromSuits(0, 0, 0x7001, 0xFFFF), sn.Convert(FromSuits(0, 0xFFFF, 0, 0x7001))); sn.Reset(); Assert.AreEqual(FromSuits(0, 0, 0x8001, 0xFFFF), sn.Convert(FromSuits(0, 0xFFFF, 0, 0x8001))); sn.Reset(); Assert.AreEqual(FromSuits(0, 0x8001, 0xF00F, 0xFFFF), sn.Convert(FromSuits(0xF00F, 0x8001, 0, 0xFFFF))); sn.Reset(); Assert.AreEqual(FromSuits(0x8001, 0xDEAD, 0xF00F, 0xFFFF), sn.Convert(FromSuits(0xFFFF, 0xF00F, 0x8001, 0xDEAD))); // Make sure equal suites keep order for 2 suits for (int s1 = 0; s1 < 4; ++s1) { for (int s2 = s1 + 1; s2 < 4; ++s2) { sn.Reset(); uint[] s = new uint[4]; s[s1] = 1; s[s2] = 1; // Convert once with equal suit ranks. sn.Convert(FromSuits(s)); // Change ranks, make sure they are ordered as suite indexes. s[s1] = 1; s[s2] = 2; Assert.AreEqual(FromSuits(0, 0, 2, 1), sn.Convert(FromSuits(s))); } } // Make sure equal suites keep order for 3 suits for (int s1 = 0; s1 < 4; ++s1) { for (int s2 = s1 + 1; s2 < 4; ++s2) { for (int s3 = s2 + 1; s3 < 4; ++s3) { sn.Reset(); uint[] s = new uint[4]; s[s1] = 1; s[s2] = 1; s[s3] = 1; // Convert once with equal suit ranks. sn.Convert(FromSuits(s)); // Change ranks, make sure they are ordered as suite indexes. s[s1] = 1; s[s2] = 2; s[s3] = 3; Assert.AreEqual(FromSuits(0, 3, 2, 1), sn.Convert(FromSuits(s))); } } } // Make sure equal suites keep order for 4 suits - only one combination is possible sn.Reset(); sn.Convert(FromSuits(1, 1, 1, 1)); Assert.AreEqual(FromSuits(4, 3, 2, 1), sn.Convert(FromSuits(4, 3, 2, 1))); // Test all permutations of some suits combinations. TestPermutations(0x1, 0x2, 0x3, 0x4); TestPermutations(0x8001, 0xFFFF, 0xF0F0, 0x0F0F); TestPermutations(0x0, 0x0, 0x0, 0x0); TestPermutations(0x0, 0x0, 0x0, 0x1); TestPermutations(0x0, 0x0, 0x1, 0x1); TestPermutations(0x0, 0x0, 0x2, 0x1); TestPermutations(0x0, 0x1, 0x1, 0x1); TestPermutations(0x0, 0x2, 0x1, 0x1); TestPermutations(0x0, 0x3, 0x2, 0x1); TestPermutations(0x1, 0x1, 0x1, 0x1); TestPermutations(0x2, 0x1, 0x1, 0x1); TestPermutations(0x2, 0x2, 0x1, 0x1); TestPermutations(0x3, 0x2, 0x1, 0x1); }
static void OnPrecalculateBoard(ref CardSet board, PrecalculationContext d) { NormSuit sei = new NormSuit(d.pocketSei); CardSet seBoard = sei.Convert(board); List <Entry01> list01 = null; List <Entry2> list2 = null; UInt32 key = GetKey((int)d.pocketKind, seBoard); bool addNew = false; // A key will be either present in the table or go to the end (greater than the rest). // This is due to the order of dealt boards in CardEnum if (d.Round < 2) { list01 = (List <Entry01>)d.list; addNew = list01.Count == 0 || list01[list01.Count - 1].Key < key; } else { list2 = (List <Entry2>)d.list; addNew = list2.Count == 0 || list2[list2.Count - 1].Key < key; } if (addNew) { List <int> pocketIdxs = StdDeck.Descriptor.GetIndexesAscending(d.pocket); List <int> boardIdxs = StdDeck.Descriptor.GetIndexesAscending(seBoard); int[] hand = new int[pocketIdxs.Count + boardIdxs.Count]; int h = 0; for (int i = 0; i < pocketIdxs.Count; ++i) { hand[h++] = pocketIdxs[i]; } for (int i = 0; i < boardIdxs.Count; ++i) { hand[h++] = boardIdxs[i]; } float[] sdhs; if (d.Round < 2) { Entry01 newEntry = new Entry01 { Key = key }; sdhs = Calculate(hand, d.Round + 1); newEntry.Hs = sdhs[0]; newEntry.SdPlus1 = sdhs[1]; sdhs = Calculate(hand, 3); newEntry.Sd3 = sdhs[1]; list01.Add(newEntry); } else { Entry2 newEntry = new Entry2 { Key = key }; sdhs = Calculate(hand, d.Round + 1); newEntry.Hs = sdhs[0]; newEntry.SdPlus1 = sdhs[1]; list2.Add(newEntry); } } d.count++; }