Help using Base SAS procedures

Allocating Values to Poker Hands

Accepted Solution Solved
Reply
Super Contributor
Posts: 259
Accepted Solution

Allocating Values to Poker Hands

I want to create an algorithm that allocates a player's hand in a poker game a value. There is only one way I can see this working:

I create a table generating every poker hand (there are approx. 2.6m distinct hands) and then perform an algorithm to allocate a ranking to each hand (there are only approx. 7600  poker values). The table might look something like this:

I'm not sure how I would go about generating the 2.6 million hands such that they are all unique. I know it is probably straighforward but I am used to generating data sets in sas.

Card 1Card 2Card 3Card 4Card 5Rank
10SJSQSKSAS1
10CJCQCKCAC1
9S10SJSQSKS2

Once I have the first 5 columns, I think the only way of generating the rank is to do a series of steps that determine what rank of hand the player holds i.e. loads of steps to check if the hand is a flush, straight etc.)

Once this table has been generated I will use it as a reference table to check hands against. In another part of the code I will simulate a poker game between x players. I am also looking for help on how to check a player's 2 cards and the 5 common cards and allocate a rank based on the first table. So the code would need to pick the best 5 card combination out of 7 and then lookup this value in the table above.

Player Card 2Player Card 1Common Card 1Common Card 2Common Card 3Common Card 4Common Card 5Rank
9H10H2S3CJD4D3D1134
KSKC2D7HJC6SQS65

  

I know this can be done in excel but excel is too slow. I need a program that can simulate 1000s of poker games and I think SAS is far superior for this task. But I'm a bit concerned that it will still be too slow if it needs to read a table with 2.6m rows to allocate a rank for every hand. The poker games I'm trying to simulate might only involve 50 hands altogether but hat means looking up the rank table 300 times. I suppose I won't know until I've created the algorithm but It is a concern.

Any help on this would be very much appreciated


Accepted Solutions
Solution
‎06-20-2014 12:05 PM
Respected Advisor
Posts: 3,124

Re: Allocating Values to Poker Hands

Well, I came from non-western culture where Poker has different rules. Since it took me some effort to know Poker rules using Wiki, I will probably use it as the material for a paper for next year SESUG.Smiley Happy All of the business requirements are obtained from Wikipedia: List of poker hands - Wikipedia, the free encyclopedia

/*I use 14 to address 'A' for the simplicity of coding. There are 2,598,960 distinct hands,

out of which, there are 7,462 distinct scores, The whole process runs less than 10 secs on my

4x core pc, win7, if you already have the hands, to rank 100 of them takes less than 1 sec*/

/*TO GENERATE 52 CARDS POOL*/

DATA CAT;

INPUT SUIT :$1. @@;

CARDS;

S C H D

;

DATA SEQ;

INPUT NUM :$2. @@;

CARDS;

14 13 12 11 10 09 08 07 06 05 04 03 02

;

PROC SQL NOPRINT;

SELECT DISTINCT QUOTE(CATS(SUIT,NUM)) INTO :HANDS SEPARATED BY ' ' FROM CAT, SEQ;

QUIT;

/*EMBED RANKING ALGORITHM INTO THE FOLLOWING MACRO*/

%MACRO SIM;

DO Z=1 TO 5;

           FST(Z)=FIRST(C(Z));

           NUM(Z)=INPUT(COMPRESS(C(Z),,'KD'),2.);

END;

CALL SORTC (OF FST(*));

CALL SORTN (OF NUM(*));

/*STRAIGHT FLUSH*/

IF FST(1)=FST(5) AND NUM(5)-NUM(4)=1 AND NUM(4)-NUM(3)=1 AND NUM(3)-NUM(2)=1 AND NUM(2)-NUM(1)=1 THEN

           DO;

                RANK1=9;

                RANK2=NUM(5);

                RANK3=999;

                RANK4=999;

                RANK5=999;

                RANK6=999;

           END;

              ELSE IF FST(1)=FST(5) AND NUM(1)=2 AND NUM(2)=3 AND NUM(3)=4 AND NUM(4)=5 AND NUM(5)=14 THEN DO;

RANK1=9;

                RANK2=NUM(4);

                RANK3=999;

                RANK4=999;

                RANK5=999;

                RANK6=999;

                     END;

/*FOUR OF A KIND*/

ELSE IF NUM(1)=NUM(4) OR NUM(2)=NUM(5) THEN

           DO;

                RANK1=8;

                IF NUM(1)=NUM(4) THEN

                     DO;

                           RANK2=NUM(1);

                           RANK3=NUM(5);

                           RANK4=999;

                           RANK5=999;

                           RANK6=999;

                     END;

                ELSE IF NUM(2)=NUM(5) THEN

                     DO;

                           RANK2=NUM(2);

                           RANK3=NUM(1);

                           RANK4=999;

                           RANK5=999;

                           RANK6=999;

                     END;

           END;

/*FULL HOUSE*/

ELSE IF (NUM(1)=NUM(2) AND NUM(3)=NUM(5)) OR (NUM(1)=NUM(3) AND NUM(4)=NUM(5)) THEN

           DO;

                RANK1=7;

                IF (NUM(1)=NUM(2) AND NUM(3)=NUM(5)) THEN

                     DO;

                           RANK2=NUM(3);

                          RANK3=NUM(1);

                           RANK4=999;

                           RANK5=999;

                           RANK6=999;

END;

                ELSE  IF (NUM(1)=NUM(3) AND NUM(4)=NUM(5)) THEN

                     DO;

                           RANK2=NUM(1);

                           RANK3=NUM(4);

                           RANK4=999;

                           RANK5=999;

                           RANK6=999;

                     END;

           END;

/*FLUSH*/

ELSE IF FST(1)=FST(5) THEN

           DO;

                RANK1=6;

                RANK2=NUM(5);

                RANK3=NUM(4);

                RANK4=NUM(3);

                RANK5=NUM(2);

                RANK6=NUM(1);

           END;

/*STRAIGHT*/

ELSE IF NUM(5)-NUM(4)=1 AND NUM(4)-NUM(3)=1 AND NUM(3)-NUM(2)=1 AND NUM(2)-NUM(1)=1 THEN

           DO;

                RANK1=5;

                RANK2=NUM(5);

                RANK3=999;

                RANK4=999;

                RANK5=999;

                RANK6=999;

           END;

ELSE IF NUM(1)=2 AND NUM(2)=3 AND NUM(3)=4 AND NUM(4)=5 AND NUM(5)=14 THEN

           DO;

                RANK1=5;

                RANK2=NUM(4);

                RANK3=999;

                RANK4=999;

                RANK5=999;

                RANK6=999;

           END;

/*THREE OF A KIND*/

ELSE IF (NUM(1)=NUM(3) OR NUM(2)=NUM(4) OR NUM(3)=NUM(5)) THEN

           DO;

                RANK1=4;

                IF NUM(1)=NUM(3) THEN

                     DO;

                           RANK2=NUM(1);

                           RANK3=NUM(5);

                           RANK4=NUM(4);

                           RANK5=999;

                           RANK6=999;

                     END;

                IF NUM(2)=NUM(4) THEN

                     DO;

                           RANK2=NUM(2);

                           RANK3=NUM(5);

                           RANK4=NUM(1);

                           RANK5=999;

                           RANK6=999;

                     END;

                IF NUM(3)=NUM(5) THEN

                     DO;

                           RANK2=NUM(3);

                           RANK3=NUM(2);

                           RANK4=NUM(1);

                           RANK5=999;

                           RANK6=999;

                     END;

           END;

/*TWO PAIR*/

ELSE IF (NUM(1)=NUM(2) AND NUM(3)=NUM(4)) OR (NUM(1)=NUM(2) AND NUM(4)=NUM(5)) OR (NUM(2)=NUM(3) AND NUM(4)=NUM(5)) THEN

           DO;

                RANK1=3;

                IF (NUM(1)=NUM(2) AND NUM(3)=NUM(4)) THEN

                     DO;

                           RANK2=NUM(3);

                           RANK3=NUM(1);

                           RANK4=NUM(5);

                           RANK5=999;

                           RANK6=999;

                     END;

                IF (NUM(1)=NUM(2) AND NUM(4)=NUM(5)) THEN

                     DO;

                           RANK2=NUM(5);

                           RANK3=NUM(1);

                           RANK4=NUM(3);

                           RANK5=999;

                           RANK6=999;

                     END;

                IF (NUM(3)=NUM(2) AND NUM(5)=NUM(4)) THEN

                     DO;

                           RANK2=NUM(5);

                           RANK3=NUM(3);

                           RANK4=NUM(1);

                           RANK5=999;

                           RANK6=999;

                     END;

           END;

/*ONE PAIR*/

ELSE IF NUM(1)=NUM(2) OR NUM(2)=NUM(3) OR NUM(3)=NUM(4) OR NUM(4)=NUM(5) THEN

           DO;

                RANK1=2;

                IF NUM(1)=NUM(2) THEN

                     DO;

                           RANK2=NUM(1);

                           RANK3=NUM(5);

                           RANK4=NUM(4);

                           RANK5=NUM(3);

                           RANK6=999;

                     END;

                IF NUM(2)=NUM(3) THEN

                     DO;

                           RANK2=NUM(3);

                           RANK3=NUM(5);

                           RANK4=NUM(4);

                           RANK5=NUM(1);

                           RANK6=999;

                     END;

                IF NUM(3)=NUM(4) THEN

                     DO;

                           RANK2=NUM(4);

                           RANK3=NUM(5);

                           RANK4=NUM(2);

                           RANK5=NUM(1);

                           RANK6=999;

                     END;

                IF NUM(4)=NUM(5) THEN

                     DO;

                           RANK2=NUM(5);

                           RANK3=NUM(3);

                           RANK4=NUM(2);

                           RANK5=NUM(1);

                           RANK6=999;

                     END;

           END;

/*HIGH CARD*/

ELSE

           DO;

                RANK1=1;

                RANK2=NUM(5);

                RANK3=NUM(4);

                RANK4=NUM(3);

                RANK5=NUM(2);

                RANK6=NUM(1);

           END;

%MEND;

/*SCORE ALL OF THE COMBINATIONS*/

data HANDS;

array c[5] $3;

array x[52] $3 (&HANDS.);

array i[5];

ARRAY NUM(5) num1-num5;

ARRAY FST(5) $ 1 fst1-fst5;

n=dim(x);

k=dim(i);

i[1]=0;

ncomb=comb(n,k);

do j=1 to ncomb;

           call allcombi(n, k, of i

  • );
  •            do h=1 to k;

                    c=x[i];

               end;

               %SIM

               OUTPUT;

    end;

    KEEP C: RANK: num:;

    run;

    /*ORDER AND RANK DISTINCT SCORES*/

    PROC SORT DATA=HANDS OUT=HAND_SORT;

    BY DESCENDING RANK1 DESCENDING RANK2 DESCENDING RANK3 DESCENDING RANK4 DESCENDING RANK5 DESCENDING RANK6;

    RUN;

    DATA RANKS (KEEP=RANK: ORDER);

    SET HAND_SORT;

    BY DESCENDING RANK1 DESCENDING RANK2 DESCENDING RANK3 DESCENDING RANK4 DESCENDING RANK5 DESCENDING RANK6;

    IF FIRST.RANK6;

    ORDER+1;

    RUN;

    /*RANDOM SAMPLE: CAN ALSO BE DONE USING DATA STEP*/

    PROC SURVEYSELECT DATA=WORK.HANDS

    OUT=WORK.SAMPLE (KEEP=CSmiley Happy

    METHOD=SRS

    N=90000;

    RUN;

    /*RANK THE SAMPLE DATA, THERE ARE MANY WAYS FOR THIS KIND OF LOOK UP, HERE IS TO USE HASH() TABLE*/

    DATA WANT;

    IF _N_=1 THEN

               DO;

                    IF 0 THEN

                         SET RANKS;

                    DECLARE HASH H(DATASET:'RANKS');

                    H.DEFINEKEY('RANK1', 'RANK2','RANK3','RANK4', 'RANK5','RANK6');

                    H.DEFINEDATA(ALL:'Y');

                    H.DEFINEDONE();

               END;

    SET SAMPLE;

    array c[5] $3;

    ARRAY NUM(5) num1-num5;

    ARRAY FST(5) $ 1 fst1-fst5;

    %SIM

    RC=H.FIND();

    KEEP C: ORDER;

    run;


    Update:

    Got a PM saying that since I use '14' for ACE that I miscategorized 'Steel Wheel' and 'Wheel' (Meaning A-2-3-4-5 is still qualified for 'Straight') , hence the update.


    Update 2:

    FYI: Given OP has 300 games, 6 players and each for 50 plays, that counts for 90,000 hand. To rank them took less than 1 sec on my machine. It is really not a heavy-duty computing job by any means.

    View solution in original post


    All Replies
    Super User
    Posts: 9,681

    Re: Allocating Values to Poker Hands

    Maybe you should check call greycode() routine.But I don't know if it could handle 26 cards ,check documentation.

    Xia Keshan

    Super User
    Posts: 5,082

    Re: Allocating Values to Poker Hands

    Generating the combinations is straightforward:

    data all_combinations;

       do card1=1 to 48;

          do card2=card1+1 to 49;

             do card3=card2+1 to 50;

                do card4=card3+1 to 51;

                   do card5=card4+1 to 52;

                       output; 

       end;end;end;end;end;

    run;

    I'm assuming you can translate a number from 1 to 52 into a specific card in the deck.  Assigning rankings to 2.6M hands might be a bit harder, but this should at least move you a step closer.

    Good luck.

    Super Contributor
    Posts: 259

    Re: Allocating Values to Poker Hands

    Hi Astounding

    I've started writing the code for the poker hand evaluator. Basically the algorithm looks up 5 cards (in order of number e.g. 02S 03D 07H 12H 13D) and it is run through the code to check if it's a straight flush, 4 of a kind, full house etc. and a unique hand value is assigned to the hand. So for a royal flush, the value is 1 and four hands have this value, for a straight flush king high, the value is 2, and so on. I'm just wondering if my approach is too tedious and I'm overcomplicating things? I'm using lots of else do; end; and macros within macros and alhough I will get it out eventually, if there's a better approach I'll use it. Otherwise i'm happy to work away on the code below.

    The dataset Sample is just a five column data set with the fields card1,card2,...,card5 with values in the form as above.

    Thanks

    I would post the code directly but I can't paste into these forums.

    Poker Hand Eval..png

    Super User
    Posts: 10,500

    Re: Allocating Values to Poker Hands

    It looks like you're going to be doing a whole lot of splitting out of the codes they way you requested the cards to look.

    It might be better to have two variables for each card, value and suit and possibly as numeric value 1-13 and 1-4 with appropriate formats to display as A, K, Q and J or C,D,H and S as needed.

    I have a sneaking suspicion this project my be more amenable in IML, but that's a guess.

    Super Contributor
    Posts: 259

    Re: Allocating Values to Poker Hands

    Hi Ballardw

    I think for what I'm doing IML sounds like the way to go. I've downloaded the free SAS University edition as my company doesn't uses SAS 9.2 which does not have SAS/IML.

    I also think from the feedback on the forums that a pairwise algorithm is the best apparoach to follow for evaluating which cards are best amongs 6 players.

    I was wondering if you know of any good resources that would help me write the code for this algorithm.

    Thanks

    Matthew

    Super User
    Posts: 5,082

    Re: Allocating Values to Poker Hands

    If it were me ...

    I would perform as much of the processing up front, apart from examining any particular deal.  For example, suppose you created a data set with 2.6M rows and 2 columns (hand identifier and rank).  The hand identifier would be a 10-character field representing the 5 cards, such as:  0105234252

    That would be a combination of cards "01", "05", "23", "42", and "52", with a separate column indicating the rank.  Most of the work would be creating such a file, but you wouldn't have to re-create the logic every time you wanted to use the results.  Using it could take various forms.  You could load it into a format (permanently saved) or load it as a hash table into a DATA step.  Then the look-up would be quick, requiring only that you turn the 5 cards of a hand into a matching 10-character string.

    Super Contributor
    Posts: 259

    Re: Allocating Values to Poker Hands

    Thanks Astounding

    What's your opionion on using IML for this job? Rick has mentioned using a pairwise algorithm for comparing hands but I'm not sure how that would work without having a complex algorithm since poker hands don't follow a natural ordering or score - comparing a flush with a straight? I know there is some order but I don''t know how you would see if one hand is better than the other without go through loads of checks. If you are familiar with IML would you propose a logic for achieving this?

    Regarding your approach I have two questions:

    1. Is my code above on the right track assuming a change to the number system you have outlined. I will still need to do a load of checks to determine rank i.e. check for flush, straight, 4 of a kind etc.

    2. Will having a table with 2.6m entries be too slow. Let say I want to run 300 games and each game has 6 players and 50 plays - how long do you think this would take?

    Thank you

    Matthew

    SAS Super FREQ
    Posts: 3,477

    Re: Allocating Values to Poker Hands

    I don't think you want to generate all combinations. Just write a pairwise comparison algorithm: given two five-card hands, write a function returns whether the first hand beats the second.  This binary comparison will enable you to determine the winner of any simulated deal. 

    Super Contributor
    Posts: 259

    Re: Allocating Values to Poker Hands

    Hi Rick

    Thanks for your advice. Would you know if any good resources on generating a pairwise algorithm in sas. Also, does it work if there are 6 players and you are trying to determine the best hand, second best and so on?

    I work with a team of actuaries who currently don't use (and who are unaware of IML) but I think this would be highliy benefiocial as speed is always an issue for us. We would be working with huge data sets. We have all have SAS version 9 licenses - is it excpensive to get IML as an addition?

    Thanks

    Matthew

    SAS Super FREQ
    Posts: 3,477

    Re: Allocating Values to Poker Hands

    Regarding resources: no, I am not familiar with an existing program that evaluates poker hands.

    Regarding "does it work if there are 6 players": yes. Pairwise comparison is the basis for sorting algorithms. If you want to put six words in alphabetical order, you carry out pairwise  comparisons in order to rank the words relative to one another.

    Super Contributor
    Posts: 259

    Re: Allocating Values to Poker Hands

    Thanks Rick,

    Well if you knew of resources thgat covered pairwise comparisons in sas that would be a good start - do you cover these in your books?

    Thanks

    Super User
    Posts: 10,500

    Re: Allocating Values to Poker Hands

    And this model will not model actual playing as very few hands of holdem have all of the players seeing all of the cards. Many drop out before seeing any of the common cards.


    Solution
    ‎06-20-2014 12:05 PM
    Respected Advisor
    Posts: 3,124

    Re: Allocating Values to Poker Hands

    Well, I came from non-western culture where Poker has different rules. Since it took me some effort to know Poker rules using Wiki, I will probably use it as the material for a paper for next year SESUG.Smiley Happy All of the business requirements are obtained from Wikipedia: List of poker hands - Wikipedia, the free encyclopedia

    /*I use 14 to address 'A' for the simplicity of coding. There are 2,598,960 distinct hands,

    out of which, there are 7,462 distinct scores, The whole process runs less than 10 secs on my

    4x core pc, win7, if you already have the hands, to rank 100 of them takes less than 1 sec*/

    /*TO GENERATE 52 CARDS POOL*/

    DATA CAT;

    INPUT SUIT :$1. @@;

    CARDS;

    S C H D

    ;

    DATA SEQ;

    INPUT NUM :$2. @@;

    CARDS;

    14 13 12 11 10 09 08 07 06 05 04 03 02

    ;

    PROC SQL NOPRINT;

    SELECT DISTINCT QUOTE(CATS(SUIT,NUM)) INTO :HANDS SEPARATED BY ' ' FROM CAT, SEQ;

    QUIT;

    /*EMBED RANKING ALGORITHM INTO THE FOLLOWING MACRO*/

    %MACRO SIM;

    DO Z=1 TO 5;

               FST(Z)=FIRST(C(Z));

               NUM(Z)=INPUT(COMPRESS(C(Z),,'KD'),2.);

    END;

    CALL SORTC (OF FST(*));

    CALL SORTN (OF NUM(*));

    /*STRAIGHT FLUSH*/

    IF FST(1)=FST(5) AND NUM(5)-NUM(4)=1 AND NUM(4)-NUM(3)=1 AND NUM(3)-NUM(2)=1 AND NUM(2)-NUM(1)=1 THEN

               DO;

                    RANK1=9;

                    RANK2=NUM(5);

                    RANK3=999;

                    RANK4=999;

                    RANK5=999;

                    RANK6=999;

               END;

                  ELSE IF FST(1)=FST(5) AND NUM(1)=2 AND NUM(2)=3 AND NUM(3)=4 AND NUM(4)=5 AND NUM(5)=14 THEN DO;

    RANK1=9;

                    RANK2=NUM(4);

                    RANK3=999;

                    RANK4=999;

                    RANK5=999;

                    RANK6=999;

                         END;

    /*FOUR OF A KIND*/

    ELSE IF NUM(1)=NUM(4) OR NUM(2)=NUM(5) THEN

               DO;

                    RANK1=8;

                    IF NUM(1)=NUM(4) THEN

                         DO;

                               RANK2=NUM(1);

                               RANK3=NUM(5);

                               RANK4=999;

                               RANK5=999;

                               RANK6=999;

                         END;

                    ELSE IF NUM(2)=NUM(5) THEN

                         DO;

                               RANK2=NUM(2);

                               RANK3=NUM(1);

                               RANK4=999;

                               RANK5=999;

                               RANK6=999;

                         END;

               END;

    /*FULL HOUSE*/

    ELSE IF (NUM(1)=NUM(2) AND NUM(3)=NUM(5)) OR (NUM(1)=NUM(3) AND NUM(4)=NUM(5)) THEN

               DO;

                    RANK1=7;

                    IF (NUM(1)=NUM(2) AND NUM(3)=NUM(5)) THEN

                         DO;

                               RANK2=NUM(3);

                              RANK3=NUM(1);

                               RANK4=999;

                               RANK5=999;

                               RANK6=999;

    END;

                    ELSE  IF (NUM(1)=NUM(3) AND NUM(4)=NUM(5)) THEN

                         DO;

                               RANK2=NUM(1);

                               RANK3=NUM(4);

                               RANK4=999;

                               RANK5=999;

                               RANK6=999;

                         END;

               END;

    /*FLUSH*/

    ELSE IF FST(1)=FST(5) THEN

               DO;

                    RANK1=6;

                    RANK2=NUM(5);

                    RANK3=NUM(4);

                    RANK4=NUM(3);

                    RANK5=NUM(2);

                    RANK6=NUM(1);

               END;

    /*STRAIGHT*/

    ELSE IF NUM(5)-NUM(4)=1 AND NUM(4)-NUM(3)=1 AND NUM(3)-NUM(2)=1 AND NUM(2)-NUM(1)=1 THEN

               DO;

                    RANK1=5;

                    RANK2=NUM(5);

                    RANK3=999;

                    RANK4=999;

                    RANK5=999;

                    RANK6=999;

               END;

    ELSE IF NUM(1)=2 AND NUM(2)=3 AND NUM(3)=4 AND NUM(4)=5 AND NUM(5)=14 THEN

               DO;

                    RANK1=5;

                    RANK2=NUM(4);

                    RANK3=999;

                    RANK4=999;

                    RANK5=999;

                    RANK6=999;

               END;

    /*THREE OF A KIND*/

    ELSE IF (NUM(1)=NUM(3) OR NUM(2)=NUM(4) OR NUM(3)=NUM(5)) THEN

               DO;

                    RANK1=4;

                    IF NUM(1)=NUM(3) THEN

                         DO;

                               RANK2=NUM(1);

                               RANK3=NUM(5);

                               RANK4=NUM(4);

                               RANK5=999;

                               RANK6=999;

                         END;

                    IF NUM(2)=NUM(4) THEN

                         DO;

                               RANK2=NUM(2);

                               RANK3=NUM(5);

                               RANK4=NUM(1);

                               RANK5=999;

                               RANK6=999;

                         END;

                    IF NUM(3)=NUM(5) THEN

                         DO;

                               RANK2=NUM(3);

                               RANK3=NUM(2);

                               RANK4=NUM(1);

                               RANK5=999;

                               RANK6=999;

                         END;

               END;

    /*TWO PAIR*/

    ELSE IF (NUM(1)=NUM(2) AND NUM(3)=NUM(4)) OR (NUM(1)=NUM(2) AND NUM(4)=NUM(5)) OR (NUM(2)=NUM(3) AND NUM(4)=NUM(5)) THEN

               DO;

                    RANK1=3;

                    IF (NUM(1)=NUM(2) AND NUM(3)=NUM(4)) THEN

                         DO;

                               RANK2=NUM(3);

                               RANK3=NUM(1);

                               RANK4=NUM(5);

                               RANK5=999;

                               RANK6=999;

                         END;

                    IF (NUM(1)=NUM(2) AND NUM(4)=NUM(5)) THEN

                         DO;

                               RANK2=NUM(5);

                               RANK3=NUM(1);

                               RANK4=NUM(3);

                               RANK5=999;

                               RANK6=999;

                         END;

                    IF (NUM(3)=NUM(2) AND NUM(5)=NUM(4)) THEN

                         DO;

                               RANK2=NUM(5);

                               RANK3=NUM(3);

                               RANK4=NUM(1);

                               RANK5=999;

                               RANK6=999;

                         END;

               END;

    /*ONE PAIR*/

    ELSE IF NUM(1)=NUM(2) OR NUM(2)=NUM(3) OR NUM(3)=NUM(4) OR NUM(4)=NUM(5) THEN

               DO;

                    RANK1=2;

                    IF NUM(1)=NUM(2) THEN

                         DO;

                               RANK2=NUM(1);

                               RANK3=NUM(5);

                               RANK4=NUM(4);

                               RANK5=NUM(3);

                               RANK6=999;

                         END;

                    IF NUM(2)=NUM(3) THEN

                         DO;

                               RANK2=NUM(3);

                               RANK3=NUM(5);

                               RANK4=NUM(4);

                               RANK5=NUM(1);

                               RANK6=999;

                         END;

                    IF NUM(3)=NUM(4) THEN

                         DO;

                               RANK2=NUM(4);

                               RANK3=NUM(5);

                               RANK4=NUM(2);

                               RANK5=NUM(1);

                               RANK6=999;

                         END;

                    IF NUM(4)=NUM(5) THEN

                         DO;

                               RANK2=NUM(5);

                               RANK3=NUM(3);

                               RANK4=NUM(2);

                               RANK5=NUM(1);

                               RANK6=999;

                         END;

               END;

    /*HIGH CARD*/

    ELSE

               DO;

                    RANK1=1;

                    RANK2=NUM(5);

                    RANK3=NUM(4);

                    RANK4=NUM(3);

                    RANK5=NUM(2);

                    RANK6=NUM(1);

               END;

    %MEND;

    /*SCORE ALL OF THE COMBINATIONS*/

    data HANDS;

    array c[5] $3;

    array x[52] $3 (&HANDS.);

    array i[5];

    ARRAY NUM(5) num1-num5;

    ARRAY FST(5) $ 1 fst1-fst5;

    n=dim(x);

    k=dim(i);

    i[1]=0;

    ncomb=comb(n,k);

    do j=1 to ncomb;

               call allcombi(n, k, of i

  • );
  •            do h=1 to k;

                    c=x[i];

               end;

               %SIM

               OUTPUT;

    end;

    KEEP C: RANK: num:;

    run;

    /*ORDER AND RANK DISTINCT SCORES*/

    PROC SORT DATA=HANDS OUT=HAND_SORT;

    BY DESCENDING RANK1 DESCENDING RANK2 DESCENDING RANK3 DESCENDING RANK4 DESCENDING RANK5 DESCENDING RANK6;

    RUN;

    DATA RANKS (KEEP=RANK: ORDER);

    SET HAND_SORT;

    BY DESCENDING RANK1 DESCENDING RANK2 DESCENDING RANK3 DESCENDING RANK4 DESCENDING RANK5 DESCENDING RANK6;

    IF FIRST.RANK6;

    ORDER+1;

    RUN;

    /*RANDOM SAMPLE: CAN ALSO BE DONE USING DATA STEP*/

    PROC SURVEYSELECT DATA=WORK.HANDS

    OUT=WORK.SAMPLE (KEEP=CSmiley Happy

    METHOD=SRS

    N=90000;

    RUN;

    /*RANK THE SAMPLE DATA, THERE ARE MANY WAYS FOR THIS KIND OF LOOK UP, HERE IS TO USE HASH() TABLE*/

    DATA WANT;

    IF _N_=1 THEN

               DO;

                    IF 0 THEN

                         SET RANKS;

                    DECLARE HASH H(DATASET:'RANKS');

                    H.DEFINEKEY('RANK1', 'RANK2','RANK3','RANK4', 'RANK5','RANK6');

                    H.DEFINEDATA(ALL:'Y');

                    H.DEFINEDONE();

               END;

    SET SAMPLE;

    array c[5] $3;

    ARRAY NUM(5) num1-num5;

    ARRAY FST(5) $ 1 fst1-fst5;

    %SIM

    RC=H.FIND();

    KEEP C: ORDER;

    run;


    Update:

    Got a PM saying that since I use '14' for ACE that I miscategorized 'Steel Wheel' and 'Wheel' (Meaning A-2-3-4-5 is still qualified for 'Straight') , hence the update.


    Update 2:

    FYI: Given OP has 300 games, 6 players and each for 50 plays, that counts for 90,000 hand. To rank them took less than 1 sec on my machine. It is really not a heavy-duty computing job by any means.

    Super Contributor
    Posts: 259

    Re: Allocating Values to Poker Hands

    Hi Hai.kuo

    Thanks for your help. In your update, have you changed your code so no a steal weel still qualifies for a straight?

    Re the speed, that's great. I really appreciate your help - i wouldn't have been able to come up with something like that myself.

    I have drafted up an email and I was going to PM you. Would that be ok? I've just outlined the background of what I'm trying to do.

    Thanks

    ☑ This topic is SOLVED.

    Need further help from the community? Please ask a new question.

    Discussion stats
    • 20 replies
    • 834 views
    • 2 likes
    • 6 in conversation