The following intructions assumes you are in the cpp directory. If you are in the root directory, please change to cpp first.
cd cpp
This library can be built using CMake. A recommended way of building it is:
mkdir -p build
cd build
cmake ..
make
This will generate a static-linked library libpheval.a
, as well as
a unit test binary unit_tests
.
Run unit_tests
to perform the unit tests:
./unit_tests
Another build option is to build the library only, after generating the CMake files,
run make pheval
to build the static-linked library.
mkdir -p build
cd build
cmake ..
make pheval
The unit tests depends on Google Test suite, which isn't available in Windows. This way allows us to build the libraries and examples.
mkdir -p build
cd build
cmake -DBUILD_TESTS=OFF ..
After successfully running the cmake
command, each build target will generate a
.vcxproj
file, which is a project file that can be imported to Visual Studio.
This cpp directory also includes a Makefile, for users that want to use native GNU Make to compile the library.
Simply run make
to build the static-linked library libpheval.a
.
In the examples, there is another Makefile to compile the examples with the library linked.
cd examples
make
After running make
, you can see the following library files generated:
libpheval.a # library pheval
libpheval5.a # library pheval5
libpheval6.a # library pheval6
libpheval7.a # library pheval7
libphevalplo4.a # library phevalplo4
libphevalplo5.a # library phevalplo5
libphevalplo6.a # library phevalplo6
The corresponding library file is libpheval.a
.
This library includes 5-card, 6-card, and 7-card evaluators.
It also includes all the methods of describing a rank. However, the additional
memory usage of these rank describing methods is significantly high (356k), due
to the rank description table declared in src/7462.c
.
The example usage of this library can be found in examples/c_example.c
and
examples/cpp_example.cc
.
The corresponding library files are libpheval5.a
, libpheval6.a
, and
libpheval7.a
.
These libraries are memory optimized for evaluating 5-card hands, 6-card hands, and 7-card hands respectively.
These libraries don't include the rank describing methods, in order to save the memory usage.
The example usage of these libraries can be found in
examples/evaluator5_standalone_example.cc
,
examples/evaluator6_standalone_example.cc
and
examples/evaluator7_standalone_example.cc
.
The corresponding library files are libphevalplo4.a
, libphevalplo5.a
, and
libphevalplo6.a
.
These libraries are made for evaluator Pot Limit Omaha 4 (standard Omaha) hands, Pot Limit Omaha 5 hands, and Pot Limit Omaha 6 hands respectively.
These libraries also include all the methods of describing a rank. The additional memory usage of these rank describing methods is insignificant compared to the memory usage of the basic omaha evaluators.
The example usage of these libraries can be found in examples/plo4_example.cc
,
examples/plo5_example.cc
and examples/plo6_example.cc
.
After building the libraries, you can add the ./include
directory to your includes path, and link the library to your source
code. In addition, at least C++11 standard is required for compiling.
For example:
g++ -I include/ -std=c++11 your_source_code.cc libpheval.a -o your_binary
In this example we use a scenario in the game Texas Holdem:
Community cards: 9c 4c 4s 9d 4h (both players share these cards)
Player 1: Qc 6c
Player 2: 2c 9h
Both players have full houses. But player 1 only has a four full house over nine, while player 2 has nine full house over four, which is stronger than player 1.
The following two sections will show us how this example hands are evaluated using PHEvaluator. All the code and compiling can be found in the examples directory.
We can construct a Card by providing a two character string, like this:
phevaluator::Card a = phevaluator::Card("Qc");
Then the method EvaluateCards
will take parameters from 5 to 7 Cards and
return a Rank type. Sometimes, you can provide the strings directly to the
method and let the Cards be constructed implicitly, to make your code
cleaner.
phevaluator::Rank rank1 =
phevaluator::EvaluateCards("9c", "4c", "4s", "9d", "4h", "Qc", "6c");
phevaluator::Rank rank2 =
phevaluator::EvaluateCards("9c", "4c", "4s", "9d", "4h", "2c", "9c");
Now that we have the Ranks from both players' hands. What information can we get from them?
First, we can do comparison on these Ranks. A stronger hand is greater than a weaker hand.
assert(rank1 < rank2); // rank2 is stronger
We can also get its rank in all 7562 possible hands. This ranking is identical to the return value of the Cactus Kev's evaluator: the best rank has value 1, which is a Royal Straight Flush, while the worst rank is 7462.
int value1 = rank1.value(); // 292
int value2 = rank2.value(); // 236
We can also tell the ranking category of the rank: either using the method
category
which returns an enumerator, or the method describeCategory
which returns a string. In this example, both players are holding full houses.
assert(rank1.category() == FULL_HOUSE);
assert(rank1.describeCategory() == "Full House");
assert(rank2.category() == FULL_HOUSE);
assert(rank2.describeCategory() == "Full House");
Apart from the ranking category, we can get more detail from the rank, using
the describeRank
or the describeSampleHand
method.
Let's see a sample hand from the rank2
:
assert(rank2.describeSampleHand() == "99944");
As we can see, the best 5-card hand from player 2 is 9-9-9-4-4. Suit information is missing from this method, because usually they don't matter, unless all the five cards have the same suit. So we have another method that tells us whether the sample hand is a flush. In this example, it is not.
assert(!rank2.isFlush());
Finally, we have another method to give us a short description of the sample hand:
assert(rank2.describeRank() == "Nines Full over Fours");
In the C version, the evaluation would be tricker, since we have to convert the card to an integer by ourselves.
The formula is rank * 4 + suit
.
We use 0 for the clubs, 1 for the diamonds, 2 for the hearts, and 3 for the spades.
And the rank values are: deuce = 0, trey = 1, four = 2, five = 3, six = 4, seven = 5, eight = 6, nine = 7, ten = 8, jack = 9, queen = 10, king = 11, ace = 12.
And the suits are: club = 0, diamond = 1, heart = 2, spade = 3
The mapping of a Card and its integer value can be found in Card Id.
// Community cards
int a = 7 * 4 + 0; // 9c
int b = 2 * 4 + 0; // 4c
int c = 2 * 4 + 3; // 4s
int d = 7 * 4 + 1; // 9d
int e = 2 * 4 + 2; // 4h
// Player 1
int f = 10 * 4 + 0; // Qc
int g = 4 * 4 + 0; // 6c
// Player 2
int h = 0 * 4 + 0; // 2c
int i = 7 * 4 + 2; // 9h
After constructing all the Cards, we will use evaluate_7cards
to get a
rank value. A rank value indicates its rank in the 7462 ranking table. The
best rank is 1, which is a Royal Straight Flush, and the worst rank is 7462.
int rank1 = evaluate_7cards(a, b, c, d, e, f, g); // 292
int rank2 = evaluate_7cards(a, b, c, d, e, h, i); // 236
If we compare these two rank value, the rank with a smaller value is stronger.
assert(rank1 > rank2); // rank2 is stronger
Similar to the C++ interfaces, we can see the rank category:
enum rank_category category = get_rank_category(rank1);
assert(category == FULL_HOUSE);
const char * categoryDesc = describe_rank_category(category); // "Full House"
Or get the sample hand from the rank:
describe_sample_hand(rank2); // 9 9 9 4 4
We can see the 5 best cards from player 2 are 9 9 9 4 4.
Although suit information is missing here, indeed we only care about whether
all five cards are in the same suit or not. We can check it using the
is_flush
method:
is_flush(rank2); // false
Finally, we can use rank_description
to get a short description of the rank:
describe_rank(rank2); // Nines Full over Fours
We can use an integer to represent a card. The two least significant bits represent the 4 suits, ranged from 0-3. The rest of it represent the 13 ranks, ranged from 0-12.
More specifically, the ranks are:
deuce = 0, trey = 1, four = 2, five = 3, six = 4, seven = 5, eight = 6, nine = 7, ten = 8, jack = 9, queen = 10, king = 11, ace = 12.
And the suits are: club = 0, diamond = 1, heart = 2, spade = 3
So that you can use rank * 4 + suit
to get the card ID.
The complete card Id mapping can be found below. The rows are the ranks from 2 to Ace, and the columns are the suits: club, diamond, heart and spade.
C | D | H | S | |
---|---|---|---|---|
2 | 0 | 1 | 2 | 3 |
3 | 4 | 5 | 6 | 7 |
4 | 8 | 9 | 10 | 11 |
5 | 12 | 13 | 14 | 15 |
6 | 16 | 17 | 18 | 19 |
7 | 20 | 21 | 22 | 23 |
8 | 24 | 25 | 26 | 27 |
9 | 28 | 29 | 30 | 31 |
T | 32 | 33 | 34 | 35 |
J | 36 | 37 | 38 | 39 |
Q | 40 | 41 | 42 | 43 |
K | 44 | 45 | 46 | 47 |
A | 48 | 49 | 50 | 51 |