Optimizing hand-evaluation algorithm for Poker-Monte-Carlo-Simulation <p>I've written an equilator for Hold'em Poker as a hobbyproject. It works correctly, but there is still one thing I am not happy with: In the whole process of simulating hands, the process of evaluating the hands takes about 35% of the time. That seems to be pretty much to me compared with what else has to be done like iterating through and cloning large arrays and stuff.</p> <p>Any idea of how to get this more performant would be great.</p> <p>This is the code:</p> <pre><code> private static int getHandvalue(List&lt;Card&gt; sCards) { // --- Auf Straight / Straight Flush prüfen --- if ((sCards[0].Value - 1 == sCards[1].Value) &amp;&amp; (sCards[1].Value - 1 == sCards[2].Value) &amp;&amp; (sCards[2].Value - 1 == sCards[3].Value) &amp;&amp; (sCards[3].Value - 1 == sCards[4].Value)) { if ((sCards[0].Color == sCards[1].Color) &amp;&amp; (sCards[1].Color == sCards[2].Color) &amp;&amp; (sCards[2].Color == sCards[3].Color) &amp;&amp; (sCards[3].Color == sCards[4].Color)) return (8 &lt;&lt; 20) + (byte)sCards[0].Value; // Höchste Karte Kicker else return (4 &lt;&lt; 20) + (byte)sCards[0].Value; // Höchste Karte Kicker (Straight) } // --- Auf Wheel / Wheel Flush prüfen --- if ((sCards[4].Value == Card.CardValue.Two) &amp;&amp; (sCards[3].Value == Card.CardValue.Three) &amp;&amp; (sCards[2].Value == Card.CardValue.Four) &amp;&amp; (sCards[1].Value == Card.CardValue.Five) &amp;&amp; (sCards[0].Value == Card.CardValue.Ace)) { if ((sCards[0].Color == sCards[1].Color) &amp;&amp; (sCards[1].Color == sCards[2].Color) &amp;&amp; (sCards[2].Color == sCards[3].Color) &amp;&amp; (sCards[3].Color == sCards[4].Color)) return(8 &lt;&lt; 20) + (byte)sCards[1].Value; // Zweithöchste Karte Kicker else return(4 &lt;&lt; 20) + (byte)sCards[1].Value; // Zweithöchste Karte Kicker (Straight) } // --- Auf Flush prüfen --- if ((sCards[0].Color == sCards[1].Color) &amp;&amp; (sCards[1].Color == sCards[2].Color) &amp;&amp; (sCards[2].Color == sCards[3].Color) &amp;&amp; (sCards[3].Color == sCards[4].Color)) return (5 &lt;&lt; 20) + ((byte)sCards[0].Value &lt;&lt; 16) + ((byte)sCards[1].Value &lt;&lt; 12) + ((byte)sCards[2].Value &lt;&lt; 8) + ((byte)sCards[3].Value &lt;&lt; 4) + (byte)sCards[4].Value; // --- Auf Vierling prüfen --- if (((sCards[0].Value == sCards[1].Value) &amp;&amp; (sCards[1].Value == sCards[2].Value) &amp;&amp; (sCards[2].Value == sCards[3].Value)) || ((sCards[1].Value == sCards[2].Value) &amp;&amp; (sCards[2].Value == sCards[3].Value) &amp;&amp; (sCards[3].Value == sCards[4].Value))) return (7 &lt;&lt; 20) + (byte)sCards[1].Value; // Wert des Vierlings (keine Kicker, da nicht mehrere Spieler den selben Vierling haben können) // --- Auf Full-House / Drilling prüfen --- // Drilling vorne if ((sCards[0].Value == sCards[1].Value) &amp;&amp; (sCards[1].Value == sCards[2].Value)) { // Full House if (sCards[3].Value == sCards[4].Value) return (6 &lt;&lt; 20) + ((byte)sCards[0].Value &lt;&lt; 4) + (byte)sCards[3].Value; // Drilling (höher bewerten) // Drilling return (3 &lt;&lt; 20) + ((byte)sCards[0].Value &lt;&lt; 8) + ((byte)sCards[3].Value &lt;&lt; 4) + (byte)sCards[4].Value; // Drilling + Kicker 1 + Kicker 2 } // Drilling hinten if ((sCards[2].Value == sCards[3].Value) &amp;&amp; (sCards[3].Value == sCards[4].Value)) { // Full House if (sCards[0].Value == sCards[1].Value) return (6 &lt;&lt; 20) + ((byte)sCards[2].Value &lt;&lt; 4) + (byte)sCards[0].Value; // Drilling (höher bewerten) // Drilling return (3 &lt;&lt; 20) + ((byte)sCards[2].Value &lt;&lt; 8) + ((byte)sCards[0].Value &lt;&lt; 4) + (byte)sCards[1].Value; // Drilling + Kicker 1 + Kicker 2 } // Drilling mitte if ((sCards[1].Value == sCards[2].Value) &amp;&amp; (sCards[2].Value == sCards[3].Value)) return (3 &lt;&lt; 20) + ((byte)sCards[1].Value &lt;&lt; 8) + ((byte)sCards[0].Value &lt;&lt; 4) + (byte)sCards[4].Value; // Drilling + Kicker 1 + Kicker 2 // --- Auf Zwei Paare prüfen --- // Erstes Paar vorne, zweites Paar mitte if ((sCards[0].Value == sCards[1].Value) &amp;&amp; (sCards[2].Value == sCards[3].Value)) return (2 &lt;&lt; 20) + ((byte)sCards[0].Value &lt;&lt; 8) + ((byte)sCards[2].Value &lt;&lt; 4) + (byte)sCards[4].Value; // Erstes Paar + Zweites Paar + Kicker // Erstes Paar vorne, zweites Paar hinten if ((sCards[0].Value == sCards[1].Value) &amp;&amp; (sCards[3].Value == sCards[4].Value)) return (2 &lt;&lt; 20) + ((byte)sCards[0].Value &lt;&lt; 8) + ((byte)sCards[3].Value &lt;&lt; 4) + (byte)sCards[2].Value; // Erstes Paar + Zweites Paar + Kicker // Erstes Paar mitte, zweites Paar hinten if ((sCards[1].Value == sCards[2].Value) &amp;&amp; (sCards[3].Value == sCards[4].Value)) return (2 &lt;&lt; 20) + ((byte)sCards[1].Value &lt;&lt; 8) + ((byte)sCards[3].Value &lt;&lt; 4) + (byte)sCards[0].Value; // Erstes Paar + Zweites Paar + Kicker // --- Auf Paar prüfen --- // Paar vorne if (sCards[0].Value == sCards[1].Value) return (1 &lt;&lt; 20) + ((byte)sCards[0].Value &lt;&lt; 12) + ((byte)sCards[2].Value &lt;&lt; 8) + ((byte)sCards[3].Value &lt;&lt; 4) + (byte)sCards[4].Value; // Paar + Kicker 1 + Kicker 2 + Kicker 3 // Paar mitte-vorne if (sCards[1].Value == sCards[2].Value) return (1 &lt;&lt; 20) + ((byte)sCards[1].Value &lt;&lt; 12) + ((byte)sCards[0].Value &lt;&lt; 8) + ((byte)sCards[3].Value &lt;&lt; 4) + (byte)sCards[4].Value; // Paar + Kicker 1 + Kicker 2 + Kicker 3 // Paar mitte-hinten if (sCards[2].Value == sCards[3].Value) return (1 &lt;&lt; 20) + ((byte)sCards[2].Value &lt;&lt; 12) + ((byte)sCards[0].Value &lt;&lt; 8) + ((byte)sCards[1].Value &lt;&lt; 4) + (byte)sCards[4].Value; // Paar + Kicker 1 + Kicker 2 + Kicker 3 // Paar hinten if (sCards[3].Value == sCards[4].Value) return (1 &lt;&lt; 20) + ((byte)sCards[3].Value &lt;&lt; 12) + ((byte)sCards[0].Value &lt;&lt; 8) + ((byte)sCards[1].Value &lt;&lt; 4) + (byte)sCards[2].Value; // Paar + Kicker 1 + Kicker 2 + Kicker 3 // --- High Card bleibt übrig --- return ((byte)sCards[0].Value &lt;&lt; 16) + ((byte)sCards[1].Value &lt;&lt; 12) + ((byte)sCards[2].Value &lt;&lt; 8) + ((byte)sCards[3].Value &lt;&lt; 4) + (byte)sCards[4].Value; // High Card + Kicker 1 + Kicker 2 + Kicker 3 + Kicker 4 } </code></pre> <p>This method returns an exact value for every sorted 5-Card-Combination in poker. It gets called by another method:</p> <pre><code> private static int getHandvalueList(List&lt;Card&gt; sCards) { int count = sCards.Count; if (count == 5) return getHandvalue(sCards); int HighestValue = 0; Card missingOne; int tempValue; for (int i = 0; i &lt; count - 1; i++) { missingOne = sCards[i]; sCards.RemoveAt(i); tempValue = getHandvalueList(sCards); if (tempValue &gt; HighestValue) HighestValue = tempValue; sCards.Insert(i, missingOne); } missingOne = sCards[count - 1]; sCards.RemoveAt(count - 1); tempValue = getHandvalueList(sCards); if (tempValue &gt; HighestValue) HighestValue = tempValue; sCards.Add(missingOne); return HighestValue; } </code></pre> <p>This recursive method returns the highest value of all possible 5-card-combinations. And this one gets called by the final public method:</p> <pre><code> public static int GetHandvalue(List&lt;Card&gt; sCards) { if (sCards.Count &lt; 5) return 0; sCards.Sort(new ICardComparer()); return getHandvalueList(sCards); } </code></pre> <p>It gets delivered a maximum of 7 cards.</p> <p><strong>Update</strong></p> <p>So far: Each time, the public function gets called with 7 cards (which is the case most of the time), it has to call the hand-evaluation method 21 times (one time for every possible 5-card-combo).</p> <p>I thought about caching the value for each possible set of 5 to 7 cards in a hashtable und just look it up. But if I am not wrong, it would have to store more than 133.784.560 32-bit-integer values, which is about 500MB.</p> <p>What could be good hashfunction to assign every possible combination to exactly one arrayindex?</p> <p>Created a new question on that: <a href="http://stackoverflow.com/questions/22477192/hashfunction-to-map-combinations-of-5-to-7-cards">Hashfunction to map combinations of 5 to 7 cards</a></p> <p>Update: For further improvement regarding the accepted answer, have alook at: <a href="http://stackoverflow.com/questions/39317649/efficient-way-to-randomly-select-set-bit">Efficient way to randomly select set bit</a></p>