![]() |
|
#171
|
|||
|
|||
|
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... |
|
#172
|
|||
|
|||
|
Thanks Ray, I don't know where I am going wrong so.... I actually had that line in my code and it is never hit either, yet my 7 card evaluator blows up. Ill have a fiddle around but its strange it works fine for you [img]/images/graemlins/smile.gif[/img]
|
|
#173
|
|||
|
|||
|
Just before the switch statement where the eval's are done, I added the following lines. This shows that one of the workcards being sent to my evaluator has a rank of >12. I don't know whats going on now...
My code gets the out of bounds first in the 7 card evaluator, and with 7 card evals commented out, the 6 card evaluator goes out of bounds soon afterwards. <font class="small">Code:</font><hr /><pre> for (int cardNo=0; cardNo<5; cardNo++) { if (((workcards[cardNo]>>>8)& 0xF) > 12) { System.out.println("WOOPS, this cards rank was above 12"); System.exit(0); } } switch (numevalcards) { // run Cactus Keys routines case 5 : holdrank = eval_5cards(workcards[0],workcards[1],workcards[2],workcards[3],workcards[4]); </pre><hr /> |
|
#174
|
|||
|
|||
|
Hi EVERYONE!!!
I did have a bug in the program in the DoEval Routine!!! Please change the line at the top of the routine: int suititerator = 0; to int suititerator = 1; This should eliminate your problem with Java... For the C People out there... You should change this line in your code, but it didn't make a difference in the C routines because the only thing that this affected is the 0s for suit coming into the high bit of the rank. Suit didn't matter on these (because of the 0 suit), and if you don't have a suited hand it works off the prime numbers (not the rank >> 8). Interesting hit though, to be safe please rerun your Setup Programs... Ray... |
|
#175
|
|||
|
|||
|
Sweet, that fixed my problems [img]/images/graemlins/smile.gif[/img] Here is the output and thanks alot for the efforts.
Getting Card IDs! Setting HandRanks! maxHR = 612977 32487833 Training time: 44.813 seconds Starting Test 0 23294460 58627800 31433400 6461620 6180020 4047644 3473184 224848 41584 Total Hands = 133784560 0.783 seconds |
|
#176
|
|||
|
|||
|
Anyone ever post the .NET version? I'd love to take a look at that.
rvg |
|
#177
|
|||
|
|||
|
I am thinking of not storing an integer hand rank in the table but storing the actual effective hand strength. With effective hand strength I mean the probability that this hand will win the game if it comes to showdown. I start by generating the effective hand strengths for the 7-card combinations and then work my way backwards so I've got tables for 6,5 and 2 cards.
Has anyone tried this so far? Thomas |
|
#178
|
|||
|
|||
|
Just can't resist... [img]/images/graemlins/smile.gif[/img]
My code isn't like any of yours I don't think. My goal wasn't to write a fast evaluator, necesarrily, but to see if I could figure out how to evaluate a 7-card holdem hand with logic & no lookup tables. So that's what I did. Its not fast, but it does what I wanted. Just a different approach. <font class="small">Code:</font><hr /><pre> #include "stdafx.h" #include "score.h" #include <set> #include <vector> static const size_t sic = 0, sis = 1, sih = 2, sid = 3; static const size_t ria = 0, rik = 1, riq = 2, rij = 3, rit = 4, ri9 = 5, ri8 = 6, ri7 = 7, ri6 = 8, ri5 = 9, ri4 = 10, ri3 = 11, ri2 = 12; struct matrix { // running totals of each suit typedef std: air<int,int> suit_ttl; // first = total cards of this suit, second = high card in this suitsuit_ttl suit_ttls[4]; // running totals of each rank typedef int rank_ttl; rank_ttl rank_ttls[13]; // table card matrix struct col { bool suit[4]; bool rank[13]; }; col board[7]; }; void BuildHEMatrix(card cards[7], bool suit[4][7], bool rank[13][7]) { for( int i = 0; i < 7; ++i ) { suit[cards[i].suit][i] = true; rank[cards[i].rank][i] = true; } } inline handval BuildScore(int mask, int a, int b, int c, int d, int e) { handval ret = a; ret <<= 4; ret |= b; ret <<= 4; ret |= c; ret <<= 4; ret |= d; ret <<= 4; ret |= e | mask; return ret; } handval ScoreHE(const card cards[7]) { // build the card matrix int flush_ttl[4] = {0}; int flush_hicard[4] = {0}; // int flush_locard[4] = {13}; int rank_ttl[13] = {0}; bool card_matrix[13][4] = {false}; for( int i = 0; i < 7; ++i ) { const card& c = cards[i]; card_matrix[c.rank][c.suit] = true; ++flush_ttl[c.suit]; if( c.rank > flush_hicard[c.suit] ) flush_hicard[c.suit] = c.rank; // if( c.rank < flush_locard[c.suit] ) flush_locard[c.suit] = c.rank; ++rank_ttl[c.rank]; } // look for straight flush for(int s = 0; s < 4; ++s ) { int remain = flush_ttl[s]; int run = 0; int sf_rank = -1; for( int r = flush_hicard[s]; run < 5 && r <= 12 && (remain+run)>=5; --r, --remain ) { if( card_matrix[r][s] ) { if( ++run == 1 ) sf_rank = r; } else run = 0; } if( 5 == run ) return BuildScore(hipk_sflush, sf_rank, sf_rank-1, sf_rank-2, sf_rank-3, sf_rank-4 ); // we found a straight flush } // look for quads, trips, pairs etc int quads_rank = -1, trips_rank = -1, twpr_rank = -1, pr_rank = -1, str_rank = -1, str_run = 0; for( int r = 12; r >= 0; --r ) { if( quads_rank == -1 && rank_ttl[r] == 4 ) quads_rank = r; if( trips_rank == -1 && rank_ttl[r] == 3 ) trips_rank = r; if( twpr_rank == -1 && rank_ttl[r] == 2 ) { if( pr_rank == -1 ) pr_rank = r; else { if( pr_rank > r ) { twpr_rank = pr_rank; pr_rank = r; } else twpr_rank = r; } } if( str_rank == -1 ) { if( rank_ttl[r] == 0 ) str_run = 0; else if( ++str_run == 5 ) str_rank = r+4; } } // score quads if( quads_rank > -1 ) { int kick = -1; for( int r = 12; r >= 0 && -1 == kick; --r ) if( rank_ttl[r] > 0 && rank_ttl[r] != 4 ) kick = r; // find kicker return BuildScore(hipk_quads, quads_rank, quads_rank, quads_rank, quads_rank, kick); } // score boat if( trips_rank != -1 && pr_rank != -1 ) { if( twpr_rank != -1 ) return BuildScore(hipk_boat, trips_rank, trips_rank, trips_rank, twpr_rank, twpr_rank); else return BuildScore(hipk_boat, trips_rank, trips_rank, trips_rank, pr_rank, pr_rank); } // score flush for( int s = 0; s < 4; ++s ) { if( flush_ttl[s] < 5 ) continue; std::vector<int> fc; for( int r = flush_hicard[s]; r >=0 && fc.size() < 5; --r ) { if( card_matrix[r][s] ) fc.push_back(r); } return BuildScore(hipk_flush, fc[0], fc[1], fc[2], fc[3], fc[4]); } // score straight if( str_rank != -1 ) return BuildScore(hipk_straight, str_rank, str_rank-1, str_rank-2, str_rank-3, str_rank-4); // score trips if( trips_rank != -1 ) { std::vector<int> kickers; for( int r = 12; r >= 0 && kickers.size() < 2; --r ) { if( r != trips_rank && rank_ttl[r] > 0 ) kickers.push_back(r); } return BuildScore(hipk_trips, trips_rank, trips_rank, trips_rank, kickers[0], kickers[1]); } // score two pair if( twpr_rank != -1 ) { int kick = -1; for( int r = 12; r >= 0 && -1 == kick; --r ) if( r != twpr_rank && r != pr_rank && rank_ttl[r] > 0 ) kick = r; // find kicker return BuildScore(hipk_2pr, twpr_rank, twpr_rank, pr_rank, pr_rank, kick); } // score pair if( pr_rank != -1 ) { std::vector<int> kicks; for( int r = 12; r >= 0 && kicks.size() < 3; --r ) if( rank_ttl[r] == 1 ) kicks.push_back(r); // find 3 kickers return BuildScore(hipk_1pr, pr_rank, pr_rank, kicks[2], kicks[1], kicks[0]); } // score hi cards std::vector<int> kicks; for( int r = 12; r >= 0 && kicks.size() < 5; --r ) if( rank_ttl[r] > 0 ) kicks.push_back(r); return BuildScore(hipk_hicard, kicks[4], kicks[3], kicks[2], kicks[1], kicks[0]); } </pre><hr /> |
|
#179
|
|||
|
|||
|
here's a test harness:
<font class="small">Code:</font><hr /><pre> /*** John Dibling johndotdiblingatsungarddotcom ***/ #include "stdafx.h" #include "score.h" #include <algorithm> #include <time.h> #include <string> #include <iostream> //#include "x:\utils\stlext\stringext.h" #include <string> #include <vector> #include <algorithm> #include <list> #include <cstdarg> #include <ctype.h> /*** NOTE : The following functions in namespace std are from my STL Extensions library. Only the necesarry code has been copied out of the STXEXT library and pasted here. ***/ namespace std { /* --- Formatted Print template<class C> int strprintf(basic_string<C>* pString, const C* pFmt, ...); template<class C> int vstrprintf(basic_string<C>* pString, const C* pFmt, va_list args); Returns : # characters printed to output Effects : Writes formatted data to a string. strprintf() works exactly the same as sprintf(); see your documentation for sprintf() for details of peration. vstrprintf() also works the same as sprintf(), but instead of accepting a variable paramater list it accepts a va_list argument. Requires : pString is a pointer to a basic_string<> --- */ inline int vstrprintf(string* pString, const char* pFmt, va_list args) { // prologue static const size_t ChunkSize = 1024; int retval = 0; // get local work buffer size_t nBufSize = 0; char* pBuf = 0; // format up string int i = -1; for( ; i == -1; ) { // realloc local buffer if( pBuf ) delete pBuf; pBuf = new char[nBufSize+=ChunkSize]; // try to sprintf i = _vsnprintf(pBuf,nBufSize,pFmt,args); } retval = i; // epilogue pString->assign(pBuf,retval); delete pBuf; return retval; }; /* --- Inline Formatted Print string strprintf(const char* Format, ...); Returns : Formatted string Effects : Writes formatted data to a string. formatstr() works the same as sprintf(); see your documentation for sprintf() for details of operation. --- */ std::string formatstr(const char * fmt, ...) { std::string ret; va_list args; va_start(args, fmt); int retval = vstrprintf(&ret, fmt, args); va_end(args); return ret; } }; // namespace std void deal_cards(card * deck, size_t n) { static bool seeded = false; if( !seeded ) { srand((unsigned)time(0)); seeded = true; } for( size_t i = 0; i < n; ++i ) { for( bool cont = true; cont; ) { deck[i].rank = (cardrank)int(((double)rand()/(double)RAND_MAX) * 12); deck[i].suit = (cardsuit)int( 3*((double)rand()/(double)RAND_MAX) ); cont = &deck[i] != std::find(&deck[0],&deck[i],deck[i]); } } } std::string card_abbrev(const card& c, bool incl_suit) { std::string ret; static const char suitc[] = "cshd"; static const char rankc[] = "23456789TJQKA"; ret += rankc[c.rank]; if( incl_suit ) ret += suitc[c.suit]; return ret; } std::string print_hand(card* first, card* last) { std::string ret; for( card* it = first; it != last; ++it ) { if( it != first ) ret += " "; ret += card_abbrev(*it,true); } return ret; } std::string rank_name(int rank) { switch( rank ) { case 12 : return "Ace"; case 11 : return "King"; case 10 : return "Queen"; case 9 : return "Jack"; case 8 : return "Ten"; case 7 : return "Nine"; case 6 : return "Eight"; case 5 : return "Seven"; case 4 : return "Six"; case 3 : return "Five"; case 2 : return "Four"; case 1 : return "Trey"; case 0 : return "Deuce"; default : return "Bug"; } } std::string suit_name(cardsuit s) { switch( s ) { case club : return "Clubs"; case spade : return "Spades"; case diamond : return "Diamonds"; case heart : return "Hearts"; default : return "Wands"; } } std::string card_name(card c) { return std::formatstr("%s of %s", rank_name(c.rank).c_str(), suit_name(c.suit).c_str()); } std::string card_name(int r, cardsuit s) { return std::formatstr("%s of %s", rank_name(r).c_str(), suit_name(s).c_str()); } std::string score2string(const handval& val) { switch( val & 0xF0000000 ) { case hipk_sflush : if( (0xf & (val >> 16)) == 12 ) return "Royal Flush"; else return std::formatstr("Straight Flush, %s High", rank_name((0xf & (val >> 16))).c_str()); case hipk_quads: return std::formatstr("Four of a Kind, %ss (%s Kicker)", rank_name((0xf & (val >> 16))).c_str(), rank_name((0xf & val)).c_str()); case hipk_boat : return std::formatstr("Full House, %ss Full of %ss", rank_name((0xf & (val >> 16))).c_str(), rank_name((0xf & val)).c_str()); case hipk_flush : return std::formatstr("Flush, %s-high", rank_name((0xf & (val >> 16))).c_str()); case hipk_straight : return std::formatstr("Straight, %s-high", rank_name((0xf & (val >> 16))).c_str()); case hipk_trips : return std::formatstr("Three of a Kind, %ss (%s-%s Kickers)", rank_name((0xf & (val >> 16))).c_str(), rank_name((0xf & (val >> 4))).c_str(), rank_name((0xf & val)).c_str()); case hipk_2pr : return std::formatstr("Two Pair, %ss over %ss (%s Kicker)", rank_name((0xf & (val >> 16))).c_str(), rank_name((0xf & (val >> 8))).c_str(), rank_name((0xf & val)).c_str()); case hipk_1pr : return std::formatstr("One Pair, %ss (%s-%s-%s Kickers)", rank_name((0xf & (val >> 16))).c_str(), rank_name((0xf & (val >> 8))).c_str(), rank_name((0xf & (val >> 4))).c_str(), rank_name((0xf & val)).c_str()); case hipk_hicard : return std::formatstr("High Card, %s-%s-%s-%s-%s", rank_name((0xf & (val >> 16))).c_str(), rank_name((0xf & (val >> 12))).c_str(), rank_name((0xf & (val >> 8))).c_str(), rank_name((0xf & (val >> 4))).c_str(), rank_name((0xf & val)).c_str()); default : return "Something Wierd!"; } } struct deal_block { card deal[7]; deal_block(card in[7]) { std::copy(&in[0], &in[7], &deal[0]); } }; int _tmain(int argc, _TCHAR* argv[]) { card exp[] = { {club,7}, {club,6}, {club,5}, {club,4}, {club,3}, {club,2}, {club,1}, // sf {club,7}, {spade,10}, {club,5}, {heart,10}, {diamond,10}, {club,2}, {club,10},// quads {heart,12}, {heart,11}, {diamond,11}, {diamond,12}, {spade,12}, {club,3}, {club,2}, // full house {club,7}, {club,6}, {club,9}, {club,4}, {club,3}, {club,2}, {club,1},// flush {club,7}, {heart,6}, {spade,5}, {diamond,4}, {club,3}, {club,2}, {club,1},// straight {heart,12}, {heart,11}, {diamond,11}, {diamond,11}, {spade,9}, {club,3}, {club,2},// trips {heart,12}, {heart,11}, {diamond,11}, {diamond,12}, {spade,9}, {club,3}, {club,2},//2pair {heart,12}, {heart,11}, {diamond,10}, {diamond,9}, {spade,7}, {club,3}, {club,2},// pair {heart,12}, {heart,11}, {diamond,10}, {diamond,9}, {spade,7}, {club,3}, {club,2}, // high card }; size_t deals = (sizeof(exp)/sizeof(exp[0]))/7; for( size_t i = 0; i < deals; ++i ) { size_t ii = 7*i; handval hv = ScoreHE(&exp[ii]); std::cout << print_hand(&exp[ii], &exp[ii+7]).c_str() << " -- " << score2string(hv).c_str() << std::endl; } for( size_t i = 0; i < deals; ++i ) { size_t ii = 7*i; card shuffled[7]; std::copy(&exp[ii], &exp[ii+7], shuffled); std::random_shuffle(&shuffled[0], &shuffled[7]); handval hv = ScoreHE(shuffled); std::cout << print_hand(shuffled, &shuffled[7]).c_str() << " -- " << score2string(hv).c_str() << std::endl; } for( int i = 0; i < 10; ++i ) { card a[7]; size_t na = sizeof(a)/sizeof(a[0]); deal_cards(a,na); std::cout << "[" << i+1 << "] : "; for( size_t j = 0; j < na; ++j ) std::cout << card_abbrev(a[j],true).c_str() << " "; std::cout << std::endl; ScoreHE(a); } // time 1 million scores #ifdef _DEBUG const int trials = 200; #else const int trials = 10000000; #endif std::cout << "Dealing " << trials << " games..." << std::endl; std::vector<deal_block> bigdeal; bigdeal.reserve(trials); card deal[7]; for( int i = 1; i <= trials; ++i ) { if( i%(trials/10) == 0 ) std::cout << "."; deal_cards(deal,7); bigdeal.push_back(deal); } std::cout << std::endl << "Scoring games..." << std::endl; unsigned long results[9] = {0}; time_t start = time(0); handval hv; for( int i = 0; i < trials; ++i ) { if( i%(trials/10) == 0 ) std::cout << "."; hv = ScoreHE(bigdeal.at(i).deal); ++results[hv>>28]; } time_t end = time(0); std::cout << std::endl << "Elapsed Time: " << (long)end-start; if( (end-start)>0 ) std::cout << ", Scores per second: " << trials/((long)end-start); std::cout << std::endl << "Results:" << std::endl << "S-Flushes: " << results[8] << "\t (" << 100*results[8]/trials << "%)" << std::endl << "Quads: " << results[7] << "\t (" << 100*results[7]/trials << "%)" << std::endl << "Full Boats: " << results[6] << "\t (" << 100*results[6]/trials << "%)" << std::endl << "Flushes: " << results[5] << "\t (" << 100*results[5]/trials << "%)" << std::endl << "Straights: " << results[4] << "\t (" << 100*results[4]/trials << "%)" << std::endl << "Trips: " << results[3] << "\t (" << 100*results[3]/trials << "%)" << std::endl << "2-Pairs: " << results[2] << "\t (" << 100*results[2]/trials << "%)" << std::endl << "1-Pairs: " << results[1] << "\t (" << 100*results[1]/trials << "%)" << std::endl << "Hi-Cards: " << results[0] << "\t (" << 100*results[0]/trials << "%)" << std::endl; return 0; } </pre><hr /> |
|
#180
|
|||
|
|||
|
Hand Strength or probability that your hand is ahead / behind depends on the other players cards, aswell as how many players you are against. Even if you just compare your hand versus x random hands, the number x (players playing) has a massive impact on the probabilities so I don't think what you are thinking of doing thomash is possible in this sense.
|
![]() |
|
|