#11
|
|||
|
|||
Re: Algorithm for Figuring out Your Hold\'em Hand
I have written code that can compare up to nine card hands, after that I really did not want to worry about double flushes, straights, etc. But I did not know about the sourceforge project when I wrote mine (also, since I did it like 7 years ago originally, it may not have existed then, though I have since re-written it in java).
|
#12
|
|||
|
|||
Re: Algorithm for Figuring out Your Hold\'em Hand
See my post in the probability section about poker calculator.
|
#13
|
|||
|
|||
Re: Algorithm for Figuring out Your Hold\'em Hand
[ QUOTE ]
I might be interested in some sort of code to work out how strong a hand is with less than 7 cards. So say after turn, it could classify the hands as 'two pair' or 'two pair with flush draw' or 'flush draw' etc. [/ QUOTE ] I've written this type of code. It's more tedious and more open for interpretation than you'd think. The problem is how to label the various straight draws and gutshots mixed in with overcards. |
#14
|
|||
|
|||
Re: Algorithm for Figuring out Your Hold\'em Hand
If you're going to do this for a living, the most important lesson you can learn is that no one will EVER through your code. This is important for email communications. Reading someone else's code is actually harder in some sense than writing your own.
I am not trying to be cute -- I made this mistake as an intern. Also, an important skill is to able to write adequate tests for your code and debug it. Bad engineers skip this part too often. Poker code is good practice for this. [ QUOTE ] In case anyone was wondering... here is the code I came up with. I still have to find a way to check for A2345 straights and straightflushes, since I made the Ace count as high when I coded it. <font class="small">Code:</font><hr /><pre> HAND evalHand(Player * thePlayer, Board * theBoard) { //stores the player's hole cards vector<Card> holeCards; holeCards.push_back(thePlayer->getHoleCard(0)); holeCards.push_back(thePlayer->getHoleCard(1)); //stores the board cards vector<Card> boardCards; for(int i = 0; i < 5; ++i){ boardCards.push_back(theBoard->at(i)); } sort(boardCards.begin(), boardCards.end()); //add holecards to form a "total" hand, they are left seperate for "incomplete" hand evaluation //later on in a different function vector<Card> allCards; allCards.push_back(holeCards[0]); allCards.push_back(holeCards[1]); for(int i = 0; i < 5; ++i){ allCards.push_back(boardCards[i]); } sort(allCards.begin(), allCards.end(), sortBySuit()); //first sort by suit to check for straightflush //------begin checking hands-------------------- //************check for flush or straightflush********************* bool flush = false; Card c = allCards[6]; int flushCount = 1, straightFlushCount = 1; int flushIndex= 6, straightFlushIndex = 6; for(int i = 5; i >= 0; --i){ //loop through the array backwards, checking the highest card first if(c.getSuit() == allCards[i].getSuit()){ //next in flush if(c.getRank() - allCards[i].getRank() == 1){ //straight-flush count straightFlushCount++; //begin building straightflush flushCount++; } else { //no straight-flush, but still could be flush straightFlushCount = 1; straightFlushIndex = i; flushCount++; } } else { //no flush or straightflush straightFlushCount = 1; straightFlushIndex = i; if(!flush){ //don't reset flush counts if we already have one flushCount = 1; flushIndex = i; } } if(flushCount >= 5){ //flush! if(straightFlushCount == 5) { //could be a straight-flush return STRAIGHTFLUSH; } else { flush = true; //can't return yet since we have to check for rest of straightflush, //quads or fullhouse } } c = allCards[i]; } //*********check for four of a kind, trips, two pair, one pair****************** int threeKind = 0, pair = 0; int pairCount[7] = {1,1,1,1,1,1,1}; for(int j = 0; j < 7; ++j){ for(int i = 0; i < 7; ++i){ if(i != j){ if(allCards[j].getRank() == allCards[i].getRank()){ pairCount[j]++; } } } if(pairCount[j] == 4){ return FOURKIND; } else if(pairCount[j] == 3){ threeKind++; } else if(pairCount[j] == 2){ pair++; } } //*************check for full house********************** if((threeKind == 3 && (pair == 2 || pair == 4)) || threeKind == 6){ return FULLHOUSE; } //*************check for flush*************************** if(flush){ return FLUSH; } //**************check for straight******************* sort(allCards.begin(), allCards.end()); //now sort by rank to check for straight int straightCount = 1, straightIndex = 6; c = allCards[6]; for(int i = 5; i >= 0; --i){ //loop through the array backwards, checking the highest card first if(c.getRank() - allCards[i].getRank() == 1){ //next in the straight straightCount++; //if there is not a pair, reset straight counts and straightflush counts } else if(c.getRank() != allCards[i].getRank()){ straightCount = 1; straightIndex = i; } if(straightCount >= 5){ //straight! return STRAIGHT; } c = allCards[i]; } //*************check for trips********************** if(threeKind == 3){ return THREEKIND; } //************check for two pair******************** if(pair == 4 || pair == 6){ return TWOPAIR; } //***********check for one pair********************* if(pair == 2){ return ONEPAIR; } //***************HIGH CARD*************** return HIGHCARD; } </pre><hr /> [/ QUOTE ] |
#15
|
|||
|
|||
Re: Algorithm for Figuring out Your Hold\'em Hand
[ QUOTE ]
Also, I just want an algorithm, not actual code. I'm really just trying to keep my programing skills sharpened during the summer. [/ QUOTE ] step 1 create a table of all valid hands starting with lowest (2,3,4,5,7) so it returns 1 and ending with highest (royal flush) so it returns 7462 step 2 if the score is 1-1277 its a highcard hand (no pair) if the score is 1278 - 4137 its a one pair hand etc.. if the score is 7452 - 7462 it is a straight flush You can get more detailed if you want like 1124-1277 is an Ace high hand. and look here http://forumserver.twoplustwo.com/showfl...e=0#Post6652490 |
#16
|
|||
|
|||
Re: Algorithm for Figuring out Your Hold\'em Hand
[ QUOTE ]
In case anyone was wondering... here is the code I came up with. [/ QUOTE ] I'm not trying to criticize, but that is insanely inefficient. |
#17
|
|||
|
|||
Re: Algorithm for Figuring out Your Hold\'em Hand
Here is the main guts of a hand evaluator I wrote.
Most of the "labor" was in creating the tables, which I have elsewhere in the code as constants. It takes a 64 bit value (each card is represented by a bit) This code works for 5, 6, and 7 cards. It returns a 24 bit value (top 4 = hand type) and (4 per card) represent the specific hand. 0x55432E represents a 5 high straight 0x5EDCBA represents a A high straight 0x796000 represents a Full House 9's over 6's 0x175432 represents the worst possible hand. etc. If there is interest, I can explain what the code is doing each step of the way. <font class="small">Code:</font><hr /><pre> function GetScore(Hand : THand) : integer; asm push esi push edi push edx push ecx push ebx mov esi,DWORD[Hand.SpadesAndHearts] mov ecx,DWORD[Hand.DiamondsAndClubs] mov eax,$FFFF mov ebx,esi mov edx,ecx and esi,eax shr ebx,16 and ecx,eax shr edx,16 xor eax,eax or eax,DWORD[esi*4+FiveRankTable] or eax,DWORD[ebx*4+FiveRankTable] or eax,DWORD[ecx*4+FiveRankTable] or eax,DWORD[edx*4+FiveRankTable] jz @NoFlush @IsFlush: cmp eax,Code_Straight jl @NoStraightFlush add eax,Code_StraightFlush-Code_Straight jmp @Done @NoStraightFlush: add eax,Code_Flush-Code_HighCard jmp @Done @NoFlush: mov edi,esi and edi,ebx or esi,ebx mov ebx,edi and edi,ecx mov eax,ecx and eax,esi or ebx,eax or esi,ecx mov ecx,edi and edi,edx mov eax,ebx and eax,edx or ecx,eax mov eax,esi and eax,edx or ebx,eax or esi,edx mov edx,edi test edx,edx jz @NoQuads xor esi,edx mov eax,Code_Quads or eax,DWORD[edx*4+Put1In1] or eax,DWORD[esi*4+Put1In2] jmp @Done @NoQuads: test ecx,ecx jz @NoFullHouse xor ebx,DWORD[ecx*4+Get1Bit] test ebx,ebx jz @NoFullHouse mov eax,Code_FullHouse or eax,DWORD[ecx*4+Put1In1] or eax,DWORD[ebx*4+Put1In2] jmp @Done @NoFullHouse: mov eax,DWORD[esi*4+FiveRankTable] cmp eax,Code_Straight jg @Done test ecx,ecx jz @NoTrips xor esi,ecx mov eax,Code_Trips or eax,DWORD[ecx*4+Put1In1] or eax,DWORD[esi*4+Put1_2In2_3] jmp @Done @NoTrips: mov edi,DWORD[ebx*4+Put1_2In1_2] test edi,edi jz @NoTwoPair xor esi,DWORD[ebx*4+Get1_2Bit] mov eax,Code_TwoPair or eax,edi or eax,DWORD[esi*4+Put1In3] jmp @Done @NoTwoPair: test ebx,ebx jz @Done xor esi,ebx mov eax,Code_OnePair or eax,DWORD[ebx*4+Put1In1] or eax,DWORD[esi*4+Put1_3In2_4] @Done: pop ebx pop ecx pop edx pop edi pop esi end; </pre><hr /> |
#18
|
|||
|
|||
Re: Algorithm for Figuring out Your Hold\'em Hand
[ QUOTE ]
Here is the main guts of a hand evaluator I wrote. Most of the "labor" was in creating the tables, which I have elsewhere in the code as constants. It takes a 64 bit value (each card is represented by a bit) This code works for 5, 6, and 7 cards. It returns a 24 bit value (top 4 = hand type) and (4 per card) represent the specific hand. 0x55432E represents a 5 high straight 0x5EDCBA represents a A high straight 0x796000 represents a Full House 9's over 6's 0x175432 represents the worst possible hand. etc. If there is interest, I can explain what the code is doing each step of the way. <font class="small">Code:</font><hr /><pre> function GetScore(Hand : THand) : integer; asm push esi push edi push edx push ecx push ebx mov esi,DWORD[Hand.SpadesAndHearts] mov ecx,DWORD[Hand.DiamondsAndClubs] mov eax,$FFFF mov ebx,esi mov edx,ecx and esi,eax shr ebx,16 and ecx,eax shr edx,16 xor eax,eax or eax,DWORD[esi*4+FiveRankTable] or eax,DWORD[ebx*4+FiveRankTable] or eax,DWORD[ecx*4+FiveRankTable] or eax,DWORD[edx*4+FiveRankTable] jz @NoFlush @IsFlush: cmp eax,Code_Straight jl @NoStraightFlush add eax,Code_StraightFlush-Code_Straight jmp @Done @NoStraightFlush: add eax,Code_Flush-Code_HighCard jmp @Done @NoFlush: mov edi,esi and edi,ebx or esi,ebx mov ebx,edi and edi,ecx mov eax,ecx and eax,esi or ebx,eax or esi,ecx mov ecx,edi and edi,edx mov eax,ebx and eax,edx or ecx,eax mov eax,esi and eax,edx or ebx,eax or esi,edx mov edx,edi test edx,edx jz @NoQuads xor esi,edx mov eax,Code_Quads or eax,DWORD[edx*4+Put1In1] or eax,DWORD[esi*4+Put1In2] jmp @Done @NoQuads: test ecx,ecx jz @NoFullHouse xor ebx,DWORD[ecx*4+Get1Bit] test ebx,ebx jz @NoFullHouse mov eax,Code_FullHouse or eax,DWORD[ecx*4+Put1In1] or eax,DWORD[ebx*4+Put1In2] jmp @Done @NoFullHouse: mov eax,DWORD[esi*4+FiveRankTable] cmp eax,Code_Straight jg @Done test ecx,ecx jz @NoTrips xor esi,ecx mov eax,Code_Trips or eax,DWORD[ecx*4+Put1In1] or eax,DWORD[esi*4+Put1_2In2_3] jmp @Done @NoTrips: mov edi,DWORD[ebx*4+Put1_2In1_2] test edi,edi jz @NoTwoPair xor esi,DWORD[ebx*4+Get1_2Bit] mov eax,Code_TwoPair or eax,edi or eax,DWORD[esi*4+Put1In3] jmp @Done @NoTwoPair: test ebx,ebx jz @Done xor esi,ebx mov eax,Code_OnePair or eax,DWORD[ebx*4+Put1In1] or eax,DWORD[esi*4+Put1_3In2_4] @Done: pop ebx pop ecx pop edx pop edi pop esi end; </pre><hr /> [/ QUOTE ] Sweet to see some assembler! I think, sadly, it's a dieing art thesedays though... [img]/images/graemlins/frown.gif[/img] Can I ask why you coded this up in asm? I remember the days when I could gain quite alot from hand coding asm routines (z80, 600x0, 8086, 80x86, ...) but thesedays I just can't beat the modern optimizing compilers; they know way more about all the pipelines and t-state timings than I ever will, and most times they can outperform my hand coded asm routines hand down. I hope asm doesn't die out (as M$ would hope), as I think there is still alot to be gained from learning low level coding. Just my 2c - Juk [img]/images/graemlins/smile.gif[/img] |
#19
|
|||
|
|||
Re: Algorithm for Figuring out Your Hold\'em Hand
Most of what I write is in Delphi (Pascal) and at times it doesn't seem to be the most efficient, so to keep all the computation (bit twiddling) in the registers I had to resort to asm.
Likewise, I got my start with 6800, 6502, 8080, then advanced to the Z80 [img]/images/graemlins/smile.gif[/img] |
#20
|
|||
|
|||
Re: Algorithm for Figuring out Your Hold\'em Hand
[ QUOTE ]
Likewise, I got my start with 6800, 6502, 8080, then advanced to the Z80 [img]/images/graemlins/smile.gif[/img] [/ QUOTE ] Hehe, I'm too young to remember much before the Z80... I do remember using "BBC Micros" and an "Acorn Electron" when I was a small child (both used 6502's I think). I started on a ZX-Spectrum, and soon worked out that if I wanted to do anything fast then interpreted BASIC really sucked, and I was gonna have to use "machine code"! [img]/images/graemlins/confused.gif[/img] Still, I think what I learn way back then, when computers and coding were so much simpler, has helped me more than I can put into words... Juk [img]/images/graemlins/smile.gif[/img] |
|
|