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×. as
select * from cards
order by rand("uniform");
quit;
%mend shuffle;
%macro deal(times=);
data deal×.;
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×.;
_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 * ×./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 * ×./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 * ×./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
... View more