Poker-AI.org

Poker AI and Botting Discussion Forum
It is currently Mon Nov 13, 2023 12:27 pm

All times are UTC




Post new topic Reply to topic  [ 53 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
PostPosted: Fri Aug 16, 2013 10:37 pm 
Offline
Junior Member

Joined: Sun Jul 07, 2013 11:13 am
Posts: 49
Quote:
I use this in my bot with a wrapper.

I would be interested in having a look at that wrapper. How can I get it?


Top
 Profile  
 
PostPosted: Sat Aug 17, 2013 6:48 pm 
Offline
Junior Member

Joined: Wed May 15, 2013 10:15 pm
Posts: 42
I wrote the wrapper...

I'll try to isolate the functions and write a wrapper that works for the example, so you will see.


Top
 Profile  
 
PostPosted: Sat Aug 17, 2013 11:17 pm 
Offline
Junior Member

Joined: Wed May 15, 2013 10:15 pm
Posts: 42
This is an example of how to use XPokerEquity with C#; you should compile it in Release, or it will be very slow.

There is also a function to free the memory, because there was a bug that it wasn't freeing the memory allocated.
Also exhaustive method is reported to be bugged at river in certain circumstances, so i use only Monte Carlo simulation.


Attachments:
XPokerEquityCSharp.rar [590.55 KiB]
Downloaded 1063 times
Top
 Profile  
 
PostPosted: Sun Aug 18, 2013 10:06 am 
Offline
Junior Member

Joined: Sun Jul 07, 2013 11:13 am
Posts: 49
Thanks for sharing shadehs.

I'll have a look at it. I am busy with other things now so it might take me a while.


Top
 Profile  
 
PostPosted: Sun Aug 18, 2013 1:19 pm 
Offline
Junior Member

Joined: Sun Mar 03, 2013 12:09 pm
Posts: 14
Hi,

I always used the poker-eval c library - pinvoked from c#.

However I'd recommend lots pre-calculation and lookup tables. With a bit of effort you can avoid almost all live hand evaluations this way - making the performance of the evaluator fairly irrelevant. In fact this approach opens the door to doing far more complex evaluations than would be possible to calculate in realtime - e.g. calculating equity against a probability distribution of 1326 hands becomes trivial with a pre-calculated matrix - but would be challenging if calculated explicitly.

The only place I think live evaluation is necessary is on the river - where the calculations are trivial anyway.

- PeppaPig


Top
 Profile  
 
PostPosted: Mon Aug 19, 2013 9:39 am 
Offline
Regular Member

Joined: Sun Mar 03, 2013 11:55 am
Posts: 64
The only place I do live evaluation is showdown... perfectly possible to pre-calculate everything for the river too.


Top
 Profile  
 
PostPosted: Fri Aug 23, 2013 9:53 am 
Offline
Junior Member

Joined: Sun Jul 07, 2013 11:13 am
Posts: 49
Quote:
calculating equity against a probability distribution of 1326 hands becomes trivial with a pre-calculated matrix

and
Quote:
The only place I do live evaluation is showdown... perfectly possible to pre-calculate everything for the river too

OK guys, I hear what you are saying! Pre-calculation is obviously the best way to speed up hand evaluation.

Could you please tell me how to actually do it with 1 to 9 opponents (all with different hand ranges) and for all betting rounds?


Top
 Profile  
 
PostPosted: Sat Aug 24, 2013 4:31 am 
Offline
Junior Member

Joined: Sat Jun 29, 2013 1:43 am
Posts: 11
Seikez wrote:
I need a reliable, easy to use and fast (in that priority order) hand evaluator for my Holdem C# Bot. Preferably with documentation and usage examples.

So for this bot

It should handle preflop, flop, turn and river (2, 5, 6 and 7 cards). It should handle 1 - 9 opponents. I also need functions to calculate win probability, EV and other things my bot might need.

The alternatives I have found are all several years old, which makes me unsure which is the best choice today.

I therefore turn to you guys for some advice, it will be greatly appreciated!


Hi I was reading through this thread and can tell you from personally coding hand evaluators in both C# and then porting my code to c++ is that C++ is faster.

I have two apps that sell in the iTunes app store one is cloud based Windows Azure Single Core processor with C# api engine based a lot of the same approach that Keith Rule did.

The other was converted to c++ and Runs for five HORSE games and uses logic and approach from various libraries and own code, none of which are poker eval, although im sure all the ideas derived from that since its pretty much the grandfather of evaluators. I used similar logic and approach for holdem to Stud and Eight or better. I do not use pinvoke and I do not have lookup tables since I can't have an app in the store that is 150mb :)

Pointers make a huge difference and while you can use unsafe code in c# it still is not as fast as moving to raw c++.

If you use Keith Rules Code base you should get pretty fast times.

If you want to know how equity can be incorporated into it, Here is what I did and its how you could use Keith Rules Library since the if logic is nearly the same for all evaluators.

In Keith's the evaluator code where you see a line like

for(int i = 0; i < playerCount; i++)
{
if(pocketHands[i] == bestpocket)
{
if(bestCount > 1)
{
//Equity numerator is a "1" its always 1 divided by the number of people participating in the tie.
playerEquity[i] += equitynumerator / bestcount;
playerties[i] ++;
}
else
{
playerwins[i]++;
playerEquity[i]++;
}
}
}


I have separate arrays since I want wins, ties and equity. Look at Keith's code and you can add a float or double whichever to get the equity on top of wins or ties.
The key is knowing how many people tie on each iteration. Is there a faster way to do this ? I imagine sure probably many but that worked for me.

Also to make your c# code slightly faster go into the settings and check "allow unsafe code" Your c# will run faster and you will not be jeopardizing anything.

I had originally used some of the code logic from Keith Rules project when I had done the C# version but starting deviating and then by the time I had writing the c++ logic more of it was new new besides assigning values to cards.

I suspect most of the commercial poker software be it, HUDs, odds calculators are using some evolution of poker eval, Two Plus Two etc. The lookup tables are the fastest but you can still get terrific speeds without.

Now do a search for PokerStove evaluator.
The guy recently put all of his source code available for download and most people consider that the best Equity Calculator.

https://github.com/andrewprock/pokerstove

I haven't looked at this yet but bet a lot of his logic is similar to the older libraries.

Feel free to email me [email protected] if you have any other questions I like helping out others when I can since if it wasn't for these open source libraries most
of the software would never exist at least not as widely as it does today :)


Top
 Profile  
 
PostPosted: Sat Aug 24, 2013 9:57 pm 
Offline
Regular Member

Joined: Sun Mar 03, 2013 11:55 am
Posts: 64
Quote:
The lookup tables are the fastest but you can still get terrific speeds without.

I can't say I've done any benchmarking, but I would say this is not strictly true... By far and away the slowest thing a modern PC does is accessing a disk, and the second slowest thing a modern PC does is accessing RAM. A CPU can perform hundreds of calculations in the same amount of time it takes to read something from uncached memory.

If you somehow create a lookup you can cram into the CPU cache, then yes, it'll be faster. Also, if you perform sequential lookups, then I suspect the lookup table will be faster. For random hands, depending on the PC setup, I'd guess doing the calculations might win the race. Especially as CPU speeds have increased a lot more than RAM speeds over the years.

Maybe I'll do some experimentation sometime.

Quote:
OK guys, I hear what you are saying! Pre-calculation is obviously the best way to speed up hand evaluation.

Could you please tell me how to actually do it with 1 to 9 opponents (all with different hand ranges) and for all betting rounds?

Lookup tables.


Top
 Profile  
 
PostPosted: Sun Aug 25, 2013 12:34 am 
Offline
Junior Member

Joined: Sat Jun 29, 2013 1:43 am
Posts: 11
Let me rephrase I am not sure if they will be fast enough for a bot but for what im doing without using the Major Lookup tables and I say major because I use some of the smaller ones like for Razz lowbits or the ones similar to poker eval for checking straights or flushes, but the ones as used in the Two Plus Two that make up the 100+mb file I do not use and I get sub 600ms response time with a quad core doing Omaha on my Quad core 9550 desktop which is about 5+ years old. The key for that tool is using Cactus kev's Fast lookup with some modifications.

I know Pro Poker tools is smoking fast but I believe they are using LUTs and have a nice server I suppose. Could be C or Java implementation.

Does anyone here have an iPad or IPhone or iPod touch, I have some free promo codes and can let you see how fast/slow the app is on a device.

Omaha takes about 3-4 seconds without a board for iPad2 a bit less on iPad3 or iPhone 5.

All the other odds calculations are generally a second or less. Not bad with no major lookups on little mobile processors. This is without community cards of course. With them both hold'em and Omaha are instantaneous.

For Omaha heads up is 1 million + hands but in getting that there are about 120 million iterations since each player has 6 hands from their four cards. On a core I7 with no major lookups I can get it down to about 400ms.

Again LUTS are probably instantaneous but for what I need that will suffice not having LUT.

Again I'm not sure for Bots what is needed.


Top
 Profile  
 
PostPosted: Mon Aug 26, 2013 5:54 pm 
Offline
Junior Member

Joined: Wed Mar 06, 2013 8:44 am
Posts: 37
does anybody know or share a postflop lookuptable?
I' using the xpoker equity calculator for doing the ev calculations during runtime -> is very often too slow (especially every hand vs every hand in an range for 2 players)

atm I have no clue how to do it myself.


thanks


Top
 Profile  
 
PostPosted: Mon Aug 26, 2013 6:17 pm 
Offline
Veteran Member

Joined: Mon Mar 04, 2013 9:40 pm
Posts: 269
Quote:
does anybody know or share a postflop lookuptable?
I' using the xpoker equity calculator for doing the ev calculations during runtime -> is very often too slow (especially every hand vs every hand in an range for 2 players)


I am having a similar slowness problem post flop. I currently have to pass each combo to the evaluator and it is around 4-5 seconds for an equity decision which is ok for one table but not for multiple. LUTS will not really work for me as the ranges are all broken up into specific hands postflop. Preflop I guess a LUT would work most of the time but for a 3B or 4B you would still need to range a specific set of hands but I guess you could stove all those for a LUT too. Postflop I do not see a LUT working at all..especially on the turn and river for a calling range. If the villain is leading the whole time you could LUT it I guess.

Right now I am trying to use the pokerstove code that was just released a few months ago. Since it has been highly optimized over the years I am hoping I can get more speed.


Last edited by shalako on Mon Aug 26, 2013 7:05 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Mon Aug 26, 2013 6:43 pm 
Offline
Junior Member

Joined: Sat Jun 29, 2013 1:43 am
Posts: 11
Post flop should be instantaneous given the iterations are so small. The of where you do the equity should be no different to doing it preflop.

It should be in the place where you check for tie and wins. You add a +1 for each win in the iteration and if it's a tie then 1 / number of players who tied on that given iteration.
The sum of those divided by number of outcomes
Will give you the equity.


Top
 Profile  
 
PostPosted: Mon Aug 26, 2013 7:18 pm 
Offline
Veteran Member

Joined: Mon Mar 04, 2013 9:40 pm
Posts: 269
Quote:
Post flop should be instantaneous given the iterations are so small. The of where you do the equity should be no different to doing it preflop.


Well I must be doing something wrong then because its not fast at all. The only equity that is instantaneous is hand vs random hand which is pretty much useless (such as Timmys) for HU. I think (not positive) that is called absolute equity. For any kind of range equity it seems to take time as winnie and I are having similar problems. I am using the PPT java based command line tool for range equity which is probably most of my problem. Nasher said it might be compiling on each run which would cause a big slowdown. I am not sure if it does that or not so I am trying to build a native solution using the pokerstove code.

I did try using Timmys for each 1326 hand combos to see how it would fair and it did terrible. It took about a minute to complete. Pokerstove blew it away in about 3 seconds.


Top
 Profile  
 
PostPosted: Mon Aug 26, 2013 11:04 pm 
Offline
Junior Member

Joined: Sat Jun 29, 2013 1:43 am
Posts: 11
Poker stove is probably sub 100ms actually when there is a board. I guessing simply because the evaluators I have coded with or tried out are all subsecond with a board. of three or more.

Maybe it's something you are doing that is making it take more than a second with that code base.

Are you running in release or debug mode ?

I should also clarify what hand or is it hand range that you are doing ?


Top
 Profile  
 
PostPosted: Tue Aug 27, 2013 12:57 pm 
Offline
Junior Member

Joined: Sun Jul 07, 2013 11:13 am
Posts: 49
Quote:
This is an example of how to use XPokerEquity with C#;

Thanks shadehs!
I have tried it out and it works great. I can also extend your wrapper to call other functions in XPokerEquity from C#.


Top
 Profile  
 
PostPosted: Fri Aug 30, 2013 9:00 pm 
Offline
Junior Member

Joined: Wed May 15, 2013 10:15 pm
Posts: 42
Seikez wrote:
Quote:
This is an example of how to use XPokerEquity with C#;

Thanks shadehs!
I have tried it out and it works great. I can also extend your wrapper to call other functions in XPokerEquity from C#.


There is a serious bug that i forgot to remove in the files that i uploaded:
in HoldemCalculator.cpp row 48, you have to sobstitute Calculate method with this one:
Code:
///////////////////////////////////////////////////////////////////////////////
// Calculate equities for the specified matchup using either Monte Carlo
// or Exhaustive Enumeration.
///////////////////////////////////////////////////////////////////////////////
int HoldemCalculator::Calculate(const char* hands, const char* board, const char* dead, __int64 trialCount, double* outResults)
{
   PreCalculate(hands, board, dead, trialCount, outResults);

   
      CalculateMonteCarlo();
   

   return PostCalculate();
}

Or you will not be able to calculate the river for some hands.


Top
 Profile  
 
PostPosted: Mon Oct 27, 2014 5:26 pm 
Offline
Junior Member

Joined: Fri Sep 26, 2014 11:51 pm
Posts: 15
Thank you for your wrapper that I'm using it's a really nice job !!
I only needed to correct a few things in the ranges generation part, in AgnosticHand.cpp
Incrementing both first card and second card value wasn't correct in the case of KTo+ for example.
KTo+ means KTo, KJo, KQo. Your code was actually returning KTo, AJo that's why it didn't work with ranges.
Why were so many mistakes in such an important function, was it to see if we were enough good to use it ? :)
Here is the rewritten hand range combinations function.

Regards,

Autofocus

Quote:
///////////////////////////////////////////////////////////////////////////////
// Take a given agnostic hand, such as "AA" or "AJs+" or "77-TT", along with
// an optional collection of "dead" cards, and boil it down into its constituent
// specific Hold'em hands, storing these in the 'specificHands' vector passed
// in by the client.
// XxXx means a full range
// You can use the A9o - AQo notation => (A9o, ATo, AJo, AQo) or 77-TT => (77,88,99,TT)
// You can use the QQ+ notation => (QQ,KK,AA) or KTS+ => (KTs,KJs,KQs)
// You must always specify if you are considering suited and/or offsuited so don't forget the s or o suffix for each range except pockets
// There is no special rule regarding connectors, so QJs+ => (QJs) and 98o+ => (98o)
//
// Returns the number of specific hands the agnostic hand contains.
///////////////////////////////////////////////////////////////////////////////
int AgnosticHand::Instantiate(const char* handText, StdDeck_CardMask deadCards, vector<StdDeck_CardMask>& specificHands)
{
if (strcmp(handText, "XxXx") == 0)
{
return InstantiateRandom(deadCards, specificHands);
}

bool isPlus = (NULL != strchr(handText, '+'));
bool isSlice = (NULL != strchr(handText, '-'));
int handRanks[3] = { 0, 0, 0 };
if (isSlice) // TT - AA, ATo - AQo
{
const char* index = strchr(handText, '-');

char handCeil[4];
char handFloor[4];
strncpy(handFloor, handText, index - handText);
strcpy(handCeil, index + 1);

handRanks[0] = Card::CharToRank(handFloor[0]);
handRanks[1] = Card::CharToRank(handFloor[1]);
handRanks[2] = Card::CharToRank(handCeil[1]);
}
else // K2s+ or 32s
{
handRanks[0] = Card::CharToRank(handText[0]);
handRanks[1] = Card::CharToRank(handText[1]);
}

StdDeck_CardMask hand;

int combos = 0;

if (IsPair(handText))
{
StdDeck_CardMask card1, card2;

for (int rank = handRanks[0]; rank <= (isSlice ? handRanks[2] : (isPlus ? Card::Ace : handRanks[1])); rank++)
{
for(int suit1 = StdDeck_Suit_FIRST; suit1 <= StdDeck_Suit_LAST; suit1++)
{
for (int suit2 = suit1 + 1; suit2 <= StdDeck_Suit_LAST; suit2++)
{
card1 = StdDeck_MASK( StdDeck_MAKE_CARD(rank, suit1) );
card2 = StdDeck_MASK( StdDeck_MAKE_CARD(rank, suit2) );
StdDeck_CardMask_OR(hand, card1, card2);
if (!StdDeck_CardMask_ANY_SET(deadCards, hand))
{
specificHands.push_back(hand);
combos++;
}
}
}
}
}
else if (IsSuited(handText))
{
StdDeck_CardMask card1, card2, hand;

for (int rank1 = handRanks[1]; rank1 <= (isSlice ? handRanks[2] : (isPlus ? handRanks[0]-1 : handRanks[1])); rank1++)
{
for(int suit = StdDeck_Suit_FIRST; suit <= StdDeck_Suit_LAST; suit++) // 4 colors
{
card1 = StdDeck_MASK(StdDeck_MAKE_CARD(handRanks[0], suit));
card2 = StdDeck_MASK( StdDeck_MAKE_CARD(rank1, suit) );
StdDeck_CardMask_OR(hand, card1, card2);
if (!StdDeck_CardMask_ANY_SET(deadCards, hand))
{
specificHands.push_back(hand);
combos++;
}
}
}
}
else if (IsOffSuit(handText))
{
StdDeck_CardMask card1, card2, hand;

for (int rank1 = handRanks[1]; rank1 <= (isSlice ? handRanks[2] : (isPlus ? handRanks[0]-1 : handRanks[1])); rank1++)
{
for(int suit1 = StdDeck_Suit_FIRST; suit1 <= StdDeck_Suit_LAST; suit1++)
{
for (int suit2 = StdDeck_Suit_FIRST; suit2 <= StdDeck_Suit_LAST; suit2++)
{
if (suit1 == suit2)
continue;

card1 = StdDeck_MASK(StdDeck_MAKE_CARD(handRanks[0], suit1));
card2 = StdDeck_MASK( StdDeck_MAKE_CARD(rank1, suit2) );
StdDeck_CardMask_OR(hand, card1, card2);
if (!StdDeck_CardMask_ANY_SET(deadCards, hand))
{
specificHands.push_back(hand);
combos++;
}
}
}
}
}

return combos;
}


Last edited by AutoFocus on Wed Oct 29, 2014 9:21 am, edited 7 times in total.

Top
 Profile  
 
PostPosted: Mon Oct 27, 2014 9:05 pm 
Offline
Junior Member

Joined: Wed May 15, 2013 10:15 pm
Posts: 42
Thanks for finding the bug, but I tested your code and it was failing at the first test.
Got "Vector subscript is out of range".
The code is not mine, is from coding the wheel website (now dead).
http://web.archive.org/web/201301221754 ... in-poker-1


Top
 Profile  
 
PostPosted: Mon Oct 27, 2014 9:49 pm 
Offline
Junior Member

Joined: Fri Sep 26, 2014 11:51 pm
Posts: 15
Hum I also tested many times and all works fine.

I must say that I changed a part, you must now enter TT-AA or ATo-AQo instead of AA-TT,AQo-ATo which is best.
It can provoque a bug, if the order isn't this one.
Please tell me which hands you entered if your bug wasn't because of it, but it's all working for me :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 53 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group