nature112091777
nature112091777
  • Threads: 1
  • Posts: 5
Joined: Jul 3, 2014
July 3rd, 2014 at 1:21:09 PM permalink
Hello everyone,

This is my first time posting on this site. I'm a big fan of Mike's site Wizard of Odds. I didn't want to contact him directly as this isn't really important, but I'm a computer engineering undergrad in Florida and I have a couple of questions I wanted to ask someone who's familiar in programming casino game simulations. So, I figured I would come here and see if anyone can help or if he would look at this post himself.

I decided to make a blackjack simulation program in C++ because I wanted to practice my coding. I've pretty much finished, but for some reason my program has a player edge of around .2 percent or more. I have a link to my github for this code below:


This program is just supposed to run through a bunch of hands of blackjack and allow me to change certain things and see the results of my changes.

I originally believed that this edge was because I was using rand() which isn't a good random generator (or so I've heard), but I tried using the Mersenne twister algorithm as well and it didn't work either. I tried to comment my code as well as I could, but I don't have a lot of experience in C++.

So, here are my questions:

First off, can anyone see right away why my program isn't giving me the correct house edge? It's using six decks, shuffling after every hand, using the correct blackjack strategy (as far as I know), dealer stands on soft 17, can resplit aces (eventually I'm going not allow this), can hit resplit aces (eventually I'm going to not allow this), can double after a split, blackjack is 3:2, surrenders are allowed with any dealer upcard.

What programming languages, or programs does Mike use to test casino games?

Has Mike ever considered creating a Wizard of Odds application for the iPhone/iPad?

Lastly, I have a question about creating a "Probability of Loss Table" for Craps like there is for Blackjack at

Since strategies in craps involves multiple bets (that resolve after multiple rolls) I was wondering how to calculate this for certain betting methods. I'm not a statistician, in fact it's one of my weak points, but I tried to create something like this myself and this is what I got.

Let's say I'm betting the pass line and the come whenever I can and I'm backing all the bets up with full odds (3X4X5X). Lets say we roll the dice 100 times. I calculated the std deviation in 100 rolls to be sqr(100) * stddev(pass/come) + 3 * sqr(100) * stddev(odds4/10) + 4 * sqr(100) * stddev(odds5/9) + 5 * sqr(100) * stddev(odds6/8). Is this correct? I guess I assumed I would be making a bet every roll which wouldn't technically be correct, but close enough for me. How would this change if I was using the 3pt strategy or solely the pass line with odds? I tried to use the avg number of rolls for each bet to be resolved, but I confused myself.

Edit: I didn't account for the 3X4X5X odds...

Sorry for such a long post. Once again I love the site, and although I'm terrible in stats, I find the math very interesting.

Keep up the good work!

Thanks,
MangoJ
MangoJ
  • Threads: 10
  • Posts: 905
Joined: Mar 12, 2011
July 3rd, 2014 at 2:49:42 PM permalink
Hit split aces gives you around .2% EV for the player, you should remove that if you want to compare things. Typical pitfalls are: do you tie dealer and player blackjacks ? Do you accidental count split hand two-card 21 as blackjack ?

And the most important question: how many hands did you simulate ?
charliepatrick
charliepatrick
  • Threads: 39
  • Posts: 2946
Joined: Jun 17, 2011
July 3rd, 2014 at 3:11:32 PM permalink
^ I don't know the exact figures, but allowing hit of split Aces is never found in normal Blackjack games (at least I've never seen it except in variations).

The Mersenne twister is a good random number generator but it is worth creating a subroutine and checking it IS creating random numbers using various [Chi-squared] tests. I'm not familiar with what the c run time library gives, but initialise it with something from a timer so you always get different results and (I'm guessing) ensure about half the bits are on. Also take off a few numbers before starting your tests.
nature112091777
nature112091777
  • Threads: 1
  • Posts: 5
Joined: Jul 3, 2014
July 6th, 2014 at 6:53:38 PM permalink
Player and house blackjacks push and I'll need to double check counting split 21's for blackjack.

I simulated 100 million hands and the player won around two hundred thousand so I figure the player edge is around .2%

Also, I'll get rid of hitting split aces and see if that'll help.

thanks
nature112091777
nature112091777
  • Threads: 1
  • Posts: 5
Joined: Jul 3, 2014
July 6th, 2014 at 6:55:09 PM permalink
Yeah, I just didn't feel like creating a new scenario for aces so I treated them as a normal split.

I'll look in to what you said. Like I said, I'm not really good with stat but hopefully I can figure it out.

Thanks for your help.
AxiomOfChoice
AxiomOfChoice
  • Threads: 32
  • Posts: 5761
Joined: Sep 12, 2012
July 8th, 2014 at 1:58:20 PM permalink
I thought I had found an error in your code but I was wrong. Having said that...

That is an awful lot of code. You really like switch statements and recursion.

Eg, your houselogic method could look something like:

while (CalculateTotal(househand) < 17) {
hit(househand);
}

rather than the 80-ish lines of code you have. It is easier to read and almost certainly faster. You would need a CalculateTotal method but this is useful in other places as well, so having it in a separate method makes sense.

Just a suggestion (from someone with many years of experience): if you are copying the same block of code many times, you are almost certainly doing something wrong (unless you are specifically doing it for performance reasons -- and, with modern compilers, this is rarely necessary)

Also, you should generally only use recursion when you have a good reason to do it, rather than doing it at every opportunity (instead of using a loop). And, while you're at it, some classes with methods would not hurt. Eg, a hand method that contains your vector of cards, as well as Total() and IsSoft() methods. Data and methods on that data together in classes -- you are using an OO language after all. You are writing in C++; use the features of the language. Do you have a background with functional languages or something?
CrystalMath
CrystalMath
  • Threads: 8
  • Posts: 1909
Joined: May 10, 2011
July 9th, 2014 at 6:10:47 AM permalink
Please check your scoring algorithm. If the dealer is dealt {5, 1, 8}, does your program calculate a total of 24 or 14?
I heart Crystal Math.
nature112091777
nature112091777
  • Threads: 1
  • Posts: 5
Joined: Jul 3, 2014
July 14th, 2014 at 12:37:46 PM permalink
Quote: AxiomOfChoice

I thought I had found an error in your code but I was wrong. Having said that...

That is an awful lot of code. You really like switch statements and recursion.

Eg, your houselogic method could look something like:

while (CalculateTotal(househand) < 17) {
hit(househand);
}

rather than the 80-ish lines of code you have. It is easier to read and almost certainly faster. You would need a CalculateTotal method but this is useful in other places as well, so having it in a separate method makes sense.

Just a suggestion (from someone with many years of experience): if you are copying the same block of code many times, you are almost certainly doing something wrong (unless you are specifically doing it for performance reasons -- and, with modern compilers, this is rarely necessary)

Also, you should generally only use recursion when you have a good reason to do it, rather than doing it at every opportunity (instead of using a loop). And, while you're at it, some classes with methods would not hurt. Eg, a hand method that contains your vector of cards, as well as Total() and IsSoft() methods. Data and methods on that data together in classes -- you are using an OO language after all. You are writing in C++; use the features of the language. Do you have a background with functional languages or something?



Yeah, like I said. I haven't used C++ in a long time, and when I last used it I pretty much just used it for data structures. Thanks for the suggestions, though, I think I'll add some more functions that are used elsewhere. I know it's long and hard to read so I had wanted to clean it up a bit more but I've been busy.
nature112091777
nature112091777
  • Threads: 1
  • Posts: 5
Joined: Jul 3, 2014
July 14th, 2014 at 12:42:31 PM permalink
Quote: CrystalMath

Please check your scoring algorithm. If the dealer is dealt {5, 1, 8}, does your program calculate a total of 24 or 14?



I'm pretty sure it will show a 14 and then the dealer will hit once again.
CrystalMath
CrystalMath
  • Threads: 8
  • Posts: 1909
Joined: May 10, 2011
July 14th, 2014 at 2:25:35 PM permalink
Quote: nature112091777

I'm pretty sure it will show a 14 and then the dealer will hit once again.



I see it now. I followed the code wrong.
I heart Crystal Math.
AcesAndEights
AcesAndEights
  • Threads: 67
  • Posts: 4300
Joined: Jan 5, 2012
July 15th, 2014 at 11:26:09 AM permalink
Quote: charliepatrick

^ I don't know the exact figures, but allowing hit of split Aces is never found in normal Blackjack games (at least I've never seen it except in variations).

The Mersenne twister is a good random number generator but it is worth creating a subroutine and checking it IS creating random numbers using various [Chi-squared] tests. I'm not familiar with what the c run time library gives, but initialise it with something from a timer so you always get different results and (I'm guessing) ensure about half the bits are on. Also take off a few numbers before starting your tests.


Obligatory plug for random.org. True randomness! Based on atmospheric noise! I just can't get over how cool this is. They have a JSON-RPC API and there's a pre-built C++ client out there somewhere.

The remote latency over the wire probably makes this slower than a Mersenne twister or other similar "good enough" PRNG algorithm. But if I ever sim a casino game, I'm totally using this for my random numbers.
"So drink gamble eat f***, because one day you will be dust." -ontariodealer
MangoJ
MangoJ
  • Threads: 10
  • Posts: 905
Joined: Mar 12, 2011
July 15th, 2014 at 11:33:13 AM permalink
Quote: AcesAndEights


Obligatory plug for random.org. True randomness! Based on atmospheric noise! I just can't get over how cool this is.



Yeah, this is all fun and games untill you realize you need a higher random number rate.
AxiomOfChoice
AxiomOfChoice
  • Threads: 32
  • Posts: 5761
Joined: Sep 12, 2012
July 15th, 2014 at 12:48:56 PM permalink
Quote: MangoJ

Quote: AcesAndEights


Obligatory plug for random.org. True randomness! Based on atmospheric noise! I just can't get over how cool this is.



Yeah, this is all fun and games untill you realize you need a higher random number rate.



Just write a program that constantly downloads them and stores them locally. Then write an API that consumes and discards them from storage. Hard drives are cheap; you could buy a 1T drive and keep it constantly full of random numbers.
MangoJ
MangoJ
  • Threads: 10
  • Posts: 905
Joined: Mar 12, 2011
July 16th, 2014 at 10:30:32 AM permalink
Then you have a buffer, but in the end you are still limited to the download rate. If you are into something actually meaningfull, say numerically integrating a stochastic differential equation, for each integration step you need a "fresh and new" random variable. Each integration step is terribly cheap (most often only some multiplication and addition of only a few variables) but waiting a download (or even the harddisk) is waiting dead.
AxiomOfChoice
AxiomOfChoice
  • Threads: 32
  • Posts: 5761
Joined: Sep 12, 2012
July 16th, 2014 at 12:35:49 PM permalink
Quote: MangoJ

Then you have a buffer, but in the end you are still limited to the download rate. If you are into something actually meaningfull, say numerically integrating a stochastic differential equation, for each integration step you need a "fresh and new" random variable. Each integration step is terribly cheap (most often only some multiplication and addition of only a few variables) but waiting a download (or even the harddisk) is waiting dead.



I thought we were talking about analyzing casino games.

I guess it depends how often you do it. If I run a sim once every few months, my buffer is always going to be full and I am never going to have to wait.

Also, sequential reads from disk are very, very fast. The first one is slow but on average you are not spending a lot of time waiting for the disk.

Having said that, the difference between true random and good pseudorandom numbers is irrelevent, so I use the Mersenne twister. Any lack of true randomness that exists is certainly not going to bias your results in a game analysis, which is all that I care about.
  • Jump to: