Statistical programming, matrix languages, and more

Simulating card draws with specific requirements

Reply
New Contributor
Posts: 4

Simulating card draws with specific requirements

I would like to write a program for the following card draw problem:

 

Variables:

N = Number of games to simulate.

T = number of turns each game has.

Results = A matrix of N*(6+T);

  Col1-4 - The number of cards in the initial hand (Col6 could be empty in cases where we draw 3 cards) 

  COL5 - 3/4 Depending on the outcome

  COL6 - N

  Col7-and on - Cards drawn in turn T.

 

1. From a deck of 20 "cards" - pick, without replacement, either 3 or 4 cards (chosen randomly with a probability of 50%)

2. Of the 3 or 4 cards drawn, keep 0-3 (or 4) based on some algorithm. In the example below i choose to keep ONE copy of David and Jacob.

3. Return the cards you do not keep back to the deck.

4. Redraw cards, without replacement. The number of cards in the second draw is either 3 or 4 minus the cards I kept.

5. Record the final hand in a matrix that is N*6, which includes cards you kept (if any) and the cards i redrew. (The matrix should record the 3 or 4 cards that are in the final hand (step 6)

6. Update the deck to consist of the full original deck minus the cards that are kept in the final hand (step 5).

7. Start drawing cards, one at a time per turn. Do that for T turns (e.g. 4).

 

Notes:

Some cards can be duplicates. Notice that David, Andy, Jacob,Anne,Doug, **bleep** and Jennifer appear twice in the initial deck.

 

I started putting together some code. Admittedly, my IML skills are rusty. I am sure there must be a far more elegant implementation. 

 

I am having trouble with:

 

1. incorporating vector K (the cards i keep) into the code.

2. Smart-coding step 3 above - where i update the deck based on the cards kept.

3. cases where i keep more than 2 cards.

4. I am having trouble with updating the deck so that it will not have the cards that are held in the final hand. 

5. Putting Numeric values in Col5 and 6 of Results

 

Thanks for your help.

 

 

proc iml;

N = 10; /* the number of games to play */

deck_size = 20; /* the number of cards in the deck */

T=2; /** the number of turns **/

k={David Jacob}; /** the cards to keep**/

 

 

/* create a deck of 30 playing cards */

 

deck=shape({

David

David

Jacob

Jacob

Helen

Jennifer

Jennifer

Jeff

Andy

Andy

Anne

Anne

Sophia

Rick

Doug

Doug

John

**bleep**

**bleep**

Brian},20,1);

 

Results = j(N, 6, BlankStr(nleng(Deck)));

 

do game=1 to N;

/*** decide on the cards drawn **/

 

call randgen(u, "Uniform");

Max = 4;

   k = ceil( Max*u );  /* uniform integer in 1..Max */

Min = 3;

   n = floor( (1+Max)*u ); /* uniform integer in 0..Max */

   draw = min + floor( (1+Max-Min)*u ); /* uniform integer in Min..Max */

   print draw;

 

   /* choose 3/4 cards without replacement from deck */

/*call randseed(5,0,);*/

deal1 = sample(deck, draw, "WOR");  /* sample 4 cards without replacement */

print deal1;

 

/** mulligan rules **/

/*** keep elements of deal1 if they are either David or Jacob; but only 1 of each  **/

 

i = loc(deal1 ="DAVID" | deal1="JACOB"); /** i hard code here, because i am not sure how to implement the K vector i define above. I would like to get rid of the caps **/

 

if IsEmpty(i) then do;

 

print "i is empty"

nkeep = nrow(i);

print nkeep;

draw2=draw-nkeep;

deck1=deck; /** update the deck from which to draw on the second trial**/

end;

 

 

else               do;

 

print "i is not empty";

 

 

print i;

 

keepa = deal1[i];

print keepa;

/*** keep only ONE copy of Jacob or David; i would like to alos have an option to keep two copies of David**/

keep=unique(keepa);

print keep;

 

nkeep=countn(keep);

print deal1;

print keepa;

print keep;

print nkeep;

draw2=draw-nkeep;

print draw2;

/** Return the cards not kept back to the deck - or reduce the deck by the cards kept **/

 

if nkeep>0 then do;

/*locate the index in deck of the elements of keep;*/

if nkeep=1 then do;

  j = loc(deck=keep[1,1]);

 

  if ncol(j) > nkeep then do;

   j=remove(j,1);

  end;

end;

 

if nkeep=2 then do; /*** i am hard coding here because i am not sure how to implement the k vector**/

       j = loc(deck="DAVID"|deck="JACOB");

 

  if ncol(j) > nkeep then do;

   j=remove(j,{1 3}); /**8 this is hard-coded because i am not sure how to do this step correctly **/

  end;

 

print j;

 

end;

 

/** not coding yet the cases where nkeep>2 **/

if nkeep=3 then do;

end;

 

  if nkeep=4 then do;

end;

 

print j;

 

 

/*remove the cards from the deck - not sure if this is correct;*/

 

deck1=remove(deck , j);

end;

 

 

print deck1;

end;

 

 

 

 

/*** SECOND DEALING ***/

 

if nkeep>0 then do;

/*call randseed(3,0,reinit);*/

deal2 = sample(deck1,draw2 , "WOR"); 

 

rows2=nrow(deal2);

cols2=ncol(deal2);

hand2=keep||deal2;

print hand2;

 

end;

 

if nkeep=0 then do;

/*call randseed(3,0,reinit);*/

deal2 = sample(deck1,draw2 , "WOR"); 

 

print deal2;

hand2=deal2;

 

end;

 

 

/** put the initial hand in the matrix ***/

 

   Results[game, 1:ncol(hand2)] = hand2;

   if draw=3 then do;

    Results[game, 5] = 'Three'; /**8 dont know how to put numeric valuas and how to put N in each row **/

   end;

   if draw=4 then do;

       Results[game, 5] = 'Four';

   end;

 

 

/*** DEAL TURNS 1-T; *** not sure how to implement appropriately because unsure how to update deck ***/

 

   Do turn = 1 to T;

 

   end;

 

 

 

end; /*** game loop*/

print Results;

quit;

SAS Super FREQ
Posts: 3,478

Re: Simulating card draws with specific requirements

I don't really have time to answer all your questions, but here are a few thoughts. that might help:

0) You define the variable k to mean two different things. Delete the line k = ceil( Max*u );

1) Use the ELEMENT function to see whether a deal contains specified cards. The "loc-element technique" might be useful if you need to know the positions of the cards in the hand.

2) You need to enclose "**bleep**" in quotes when defining the deck.

3) To add cards to the deck, use the vertical concatenation operator (//).  To remove cards from the deck, use subscripts or the REMOVE function.

4) I would break this problem into smaller subroutines and define modules to handle each subtask. For example Dea(), DrawCards(), ReturnCards(), Play1Game(), ResetDeck(), Shuffle(), etc. Presumably the deck would be an argument to these functions.

 

HTH, Good luck!

New Contributor
Posts: 4

Re: Simulating card draws with specific requirements

Thanks Rick. I now have some hints with which to work. I will look into all of them. 

Ask a Question
Discussion stats
  • 2 replies
  • 288 views
  • 1 like
  • 2 in conversation