Quote:
Originally Posted by tombos21
Interesting. I remember you mentioning that you had found an advantage casino game a while back.
How did you go about solving it, and what strategy did you come up with? Did you have any trouble withdrawing after your account was restricted?
This is gonna be long. I don't know how to answer the questions you asked succinctly. Poor TLDR at the bottom and I labeled sections.
They just took away all bonus offers and stopped giving me VIP points or whatever which can be redeemed for cash/free spins. I was allowed to withdraw still, and I think I could still deposit if I wanted to.
I am going off of memory and not looking at the code since it's on my dead laptop (I could get it though if/when I want to), so I may make a mistake or leave something important out. I tested everything fairly rigorously though so I don't believe I made any major mistakes in the actual algorithm.
------Solving the game-------
To solve the game, I enumerate the full game tree. At each Hero decision node, I choose the higher of 0 and the EV of calling (yet to be calculated). At each Villain decision node. I apply a function to villain's range which removes the hands I believe villain folds at that node. I am keeping track of villain's full range as an array of 1326 bits, each of which represents one of the combos. Then I calculate continue/fold frequency by the ratio of the set bits before and after villain's strategy for that node is applied to get the EV when villain fold's, and calculate the EV when villain calls, which is the average of the EV of each node after the next card(s) are dealt. At showdown I calculate the equity of hero's hand vs. villain's range to get the EV at that leaf node, and backpropagate the EV through the tree to get all optimal hero actions and the EV of each action.
To improve speed I stored the results of each node in a hashtable, using a hash function which generates the same key for nodes which are strategically equivalent. Testing the hashtable was as simple as making sure the EV was the same with and without it.
At showdown I calculated the range of hands hero chops with and the range of hands hero wins against and store each in another hashtable, ignoring flushes to save space and to get more hashtable hits. When a range is extracted from the hashtable, I determine whether the board has a 3, 4 or 5 flush and set/unset the appropriate bits in the chop/win ranges based on the suit. I forget exactly how I handled what happens when hero can beat some/all flushes, but I remember straight flushes being slightly annoying to handle. Since suits were ignored I also have to mask out combos which have a dead card. The resulting ranges are used as a bitmask with villain's range to determine the final range we need to calculate hero's equity against.
The eval function generated a value which was distinct for each five card hand in a way that the values could be ordered by strength. This way I don't have to compare each hand individually, I just have to find hands with a value higher than hero's 114858858929387 or whatever.
------Villain's strategy-------
The AI's strategy was not very complicated, but I did have trouble figuring out exactly how it handled some classes of hands, and I still don't know. Preflop it called about top 90% of hands. I figured out the exact range but don't recall of the top of my head. The only consideration it made to board texture was whether the flop was paired/trips, monotone or neither.
On unpaired flops it would call made hands K8 high or better, all the way to showdown no matter what. Flush draws would call all the way down no matter what (even if they miss and are 5-high at the river, lol). Gutters would fold turn if they miss, and OESDs would mostly call down, but the showdown frequency of missed OESDs was low by a statistically significant amount, so I think they folded river sometimes, but I can't figure out the conditions.
The only difference with monotone flops was that missed flush draws would fold the river, unless they were K8 high or better of course. This made it possible to make river bluffs in some circumstances.
On paired flops the AI would call down more hands, I assume to account for the fact that it's harder to make a pair. It calls down JT high or better now. JT and Q-high were underrepresented at showdown by a statistically significant amount, so they must have sometimes been folded but I can't figure out under what conditions.
There were a few outliers that I couldn't figure out. Backdoor straight draws seemed to call flop at some frequency and call down if they improved, but they were underrepresented in a way that they would have had to fold flop most of the time as well as the turn when they miss. Sometimes it would call down something like 6-high with no backdoor, but that only happened a few times in 100k hands.
------Hero's strategy-------
Despite the fact that the AI had position, and there was no checking, which is a huuuuuge advantage, it played so badly Hero is able to get an edge. Hero's general strategy is to call 100% of hands preflop and on the flop, with some exceptions on connected and/or monotone boards where the AI meets MDF and hero has very low equity. Right away we get a lot of EV out of the AI significantly overfolding most flops. It normally calls A-high but doesn't call wider on A-high flops to compensate for fewer high card calls, making A-high flops way overfolded. There is a similar, smaller effect on K-high flops.
On the turn, hero is supposed to call down any pair to showdown, with some exceptions with bottom pair when an Ax comes out or on A/K-high flops. On turns which don't bring a 4-straight after connected flops, 100% of hands which had enough equity to call flop can call turn, accounting for the fact that the AI folds a lot of missed gutters. On paired boards Hero calls down A-high or better, and some K-high with a good enough kicker. Of course you have to fold more on A/K/Q high paired boards because villain's range has fewer naked high-cards and is stronger. On unpaired boards Hero sometimes calls A-high and gutters depending on how many missed gutters the opponent has and how much equity hero has vs. the continuing range. Gutters like 43 on KQ76 are trivial folds for example, but something like AK has enough showdown value and fold equity, and T9 easily has enough equity from it's overcards+gutter+villain folds to call on 7622. 2-card flush draws are always called, even on trips boards, and 2-card OESDs are called with extremely rare exceptions where you have minimal fold equity and no other hand equity or dirty outs, like 54 on A976 where we have to fold even when we river a pair.
There were some spots which were unintuitive for me. Hero is supposed to call with hands as weak as middle pair on 4-flush turns, for example, despite the fact that villain never folds any flush draw on the flop. He just has a lot of A/K-high/PPs, bottom pair and worse middle pairs in his range.
This doesn't even describe the full strategy because there are a lot of exceptions and edge cases for Hero.
TLDR: Solve by doing a big EV calculation on the game tree. Strategy is to call a lot pre+flop, decide whether you want to commit on turn and call down. Chase good draws.