I'm just throwing this out in case someone has been down the same road and recognizes the pattern offhand. I've been working on it for a few days and I've run out of leads.
Thanks,
John
Divergence (when > .001)
16: (0 0 0 0 0 0 0 0 -0.0353818 -0.1024275)
17: (0 0 0 0 0 0 0 0 -0.0446574 -0.16063856)
18: (0 0 0 0 0 0 0 0 -0.06320883 -0.27686077)
19: (0 0 0 0 0 0 0 0 -0.081760154 -0.39308296)
20: (0 0 0 0 0 0 0 0 -0.11954226 -0.50940516)
21: (0 0 0 0 0 0 0 0 -0.0740243 -0.28375814)
My values
(-0.29278374 -0.25225022 -0.2110631 -0.16719267 -0.15369901 -0.47537518 -0.51051754 -0.5431497 -0.5757818 -0.7694275)
(-0.15297459 -0.117216244 -0.08057337 -0.044941377 0.011739161 -0.10680899 -0.38195097 -0.42315423 -0.4643575 -0.63863856)
(0.121741906 0.14830007 0.17585444 0.1995612 0.28344393 0.39955416 0.10595135 -0.18316336 -0.24150883 -0.37706077)
(0.38630468 0.40436295 0.4231789 0.4395121 0.49597707 0.6159765 0.59385365 0.28759676 -0.018660154 -0.11548296)
(0.6399866 0.6502721 0.66104996 0.6703597 0.7039586 0.7732272 0.79181516 0.75835687 0.43495774 0.14609484)
(0.8820065 0.88530034 0.8887673 0.89175385 0.90283674 0.92592627 0.93060505 0.93917614 0.8885757 0.63844186)
Wizard's chart for comparison
16 -0.2928 -0.2523 -0.2111 -0.1672 -0.1537 -0.4754 -0.5105 -0.5431 -0.5404 -0.667
17 -0.153 -0.1172 -0.0806 -0.0449 0.0117 -0.1068 -0.382 -0.4232 -0.4197 -0.478
18 0.1217 0.1483 0.1759 0.1996 0.2834 0.3996 0.106 -0.1832 -0.1783 -0.1002
19 0.3863 0.4044 0.4232 0.4395 0.496 0.616 0.5939 0.2876 0.0631 0.2776
20 0.64 0.6503 0.661 0.6704 0.704 0.7732 0.7918 0.7584 0.5545 0.6555
21 0.882 0.8853 0.8888 0.8918 0.9028 0.9259 0.9306 0.9392 0.9626 0.9222
So, while calculating the stand values, I throw away 2nd cards that make a blackjack because the dealer wouldn't have those at that point?
Let me try that. Be right back.
I made the adjustments and it looks like it's working. Thank you both very much. I'm kicking myself for not seeing the answer. I got overly focused on my :dealersoft flag and couldn't break away.
It takes about 9.3 seconds to generate the entire stand value table on my CoreDuo Macbook Air. I guess that's somewhere in the middle of a big range? Usable, but not amazing.
Now, time for the other player decisions, and non-infinite decks, and...
9.3 seconds is quite long. It's okay depending on what you want to do with it.
Quote: MangoJHow do you calculate the probability the dealers hand will reach 17-21 ? Do you use an infinite deck, or take card removal into account ?
9.3 seconds is quite long. It's okay depending on what you want to do with it.
Yes, I was probably being optimistic. At the moment, I'm using an infinite deck. Taking card removal into account should be relatively easy, but might make things too slow.
I'm not making any separate calculation of the dealer reaching 17-21. I have seen people do this. My goal is usability, minimizing programmer time, particularly for novel situations, like new rules variants or new games that are similar BJ. I'm sure there's some room for additional optimization within this goal, but I'm trying to make as few assumptions as possible about the form of the game. I want to be able to enter a rule in a form that's somewhat natural and get back the optimal player's strategy along with game value. It's not that important that it's fast, though I guess testing for things like countability would be easier.
It could all easily just be a waste of time, but I'll check back with progress.
If stand EVs take several seconds, what about double down EVs ? Count in a factor of 10 without any sort of optimation. And a factor of maybe 1000 for hit EVs. Don't even think about splits.
The core about basically all blackjack programms is the efficient calculation of dealer probabilities ending up in 17-21, since this is the "innerst loop" you need for any kind of EV calculations. Exploit the fact that the dealer has no decision to make, and all depends on the upcard and cards removed from the deck.
The beauty of the infinite deck approximation is, card removal takes no effect, and hence the dealer probabilities only depend on the upcard. Once you have that, the stand EV of the players hand is simply given by summing up the paytable for the hands total, weighted by the dealer probabilities.
Quote: MangoJMinimizing programmer time is a valid goal. But it won't make you happy if the results you need take week or months to calculate.
If stand EVs take several seconds, what about double down EVs ? Count in a factor of 10 without any sort of optimation. And a factor of maybe 1000 for hit EVs. Don't even think about splits.
This would be an excellent place for a sanity check now that I have something tangible.
I guess what I said before wasn't quite right. I'm calculating the dealer values recursively, but the function is memoized. So I'm avoiding a lot of duplicated effort, and everything is a lookup after the first pass. To be fair, I was only trying to duplicate the wizard's 16-A table earlier, so to do all stand values from the ground up could take 30 seconds, but a lot of the subsequent "work" is then just a lookup.
...
After giving it some thought (30 minutes or so), I don't see any reason not to continue this way. I did find one flaw in the design I was using regarding memory requirements for my memo'd table, but I think there's a reasonable computation trade off. I'm betting runs end up in the minutes, or maybe 10's of minutes, range. Of course, I could be missing something obvious again.
Anyway, if you have the dealer probabilities the stand EV is a straight forward calculation, as you compare the players totals against the dealers totals, determine the winner, and weight the payout by the corresponding dealer probabilities.
A full scale infinite deck calculation can be done in a simple spreadsheet, and takes only a split second for all stand, hit, double and split EVs. If 10 minutes is fine for you, with the benefit of simple rule adjustments, that is what will probably fit you well.
There is a GNU Blackjack C lib published somewhere, you can use it for various calculations, also with pretty simple rule adjustments. Why not give it a try ?
Quote: MangoJ...Recursive is fine, especially for infinite deck (where you do it only one single time). There is a linear algorithm which is way faster, and usefull if you do finite-deck calculations.
...If 10 minutes is fine for you, with the benefit of simple rule adjustments, that is what will probably fit you well.
There is a GNU Blackjack C lib published somewhere, you can use it for various calculations, also with pretty simple rule adjustments. Why not give it a try ?
There's the obvious thing I was missing… multiple decks don't only complicate the player side of the equation. You may have just saved me a lot of work. hmmm… still, this should be highly parallelizable, right? Can I just rent a bunch of workers on heroku and fork-join my way to temporal sanity?
I appreciate the feedback. To be clear, I'm not a BJ player. I'm an ex-poker player with an interest in game design and/or producing tools for game design. That being the case, I'm neccesarily interested in situations beyond "simple rule adjustments".
I've seen C source code from a couple of libraries, including the one from that guy with steiner tree optimizations over blackjacktheforum.com. It looked impressive to say the least. These libraries, at 2-4k lines, are not what I want to deal with, especially once the 1000's of additional lines of unrolled arrays(?) are taken into account, or rather whatever algorithm produces them. I don't pretend to understand what was going on. I saw one simulation program in python at about 500 lines, but I don't know how complete it was, and I'm sure it was quite slow.
I honestly don't know how much of a benefit this may or may not be over other approaches. So, let me ask, if, say, I wanted to add a super-insurance rule where I had to pay 2 bets up front, but got three times the return if the dealer busted... how much (programmer) time would I be looking at to find value charts and optimal player strategy, once I got to know these other libraries? If my method ends up requiring 5-10 minutes, but the other libraries require 20, then it's probably not worth it, but if it's going to take an hour or two, maybe it is. With my method, I could envision a design GUI that allowed non-programmers make this new rule: add flag on super-insurance, test for flag on dealer bust and modify payout. The strategy charts might require an extra if-super-insured chart, but it could still be automated. I would never attempt making that design GUI on top of those C libraries.
Quote: AcesAndEightssocks, can I ask what is your end goal? It seems like all the problems you're solving have already been solved. If you're laying down the foundation for further analysis, that's cool, or I guess if you're just doing it for fun I could understand that too :).
I see 4 potential end uses:
1) Analyzing my own or my friends designs. Especially those that may not fall into simple rules variations (One comes to mind)
2) Though I'm not an AP, I might be tempted to try if get in early on some new game.
3) as part of a product targeted toward non-mathematician/programmers. Again, with an eye toward larger design variations than what might be typically supported by standard BJ software.
4) as part of a service, design or math analysis.
Also, there's the obvious benefit of experience, though I don't necessarily think of this as fun.
-John