Open Side Menu Go to the Top
Register
Turn Flush Draw - Probability Check Turn Flush Draw - Probability Check

05-19-2019 , 05:24 PM
I calculated the probability that a player gets a turn flush draw (no flush) if he doesn’t fold to be 9.715%. He can have a suited or non-suited hand and their probabilities are included in the calc.

I then simulated the situation and got a slightly lower result ~9.680%, with no large trials over 1m ever showing a result exceeding 9.715%. I used Excel VBA.

Cannot discover where the discrepancy is.

Will someone please do an independent calc?

Thanks
Turn Flush Draw - Probability Check Quote
05-19-2019 , 08:15 PM
At first I interpreted wrong, but from your numbers I can see that if you flop a flush draw and turn a blank, that counts. Another clarification is that a 4-flush board doesn't count.

I get 9.7157 %

(14/15) * 4*C(13,4)*C(39,2) / C(52,6)

I'm pretty confident that there's a bug in your code, but if you're sure of your code then maybe I'll do a sim of my own.
Turn Flush Draw - Probability Check Quote
05-19-2019 , 08:18 PM
I am interpreting your question as what is the prob of having a flush draw on the turn in NLHE. Meaning that you don't have to turn a flush draw (on the turn). I am also ignoring the degenerate case of all four board cards of the same suit, since that is not really having a meaningful flush draw.

Case 1: Your hole cards are suited and exactly 2 of the 4 board cards are of that suit
= C(4,1)*C(13,2)*C(11,2)*C(39,2)
= 12,715,560

Case 2: Your hole cards are unsuited and exactly 3 of the 4 board cards are of the same suit as 1 of your 2 hole cards
= C(4,2)*C(13,1)*C(13,1)*C(2,1)*C(12,3)*C(38,1)
= 16,954,080

TOTAL:
= 12,715,560 + 16,954,080
= 29,669,640

Denominator: 2 hole cards and 4 board cards
= C(52,2)*C(50,4)
= 305,377,800

Percent:
= 29,669,640 / 305,377,800
= 9.7157161%
Turn Flush Draw - Probability Check Quote
05-19-2019 , 09:53 PM
Thanks to both; they confirm what I got. I've looked at the simulation like forever. Printed out hands that it rejected and accepted and can't see any mistake yet it never reaches the theoretical. So, I assumed my calc was wrong and then I did the calc four more ways and always got the same answer -- 0.0971572.

I'll let it ride for a few days and I'm sure if and when I get back to it my dumb mistake will pop out, maybe!

Thanks again.
Turn Flush Draw - Probability Check Quote
05-20-2019 , 03:37 AM
Since this is very easy to code I coded both a simulation and a brute force routine. For what it is worth, I will post the code knowing that it is surely inefficient but it seemed to get the job done.

Simulation
Code:
simturnflushdraw=function(trials)
{
  tally=0
  
  for(dealy in 1:trials)
  {
    cardy=sample(52,6)
    suity=suits(cardy)
    suitcounts=tabulate(suity,nbins=4)
    if((max(suitcounts))==4)
    {
      foursuit=which(suitcounts==4)
      holeysuits=suity[1:2]
      if((sum(holeysuits==foursuit))>0) tally=tally+1
    }
  }
  
  pct=100*tally/trials
  
  return(pct)
}
Simulation results of 5 batches of 10 million trials each:
9.72085%
9.71008%
9.71537%
9.71651%
9.71166%


Brute Force Program

Code:
tallyturnflushdraw=function(dummy)
{
  count=0
  tallyzero=0
  tallyones=0
  tallytwos=0
  
  for(b1 in 1:49)
  {
    for(b2 in (b1+1):50)
    {
      for(b3 in (b2+1):51)
      {
        for(b4 in (b3+1):52)
        {
          boardy=c(b1,b2,b3,b4)
          stubby=setdiff((1:52),boardy)
          
          for(h1 in 1:47)
          {
            for(h2 in (h1+1):48)
            {
              count=count+1
              holey=stubby[c(h1,h2)]
              allsix=c(boardy,holey)
              suitsix=suits(allsix)
              suitholey=suitsix[c(5,6)]
              suitcounts=tabulate(suitsix,nbins=4)
              maxsuitcounts=max(suitcounts)
              if(maxsuitcounts==4)
              {
                foursuit=which(suitcounts==4)
                if((sum(suitholey==foursuit))==0) tallyzero=tallyzero+1
                if((sum(suitholey==foursuit))==1) tallyones=tallyones+1
                if((sum(suitholey==foursuit))==2) tallytwos=tallytwos+1
              }
            }
          }
        }
      }
    }
  }
  
  temp=c(tallyzero,tallyones,tallytwos,count)
  return(temp)
      
}
Brute force results were as follows (these agree with the combinatoric results posted up thread):
- Number of flush draws using 2 hole cards = 12,715,560
- Number of flush draws using 1 hole cards = 16,954,080
- Number of flush draws using 0 hole cards = 2,119,260
- Total number of cases (denominator) = 305,377,800
Turn Flush Draw - Probability Check Quote
05-20-2019 , 12:21 PM
I wrote another sim based on counting how many 6 card deals had 4 of one suit and at least one of the suit was dealt to the player. I got the same kind of result, Avg. FD hit about 0.09680 with no large runs exceeding the theo of 0.09715. Because the difference from theo is quite small (0.0035), I think it unlikely to be a logic error.

i wrote a program to check how “random” the deal was and could not find any apparent discrepancies – e.g. % of clubs, diamonds, h,s were all close to 25%.

The code I used for the second sim is below. You are not permitted to laugh at my coding.

Havedraw = 0 'track total hits
For iSIM = 1 To nSim 'sim loop *******
Erase Dealt, Have 'clear the arrays Dealt and Have for new check for fd

'Deal 6 cards; first two are the player’s
For k = 1 To 6
Deal: xCard = Int(52 * Rnd) 'range 0 to 51
If Dealt(xCard) = True Then GoTo Deal
Dealt(xCard) = True
Suit(k) = xCard Mod 4 'range 0 to 3
'get suit distrib
Have(Suit(k)) = Have(Suit(k)) + 1 'count each of 4 suits; 0=club to 3=spade
Next k

'check for 4 of one suit with player having at least 1 of the suit
For Soot = 0 To 3
If Have(Soot) = 4 And (Suit(1) = Soot Or Suit(2) = Soot) Then Havedraw = Havedraw + 1: GoTo Nextsim
Next

Nextsim:
Next iSIM ‘******

Answer = Havedraw / nSim 'show result
Turn Flush Draw - Probability Check Quote
05-20-2019 , 01:48 PM
Quote:
Originally Posted by statmanhal
Suit(k) = xCard Mod 4 'range 0 to 3
Should be mod 13, no?

Edit: nvm lol. I would have done it by taking floor(xcard / 13) but mod 4 works too.

Idk where the bug is but I also don't know VBA so maybe I'm missing something that looks right but isn't. Perhaps I'll translate your code to Julia.

Last edited by heehaww; 05-20-2019 at 01:58 PM.
Turn Flush Draw - Probability Check Quote
05-20-2019 , 02:29 PM
Quote:
Originally Posted by heehaww
Should be mod 13, no?

Edit: nvm lol. I would have done it by taking floor(xcard / 13) but mod 4 works too.

Idk where the bug is but I also don't know VBA so maybe I'm missing something that looks right but isn't. Perhaps I'll translate your code to Julia.
Okay -- I don't know Julia but look forward to see the results if you do the translate.
Turn Flush Draw - Probability Check Quote
05-20-2019 , 02:52 PM
Your algorithm looks correct.

I wrote the same algorithm in R and will post the results of 10 batches of 1 million below. Again, I am sure that nobody cares but I'll post my parallel R code here:

Code:
statman=function(nsim)
{
  havedraw=0
  
  for(isim in 1:nsim)
  {
    dealt=rep(0,52)
    have=rep(0,4)
    suit=rep(-1,6)
    suitplus=rep(-1,6)
    
    for(k in 1:6)
    {
      newcard=FALSE
      while(newcard==FALSE)
      {
        rnd=runif(1)
        xcard=floor(rnd*52) # 0 to 51
        xcardplus=xcard+1   # 1 to 52
      
        if(dealt[xcardplus]==0)
        {
          newcard=TRUE
          dealt[xcardplus]=1
          suit[k]=xcard %% 4  # 0 to 3
          suitplus[k]=suit[k]+1  # 1 to 4
          have[suitplus[k]]=have[suitplus[k]]+1
        }
      }
    }
    
    for(soot in 1:4)
    {
      if((have[soot]==4) & ((suitplus[1]==soot) | (suitplus[2]==soot)))
      {
        havedraw=havedraw+1
        break
      }
    }
    
  }
    
  tempy=100*havedraw/nsim
    
  return(tempy)
  
}
Results of 10 batches of 1 million trials each:
9.7244%
9.6789%
9.7010%
9.6659%
9.7341%
9.6834%
9.6640%
9.6874%
9.7556%
9.7083%
======
9.7003% average over 10 million trials

Here I am using R's "uniform" random number generator (runif) which, I think, is the equivalent of RND in statmanhal's program.

Perhaps the RND you are using is not precise in some way. I am reminded of a similar situation I went through a few years ago on this forum. I tried to replicate a known result using simulation and just could not get there. I cannot remember but I always came in slightly too high or slightly too low (beyond the threshold of random chance).

Upon further investigation the RNG of the software I was using was way "out of date". I think it was an 8-bit RNG, or something like that, and exhibited "patterns" that never washed out no matter how many trials I took. I changed my poker platform to R which is far from ideal, but at least its RNG is much better.
Turn Flush Draw - Probability Check Quote
05-20-2019 , 03:17 PM
Quote:
Originally Posted by whosnext
Your algorithm looks correct.

I am sure that nobody cares but I'll post my parallel R code here:
Hey, I care. Thanks for doing this.

I have an old Internet posting that severely criticised Excel's VBA random number generator but that was for Excel 10, I believe. I would have thought Microsoft would have updated it for the Excel 16 version I now have.

As I said I looked at how the suits compare to the 25% theoretical but did not do any testing so based on what you and Heehaw did, unless shown otherwise, I have to believe it's the generator not me that's causing the discrepancy.
Turn Flush Draw - Probability Check Quote
05-20-2019 , 04:12 PM
Code:
function turnflush(n::Int64)
    havedraw = 0
    dealt = Vector{Bool}(undef,52)
    have = Vector{Int64}(undef,4)
    suit = Vector{Int64}(undef,6)
    for t in 1:n
        fill!(dealt,false)
        fill!(have,0)
        for k=1:6
            r = rand(1:52)
            while dealt[r] begin r = rand(1:52) end end
            dealt[r] = true
            suit[k] = (r % 4)+1
            have[suit[k]] += 1
        end
        for s=1:4
            have[s]==4 && (suit[1]==s || suit[2]==s) && begin havedraw += 1 end
        end
    end
    return havedraw / n
end
100 million trials:
Quote:
turnflush(100000000)
0.09715524
Julia's RNG is Mersenne Twister.
Turn Flush Draw - Probability Check Quote
05-20-2019 , 04:37 PM
Julia looks like a nice program, heehaww, and I can see where your application and whosnext's application use similiar logic to what I did.

So, I will stay with blaming the VBA generator for the slight discrepancy.
Turn Flush Draw - Probability Check Quote
05-20-2019 , 04:55 PM
IIRC Excel has both a RAND and a RANDBETWEEN function. Have you tried using both functions? Does the "discrepancy" exist (to the same degree) when using both functions?
Turn Flush Draw - Probability Check Quote
05-20-2019 , 05:05 PM
Hmmm:
Quote:
Originally Posted by office.com
As of Excel 2010, Excel uses the Mersenne Twister algorithm (MT19937) to generate random numbers.
But I'm still inclined to blame their RNG. It's either that or whosnext and I mistranslated statman's code.
Turn Flush Draw - Probability Check Quote
05-20-2019 , 05:16 PM
IIRC when VBA is used to "call" Excel, it still uses the old (crappy) RNG.
Turn Flush Draw - Probability Check Quote
05-20-2019 , 06:48 PM
Quote:
Originally Posted by whosnext
IIRC Excel has both a RAND and a RANDBETWEEN function. Have you tried using both functions? Does the "discrepancy" exist (to the same degree) when using both functions?
WHOAA!! whosnext, I think you're onto something.

VBA doesn't have a RandBetween but the worksheet does and you can activate it in VBA with the command Application.WorksheetFunction.RandBetween. The problem using it is that it’s so slow. A million simulations of my program took 56 seconds!!! Using RND, the time was 0.9 seconds

However, the result I got was 0.097399. Several runs or 2 million also got higher results than 0.097157 That’s the first time in dozens of runs of 1 million or more trials that a simulation result was higher than the theoretical value.

Microsoft, are you aware of a possible VBA RND issue and if it exists are you doing something about it?
Turn Flush Draw - Probability Check Quote

      
m