BookmarkSubscribeRSS Feed
VDD
Ammonite | Level 13 VDD
Ammonite | Level 13

I am Playing Black Jack / 21 with 1 player (me) and the dealer.

 

I have created a dataset that represents a deck of cards.  Works as expected.

 

The cards are then shuffled.  Works as expected.

 

I deal out the first hand of cards from the shuffled deck of cards.   Works as expected.

I have bounds and rules for dealing the cards if the dealer has < 17 total value and if the player has less than 16 total value.  Words as expected for the first hand.

 

I am having problems with dealing the second hand from the deck of cards.

First issue a card is read and never dealt out to either player.

the logic for calling the order dealing doesn't work after the first hand has finished.  That is the part where MOD is used.

 

Can you help me fix the issues so that I can deal the 2--8 hands correctly?

 

data cards(drop=c2);
length card $5 face $2;
	do suit = "C", "D", "H", "S";
		do c2= 1 to 13;
			*card=cats(c2,suit);
			if c2 in (1) then value = 1*11;
			else if c2 in (11, 12, 13) then value = 10;
			else; 
				do;
				if c2 in (2) then value = 2;
				else if c2 in (3) then value = 3;
				else if c2 in (4) then value = 4;
				else if c2 in (5) then value = 5;
				else if c2 in (6) then value = 6;
				else if c2 in (7) then value = 7;
				else if c2 in (8) then value = 8;
				else if c2 in (9) then value = 9;
				else if c2 in (10) then value = 10;
				Face = c2;
				end;
			
			if face = "11" then face = "J";
			else if face = "12" then face = "Q";
			else if face = "13" then face = "K";
			else if value = 11 then face = "A";
			card=cats(face,"-",suit);
			put c2;
			output;
		end;
	end;
run;
%macro shuffle(times=);
proc sql;
	create table shuffled&times. as 
	select * from cards 
	order by rand("uniform");
quit;
%mend shuffle;

%macro deal(times=);
data deal&times.;
length p1 p2 $24.;
retain p1 '' p2 '' total1 total2 0; 
set shuffled&times.;
/* need to deal the cards out in the correct order
	this only works for a newly shuffled datasets.
	*/
if _n_ < 5 then do;

	if mod(_n_,2) = 0 then do;
	p2 = card||p2;
	total2 +value;
	end;
	else do;
	p1 = card||p1;
	total1 +value;
	end;
end;
/* this works for the first hand of cards but fails 
	for additional hands being played from
	the shuffled dataset. */
else do;
	if total1 < 16 then do;
	p1 = card||p1;
	total1 +value;
	end;
	else if total2 < 17 then do;
		p2 = card||p2;
		total2 +value;
	end;
else do;
/* this works but I lose the card that should be
   held for the new hand to be played after
   the current hand is finished */
	output; p1='';p2='';total1=0;total2=0;
end;
end;

run;
%mend deal;

%shuffle(times=1);
%deal(times=1);
%shuffle(times=2);
%deal(times=2);
%shuffle(times=3);
%deal(times=3);


 

 

 

4 REPLIES 4
mkeintz
PROC Star

The core of the problem seems to be that the DEAL macro reads in a card BEFORE it determines whether either player needs it.  So that card is lost to the next hand.  I suggest a strategy in which you determine whether there is a need for the card PRIOR to reading it in. 

 

The program below establishes a value for variable _P (_P= 1, 2, or .).  If it's a 1 or 2 then then read a card, and update P1 and TOTAL1 (or P2 and TOTAL2).  If it's missing then don't read a card, but output the hands and clear P1, P2, TOTAL1, and TOTAL2.  You can make this work by using arrays of two elements each, as below.

 

I haven't tested this  (edited to include the variable _N to be used in place of _N_):

 

data deal&times. (drop=_:);
  array p {2} $24;
  array total{2} ;
  retain p1 '' p2 '' total1 total2 0 _N 1;

  if _n < 5 then do;
    if mod(_N,2)=0 then _p=2;
    else _p=1;
  end;
  else if total1<16 then _p=1;
  else if total2<17 then _p=2;

  if _p in (1,2) then do;
    set shuffled&times;
    _N+1;
    p{_p}=card||p{_p};
    total{_p}=total{_p}+value;
  end;
  else do;
    output; 
    p1='';p2='';total1=0;total2=0;_N=1;
  end;
run;

 

This solves the problem of the lost card between hands.

 

However, I don't see how the calculation of total accommodates choosing whether to value an ACE as either 1 or 11.  It seems to be 11 regardless of the other cards.

 

Also the logic in both your code and my code means that player 1 takes new cards until total1>=16 BEFORE player 2 has an opportunity for a 3rd card.  I.e. if

  • player 1 starts with a 2 and a 3,
  • player 2 starts with a 10 and a 5
  • then if player 1's 3rd card is an 8  (total1=13), player 1 will take a 4th card before player 2 takes a 3rd card.

Is this intended?

 

 

 

 

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
art297
Opal | Level 21

It's been years since I've played blackjack, so I had to read up on the rules.

 

I agree with @mkeintz  regarding why you were skipping cards, but think that the way you were dealing cards was correct.

 

The following runs correctly, but I haven't tested it for either efficiency, completeness, or correctness. I modified your code to allow how many decks of cards would be included in any run, as well as how many players there would be, and how many hands would be dealt.

 

I played around with how to handle aces, set rules for whether any player or the dealer would take a hit, incorporated decision making based on dealer's facecard, and shortened the game if a dealer got a blackjack. I didn't expand on the code to allow for splitting or doubling down, or when to reshuffle the card deck.

%macro deal(games=3,decks=6,players=3);
  /* create deck */
  data cards (drop=decks face suit);
    length card $5 face $2;
    do decks=1 to &decks.;
      do suit = "C", "D", "H", "S";
        do c2= 1 to 13;
          if c2 eq 1 then value = 11;
          else if c2 in (11, 12, 13) then value = 10;
          else value = c2;
          if c2 = 11 then face = "J";
          else if c2 = 12 then face = "Q";
          else if c2 = 13 then face = "K";
          else if c2 = 1 then face = "A";
          else face=put(c2,2.);
          card=cats(face,"-",suit);
          output;
        end;
      end;
    end;
  run;

  /* shuffle deck */
  proc sql noprint;
    create table shuffled as 
      select * from cards 
        order by rand("uniform")
    ;
  quit;

  data deal (drop=_: card c2 value stop_value total);
/*   last hand is dealers hand */
    array hands(&players.,11)   _temporary_ ;
    array values(&players.,11)  _temporary_ ;
    array cardsdealt(&players.,11) $ _temporary_;
    array hand(&players.) $24.;
    retain stop_value hand;
/*     deal one card to each player until all players have 2 cards */
    do _g=1 to &games.;
      call missing(of hands{*});
      call missing(of values{*});
      call missing(of cardsdealt{*});
      _c=0;
      _done=0;
      do _p=1 to (2*&players.);
        if _c lt (&players*2) then do;
          set shuffled;
          _c+1;
          if _c le &players. then do;
            hands{&players.-mod(_c,&players),1} = c2;
            values{&players.-mod(_c,&players),1} = value;
            cardsdealt{&players.-mod(_c,&players),1} = card;
          end;
          else do;
            hands{&players.-mod(_c,&players),2} = c2;
            values{&players.-mod(_c,&players),2} = value;
            cardsdealt{&players.-mod(_c,&players),2} = card;
          end;
        end; /* if _c lt (&players*2) then do */
      end; /* do _p=1 to (2*&players.) */

/* Check to see if dealer has blackjack and, if not, deal rest of cards*/
      if sum(of values{&players,1},
                    values{&players,2}) ne 21 then do;

/* if necessary deal rest of cards for all players */
        do _p=1 to &players.;
/*        check dealers face card to set stop_value */
          if _p eq &players. then do;
            if sum(values{&players.,1},values{&players.,2}) eq 17 and
             values{&players.,1} in (6,11) then stop_value=18;
            else stop_value=17;
          end;
          else do;
            select (values{&players.,1});
              when (in (4,5,6))      stop_value=12;
              when (in (2,3))        stop_value=13;
              otherwise              stop_value=17;
            end;
          end;
          
          _c=2;
          do until (total ge stop_value);
            total=sum(of values{_p,1},
                         values{_p,2},
                         values{_p,3},
                         values{_p,4},
                         values{_p,5},
                         values{_p,6},
                         values{_p,7},
                         values{_p,8},
                         values{_p,9},
                         values{_p,10},
                         values{_p,11});
            if total gt 21 then do;
              do _t=1 to 11;
                if values{_p,_t} eq 11 then values{_p,_t}=1;
              end;
              total=sum(of values{_p,1},
                           values{_p,2},
                           values{_p,3},
                           values{_p,4},
                           values{_p,5},
                           values{_p,6},
                           values{_p,7},
                           values{_p,8},
                           values{_p,9},
                           values{_p,10},
                           values{_p,11});
            end; /* if total gt 21 then do; */
            if total lt stop_value then do;
              set shuffled;
              _c+1;
              hands{_p,_c} = c2;
              values{_p,_c} = value;
              cardsdealt{_p,_c} = card;
              total=sum(of values{_p,1},
                           values{_p,2},
                           values{_p,3},
                           values{_p,4},
                           values{_p,5},
                           values{_p,6},
                           values{_p,7},
                           values{_p,8},
                           values{_p,9},
                           values{_p,10},
                           values{_p,11});
              if total gt 21 and value eq 11 then do;
                values{_p,_c} = 1;
                total=sum(of values{_p,1},
                             values{_p,2},
                             values{_p,3},
                             values{_p,4},
                             values{_p,5},
                             values{_p,6},
                             values{_p,7},
                             values{_p,8},
                             values{_p,9},
                             values{_p,10},
                             values{_p,11});
              end; /* if total gt 21 and value eq 11 then do */
              if stop_value eq 18 then stop_value=17;
            end; /* if total lt stop_value then do */
          end; /* do until (total ge stop_value) */
        end; /* do _p=1 to &players.; */
      end; /*       if not sum(of values{&players,1},
                    values{&players,2}) eq 21 then do */
      call missing(of hand{*});
      do _p=1 to &players.;
        do _d=1 to dim(hand);
          if not missing(cardsdealt{_p,_d}) then
            hand{_p}=catx(',',hand{_p},cardsdealt{_p,_d});
        end; /* _d=1 to dim(hand) */
      end; /* do _p=1 to &players. */
      output;
      if _g eq &games. then stop;
    end; /* do _g=1 to &games. */
  run;
%mend deal;
%deal;

Art, CEO, AnalystFinder.com

 

VDD
Ammonite | Level 13 VDD
Ammonite | Level 13

Thank you @mkeintz for the clarity needed.  While all of your assumptions are correct I currently was not dealing with those rules.  I am trying to get MOD to correctly be assigned to the ordered players after the first had has completed. 

Example would be if the first 5 cards were played from the deck of cards at the start of the second hand player 1 should receive the first card.  But the way I have used MOD it assigns player 2 the first card with is incorrect since player 2 is the dealer in a 2 person game

 

@art297 I have tested the code but it fails to clean house correctly and reuses cards from a single deck of cards.  

 

I have made updates to the SAS program which works as expected for only a single game per shuffled deck of cards.

I would like to make the process use the cards that remain in the deck for a 2nd, 3rd and 4th hand at least currently.

 

data cards(drop=c2);
length card $5 face $2;
	*do decks = 1 to 5;
	do suit = "C", "D", "H", "S";
		do c2= 1 to 13;
			*card=cats(c2,suit);
			if c2 in (1) then value = 1*11;
			else if c2 in (11, 12, 13) then value = 10;
			else; 
				do;
				if c2 in (2) then value = 2;
				else if c2 in (3) then value = 3;
				else if c2 in (4) then value = 4;
				else if c2 in (5) then value = 5;
				else if c2 in (6) then value = 6;
				else if c2 in (7) then value = 7;
				else if c2 in (8) then value = 8;
				else if c2 in (9) then value = 9;
				else if c2 in (10) then value = 10;
				Face = c2;
				end;
			
			if face = "11" then face = "J";
			else if face = "12" then face = "Q";
			else if face = "13" then face = "K";
			else if value = 11 then face = "A";
			card=cats(face,"-",suit);
			put c2;
			output;
		end; /* values */
	end; /* suits */
	*end; /* do decks */
run;
%macro shuffle(times=);
proc sql;
	create table shuffled&times. as 
	select * from cards 
	order by rand("uniform");
quit;
%mend shuffle;

%macro deal(times=);
data deal&times.;
array p {2} $24.;
array total {2} ;
retain p1 '' p2 '' total1 total2 0 p1a p1a2 p2a p2a2 ace_dealt 
	d_ace_dealt db pb 0 flag 1 _n 1 winner '        '; 
if flag ne 0 then do;
set shuffled&times.;
end;
/* need to deal the cards out in the correct order
	this only works for a newly shuffled datasets.
	*/
*if flag ne 1;
if _n < 5 then do;
/* dealer should always be the last player and last hand */
	if mod(_n,2) = 0 then do;
	p2 = card||p2;
	total2 +value;
	if value = 11 and p2a = 0 then p2a = 1;
	else if value = 11 and p2a = 1 then p2a2 = 1;
	end;
	else do;
	p1 = card||p1;
	total1 +value;
	if value = 11 and p1a = 0 then p1a = 1;
	else if value = 11 and p1a = 1 then p1a2 = 1;
	end;
	_n+1;
	if total2 = 21 then db = 1;
	if total1 = 21 then pb = 1;
end;
/* this works for the first hand of cards but fails 
	for additional hands being played from
	the shuffled dataset. */
else do; /* deal cards for the remander of the hand */
/* test if dealer wins with 21 on the deal */
	if total2 = 21 and db = 1 then do;
		black_jack = "Dealer";
		winner = "Dealer";
		flag = 0;
		bet=5;*2.5 * &times./2;
		cashout = bet;
		/* this works but I lose the card that should be
		   held for the new hand to be played after
		   the current hand is finished */
			output; p1='';p2='';total1=0;total2=0;_n=1;winner='';
			*total1=17;
	end;/* end if total2 = 21 then do; */

	/* Players hand */
	else if total1=21 and pb = 1 then /* (p1a=1 or p1a2=1) and total2 < 21 then*/
	do;
	black_jack = "Player";
	winner = "Player";
		flag = 0;
		bet=5;*2.5 * &times./2;
		cashin = bet*2;
		*cashin = bet*2;
		/* this works but I lose the card that should be
		   held for the new hand to be played after
		   the current hand is finished */
			output; p1='';p2='';total1=0;total2=0;_n=1;winner='';
			*total1=17;
	end;

	else if total1 <= 13 or (total1 <= 16 and (p1a = 1 or p1a2 = 1)) then do;
		if value = 11 then ace_dealt = ace_dealt +1;
		p1 = card||p1;
		total1 +value;
		/* test if the player had an ACE in their hand */
		/* if hand over 21 and had an ACE recalculate hand value */
		if total1 > 21 and p1a = 1 then do;
			total1 = total1-10;
			p1a = 0;
			end;
		else if total1 > 21 and p1a2 = 1 then do;
			total1 = total1-10;
			p1a2 = 0;
			end;
	/* test if the current card being drawn is an ACE and if the value is over 21 */
		else if total1 > 21 and (ace_dealt > 0 or value = 11) then do;
				total1 = total1-10;
				if value = 11 then ace_dealt = ace_dealt -1;
				end;
		end;
	/* Dearlers hand */
	else if (total2 < 17 and total1 < 22) or (total2 = 22 and (p2a = 1 or p2a2 = 1)) then do;
		if value = 11 then d_ace_dealt +1;
		p2 = card||p2;
		total2 +value;
		if total2 > 21 and p2a = 1 then do; 
			total2 = total2-10;
			p2a = 0;
			end;
		else if total2 > 21 and p2a2 = 1 then do;
			total2 = total2-10;
			p2a2 = 0;
			end;
		else if total2 > 21 and value = 11 then total2 = total2-10;
		
	end;
else do;
	if total2 = 21 then winner = "Dealer";
	else if (total1 < 22 and total1 > total2) or total2 > 21 then winner = "Player";
	else winner = "Dealer";
	flag = 0;
	bet=5;*2.5 * &times./2;
	if winner = "Player" then cashin = bet *1;
	else cashout = bet;
	/* this works but I lose the card that should be
	   held for the new hand to be played after
	   the current hand is finished */
		output; p1='';p2='';total1=0;total2=0;_n=1;winner='';
	end;
end;

/*
if _n_ < 46 then do;
flag = 1;
end;
*/
*end;/* end for flag = 0 */
run;
%mend deal;

/* call the game */
data _null_ ;
	i = 1;
	do until (i = 101);
		call execute (cats('%nrstr(%shuffle)(times=',i,')'));
		call execute (cats('%nrstr(%deal)(times=',i,')'));
	i=i+1;
	end;

run;

/* put the datasets together */
proc sql ;		
	/* get all the file names into a macro var */
	select 		
		trim(libname) || '.' || memname into :dataset_vars separated by ' '
	from dictionary.tables
	where upcase(libname)="WORK"
	and upcase(memname) like 'DEAL%' 
	;
	
quit;
data Hands;
	set &dataset_vars;* (drop=month);
run;
/* Clean house */
proc sql noprint ;
	select 'drop table work.'||memname 
			into :empties separated 
			by ';'
	from dictionary.tables
		where libname='WORK' and upcase(memname) like 'DEAL%'
	;
	&empties;
quit;
proc sql noprint ;
	select 'drop table work.'||memname 
			into :empties separated 
			by ';'
	from dictionary.tables
		where libname='WORK' and upcase(memname) like 'SHUFFLED%'
	;
	&empties;
quit;

/* Calculate wins and losses */
options missing = 0;
data hands_winner(keep=house_profit hands_played total_bet player_cash phands house_cash_pulled hhands pblackj dblackj Player_win_lost);
	retain hands_played total_bet player_cash phands house_cash_pulled hhands pblackj dblackj 0;
	set hands end=eof;
	total_bet + bet;
	hands_played +1;
	if winner = "Player" then do;
		player_cash = player_cash + cashin;
		phands +1;
		if black_jack = "Player" then pblackj +1;
	end;
	else if winner = "Dealer" then do;
		house_cash_pulled =house_cash_pulled + cashout;
		hhands +1;
		if black_jack = "Dealer" then dblackj +1;
	end;
	if eof=1 then do;
		Player_win_lost = player_cash - total_bet;
		house_profit=total_bet-player_cash;
		output;

	end;
run;
/* Just checking */
proc freq data=hands;
	tables black_jack / missing;
run;

 

 

 

 

 
art297
Opal | Level 21

I'm not sure what you want to do, but did modify your code a bit. Hope the changes will be of some help.

 

One problem you had was starting your counter (_n) at 1 and then increasing it each time you read a record. The way you had it will mess up your use of mod since mod will be expecting the first four records to have _n values of 1, 2, 3 and 4.

 

Second, you used the * to comment out some lines or parts of lines. That can have adverse effects in a macro. I suggest, in a macro, always using /*  ... */ type comments or macro comments.

 

Third, you don't account for ties .. which happen all of the time in blackjack.

 

Fourth, you give the dealer a double payout for blackjack. I don't think that is how the game works.

 

Anyhow, while I didn't correct any of the above (other than the comments and the use of _n), here is what I changed:

data cards(drop=c2);
length card $5 face $2;
	*do decks = 1 to 5;
	do suit = "C", "D", "H", "S";
		do c2= 1 to 13;
			*card=cats(c2,suit);
			if c2 in (1) then value = 1*11;
			else if c2 in (11, 12, 13) then value = 10;
			else; 
				do;
				if c2 in (2) then value = 2;
				else if c2 in (3) then value = 3;
				else if c2 in (4) then value = 4;
				else if c2 in (5) then value = 5;
				else if c2 in (6) then value = 6;
				else if c2 in (7) then value = 7;
				else if c2 in (8) then value = 8;
				else if c2 in (9) then value = 9;
				else if c2 in (10) then value = 10;
				Face = c2;
				end;
			
			if face = "11" then face = "J";
			else if face = "12" then face = "Q";
			else if face = "13" then face = "K";
			else if value = 11 then face = "A";
			card=cats(face,"-",suit);
			put c2;
			output;
		end; /* values */
	end; /* suits */
	*end; /* do decks */
run;
%macro shuffle(times=);
proc sql;
	create table shuffled&times. as 
	select * from cards 
	order by rand("uniform");
quit;
%mend shuffle;

%macro deal(times=);
  data deal&times.;
    array p {2} $24.;
    array total {2} ;
    retain p1 '' p2 '' total1 total2 0 p1a p1a2 p2a p2a2 ace_dealt 
    d_ace_dealt db pb 0 flag 1 _n 0 winner '        '; 
/*     if flag ne 0 then do; */
    set shuffled&times.;
    _n+1;
/*     end; */
/* need to deal the cards out in the correct order
	this only works for a newly shuffled datasets.
	*/
/* *if flag ne 1; */
    if _n < 5 then do;
/* dealer should always be the last player and last hand */
      if mod(_n,2) = 0 then do;
        p2 = card||p2;
        total2 +value;
        if value = 11 and p2a = 0 then p2a = 1;
        else if value = 11 and p2a = 1 then p2a2 = 1;
      end;
      else do;
        p1 = card||p1;
        total1 +value;
        if value = 11 and p1a = 0 then p1a = 1;
        else if value = 11 and p1a = 1 then p1a2 = 1;
      end;
/* 	 _n+1; */
      if total2 = 21 then db = 1;
      if total1 = 21 then pb = 1;
/* end; */
/* this works for the first hand of cards but fails 
	for additional hands being played from
	the shuffled dataset. */
/* else do; */ /* deal cards for the remander of the hand */
/* test if dealer wins with 21 on the deal */
      if db or pb then do;
        if db /* total2 = 21 */ /* and db = 1 */ then do;
          black_jack = "Dealer";
          winner = "Dealer";
          /* flag = 0; */
          bet=5;/* *2.5 * &times./2; */
          cashout = bet;
          /* this works but I lose the card that should be
             held for the new hand to be played after
             the current hand is finished */
/*           output; p1='';p2='';total1=0;total2=0;_n=1;winner=''; */
			*total1=17;
        end;/* end if db1 then do; */

	/* Players hand */
        if pb /*total1=21 and pb = 1*/ then /* (p1a=1 or p1a2=1) and total2 < 21 then*/ do;
          black_jack = "Player";
          winner = "Player";
/*        flag = 0; */
          bet=5;*2.5 * &times./2;
          cashin = bet*2;
          /* *cashin = bet*2; */
		  /* this works but I lose the card that should be
		     held for the new hand to be played after
		     the current hand is finished */
/*           output; p1='';p2='';total1=0;total2=0;_n=1;winner=''; */
          /* *total1=17; */
        end;
        if db and pb then winner="Tie";
        if _n eq 4 then do;
          output; p1='';p2='';db=0;pb=0;total1=0;total2=0;_n=1;winner='';
        end;
      end; /* if db or pb */
    end; /* if _n < 5 then do; */
   
    else do;
      if total1 <= 13 or (total1 <= 16 and (p1a = 1 or p1a2 = 1)) then do;
        if value = 11 then ace_dealt = ace_dealt +1;
        p1 = card||p1;
        total1 +value;
        /* test if the player had an ACE in their hand */
        /* if hand over 21 and had an ACE recalculate hand value */
        if total1 > 21 and p1a = 1 then do;
          total1 = total1-10;
          p1a = 0;
        end;
        else if total1 > 21 and p1a2 = 1 then do;
          total1 = total1-10;
          p1a2 = 0;
        end;
	    /* test if the current card being drawn is an ACE and if the value is over 21 */
        else if total1 > 21 and (ace_dealt > 0 or value = 11) then do;
          total1 = total1-10;
          if value = 11 then ace_dealt = ace_dealt -1;
	    end;
      end; /* else if total1 <= 13 or (total1 <= 16 and (p1a = 1 or p1a2 = 1)) then do; */

      /* Dearlers hand */
      else if (total2 < 17 and total1 < 22) or (total2 = 22 and (p2a = 1 or p2a2 = 1)) then do;
        if value = 11 then d_ace_dealt +1;
        p2 = card||p2;
        total2 +value;
        if total2 > 21 and p2a = 1 then do; 
          total2 = total2-10;
          p2a = 0;
        end;
        else if total2 > 21 and p2a2 = 1 then do;
          total2 = total2-10;
          p2a2 = 0;
        end;
        else if total2 > 21 and value = 11 then total2 = total2-10;
      end; /* else if (total2 < 17 and total1 < 22) or (total2 = 22 and (p2a = 1 or p2a2 = 1)) then do; */
      else do;
        if total2 = 21 then winner = "Dealer";
        else if (total1 < 22 and total1 > total2) or total2 > 21 then winner = "Player";
        else winner = "Dealer";
        flag = 0;
        bet=5; /* *2.5 * &times./2; */
        if winner = "Player" then cashin = bet *1;
        else cashout = bet;
        /* this works but I lose the card that should be
           held for the new hand to be played after
           the current hand is finished */
        output; p1='';p2='';total1=0;total2=0;_n=0;winner='';
      end; /*else do; */
    end; /*else do; */

/*
if _n_ < 46 then do;
flag = 1;
end;
*/
/* *end;*/ /* end for flag = 0 */
  run;
%mend deal;

/* call the game */
data _null_ ;
	i = 1;
	do until (i = 101);
		call execute (cats('%nrstr(%shuffle)(times=',i,')'));
		call execute (cats('%nrstr(%deal)(times=',i,')'));
	i=i+1;
	end;

run;

/* put the datasets together */
proc sql ;		
	/* get all the file names into a macro var */
	select 		
		trim(libname) || '.' || memname into :dataset_vars separated by ' '
	from dictionary.tables
	where upcase(libname)="WORK"
	and upcase(memname) like 'DEAL%' 
	;
	
quit;
data Hands;
	set &dataset_vars;* (drop=month);
run;
/* Clean house */
proc sql noprint ;
	select 'drop table work.'||memname 
			into :empties separated 
			by ';'
	from dictionary.tables
		where libname='WORK' and upcase(memname) like 'DEAL%'
	;
	&empties;
quit;

proc sql noprint ;
	select 'drop table work.'||memname 
			into :empties separated 
			by ';'
	from dictionary.tables
		where libname='WORK' and upcase(memname) like 'SHUFFLED%'
	;
	&empties;
quit;

/* Calculate wins and losses */
options missing = 0;
data hands_winner(keep=house_profit hands_played total_bet player_cash phands house_cash_pulled hhands pblackj dblackj Player_win_lost);
	retain hands_played total_bet player_cash phands house_cash_pulled hhands pblackj dblackj 0;
	set hands end=eof;
	total_bet + bet;
	hands_played +1;
	if winner = "Player" then do;
		player_cash = player_cash + cashin;
		phands +1;
		if black_jack = "Player" then pblackj +1;
	end;
	else if winner = "Dealer" then do;
		house_cash_pulled =house_cash_pulled + cashout;
		hhands +1;
		if black_jack = "Dealer" then dblackj +1;
	end;
	if eof=1 then do;
		Player_win_lost = player_cash - total_bet;
		house_profit=total_bet-player_cash;
		output;

	end;
run;
/* Just checking */
proc freq data=hands;
	tables black_jack / missing;
run;

Art, CEO, AnalystFinder.com

 

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
Mastering the WHERE Clause in PROC SQL

SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 4 replies
  • 709 views
  • 0 likes
  • 3 in conversation