-
Notifications
You must be signed in to change notification settings - Fork 84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Java implementation #5
Comments
I would like to pick this up. |
Thank you. @hellraiserinchief |
Hi @hellraiserinchief, I've just updated the Contributing file, which specified the code style. Feel free to ask me if you have any questions related to the implementation. Good luck! |
I have some advice/guide that may help you with this implementation: You can start implementing a 5-card or a 7-card evaluator only, with unit tests, and make a PR for it. Then make consequential PRs for the rest of the evaluators. It might not be easy to write test codes fully cover all the possible hands (enumerating all possibilities like the C++ implementation, which is using Cactus Kev's evaluator as a reference). To make it easier, you can just write test code only choosing a few examples in each rank category. For example, choose a few hands from Straight Flush, then a few from Four of a Kind, etc. |
Makes sense, I will get stated on a 5-card evaluator and take things from there. |
Hi, seems like we are just returning the ranks using the hash tables after some simple operations. Can you please let me know how these hash tables were created in the first place? I would like to learn how we generated these hash tables. |
Sure, @hellraiserinchief. The basic idea of the algorithm is, given a hand of more than 5 cards, it will find its strength value in a hash table. Splitting the hands by whether it is a flush, will reduce the total size of the hash table. So there will be two hash tables: The way I generated the As for the other tables, I can give you a little bit more code walk first. The entry is the method int evaluate_5cards(int a, int b, int c, int d, int e)
{
int suit_hash = 0;
int suit_binary[4] = {0};
unsigned char quinary[13] = {0};
int hash;
suit_hash += suitbit_by_id[a];
suit_hash += suitbit_by_id[b];
suit_hash += suitbit_by_id[c];
suit_hash += suitbit_by_id[d];
suit_hash += suitbit_by_id[e];
if (suits[suit_hash])
{
suit_binary[a & 0x3] |= binaries_by_id[a];
suit_binary[b & 0x3] |= binaries_by_id[b];
suit_binary[c & 0x3] |= binaries_by_id[c];
suit_binary[d & 0x3] |= binaries_by_id[d];
suit_binary[e & 0x3] |= binaries_by_id[e];
return flush[suit_binary[suits[suit_hash]-1]];
}
quinary[(a >> 2)]++;
quinary[(b >> 2)]++;
quinary[(c >> 2)]++;
quinary[(d >> 2)]++;
quinary[(e >> 2)]++;
hash = hash_quinary(quinary, 13, 5);
return noflush5[hash];
} The first part is generating a suit hash and looking it up in a table named Actually, the int evaluate_5cards(int a, int b, int c, int d, int e) {
int suit_counter[4] = {0};
// The last two bits is the suit of the card, this will count how many cards are in each suit.
suit_counter[a & 0x3]++;
suit_counter[b & 0x3]++;
suit_counter[c & 0x3]++;
suit_counter[d & 0x3]++;
suit_counter[e & 0x3]++;
for (int i = 0; i < 4; i++) {
if (suit_counter[i] >= 5) { // One of the suit has more than five cards, making it a flush
int suit_binary[4] = {0};
// Dividing by 4 will get rid of the suit information, giving us the rank of the card
suit_binary[a & 0x3] |= 1 << (a / 4);
suit_binary[b & 0x3] |= 1 << (b / 4);
suit_binary[c & 0x3] |= 1 << (c / 4);
suit_binary[d & 0x3] |= 1 << (d / 4);
suit_binary[e & 0x3] |= 1 << (e / 4);
return flush[suit_binary[i]];
}
}
unsigned char quinary[13] = {0};
quinary[(a >> 2)]++;
quinary[(b >> 2)]++;
quinary[(c >> 2)]++;
quinary[(d >> 2)]++;
quinary[(e >> 2)]++;
int hash = hash_quinary(quinary, 13, 5);
return noflush5[hash];
} In case you'd still like to know how the Then we can take a look at the int hash_quinary(unsigned char q[], int len, int k)
{
int sum = 0;
for (int i=0; i<len; i++)
{
sum += dp[q[i]][len-i-1][k];
k -= q[i];
if (k <= 0)
{
break;
}
}
return sum;
} The table Have fun coding! |
Wow!! This super helpful. Thanks for taking time out to explain this in such detail. |
Have the implementation complete. Adding benchmarking and tests, as well as some other helper methods. @HenryRLee would you be able to dump the eval values for each hand into a file for me? I don't want to mess with setting up the cpp build and this seemed like a decent way to do so. This way for testing it'll just compare the values to a file instead of setting up another known evaluator into the repo. |
Hi @Mkerian10, thanks for contributing. Yes, having a language-independent test data makes sense. I'll generate such test data for 5, 6 and 7 card hands. |
@HenryRLee glad to hear it. For now I have eval5-9 implemented. If you want me to implement Omaha I could but I don't have an interest in it so I don't plan to currently. Outside of that I want to expand some more evaluations of equity, Preflop equity vs. a full range is very simple to figure out. I'm looking at implementing more solutions but I'm sure you're more in touch with poker programming so if you know more about this stuff feel free to let me know. |
Hi @Mkerian10, I created a pull request, adding 5-card hands test data #29. You are welcome to review it. I actually generated test data for 6 and 7 card hands, too. But the file sizes are too large to fit in Github. So it's likely I'll only provide a subset of them instead of providing all possible hands. But the format should be consistent. |
Awesome, let me know when you merge it and I'll add the tests and can push my branch. |
Hi @Mkerian10, just added some random test data for 6-card and 7-card hands. Also merged the PR. Looking forward to your changes. |
I never forked the repo so can I just be listed as a contributor and I'll submit the pr. All tests are passing. |
Hi @Mkerian10. Actually I don't have control of deciding who can be on contributor list. Github manages that. But I am happy to help you to have you listed in the contributors list. The easiest way is to create a pull request, I review the pull request, and then merge it. But usually you have to fork the repository in order to create a pull request. (You can delete the fork after the PR is merged anyway.) There are other ways, though they are not easy. For example you can send me the patch and I apply the patch using your name and email address. And then there are a number of approaches: either I push these commits to the master branch directly, or I can push them to another branch, so that you can create a pull request. However, if I push the commits directly, you still need to have some interactions with this repo in order to have these commits counted towards your name, e.g. star the repo, fork the repo, or create a new issue (because Github doesn't want me to create a commit using Linus Torvalds' name, and then say Linus is a contributor of my repo). You may find this official document useful. In particular, you need to follow the section that how to have your commits counted as your contribution. |
For some reason I thought I needed permissions but my IntelliJ was being rude last night. Restarted and it fixed it. |
Add Java implementation, using the same algorithm, similar to the C++ implementation.
Create a directory named
java
and add Java source code in it.The text was updated successfully, but these errors were encountered: