zekyll / ompeval Goto Github PK
View Code? Open in Web Editor NEWFast C++ poker hand evaluator and equity calculator
License: ISC License
Fast C++ poker hand evaluator and equity calculator
License: ISC License
Hi I am trying to write a code similar to an evaluator which will look up hands in a csv and group them. Would you be interested in helping me? I would pay of course. If interested, please email me [email protected]
Hey I am trying to use this library in my repository. I am using cmake under windows with visual studio 2019 compiler.
Thanks for great evaluator and calculator!
I want to create precalculated equity table for heads-up game for every board and every hand. I am just iterating all boards and all hands and save the results. That looks ineffective. Some strange things I have notices:
I see in benchmark.cpp
:
void benchmark()
{
// Benchmark only one at a time because there's some weird performance interference.
Benchmark<Omp>().run();
//Benchmark<Skpe>().run();
//Benchmark<Tpt>().run();
//Benchmark<Ace>().run();
//Benchmark<Sbhs>().run();
//Benchmark<Pse>().run();
}
I would like to benchmark the others too so I can compare them. But I am not sure how to do that.
Could someone explain the steps that would allow me to uncomment one and successfully compile it?
hello i am trying to evaluate equity for for a hands ie AcAd in holdem heads-up.
this code seem to works fine:
omp::EquityCalculator eq;
eq.start({"AcAd","random"},0,0,true,5e-5,nullptr,0.2,4);
But now i would like to use the AcAd hands as their numerical representation (4*Ranks+Suit) for "AcAd" it is [12,13]
how can i instantiate a CardRange from a Hand or an array of int ?
What should I do if the processor does not support the POPCNT instruction and an error (0xC000001D: Illegal Instruction) appears in Util.h >> bitCount (unsigned x) >> return __popcnt (x)?
Is it possible to have a 9 players support? I'm currently not sure why but I get a segmentation fault when I just change the constant from 6 to 9 here. Any further pointers would be appreciated! Thanks!
Hi,
Awesome library. Thanks very much. Is there a way to output combos for a range and a board, say count two pair+, flush combos, flush draw combos, etc.?
Great to see the latest merge! (400kb to 200kb? Seriously!?)
Btw, changing -pthread
to -lpthread
(in the Makefile) breaks things in my machine (Ubuntu 14.04 LTS). Changing it back to -pthread
makes it work again.
Hello, I want to support short deck mode in OMP, i.e., remove 2-5, flush > full house, and A6789 is the smallest straight. Do I need to change the hash table, and how is HandEvaluator::RANKS[] defined? Is there a simple modification method?
I get a wrong result returned in the following sequence of evaluations.
(i) Start up a fresh instance of EquityCalculator.
(ii) Calc a 3-handed game, ranges { "AA", "QQ", "AKo" } empty board and no dead cards.
Correct results are returned:
Eq win ties
0.761347, 0.756022, 0.005324
0.187420, 0.186052, 0.001367
0.051233, 0.045909, 0.005324
(iii) now still with the same EquityCalculator instance Calc a 3-handed game, ranges { "AA", "QQ", "AKo" } empty board but now with dead cards (AsTs).
Incorrect results are returned:
0.748711, 0.743139, 0.005572
0.198669, 0.197299, 0.001370
0.052620, 0.047048, 0.005572
I expected this result (verified using Pokerstove):
Eq win ties
0.734955, 0.728980, 0.005975
0.210303, 0.208843, 0.001460
0.054743, 0.048768, 0.005975
===========================
Oddly if I perform some calculations in a different order it always seems to works eg,.
range { "AA", "QQ", "AKo" } dead (AsTs)
then
range { "AA", "QQ", "AKo" } dead ()
then
range { "AA", "QQ", "AKo" } dead (AsTs)
All 3 calculations return the expected results.
I haven't previously ever noticed an incorrect result from this and it seems to happen only with this sequence of evaluations, weird. Perhaps it is just my set up or some slip by me.
I have tried using both a 32 bit and 64 bit version.
// Create a Hand from a card. CardIdx is an integer between 0 and 51, so that CARD = 4 * RANK + SUIT, where
// rank ranges from 0 (deuce) to 12 (ace) and suit is from 0 (spade) to 3 (diamond).
Ok, I could create enums by my own, but which order?
spade = 0,
hearts,
clubs,
diamonds
or
spade = 0,
clubs,
hearts,
diamonds
Hi
Is it possible to set weights for hands in a range just like in PioSolver ?
ex: JTo:0.2 , you have JTo in your range only 20% of the time
If not, is it possible to implement it quite easily based on how the project was developed ?
Regards
hand 1, Royal flush: As, Qs, Ts, Js, Ks
, strength: 36874
/ 4096 = 9 (9,002441406 to be exact; expected 10).
hand 2, Straight flush: 2s, 3s, 4s, 5s, 6s
, strength: 36866
/ 4096 = 9 (9,000488281).
I claim the following.
There's no such thing as a Card
class; there's only a Hand
class, which can be initialized in one of three ways:
Hand();
Hand(20);
Then single cards can be added to and removed from a Hand object at will with the +
and -
operators.
First question. Is my claim correct?
Assuming SSE support, a Hand is a 128-bit vector of type __m128i
, made up of two 64-bit integers, whose structure is roughly as the comments in Hand.h
read:
// Bits 0-31: key to non-flush lookup table (linear combination of the rank constants)
// Bits 32-47: suit counts
// Bits 48-51: card count
// Bits 64-128: bit mask for all cards (suits are in 16-bit groups).
(I think there's an off-by-one error in the last line, which should read Bits 64-127)
I've added a public method to the Hand class to print out its vector of data, called mData
, to the console, as follows:
void show(){
int64_t *v64val = (int64_t*) &mData;
printf("%.16llx %.16llx\n", (uint64)v64val[1], (uint64)v64val[0]);
}
When initializing each hand Hand(0)
, Hand(0)
, ..., Hand(51)
, I get the following output:
0001000100000001 0000000000000001
0001001000000001 0000000000010000
0001010000000001 0000000100000000
0001100000000001 0001000000000000
0001000100000005 0000000000000002
0001001000000005 0000000000020000
0001010000000005 0000000200000000
0001100000000005 0002000000000000
0001000100000018 0000000000000004
0001001000000018 0000000000040000
0001010000000018 0000000400000000
0001100000000018 0004000000000000
0001000100000070 0000000000000008
0001001000000070 0000000000080000
0001010000000070 0000000800000000
0001100000000070 0008000000000000
0001000100000209 0000000000000010
0001001000000209 0000000000100000
0001010000000209 0000001000000000
0001100000000209 0010000000000000
00010001000008c7 0000000000000020
00010010000008c7 0000000000200000
00010100000008c7 0000002000000000
00011000000008c7 0020000000000000
000100010000241c 0000000000000040
000100100000241c 0000000000400000
000101000000241c 0000004000000000
000110000000241c 0040000000000000
0001000100007867 0000000000000080
0001001000007867 0000000000800000
0001010000007867 0000008000000000
0001100000007867 0080000000000000
000100010001929a 0000000000000100
000100100001929a 0000000001000000
000101000001929a 0000010000000000
000110000001929a 0100000000000000
000100010003d12a 0000000000000200
000100100003d12a 0000000002000000
000101000003d12a 0000020000000000
000110000003d12a 0200000000000000
00010001000a2f3d 0000000000000400
00010010000a2f3d 0000000004000000
00010100000a2f3d 0000040000000000
00011000000a2f3d 0400000000000000
0001000100174a57 0000000000000800
0001001000174a57 0000000008000000
0001010000174a57 0000080000000000
0001100000174a57 0800000000000000
000100010034b250 0000000000001000
000100100034b250 0000000010000000
000101000034b250 0000100000000000
000110000034b250 1000000000000000
Second question. Is this correct?
Trying to compile this on OSX by just typing make, but getting the following:
$ make
c++ -O3 -std=c++11 -Wall -Wpedantic -pthread -c -o omp/CombinedRange.o omp/CombinedRange.cpp
omp/CombinedRange.cpp:21:47: warning: suggest braces around initialization of subobject [-Wmissing-braces]
Combo c{1ull << h[0] | 1ull << h[1], {h}, {Hand(h)}};
^
{}
In file included from omp/CombinedRange.cpp:1:
In file included from omp/CombinedRange.h:4:
In file included from omp/HandEvaluator.h:6:
In file included from omp/Hand.h:6:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/array:109:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:2950:57: error: constexpr variable '_Rp'
must be initialized by a constant expression
static _LIBCPP_CONSTEXPR const _Working_result_type _Rp = _Engine::max() - _Engine::min()
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:3123:41: note: in instantiation of
template class 'std::__1::__independent_bits_engine<omp::XoroShiro128Plus, unsigned long long>' requested here
return static_cast<result_type>(_Eng(__g, _Dt)());
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:3298:35: note: in instantiation of
function template specialization 'std::__1::uniform_int_distribution<long>::operator()<omp::XoroShiro128Plus>' requested here
difference_type __i = __uid(__g, _Pp(0, __d));
^
omp/CombinedRange.cpp:101:10: note: in instantiation of function template specialization
'std::__1::shuffle<std::__1::__wrap_iter<omp::CombinedRange::Combo *>, omp::XoroShiro128Plus &>' requested here
std::shuffle(mCombos.begin(), mCombos.end(), rng);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:2950:63: note: non-constexpr function
'max' cannot be used in a constant expression
static _LIBCPP_CONSTEXPR const _Working_result_type _Rp = _Engine::max() - _Engine::min()
^
omp/Random.h:37:21: note: declared here
static uint64_t max()
^
In file included from omp/CombinedRange.cpp:1:
In file included from omp/CombinedRange.h:4:
In file included from omp/HandEvaluator.h:6:
In file included from omp/Hand.h:6:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/array:109:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:2953:78: error: non-type template
argument is not a constant expression
static _LIBCPP_CONSTEXPR const size_t __m = __log2<_Working_result_type, _Rp>::value;
^~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:2953:78: note: initializer of '_Rp' is
not a constant expression
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:2950:57: note: declared here
static _LIBCPP_CONSTEXPR const _Working_result_type _Rp = _Engine::max() - _Engine::min()
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:2962:69: error: non-type template
argument is not a constant expression
result_type operator()() {return __eval(integral_constant<bool, _Rp != 0>());}
^~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:3131:15: note: in instantiation of
member function 'std::__1::__independent_bits_engine<omp::XoroShiro128Plus, unsigned long long>::operator()' requested here
__u = __e();
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:3298:35: note: in instantiation of
function template specialization 'std::__1::uniform_int_distribution<long>::operator()<omp::XoroShiro128Plus>' requested here
difference_type __i = __uid(__g, _Pp(0, __d));
^
omp/CombinedRange.cpp:101:10: note: in instantiation of function template specialization
'std::__1::shuffle<std::__1::__wrap_iter<omp::CombinedRange::Combo *>, omp::XoroShiro128Plus &>' requested here
std::shuffle(mCombos.begin(), mCombos.end(), rng);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:2962:69: note: initializer of '_Rp' is
not a constant expression
result_type operator()() {return __eval(integral_constant<bool, _Rp != 0>());}
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:2950:57: note: declared here
static _LIBCPP_CONSTEXPR const _Working_result_type _Rp = _Engine::max() - _Engine::min()
1 warning and 3 errors generated.
make: *** [omp/CombinedRange.o] Error 1
Using the following version of c++:
$ c++ -v
Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Sorry if this is obvious!
Sorry if this is a simple question but I'm new to using C++, but I was wondering if there was a way to access which combo is being evaluated from each player during eval so I can pass ranges that are weighted probability distributions. Thanks for the code, you've done some amazing work.
Cheers
In HandEvaluator.cpp defined the following:
const unsigned HandEvaluator::RANKS[]{0x2000, 0x8001, 0x11000, 0x3a000, 0x91000, 0x176005, 0x366000, 0x41a013, 0x47802e, 0x479068, 0x48c0e4, 0x48f211, 0x494493};
I can not find how to generate these numbers.
In SKPokerEval, the is a python script to generate these numbers. brutal force way. If these number were generated the similar way, why RANKS not begin with 0x1, 0x5, ......, but begins with 0x1 << 13.
Who can explain this to me?
Starting with two ranges, I want to calculate a matrix of hand equities, with individual hand-vs-hand values.
I do this simply in a double loop and constructing a length-2 vector of CardRange's, using 1 thread for each evaluation, like this :
for(h1 in range1){
for(h2 in range2){
...
std::vector<omp::CardRange> hands{h1, h2};
eq.start(hands, board, 0, true, 5e-5, nullptr, 0.2, 1);
eq.wait();
auto r = eq.getResults();
}
}
When running this on Linux, I sometimes get a runtime error
terminate called after throwing an instance of 'std::system_error'
what(): Resource temporarily unavailable
Which I assume has something to do with resource acquisition for the threads, although I don't understand how this happens considering I'm starting only 1 thread per caluclation and waiting for each to finish. Is it perhaps a more direct way to do hand-vs-hand evaluations without using the threading functionality?
Hi, would you happen to have an example for how to compile the .so file? I'm including all the libraries and when I run the example in Java I get "symbol lookup error: /usr/lib/libompdelta.so: undefined symbol: _ZN3omp13CombinedRangeC1Ev"
I've tried including all of the .o files but get the same. This is what I run:
g++ -std=c++11 -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -I./omp -I./ ompdelta.cpp -o libompdelta.so -Llib/ompeval.a -Lomp/*.o -shared -fPIC
Board: KsQsJsTs9d
First hand: AsAh. Strength: 36866
Second: Ac9s. Strength: 36867
First-hand makes street flush so it rank should higher.
There no any examples of mentions about omaha in OPMEval manual. I wonder to know can this parser evaluate omaha combination and are there any tests wich prove correct evaluating for omaha?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.