Thread: "Poker" AI Results

1. "Poker" AI Results

This is the results thread for the contest at: at "Poker" AI competition

Three programmers participated: Daved, jdragyn and whiteflags.

Here's a result from a sample round:
Code:
```+-------------+
| Hand #1     |
+-------------+
Daved with \$1000 is dealt 0.0843532
jdragyn with \$1000 is dealt 0.431715
whiteflags with \$1000 is dealt 0.159581
jdragyn puts in \$1 (blind) for a total of 1
whiteflags folds.
Daved folds.
jdragyn takes the \$1 pot.
+-------------+
| Hand #2     |
+-------------+
Daved with \$1000 is dealt 0.429426
jdragyn with \$1000 is dealt 0.470077
whiteflags with \$1000 is dealt 0.666311
whiteflags puts in \$1 (blind) for a total of 1
Daved folds.
jdragyn folds.
whiteflags takes the \$1 pot.
+-------------+
| Hand #3     |
+-------------+
Daved with \$1000 is dealt 0.0170904
jdragyn with \$1000 is dealt 0.964019
whiteflags with \$1000 is dealt 0.17185
Daved puts in \$1 (blind) for a total of 1
jdragyn goes all-in with \$1000 to 1000
whiteflags folds.
Daved folds.
jdragyn takes the \$1001 pot.
+-------------+
| Hand #4     |
+-------------+
Daved with \$999 is dealt 0.763573
jdragyn with \$1001 is dealt 0.760033
whiteflags with \$1000 is dealt 0.703452
jdragyn puts in \$1 (blind) for a total of 1
whiteflags folds.
Daved folds.
jdragyn takes the \$1 pot.
+-------------+
| Hand #5     |
+-------------+
Daved with \$999 is dealt 0.832331
jdragyn with \$1001 is dealt 0.796228
whiteflags with \$1000 is dealt 0.668783
whiteflags puts in \$1 (blind) for a total of 1
Daved folds.
jdragyn goes all-in with \$1001 to 1001
whiteflags goes all-in with \$999 to 1000
Total size of the pot is 2001
jdragyn shows 0.796228
whiteflags shows 0.668783
jdragyn (all-in) wins \$1000 from whiteflags
+-------------+
| Hand #6     |
+-------------+
Daved with \$999 is dealt 0.810694
jdragyn with \$2001 is dealt 0.449477
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn folds.
Daved takes the \$1 pot.
+-------------+
| Hand #7     |
+-------------+
Daved with \$999 is dealt 0.987976
jdragyn with \$2001 is dealt 0.907956
whiteflags is out.
jdragyn puts in \$1 (blind) for a total of 1
Daved goes all-in with \$999 to 999
jdragyn goes all-in with \$2000 to 2001
Total size of the pot is 3000
Daved shows 0.987976
jdragyn shows 0.907956
Daved (all-in) wins \$999 from jdragyn
jdragyn shows 0.907956
+-------------+
| Hand #8     |
+-------------+
Daved with \$1998 is dealt 0.311747
jdragyn with \$1002 is dealt 0.0845668
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn folds.
Daved takes the \$1 pot.
+-------------+
| Hand #9     |
+-------------+
Daved with \$1998 is dealt 0.0577715
jdragyn with \$1002 is dealt 0.371441
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn folds.
Daved takes the \$1 pot.
+-------------+
| Hand #10    |
+-------------+
Daved with \$1998 is dealt 0.260201
jdragyn with \$1002 is dealt 0.0758385
whiteflags is out.
jdragyn puts in \$1 (blind) for a total of 1
Daved folds.
jdragyn takes the \$1 pot.
+-------------+
| Hand #11    |
+-------------+
Daved with \$1998 is dealt 0.0833766
jdragyn with \$1002 is dealt 0.572375
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn folds.
Daved takes the \$1 pot.
+-------------+
| Hand #12    |
+-------------+
Daved with \$1998 is dealt 0.882473
jdragyn with \$1002 is dealt 0.268258
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn folds.
Daved takes the \$1 pot.
+-------------+
| Hand #13    |
+-------------+
Daved with \$1998 is dealt 0.916196
jdragyn with \$1002 is dealt 0.368267
whiteflags is out.
jdragyn puts in \$1 (blind) for a total of 1
Daved folds.
jdragyn takes the \$1 pot.
+-------------+
| Hand #14    |
+-------------+
Daved with \$1998 is dealt 0.366405
jdragyn with \$1002 is dealt 0.798425
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn goes all-in with \$1002 to 1002
Daved folds.
jdragyn takes the \$1003 pot.
+-------------+
| Hand #15    |
+-------------+
Daved with \$1997 is dealt 0.704672
jdragyn with \$1003 is dealt 0.465835
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn folds.
Daved takes the \$1 pot.
+-------------+
| Hand #16    |
+-------------+
Daved with \$1997 is dealt 0.37611
jdragyn with \$1003 is dealt 0.875057
whiteflags is out.
jdragyn puts in \$1 (blind) for a total of 1
Daved folds.
jdragyn takes the \$1 pot.
+-------------+
| Hand #17    |
+-------------+
Daved with \$1997 is dealt 0.755913
jdragyn with \$1003 is dealt 0.0829493
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn folds.
Daved takes the \$1 pot.
+-------------+
| Hand #18    |
+-------------+
Daved with \$1997 is dealt 0.438826
jdragyn with \$1003 is dealt 0.973266
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn goes all-in with \$1003 to 1003
Daved folds.
jdragyn takes the \$1004 pot.
+-------------+
| Hand #19    |
+-------------+
Daved with \$1996 is dealt 0.680746
jdragyn with \$1004 is dealt 0.915342
whiteflags is out.
jdragyn puts in \$1 (blind) for a total of 1
Daved folds.
jdragyn takes the \$1 pot.
+-------------+
| Hand #20    |
+-------------+
Daved with \$1996 is dealt 0.887082
jdragyn with \$1004 is dealt 0.14481
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn folds.
Daved takes the \$1 pot.
+-------------+
| Hand #21    |
+-------------+
Daved with \$1996 is dealt 0.648823
jdragyn with \$1004 is dealt 0.680105
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn goes all-in with \$1004 to 1004
Daved folds.
jdragyn takes the \$1005 pot.
+-------------+
| Hand #22    |
+-------------+
Daved with \$1995 is dealt 0.305795
jdragyn with \$1005 is dealt 0.345225
whiteflags is out.
jdragyn puts in \$1 (blind) for a total of 1
Daved folds.
jdragyn takes the \$1 pot.
+-------------+
| Hand #23    |
+-------------+
Daved with \$1995 is dealt 0.354656
jdragyn with \$1005 is dealt 0.182348
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn folds.
Daved takes the \$1 pot.
+-------------+
| Hand #24    |
+-------------+
Daved with \$1995 is dealt 0.498489
jdragyn with \$1005 is dealt 0.483902
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn folds.
Daved takes the \$1 pot.
+-------------+
| Hand #25    |
+-------------+
Daved with \$1995 is dealt 0.555864
jdragyn with \$1005 is dealt 0.0715354
whiteflags is out.
jdragyn puts in \$1 (blind) for a total of 1
Daved folds.
jdragyn takes the \$1 pot.
+-------------+
| Hand #26    |
+-------------+
Daved with \$1995 is dealt 0.973663
jdragyn with \$1005 is dealt 0.945647
whiteflags is out.
Daved puts in \$1 (blind) for a total of 1
jdragyn goes all-in with \$1005 to 1005
Daved puts in \$1004 (check) for a total of 1005
Total size of the pot is 2010
Daved shows 0.973663
jdragyn shows 0.945647
Daved wins the \$2010 pot.
+-------------+
| Hand #27    |
+-------------+
Daved with \$3000 is dealt 0.413862
jdragyn is out.
whiteflags is out.

Daved has 1 wins.
jdragyn has 0 wins.
whiteflags has 0 wins.```
To determine the winner, I ran 100 games to see who won the most. The result was:
Code:
```Daved has 85 wins.
jdragyn has 8 wins.
whiteflags has 7 wins.```
I conclude that the winner is Daved! Congratulations!

2. With the contestants permissions, I can post the source code of the competition program and the computer players.

3. Thanks for running the competition, Sang-drax. It was a fun diversion.

>> With the contestants permissions, I can post the source code
That's fine with me, although if anybody wanted to tweak the rules and try to get a few more contestants in to play again I would be up for that.

Actually, even then I guess I wouldn't mind my submission being posted.

4. Looks like Daved's is a wee bit smarter than mine. You takin' your bot to Vegas, Daved?

Thank you Sang-drax. It was neat to see my bot in action, even if it lost. You can post my bot if you like.

5. I didn't expect to be foiled by an all-in all the time guy, but it's not like I tested anything. I'm chomping at the bit to make the thing smarter than it turned out to be. Go ahead and post it, it's old.

6. I wouldn't mind a rematch after the algorithms are posted.

7. Originally Posted by whiteflags
I didn't expect to be foiled by an all-in all the time guy,
I'm guessing you mean yourself:
Daved with \$999 is dealt 0.832331
jdragyn with \$1001 is dealt 0.796228
whiteflags with \$1000 is dealt 0.668783
whiteflags puts in \$1 (blind) for a total of 1
Daved folds.
jdragyn goes all-in with \$1001 to 1001
whiteflags goes all-in with \$999 to 1000
Total size of the pot is 2001
jdragyn shows 0.796228
whiteflags shows 0.668783
jdragyn (all-in) wins \$1000 from whiteflags
If everyone is bluffing all the time, whiteflags would win

8. That was the hand I was the big blind.

Code:
```// whiteflags.cpp - Program Poker AI Contest 1-Mar-2010
#include <cmath>

struct GameInfo
{
int num_players;

int* money; //Chip count for each player (including myself)
bool* has_folded; //What players are still in play
int* has_betted; //What each player has betted
int curr_max_bet; //Current highest bet
};

namespace whiteflags {
int make_bet(int my_id, float my_hand, const GameInfo&  game_info);
}

int whiteflags::make_bet(int my_id , float my_hand , const GameInfo& game_info)
{
using std::floor;
using std::fabs;
static int max_bet;

int check = game_info.curr_max_bet - game_info.has_betted[my_id];
int fold = check - 1;

if(game_info.has_betted[my_id] > 0) {
if(fabs(1.0f - my_hand) < 0.03f) {
return game_info.money[my_id];
}

int call = game_info.curr_max_bet;

if(call <= 0) {
return check;
}
else if(max_bet >= call) {
max_bet -= call;
return call;
}
else {
return fold;
}
}
else {
float close_enuf = 0.24444f;
if(fabs(1.0f - my_hand) < close_enuf) {
max_bet = int(floor(my_hand * game_info.money[my_id]));
int bet = int(floor(max_bet * 0.125f));
if(game_info.curr_max_bet > bet) return fold;
max_bet -= bet;
return bet;
}
else {
return fold;
}
}
}```
I'm not entirely sure what happened, as I don't play poker. I only explicitly go all in when my hand was 0.9-something. I guess blinds count as bets, and I couldn't properly assess my risk that time.

9. Code:
```/* Daved's entry */

int make_bet(int my_id, float my_hand, const GameInfo&  game_info)
{
static int intital_chip_count = game_info.money[my_id] + game_info.has_bet[my_id];
static float intital_call_num = intital_chip_count/10.f;
static float intital_all_in_num = intital_chip_count/50.f;
static float my_prev_hand = my_hand;
if (my_hand - my_prev_hand > 0.0001f || my_prev_hand - my_hand > 0.0001f)
{
intital_chip_count = game_info.money[my_id] + game_info.has_bet[my_id];
my_prev_hand = my_hand;
}

float call_value = 1.f - (intital_call_num / intital_chip_count);
float all_in_value = 1.f - (intital_all_in_num / intital_chip_count);
if (my_hand < call_value)
return 0;
int my_call_bet = ((game_info.curr_max_bet - game_info.has_bet[my_id]) > game_info.money[my_id])
? game_info.money[my_id] : (game_info.curr_max_bet - game_info.has_bet[my_id]);
if (my_hand < all_in_value)
return my_call_bet;
return INT_MAX;
}```
My basic algorithm is fold if my hand is worse than 0.90, go all in if it is better than 0.95, and call otherwise. All that extra stuff is some tweaking I did because I didn't know if the initial chip count was 1000 or something else, and also I wanted to be more liberal with my calls and all-ins as my chip count got lower.

I had tried some other algorithms, including one that used numbers like 0.65 and 0.85 and one that paid attention to pot odds. But when I put those up against this algorithm they always lost badly, so I stuck with this in the end. I guess playing tight really helps in a game like this, especially without an increasing blind structure.

Oh, and thanks Sang-drax for fixing my code so it would compile. It appears I changed some official variables names and forgot to change them to fit the specs.

10. Mine was pretty similar to yours, Daved, except my auto-fold was pretty low, my auto-all-in was .92 and everything in between was calculated based on EV (and a very simplistic EV calculation at that). My logic was that if I had a hand worth playing, I'd just go all-in (which kinda defeats the EV calculation I did). Turns out that I got lucky against whiteflags and then your tighter play beat out mine in the long run.

I'll post mine when I get home from work unless Sang-drax posts it first. I too wouldn't mind a rematch. Maybe make something a wee bit smarter, too.

<EDIT> Here's my implementation. Don't laugh too hard.

Code:
```int make_bet(int my_id, float my_hand, const GameInfo& game_info)
{
// Check some basics
if (my_hand > 0.94f) return INT_MAX; // all-in if great hand
if (my_hand < 0.16f) return INT_MIN; // fold if 7-2 off-suit

// count players and calculate pot size
int num_pl = 0;
int pot = 0;
for (int i = 0; i < game_info.num_players; ++i)
{
if (!game_info.has_folded[i]) ++num_pl;
pot += game_info.has_bet[i];
}

// Calculate EV.  -EV and we should probably fold
float bet_value = (float)game_info.curr_max_bet / (float)pot;
float EV = my_hand - bet_value;
if (!(EV < 0)) return INT_MAX;

// -EV so look at our exceptions before we fold

//   short handed with a decent hand?  Go all-in
if ((num_pl < 4) && (my_hand > 0.6f)) return INT_MAX;

//   middle handed, good hand and no one has bet too high
if ((num_pl < 7) && (my_hand > 0.85f) &&
(game_info.curr_max_bet < game_info.money[my_id]))
return INT_MAX;

// Nope, too risky.  Just fold.
return INT_MIN;
}```

11. Here are the first 5 files used for running the contest. CBoard won't let me upload a .zip file.

12. And here are the last two files.

Study these three simple AIs and try to beat them! This competition will be held again and now you have programs to practice against!

Let me know if you want changed rules or changed interface for the next competition. The next time I want the interface to be class-based.

13. Originally Posted by Sang-drax
The next time I want the interface to be class-based.
Don't do that! If you stick with a function, you can call all the classes you want. There is nothing about this which "requires" C++ or OO.

14. Actually, the const reference to the GameInfo struct is C++, but it's such a relatively small struct that we could probably do with a copy of it without a significant performance impact:
Code:
`int make_bet(int my_id, float my_hand, struct GameInfo game_info);`
Then it really wouldn't matter about C or C++ (except for the little things like casting malloc).

I agree that, in this particular application, there really is not a compelling reason to go with a class based approach over simply having a few individual functions to implement. However, class based would probably make Sang-drax's framework easier to design if he provides a virtual base class for us to inherit from. For that reason, I would be all for a class-based approach, especially if it encourages him to design in additional ways for our AI to gather more complete information.

15. Originally Posted by MK27
Don't do that! If you stick with a function, you can call all the classes you want. There is nothing about this which "requires" C++ or OO.
Actually the struct is passed by reference, which requires C++. Well, if anyone wants to write a function only, I could convert it myself. I don't like the solution with all the namespaces.

Popular pages Recent additions