![]() |
|
#51
|
|||
|
|||
|
[ QUOTE ]
[ QUOTE ] If someone could figure out a way to assign a unique index value between 1 and 133784560 for 7 unordered cards, you could dump everything into a 133 MB lookup table. [/ QUOTE ] Single byte for hand's strength is not enough, so the table must be 266 MB at least. Andrzej Nironen [/ QUOTE ] Actually it can be done in under 133 MB... I've got an array of approx 30 million integers. One way of accessing a hand ranking is: Rank := Eval[Eval[Eval[Eval[Eval[Eval[Eval[c1]+c2]+c3]+c4]+c5]+c6]+c7]; The general idea is there are: 1 card hands. 52x52 2 card hands. 1326x52 3 card hands. 22100x52 4 card hands. 84448x52 5 card hands. 152607x52 6 card hands. 352443x52 For each N card hand, there are 52 vectors to the appropriate N+1 card hand. For 6 card hands, instead of vectors to the 7 card hand, the array holds the Hand Ranking of the 7 card hand. |
|
#52
|
|||
|
|||
|
[ QUOTE ]
Please could you all run this test on your hand evaluators and let me know the results: int c1, c2, c3, c4, c5, c6, c7; int handSetCounters[8] = {0,0,0,0,0,0,0,0}; for(c1 = 0; c1 < 52; c1++) { for(c2 = c1 + 1; c2 < 52; c2++) { for(c3 = c2 + 1; c3 < 52; c3++) { for(c4 = c3 + 1; c4 < 52; c4++) { for(c5 = c4 + 1; c5 < 52; c5++) { for(c6 = c5 + 1; c6 < 52; c6++) { for(c7 = c6 + 1; c7 < 52; c7++) { CALCULATE RANK CALCULATE SET ID (HIGH CARD TO STRAIGHT FLUSH) INCREMENT HANDSETCOUNTERS[SET ID] }}}}}}} PRINT HANDSETCOUNTERS If you could time the speed of your code in that scenario it would be most interesting! Also with a copy of your results (number of flushes etc incase your code is not designed to be 100% accurate). Thanks for anyone that participates! Tom [/ QUOTE ] <font class="small">Code:</font><hr /><pre>133784560 hands 2.640 secs 50675964 hands/sec hc 23294460 pr 58627800 tp 31433400 th 6461620 st 6180020 fl 4047644 fh 3473184 fr 224848 sf 41584 using procedure TForm1.Button2Click(Sender: TObject); var Totals : array[0..9] of integer; c1, c2, c3, c4, c5, c6, c7 : integer; Count : integer; Start, Stop : TDateTime; secs : double; Score : integer; begin Start := Now; Fillchar(Totals,sizeof(Totals),0); Count := 0; for c1 := 0 to 45 do for c2 := c1+1 to 46 do for c3 := c2+1 to 47 do for c4 := c3+1 to 48 do for c5 := c4+1 to 49 do for c6 := c5+1 to 50 do for c7 := c6+1 to 51 do begin inc(Totals[Table[Table[Table[Table[Table[Table[Table[c1+52]+c2]+c3]+c4]+c5]+c6]+c7] shr 20]); inc(Count); end; Stop := Now; secs := (Stop-Start)*86400.0; memo1.lines.add(format('%d hands',[Count])); memo1.lines.add(format('%5.3f secs',[secs])); memo1.lines.add(format('%d hands/sec',[trunc(Count/secs)])); memo1.lines.add(format('hc %d',[Totals[1]])); memo1.lines.add(format('pr %d',[Totals[2]])); memo1.lines.add(format('tp %d',[Totals[3]])); memo1.lines.add(format('th %d',[Totals[4]])); memo1.lines.add(format('st %d',[Totals[5]])); memo1.lines.add(format('fl %d',[Totals[6]])); memo1.lines.add(format('fh %d',[Totals[7]])); memo1.lines.add(format('fr %d',[Totals[8]])); memo1.lines.add(format('sf %d',[Totals[9]])); end; and 133784560 hands 1.188 secs 112613302 hands/sec hc 23294460 pr 58627800 tp 31433400 th 6461620 st 6180020 fl 4047644 fh 3473184 fr 224848 sf 41584 using procedure TForm1.Button1Click(Sender: TObject); var Totals : array[0..9] of integer; c1, c2, c3, c4, c5, c6, c7 : integer; u1, u2, u3, u4, u5, u6, u7 : integer; Count : integer; Start, Stop : TDateTime; secs : double; Score : integer; begin Start := Now; Fillchar(Totals,sizeof(Totals),0); Count := 0; for c1 := 0 to 45 do begin U1 := Table[52+c1]; for c2 := c1+1 to 46 do begin U2 := Table[U1+c2]; for c3 := c2+1 to 47 do begin U3 := Table[U2+c3]; for c4 := c3+1 to 48 do begin U4 := Table[U3+c4]; for c5 := c4+1 to 49 do begin U5 := Table[U4+c5]; for c6 := c5+1 to 50 do begin U6 := Table[U5+c6]; for c7 := c6+1 to 51 do begin inc(Totals[Table[U6+c7] shr 20]); inc(Count); end; end; end; end; end; end; end; Stop := Now; secs := (Stop-Start)*86400.0; memo1.lines.add(format('%d hands',[Count])); memo1.lines.add(format('%5.3f secs',[secs])); memo1.lines.add(format('%d hands/sec',[trunc(Count/secs)])); memo1.lines.add(format('hc %d',[Totals[1]])); memo1.lines.add(format('pr %d',[Totals[2]])); memo1.lines.add(format('tp %d',[Totals[3]])); memo1.lines.add(format('th %d',[Totals[4]])); memo1.lines.add(format('st %d',[Totals[5]])); memo1.lines.add(format('fl %d',[Totals[6]])); memo1.lines.add(format('fh %d',[Totals[7]])); memo1.lines.add(format('fr %d',[Totals[8]])); memo1.lines.add(format('sf %d',[Totals[9]])); end; </pre><hr /> This was on an AMD 3000+ with 1 gig memory running Win2k This computer produced 133784560 hands 5.156 secs 25947355 hands/sec hc 23294460 pr 58627800 tp 31433400 th 6461620 st 6180020 fl 4047644 fh 3473184 fr 224848 sf 41584 using Andrzej Nironen's "Hand Evaluator Speed Demo" |
|
#53
|
|||
|
|||
|
[ QUOTE ]
[ QUOTE ] Please could you all run this test on your hand evaluators and let me know the results: int c1, c2, c3, c4, c5, c6, c7; int handSetCounters[8] = {0,0,0,0,0,0,0,0}; for(c1 = 0; c1 < 52; c1++) { for(c2 = c1 + 1; c2 < 52; c2++) { for(c3 = c2 + 1; c3 < 52; c3++) { for(c4 = c3 + 1; c4 < 52; c4++) { for(c5 = c4 + 1; c5 < 52; c5++) { for(c6 = c5 + 1; c6 < 52; c6++) { for(c7 = c6 + 1; c7 < 52; c7++) { CALCULATE RANK CALCULATE SET ID (HIGH CARD TO STRAIGHT FLUSH) INCREMENT HANDSETCOUNTERS[SET ID] }}}}}}} PRINT HANDSETCOUNTERS If you could time the speed of your code in that scenario it would be most interesting! Also with a copy of your results (number of flushes etc incase your code is not designed to be 100% accurate). Thanks for anyone that participates! Tom [/ QUOTE ] <font class="small">Code:</font><hr /><pre>133784560 hands 2.640 secs 50675964 hands/sec hc 23294460 pr 58627800 tp 31433400 th 6461620 st 6180020 fl 4047644 fh 3473184 fr 224848 sf 41584 using procedure TForm1.Button2Click(Sender: TObject); var Totals : array[0..9] of integer; c1, c2, c3, c4, c5, c6, c7 : integer; Count : integer; Start, Stop : TDateTime; secs : double; Score : integer; begin Start := Now; Fillchar(Totals,sizeof(Totals),0); Count := 0; for c1 := 0 to 45 do for c2 := c1+1 to 46 do for c3 := c2+1 to 47 do for c4 := c3+1 to 48 do for c5 := c4+1 to 49 do for c6 := c5+1 to 50 do for c7 := c6+1 to 51 do begin inc(Totals[Table[Table[Table[Table[Table[Table[Table[c1+52]+c2]+c3]+c4]+c5]+c6]+c7] shr 20]); inc(Count); end; Stop := Now; secs := (Stop-Start)*86400.0; memo1.lines.add(format('%d hands',[Count])); memo1.lines.add(format('%5.3f secs',[secs])); memo1.lines.add(format('%d hands/sec',[trunc(Count/secs)])); memo1.lines.add(format('hc %d',[Totals[1]])); memo1.lines.add(format('pr %d',[Totals[2]])); memo1.lines.add(format('tp %d',[Totals[3]])); memo1.lines.add(format('th %d',[Totals[4]])); memo1.lines.add(format('st %d',[Totals[5]])); memo1.lines.add(format('fl %d',[Totals[6]])); memo1.lines.add(format('fh %d',[Totals[7]])); memo1.lines.add(format('fr %d',[Totals[8]])); memo1.lines.add(format('sf %d',[Totals[9]])); end; and 133784560 hands 1.188 secs 112613302 hands/sec hc 23294460 pr 58627800 tp 31433400 th 6461620 st 6180020 fl 4047644 fh 3473184 fr 224848 sf 41584 using procedure TForm1.Button1Click(Sender: TObject); var Totals : array[0..9] of integer; c1, c2, c3, c4, c5, c6, c7 : integer; u1, u2, u3, u4, u5, u6, u7 : integer; Count : integer; Start, Stop : TDateTime; secs : double; Score : integer; begin Start := Now; Fillchar(Totals,sizeof(Totals),0); Count := 0; for c1 := 0 to 45 do begin U1 := Table[52+c1]; for c2 := c1+1 to 46 do begin U2 := Table[U1+c2]; for c3 := c2+1 to 47 do begin U3 := Table[U2+c3]; for c4 := c3+1 to 48 do begin U4 := Table[U3+c4]; for c5 := c4+1 to 49 do begin U5 := Table[U4+c5]; for c6 := c5+1 to 50 do begin U6 := Table[U5+c6]; for c7 := c6+1 to 51 do begin inc(Totals[Table[U6+c7] shr 20]); inc(Count); end; end; end; end; end; end; end; Stop := Now; secs := (Stop-Start)*86400.0; memo1.lines.add(format('%d hands',[Count])); memo1.lines.add(format('%5.3f secs',[secs])); memo1.lines.add(format('%d hands/sec',[trunc(Count/secs)])); memo1.lines.add(format('hc %d',[Totals[1]])); memo1.lines.add(format('pr %d',[Totals[2]])); memo1.lines.add(format('tp %d',[Totals[3]])); memo1.lines.add(format('th %d',[Totals[4]])); memo1.lines.add(format('st %d',[Totals[5]])); memo1.lines.add(format('fl %d',[Totals[6]])); memo1.lines.add(format('fh %d',[Totals[7]])); memo1.lines.add(format('fr %d',[Totals[8]])); memo1.lines.add(format('sf %d',[Totals[9]])); end; </pre><hr /> This was on an AMD 3000+ with 1 gig memory running Win2k This computer produced 133784560 hands 5.156 secs 25947355 hands/sec hc 23294460 pr 58627800 tp 31433400 th 6461620 st 6180020 fl 4047644 fh 3473184 fr 224848 sf 41584 using Andrzej Nironen's "Hand Evaluator Speed Demo" [/ QUOTE ] Very impressive! (I think you have the results mixed up though - 112.5mil when doing extra work of incrementing the hand type counts, 50mil when not... [img]/images/graemlins/smile.gif[/img] ) Have you considered posting this method on the pokersource yahoo group? Juk [img]/images/graemlins/smile.gif[/img] EDIT: Sorry, I just noticed you print the hand type counts in both procedures... BTW: How fast does it run without doing this (ie: just assigning an integer the hand evaluation rather than incrementing totals[]?) |
|
#54
|
|||
|
|||
|
[ QUOTE ]
[ QUOTE ] <font class="small">Code:</font><hr /><pre> 133784560 hands 1.188 secs 112613302 hands/sec hc 23294460 pr 58627800 tp 31433400 th 6461620 st 6180020 fl 4047644 fh 3473184 fr 224848 sf 41584 </pre><hr /> This was on an AMD 3000+ with 1 gig memory running Win2k This computer produced 133784560 hands 5.156 secs 25947355 hands/sec hc 23294460 pr 58627800 tp 31433400 th 6461620 st 6180020 fl 4047644 fh 3473184 fr 224848 sf 41584 using Andrzej Nironen's "Hand Evaluator Speed Demo" [/ QUOTE ] Very impressive! (I think you have the results mixed up though - 112.5mil when doing extra work of incrementing the hand type counts, 50mil when not... [img]/images/graemlins/smile.gif[/img] ) Have you considered posting this method on the pokersource yahoo group? Juk [img]/images/graemlins/smile.gif[/img] EDIT: Sorry, I just noticed you print the hand type counts in both procedures... BTW: How fast does it run without doing this (ie: just assigning an integer the hand evaluation rather than incrementing totals[]?) [/ QUOTE ] 0.953 secs 140382574 hands/sec However I'm doubting the granularity of the timing process used. I'll switch to the RDTSC method and repost relative values. Using RDTSC as a timer 133784560 hands 2.640 secs 50675964 hands/sec becomes 133784560 hands 5752663748 cycles 42.999 cycles/hand 133784560 hands 1.188 secs 112613302 hands/sec becomes 133784560 hands 2645152642 cycles 19.772 cycles/hand and 133784560 hands 0.953 secs 140382574 hands/sec becomes 133784560 hands 2077269818 cycles 15.527 cycles/hand |
|
#55
|
|||
|
|||
|
I've made some revision of my code. Enumeration wasn't optimal. Now it runs 30% faster with the same hand evaluation function.
http://www.pokerbolide.com/files/handeval7cards.exe Andrzej Nironen |
|
#56
|
|||
|
|||
|
how big are the LU tables combined under this method?
|
|
#57
|
|||
|
|||
|
Follow up. Trying to figure out how u map from table 5 to 6, or table 6 to a final hand value without large memory requirements. There about 2.5 Million combinations 5 cards, thust your table would seem to require 2.5 million combinations, yielding a table 6 that is lil over 100 MB.
The one way i thought around this is that your tables may already be condensed using equivalence classes, so the numbers could be smaller. That is, maybe if I wrote the big tables, and backwards eliminated duplicates, it would condense. Did you do something like that, or totally different? P.s. your tables lookups for c1 through c3 would probably be a pretty small part of your table(s). Why not just write them as an array (52,52,52) and put duplicate values in the array to that (1,2,3) = (3,2,1). Looking up a single value from a multi dimensional array is usually much faster than looking up values from 3 different arrays, and performing addition between each lookup. |
|
#58
|
|||
|
|||
|
Made some adjustments to my code, am currently getting 279 Million games per second. Although I still think your algorithm may have greater potential (possibly if I can combine it with mine).
Still not ready to share my algorithm...but i'll provide the following sketch of it...i ommitted some parts, changed descriptive names, etc...so that it can't just be copied (at least not easily). As you can see its speed is primarily due to being able to solve for many hands in one lookup, skipping to more complex analysis as needed. Whether more complex analysis is needed is also determined by a lookup table. For c1 = 1 To 46 nFTR(1) = CN(c1) For c2 = c1 + 1 To 47 nFTR(2) = CN(c2) For c3 = c2 + 1 To 48 nFTR(3) = CN(c3) For c4 = c3 + 1 To 49 nFTR(4) = CN(c4) For c5 = c4 + 1 To 50 nFTR(5) = CN(c5) rec_number = vRec_Num(non-lexographic indexing algorithm...nftr 1 through 5 as input) With vType(nftr(1 through 5) as input) If .Type = 0 Then For c6 = c5 + 1 To 51 For c7 = c6 + 1 To 52 rank = DW_Array(rec_number + sub_index(c6,c7)) ' Select Case rank ' Case 0 To 3000 ' h1 = h1 + 1 ' Case 3001 To 7000 ' h2 = h2 + 1 ' Case 7001 To 9000 ' h3 = h3 + 1 ' Case 9001 To 11000 ' h4 = h4 + 1 ' Case 11001 To 12000 ' h5 = h5 + 1 ' Case 12001 To 15000 ' h6 = h6 + 1 ' Case 15001 To 16000 ' h7 = h7 + 1 ' Case 16001 To 17000 ' h8 = h8 + 1 ' Case Else ' h9 = h9 + 1 ' End Select Next c7 Next c6 Else ...omitted... For c6 = c5 + 1 To 51 For c7 = c6 + 1 To 52 vType = .Type vnumber = .tnumber If SN(c6) = vType Then vnumber = vnumber + 1: adjust(vnumber) = CN(c6) If SN(c7) = vType Then vnumber = vnumber + 1: adjust(vnumber) = CN(c7) Select Case vnumber Case Is condition1 rank = DW_Array(rec_number + cindex(c6, c7)) Case condition2 rank = SW_Array(Rec_number2 (another non-lexographic indexing algorithm) * XX) Case condition3 rank = SW_Array(Rec_number2 * XX + fn1(adjust(6))) Case Else rank = SW_Array(Rec_number2 * XX + cindex(c6, c7)) End Select ' Select Case rank ' Case 0 To 3000 ' h1 = h1 + 1 ' Case 3001 To 7000 ' h2 = h2 + 1 ' Case 7001 To 9000 ' h3 = h3 + 1 ' Case 9001 To 11000 ' h4 = h4 + 1 ' Case 11001 To 12000 ' h5 = h5 + 1 ' Case 12001 To 15000 ' h6 = h6 + 1 ' Case 15001 To 16000 ' h7 = h7 + 1 ' Case 16001 To 17000 ' h8 = h8 + 1 ' Case Else ' h9 = h9 + 1 ' End Select Next c7 Next c6 End If End With Next c5 Next c4 Next c3 Next c2 Next c1 'dump counters 'Output.Text = h1 & vbNewLine & h2 & vbNewLine & h3 & vbNewLine & h4 & vbNewLine & h5 & vbNewLine & h6 & vbNewLine & h7 & vbNewLine & h8 & vbNewLine & h9 & vbNewLine |
|
#59
|
|||
|
|||
|
[ QUOTE ]
Follow up. Trying to figure out how u map from table 5 to 6, or table 6 to a final hand value without large memory requirements. There about 2.5 Million combinations 5 cards, thust your table would seem to require 2.5 million combinations, yielding a table 6 that is lil over 100 MB. The one way i thought around this is that your tables may already be condensed using equivalence classes, so the numbers could be smaller. That is, maybe if I wrote the big tables, and backwards eliminated duplicates, it would condense. Did you do something like that, or totally different? P.s. your tables lookups for c1 through c3 would probably be a pretty small part of your table(s). Why not just write them as an array (52,52,52) and put duplicate values in the array to that (1,2,3) = (3,2,1). Looking up a single value from a multi dimensional array is usually much faster than looking up values from 3 different arrays, and performing addition between each lookup. [/ QUOTE ] The table I use is for best 5 of 7 cards, not best 5 of 6, or just the only 5 given. Therefore I take advantage of that information when identifing the states. The "compression" occurs starting at the 4th card. If the first 4 cards of a 7 card hand are all of different suits, there is no way we could make a flush. Therefore AsKcQdJh is given the State ID of AxKxQxJx. There are a total of 24 combinations that would map to the same State ID. A hand like 9c3sTh5c is given the State ID of Tx9c5c3x The State ID needs to indicate that 2 of the cards are clubs, in case the next 3 cards are also clubs. 5hJdKdAh would get the StateID AhKdJd5h Since we could end up with either a heart flush or a diamond flush. If we are at State ID AhKdJd5h and the next card is a 6s, the new State ID would be AxKxJx6x5x since a flush is no longer possible. The 270725 4-card combos map down to 84448 With 5 cards you need 3 of the same suit, otherwise all suits can be ignored. Using an array of (52,52,52) probably wouldn't be faster. Multi-dimension arrays tend to involve a multiply or two internally. |
|
#60
|
|||
|
|||
|
[ QUOTE ]
Made some adjustments to my code, am currently getting 279 Million games per second. Although I still think your algorithm may have greater potential (possibly if I can combine it with mine). [/ QUOTE ] This is what happens when you let lawyers near compilers [img]/images/graemlins/smile.gif[/img] I'm not 100% sure about VB, but it's possible that since you commented out where you use 'rank', the optimizer eliminated the code that compute/lookup the value for rank. You might just be timing "empty" for - next loops. |
![]() |
|
|