//private void anon(object target) //{ // Dictionary<string, int> handTypeCount = new Dictionary<string, int>() { { "High Card", 0 }, { "Pair", 0 }, { "Two Pair", 0 }, { "Three of a Kind", 0 }, { "Straight", 0 }, { "Flush", 0 }, { "Full House", 0 }, { "Four of a Kind", 0 }, { "Straight Flush", 0 }, { "Royal Flush", 0 } }; // Tuple<List<int>, List<int>, int[], Hashtable> param = (Tuple<List<int>, List<int>, int[], Hashtable>)target; // foreach (string hand in CardUtilities.enumeratePossibleHands(param.Item1,param.Item2,param.Item3)) // { // handTypeCount[hand]++; // } // lock (param.Item4) // { // param.Item4.Add(param.Item3, handTypeCount); // } //} private void anon(object target) { Dictionary <string, int> handTypeCount; Tuple <List <int>, List <int>, int[], Hashtable> param; //Loop until the concurrent stack has been removed while (workerThreadQueue != null) { //try to pop from the stack if (workerThreadQueue.TryDequeue(out param)) { handTypeCount = new Dictionary <string, int>() { { "High Card", 0 }, { "Pair", 0 }, { "Jacks or Better", 0 }, { "Two Pair", 0 }, { "Three of a Kind", 0 }, { "Straight", 0 }, { "Flush", 0 }, { "Full House", 0 }, { "Four of a Kind", 0 }, { "Straight Flush", 0 }, { "Royal Flush", 0 } }; if (param == null) { break; } //if you suceed in poping then calculate all the hand details foreach (string hand in CardUtilities.enumeratePossibleHands(param.Item1, param.Item2, param.Item3)) { handTypeCount[hand]++; } lock (param.Item4) { param.Item4.Add(param.Item3, handTypeCount); } } } }
/// <summary> /// Calculates all the odds for the current state. If you leave chosenMask as null the optimal strategy will be calculated and used /// </summary> /// <param name="chosenMask"></param> private void calculateAndDisplayProbabilities(int[] chosenMask = null) { //http://www.durangobill.com/VideoPoker.html //calculate the value of the hand ONCE so that we don't have to redo it for each comparison; string currentHandType = CardUtilities.getHandName(handCards); //Go through (and count the types of) every set of drawable cards, given the current discard values DateTime start = DateTime.Now; List <int> sortedDeckClone = CardUtilities.createSortedCloneOfDeck(deckContent); Hashtable hashedResults = new Hashtable(); Thread[] workers = new Thread[4]; if (chosenMask == null) { workerThreadQueue = new ConcurrentQueue <Tuple <List <int>, List <int>, int[], Hashtable> >(); workers[0] = new Thread(new ParameterizedThreadStart(anon)); workers[1] = new Thread(new ParameterizedThreadStart(anon)); workers[2] = new Thread(new ParameterizedThreadStart(anon)); workers[3] = new Thread(new ParameterizedThreadStart(anon)); foreach (var maskQuad in CardUtilities.enumerateHandMasks_ThreadVersion()) { try { workerThreadQueue.Enqueue(new Tuple <List <int>, List <int>, int[], Hashtable>(handCards, sortedDeckClone, maskQuad.Item1, hashedResults)); workerThreadQueue.Enqueue(new Tuple <List <int>, List <int>, int[], Hashtable>(handCards, sortedDeckClone, maskQuad.Item2, hashedResults)); workerThreadQueue.Enqueue(new Tuple <List <int>, List <int>, int[], Hashtable>(handCards, sortedDeckClone, maskQuad.Item3, hashedResults)); workerThreadQueue.Enqueue(new Tuple <List <int>, List <int>, int[], Hashtable>(handCards, sortedDeckClone, maskQuad.Item4, hashedResults)); if (workers[0].ThreadState == ThreadState.Unstarted) { //hand, deck , mask, Storage_hashTable workers[0].Start(new Tuple <List <int>, List <int>, int[], Hashtable>(handCards, sortedDeckClone, maskQuad.Item1, hashedResults)); workers[1].Start(new Tuple <List <int>, List <int>, int[], Hashtable>(handCards, sortedDeckClone, maskQuad.Item2, hashedResults)); workers[2].Start(new Tuple <List <int>, List <int>, int[], Hashtable>(handCards, sortedDeckClone, maskQuad.Item3, hashedResults)); workers[3].Start(new Tuple <List <int>, List <int>, int[], Hashtable>(handCards, sortedDeckClone, maskQuad.Item4, hashedResults)); } } catch (Exception e) { Console.WriteLine(e.Message); } } workerThreadQueue.Enqueue(null); workerThreadQueue.Enqueue(null); workerThreadQueue.Enqueue(null); workerThreadQueue.Enqueue(null); workers[0].Join(); workers[1].Join(); workers[2].Join(); workers[3].Join(); Console.WriteLine(DateTime.Now.Subtract(start).ToString()); if (workerThreadQueue.Count != 0) { throw new Exception(); } else { workerThreadQueue = null; } } else //This else occurs when the user wants to know about a SPECIFIC mask, not neccessarily the optimal one { //Do the chosen mask of the user Dictionary <string, int> handTypeCount = new Dictionary <string, int>() { { "High Card", 0 }, { "Pair", 0 }, { "Jacks or Better", 0 }, { "Two Pair", 0 }, { "Three of a Kind", 0 }, { "Straight", 0 }, { "Flush", 0 }, { "Full House", 0 }, { "Four of a Kind", 0 }, { "Straight Flush", 0 }, { "Royal Flush", 0 } }; foreach (string hand in CardUtilities.enumeratePossibleHands(handCards, sortedDeckClone, chosenMask)) { handTypeCount[hand]++; } hashedResults.Add(chosenMask, handTypeCount); //Compute the draw all mask, that we use for opponent draw odds if (!(chosenMask[0] == 0 && chosenMask[0] == chosenMask[1] && chosenMask[1] == chosenMask[2] && chosenMask[2] == chosenMask[3] && chosenMask[3] == chosenMask[4])) { handTypeCount = new Dictionary <string, int>() { { "High Card", 0 }, { "Pair", 0 }, { "Jacks or Better", 0 }, { "Two Pair", 0 }, { "Three of a Kind", 0 }, { "Straight", 0 }, { "Flush", 0 }, { "Full House", 0 }, { "Four of a Kind", 0 }, { "Straight Flush", 0 }, { "Royal Flush", 0 } }; int[] drawAll = new int[] { 0, 0, 0, 0, 0 }; foreach (string hand in CardUtilities.enumeratePossibleHands(handCards, sortedDeckClone, drawAll)) { handTypeCount[hand]++; } hashedResults.Add(drawAll, handTypeCount); } } //By this stage we have the raw count data. //Next thing is to use that data to find optimal strageies and caluclate the odds List <int[]> bestMasks = new List <int[]>() { new int[] { 1, 1, 1, 1, 1 } }; int[] factorials = { 1, 2, 6, 24, 120 }; double highestExpected = 0; ///Keeps track of how many tied hand masks there are int tiedMasks = 0; foreach (var singleResult in hashedResults) { double runningTotal = 0; double top = sortedDeckClone.Count; int draws = 5 - ((int[])((DictionaryEntry)singleResult).Key).Sum(); for (int i = 1; i < draws; i++) { top = top * (sortedDeckClone.Count - i); } if (draws == 0) { if (highestExpected < payoffTable[currentHandType]) { highestExpected = payoffTable[currentHandType]; bestMasks = new List <int[]>() { (int[])((DictionaryEntry)singleResult).Key }; //= (int[])((DictionaryEntry)singleResult).Key; } continue; } foreach (var pair in ((Dictionary <string, int>)((DictionaryEntry)singleResult).Value)) { runningTotal += (payoffTable[pair.Key] * pair.Value); } if (highestExpected == runningTotal / (top / factorials[draws - 1])) { tiedMasks++; bestMasks.Add((int[])((DictionaryEntry)singleResult).Key); } if (draws > 0 && highestExpected < runningTotal / (top / factorials[draws - 1])) { tiedMasks = 0; highestExpected = runningTotal / (top / factorials[draws - 1]); bestMasks = new List <int[]>() { (int[])((DictionaryEntry)singleResult).Key }; } } //Once here, we have an optimal strategy selected (or the users selected mask) double weaker = 0, tied = -1, better = 0; int[] drawAllMask = null; //We need to find the reference to the actual list on the hashtable ([0,0,0,0,0]) foreach (int[] key in hashedResults.Keys) { if (key[0] == 0 && key[0] == key[1] && key[1] == key[2] && key[2] == key[3] && key[3] == key[4]) { drawAllMask = key; break; } } foreach (var type in (Dictionary <string, int>)hashedResults[drawAllMask]) { //are we still adding values to weaker and tied? if (tied == -1) { if (type.Key == currentHandType) { tied = type.Value; } else { weaker += type.Value; } continue; } //Getting here means that tied is greater than -1 (so we must be adding to better from here on) better += type.Value; } Console.WriteLine("Opponents have a %{0:0.000} of starting with a BETTER hand than what you have", (better / (tied + weaker)) * 100); ///Alter this to find the highest held card various masks and display that foreach (var mask in bestMasks) { foreach (var elem in mask) { Console.Write(elem); } Console.WriteLine(); } btn_Card1Holding.Content = bestMasks[0][0] == 1 ? "Hold" : "Draw"; btn_Card2Holding.Content = bestMasks[0][1] == 1 ? "Hold" : "Draw"; btn_Card3Holding.Content = bestMasks[0][2] == 1 ? "Hold" : "Draw"; btn_Card4Holding.Content = bestMasks[0][3] == 1 ? "Hold" : "Draw"; btn_Card5Holding.Content = bestMasks[0][4] == 1 ? "Hold" : "Draw"; Console.WriteLine("Optimal return rate- " + highestExpected); Console.WriteLine("ties identical masks" + tiedMasks); Console.WriteLine(DateTime.Now.Subtract(start).ToString()); int betterHands = 0; int tiedHands = -1; int worseHands = 0; foreach (var pair in (Dictionary <string, int>)hashedResults[bestMasks[0]]) { if (pair.Key == currentHandType) { tiedHands = pair.Value; handTypeCountLabels[pair.Key].Foreground = new SolidColorBrush(Colors.Blue); handTypeLabels[pair.Key].Foreground = new SolidColorBrush(Colors.Blue); } else if (tiedHands == -1) { worseHands += pair.Value; handTypeCountLabels[pair.Key].Foreground = new SolidColorBrush(Colors.Red); handTypeLabels[pair.Key].Foreground = new SolidColorBrush(Colors.Red); } else { betterHands += pair.Value; handTypeCountLabels[pair.Key].Foreground = new SolidColorBrush(Colors.Green); handTypeLabels[pair.Key].Foreground = new SolidColorBrush(Colors.Green); } } double totalHands = betterHands + tiedHands + worseHands; foreach (var pair in (Dictionary <string, int>)hashedResults[bestMasks[0]]) { //The flow direction property of labels causes weird positioning of special charachters: special symols seem to go to the opposite side you place them O_o when using "RightToLeft" if (totalHands == 0) { if (pair.Key != currentHandType) { handTypeCountLabels[pair.Key].Content = "%0.00"; } else { handTypeCountLabels[pair.Key].Content = "%100.00"; } } else { double chance = (pair.Value / (totalHands) * 100); if (chance != 0 && chance < 0.01) { handTypeCountLabels[pair.Key].Content = "%0.01>"; } else { handTypeCountLabels[pair.Key].Content = string.Format("%{0:0.00}", (pair.Value / (totalHands) * 100)); } } } lbl_decrease.Content = string.Format("{0:0.0%} chance of value decreasing", worseHands / totalHands); lbl_increase.Content = string.Format("{0:0.0%} chance of value increasing", betterHands / totalHands); lbl_returnRate.Content = string.Format("{0:0.0%} estimated return rate", highestExpected); lbl_betterStart.Content = string.Format("{0:0.0%} chance of better starting hand", (better / (tied + weaker))); }