![]() |
|
|
|
#1
|
|||
|
|||
|
Hi Juk!
[ QUOTE ] I'm assuming the only benefit to using the perfect hash version faster lookup creation? (I just used Cactus Kev's source). [/ QUOTE ] Yes, the only reason I suggested Paul D. Senzee's Optimized Hand Evaluator was to keep the initial creation under a minute (and my debugging sanity [img]/images/graemlins/crazy.gif[/img])... You don't need it (you only run this once anyway). [ QUOTE ] PS: One other (unrelated) small thing I just worked out was how to get the code from within code-tags without losing all of the indentation: just hit "quote" and copy the text from within the edit box... [/ QUOTE ] Thank You for that Tip!! I was trying to figure out how to keep the formatting going on and coming out of this BBS. [img]/images/graemlins/blush.gif[/img] Sounds like you are Blazin' so I guess the instructions weren't toooo bad! Have a Profitable Day! Ray... |
|
#2
|
|||
|
|||
|
This is quite possibly the only time I've looked at someone else's code and knew what they were doing the whole way.
I like the additional vector [0] to give 5, and 6 card evaluations as well. My code peaked out at 12.5 cycles. Since our access method is the same, I've got to believe the difference is due to my 10 year old compiler. |
|
#3
|
|||
|
|||
|
Code thats blowing up on me so far
<font class="small">Code:</font><hr /><pre> static long IDs[] = new long[612978]; static int numIDs = 1; static long maxID = 0; static int numcards = 0; static int maxHR = 0; static int HR[] = new int[32487834]; static int workcards[]; static int oldnumcards=1; public static void main (String [] args) { doSetup(); } public static int SaveID(long ID) { if (ID == 0) return 0; // don't use up a record for a 0! if (ID >= maxID) { // take care of the most likely first goes on the end... if (ID > maxID) { // greater than create new else it was the last one! IDs[numIDs++] = ID; // add the new ID maxID = ID; } return numIDs - 1; } // find the slot I will find it (by a pseudo bsearch algorithm) int low = 0; int high = numIDs - 1; long testval; int holdtest; while (high - low > 1) { holdtest = (high + low + 1) / 2; testval = IDs[holdtest] - ID; if (testval > 0) high = holdtest; else if (testval < 0) low = holdtest; else return holdtest; // got it!! } // I guess it couldn't be found so must be added to the current location (high) // make space... // don't expect this much! System.arraycopy(IDs,high,IDs,(high+1),(numIDs - high) ); IDs[high] = ID; // do the insert into the hole created numIDs++; return high; } public static long MakeID(long IDin, int newcard) // adding a new card to this ID { int suitcount[] = new int[4 + 1]; int rankcount[] = new int[13 + 1]; workcards = new int [8]; // intentially keeping one as a 0 end int cardnum; int getout = 0; long ID = 0; for (cardnum = 0; cardnum < 6; cardnum++) { // can't have more than 6 cards! workcards[cardnum + 1] = (int)((IDin >>> (8 * cardnum)) & 0xff); // leave the 0 hole for new card } // my cards are 2c = 1, 2d = 2 ... As = 52 newcard--; // make 0 based! workcards[0] = (((newcard >>> 2) + 1) << 4) + (newcard & 3) + 1; // add next card formats card to rrrr00ss for (numcards = 0; workcards[numcards]!=0; numcards++) { suitcount[workcards[numcards] & 0xf]++; // need to see if suit is significant rankcount[(workcards[numcards] >>> 4) & 0xf]++; // and rank to be sure we don't have 4! if (numcards!=0) { if (workcards[0] == workcards[numcards]) { // can't have the same card twice getout = 1; // if so need to get out after counting numcards } } } if (getout!=0) { return 0; // duplicated another card (ignore this one) } int needsuited = numcards - 2; // for suit to be significant - need to have n-2 of same suit if (oldnumcards < numcards) { System.out.println("Changing to " + numcards + " " + numIDs); oldnumcards = numcards; // break point here if you need it } if (numcards > 4) { for (int rank = 1; rank < 14; rank++) { if (rankcount[rank] > 4) { // if I have more than 4 of a rank then I shouldn't do this one!! return 0; // can't have more than 4 of a rank so return an ID that can't be! } } } // However in the ID process I prefered that // 2s = 0x21, 3s = 0x31,.... Kc = 0xD4, Ac = 0xE4 // This allows me to sort in Rank then Suit order // if we don't have at least 2 cards of the same suit for 4, we make this card suit 0. if (needsuited > 1) { for (cardnum = 0; cardnum < numcards; cardnum++) { // for each card if (suitcount[workcards[cardnum] & 0xf] < needsuited) { // check suitcount to the number I need to have suits significant workcards[cardnum] &= 0xf0; // if not enough - 0 out the suit - now this suit would be a 0 vs 1-4 } } } // Sort Using XOR. Network for N=7, using Bose-Nelson Algorithm: Thanks to the thread! SWAP(0, 4); SWAP(1, 5); SWAP(2, 6); SWAP(0, 2); SWAP(1, 3); SWAP(4, 6); SWAP(2, 4); SWAP(3, 5); SWAP(0, 1); SWAP(2, 3); SWAP(4, 5); SWAP(1, 4); SWAP(3, 6); SWAP(1, 2); SWAP(3, 4); SWAP(5, 6); // long winded way to put the pieces into a long // cards in bytes --66554433221100 // the resulting ID is a 64 bit value with each card represented by 8 bits. ID = (long) workcards[0] + ((long) workcards[1] << 8) + ((long) workcards[2] << 16) + ((long) workcards[3] << 24) + ((long) workcards[4] << 32) + ((long) workcards[5] << 40) + ((long) workcards[6] << 48); return ID; } public static void SWAP(int I, int J) { if (workcards[I] < workcards[J]) { workcards[I]^=workcards[J]; workcards[J]^=workcards[I]; workcards[I]^=workcards[J]; } } public static int DoEval(long IDin) { // I guess I have some explaining to do here... I used the Cactus Kevs Eval ref http://www.suffecool.net/poker/evaluator.html // I Love the pokersource for speed, but I needed to do some tweaking to get it my way // and Cactus Kevs stuff was easy to tweak ;-) int handrank=9999; int cardnum; int workcard; int rank; int suit=0; int mainsuit = 20; // just something that will never hit... need to eliminate the main suit from the iterator int suititerator = 0; int holdrank=9999; workcards=new int[8]; // intentially keeping one as a 0 end int holdcards[]=new int[8]; int numevalcards = 0; // See Cactus Kevs page for explainations for this type of stuff... final int primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41 }; if (IDin!=0) { // if I have a good ID then do it... for (cardnum = 0; cardnum < 7; cardnum++) { // convert all 7 cards (0s are ok) holdcards[cardnum] = (int) ((IDin >>> (8 * cardnum)) & 0xff); if (holdcards[cardnum] == 0) break; // once I hit a 0 I know I am done numevalcards++; // if not 0 then count the card if ((suit = holdcards[cardnum] & 0xf) != 0) { // find out what suit (if any) was significant mainsuit = suit; // and remember it } } for (cardnum = 0; cardnum < numevalcards; cardnum++) { // just have numcards... workcard = holdcards[cardnum]; // convert to cactus kevs way!! ref http://www.suffecool.net/poker/evaluator.html // +--------+--------+--------+--------+ // |xxxbbbbb|bbbbbbbb|cdhsrrrr|xxpppppp| // +--------+--------+--------+--------+ // p = prime number of rank (deuce=2,trey=3,four=5,five=7,...,ace=41) // r = rank of card (deuce=0,trey=1,four=2,five=3,...,ace=12) // cdhs = suit of card // b = bit turned on depending on rank of card rank = (workcard >>> 4) - 1; // my rank is top 4 bits 1-13 so convert suit = workcard & 0xf; // my suit is bottom 4 bits 1-4, order is different, but who cares? if (suit == 0) { // if suit wasn't significant though... suit = suititerator++; // Cactus Kev needs a suit! if (suititerator == 5) // loop through available suits suititerator = 1; if (suit == mainsuit) { // if it was the sigificant suit... Don't want extras!! suit = suititerator++; // skip it if (suititerator == 5) // roll 1-4 suititerator = 1; } } // now make Cactus Keys Card workcards[cardnum] = primes[rank] | (rank << 8) | (1 << (suit + 11)) | (1 << (16 + rank)); } switch (numevalcards) { // run Cactus Keys routines case 5 : holdrank = eval_5cards(workcards[0],workcards[1],workcards[2],workcards[3],workcards[4]); break; // if 6 cards I would like to find HandRank for them // Cactus Key is 1 = highest - 7362 lowest I need to get the min for the permutations case 6 : holdrank = eval_5cards(workcards[0],workcards[1],workcards[2],workcards[3],workcards[4]); holdrank = min(holdrank, eval_5cards(workcards[0],workcards[1],workcards[2],workcards[3],workcards[5])); holdrank = min(holdrank, eval_5cards(workcards[0],workcards[1],workcards[2],workcards[4],workcards[5])); holdrank = min(holdrank, eval_5cards(workcards[0],workcards[1],workcards[3],workcards[4],workcards[5])); holdrank = min(holdrank, eval_5cards(workcards[0],workcards[2],workcards[3],workcards[4],workcards[5])); holdrank = min(holdrank, eval_5cards(workcards[1],workcards[2],workcards[3],workcards[4],workcards[5])); break; case 7 : holdrank = eval_7cards(workcards[0],workcards[1],workcards[2],workcards[3],workcards[4],workcards[5],workcards[6]); break; default : // problem!! shouldn't hit this... System.out.println(" Problem with numcards = " + numcards); break; } // I would like to change the format of Catus Kev's ret value to: // hhhhrrrrrrrrrrrr hhhh = 1 high card -> 9 straight flush // r..r = rank within the above 1 to max of 2861 handrank = 7463 - holdrank; // now the worst hand = 1 if (handrank < 1278) handrank = handrank - 0 + 4096 * 1; // 1277 high card else if (handrank < 4138) handrank = handrank - 1277 + 4096 * 2; // 2860 one pair else if (handrank < 4996) handrank = handrank - 4137 + 4096 * 3; // 858 two pair else if (handrank < 5854) handrank = handrank - 4995 + 4096 * 4; // 858 three-kind else if (handrank < 5864) handrank = handrank - 5853 + 4096 * 5; // 10 straights else if (handrank < 7141) handrank = handrank - 5863 + 4096 * 6; // 1277 flushes else if (handrank < 7297) handrank = handrank - 7140 + 4096 * 7; // 156 full house else if (handrank < 7453) handrank = handrank - 7296 + 4096 * 8; // 156 four-kind else handrank = handrank - 7452 + 4096 * 9; // 10 straight-flushes } return handrank; // now a handrank that I like } public static int min(int a, int b) { if (a<b) return a; else return b; } public static void doSetup() { int count = 0; int card; long ID; int IDslot; int handTypeSum[]=new int[10]; // step through the ID array - always shifting the current ID and adding 52 cards to the end of the array. // when I am at 7 cards put the Hand Rank in!! // stepping through the ID array is perfect!! int IDnum; int holdid; System.out.println("\nGetting Card IDs!\n"); // as this loops through and find new combinations it adds them to the end // I need this list to be stable when I set the handranks (next set) (I do the insertion sort on new IDs these) // so I had to get the IDs first and then set the handranks for (IDnum = 0; IDs[IDnum]!=0 || IDnum == 0; IDnum++) { // start at 1 so I have a zero catching entry (just in case) for (card = 1; card < 53; card++) { // the ids above contain cards upto the current card. Now add a new card ID = MakeID(IDs[IDnum], card); // get the new ID for it if (numcards < 7) holdid = SaveID(ID); // and save it in the list if I am not on the 7th card } System.out.println("\rID - " + IDnum); // just to show the progress -- this will count up to 612976 } System.out.println("\nSetting HandRanks!\n"); // this is as above, but will not be adding anything to the ID list, so it is stable for (IDnum = 0; IDs[IDnum]!=0 || IDnum == 0; IDnum++) { // start at 1 so I have a zero catching entry (just in case) for (card = 1; card < 53; card++) { ID = MakeID(IDs[IDnum], card); if (numcards < 7) IDslot = SaveID(ID) * 53 + 53; // when in the index mode (< 7 cards) get the id to save else IDslot = DoEval(ID); // if I am at the 7th card, get the HandRank to save maxHR = IDnum * 53 + card + 53; // find where to put it HR[maxHR] = IDslot; // and save the pointer to the next card or the handrank } if (numcards == 6 || numcards == 7) { // an extra, If you want to know what the handrank when there is 5 or 6 cards // you can just do HR[u3] or HR[u4] from below code for Handrank of the 5 or 6 card hand HR[IDnum * 53 + 53] = DoEval(IDs[IDnum]); // this puts the above handrank into the array } //if (IDnum%10000==0) System.out.println("\rID - " + IDnum); // just to show the progress -- this will count up to 612976 same as above! } System.out.println("\nNumber IDs = \nmaxHR = " + numIDs + " " + maxHR); // for warm fuzzys int c0, c1, c2, c3, c4, c5, c6; int u0, u1, u2, u3, u4, u5; //Begin timer, to be done System.out.println("Starting Test"); for (c0 = 1; c0 < 53; c0++) { u0 = HR[53+c0]; for (c1 = c0+1; c1 < 53; c1++) { u1 = HR[u0+c1]; for (c2 = c1+1; c2 < 53; c2++) { u2 = HR[u1+c2]; for (c3 = c2+1; c3 < 53; c3++) { u3 = HR[u2+c3]; for (c4 = c3+1; c4 < 53; c4++) { u4 = HR[u3+c4]; for (c5 = c4+1; c5 < 53; c5++) { u5 = HR[u4+c5]; for (c6 = c5+1; c6 < 53; c6++) { handTypeSum[HR[u5+c6] >>> 12]++; count++; } } } } } } } //stop timer, to be done for (int i = 0; i <= 9; i++) // display the results System.out.println(handTypeSum[i]); System.out.println("\nTotal Hands = " + count); //file output, to be done } </pre><hr /> |
|
#4
|
|||
|
|||
|
I'm still loving this thread when I get time to peek at it...
Just as an FYI, you should all feel free to post code, descriptions, etc. over that the overcards.com wiki pages: http://overcards.com/wiki/moin.cgi . The web pages and forums are somewhat dead, what with my retirement from poker, but the wiki pages have a life of their own as a centrum for AHK scripting nuts who play online poker. Feel free to bend the wiki to your own needs to post segments of code to discuss here - the wiki pages will keep an automatic version history of the code changes posted; just peek at the AHK pages for page layout ideas. |
|
#5
|
|||
|
|||
|
This thread got me to register for these forums.
This evaluator is great. I got it running in C++ and with it, I'm able to exaustively calculate the chance of every starting hand winning after the flop in .035 seconds. After the flop is the worst case because there are the most combinations. It goes faster for other game stages. BTW, this is on an Intel MacBook Pro. [img]/images/graemlins/smile.gif[/img] - Brad |
|
#6
|
|||
|
|||
|
Hi!
I have run this code in Java (other than the eval routines which I stubbed out with a return 1). They worked great! I also put in within DoEval (after rank = (workcard >>> 4) - 1 :<font class="small">Code:</font><hr /><pre> // my rank is top 4 bits 1-13 so convert if (rank > 12) { System.out.println(" Problem with rank = " + rank); } </pre><hr /> Which never was hit... I had to put in the heap memory allocator in: java -Xms130m -Xmx150m HandRankSetup to keep away from Heap errors. You did well doing the conversion... I believe that your code would work as is! (Pretty speedy too even in Java!) Ray... |
|
#7
|
|||
|
|||
|
Hi Ray,
Yes the java code "works" up until the point where the actual evaluations are done but breaks there. I do not think it is working correctly therefore as I know my old eval functions work given proper input. Any chance you could help us java folk by adding some printf 's in your c code to show, for example, the actual value of each id as it is created, as they seem to be created differently using my c code.. |
|
#8
|
|||
|
|||
|
Hi Mark,
Another thought... If you aren't using Cactus Kev's routine to do the evaluation of the hand, you would have a problem with the translation of the cards in the DoEval routine!! Are you using Cactus Kev's Eval routines? Ray... |
|
#9
|
|||
|
|||
|
Yep I am, I assume the problem would lie with the creation of the ID's, thanks alot by the way. I can't wait to see how fast this works in java compared to c. If you have a spare minute you might spend a moment to get your c code to print out the value or maybe even binary representation of the Id's as they are created.
Of course to be removed later when the differences are found. |
|
#10
|
|||
|
|||
|
Hi Mark,
I am running your code in Java. It worked fine.... No rank problems as I mentioned (put the rank > 12 code in as above and see if you hit that line). I didn't hit it. Also you need the heap memory increase (I am sure you had that!!). I didn't see anything wrong, and it came through cleanly (including rank). Let me know how you do... Ray... |
![]() |
| Thread Tools | |
| Display Modes | |
|
|