How can a blackjack player be assured that the deck is honest? If someone has replaced a random card in the deck with, say, an Ace, How many hands would you have to play and how many aces would he have to see and count to be confident that the deck was altered?
I started with Rick Wicklin’s blog post on creating, shuffling and randomly dealing a standard deck of 52 cards. Then I created a black jack deck of 6x52 cards. I calculated the binomial probability of drawing at least one ace from any number of deals. I used Proc Freq to count the number of Aces that result from these deals. I did the same with an altered deck where I replaced the 2 of Clubs with an Ace of Clubs.
But I don’t know how to get to the core question: How many deals of the altered deck would it take for a player to be, say, 90% confident that there were too many aces in it?
I’ve attached the code that I developed so far to address this question. I hope someone can bring some insight into how it can be modified to address the question.
Thanks in advance for any guidance you can provide,
Gene
/* Create one deck of cards */
data Cards;
length Value $2 Suit $8 Card $3;
array Values[13] $ _temporary_ ('A','2','3','4','5','6','7','8','9','T','J','Q','K');
array Suits[4] $ _temporary_ ('Clubs', 'Diamonds', 'Hearts', 'Spades');
do v = 1 to 13;
do s = 1 to 4;
Value = Values[v]; Suit = Suits[s]; Card = cats(Value,substr(Suit,1,1));
output;
end;
end;
run;
/*For BlackJack we need 6 Decks */
data work.Deck1 work.Deck2 work.Deck3 work.Deck4 work.Deck5 work.Deck6;
set Cards;
run;
data work.HonestBlackJackDeck;
set work.Deck1 work.Deck2 work.Deck3 work.Deck4 work.Deck5 work.Deck6;
run;
/*Create an altered BlackJackDeck by replacing one 2 of Clubs with an Ace of Clubs */
Proc sort data=HonestBlackJackDeck;
by v s;
run;
data work.AlteredBlackJackDeck;
set HonestBlackJackDeck;
By v;
if first.v and v=2 then do;
Value='A';
Suit="Clubs";
Card='AC';
v=1;
s=1;
end;
run;
/*Set number of cards per player */
%Let nCards=2;
/*Set number of players */
%Let nPlayers=1;
/*Set number of deals */
%Let nDeals=100;
/* HONEST BLACK JACK DECK */
/* Standard deviation of expected frequency of drawing at least one ace
in an honest Black Jack Deck */
data _null_;
Title "Binomial Distribution Calculations: Honest Black Jack Deck";
File Print;
Ctot=(312*311)/(2*1);
Put "Number of possible hands: " Ctot;
/*Hands with no aces */
CnoA=(312-24)*(312-24-1)/(2*1);
Put "Number of hands with no aces: " CnoA;
/*Probability of no aces */
PnoA=CnoA/Ctot;
Put "Probability of no aces: " PnoA;
/*Probability of at least one ace */
PA=1-PnoA;
Put "Probability of at least 1 ace: " PA;
/* Expected number of hands with at least 1 ace */
Ndeals=&ndeals;
Put "Number of Deals: " Ndeals;
Expect=&nDeals*PA;
Put "Expected number of hands with at least 1 ace: " Expect;
/* Standard Deviation of a Binomial Distribution */
sigma=sqrt(&nDeals*PA*PnoA);
Put "Standard deviation of hands with of at least 1 ace: " sigma;
/* 90% Confidence Interval */
CI90=1.645*(sigma/sqrt(ndeals));
Put "90% Confidence Interval: " CI90;
Prob_LE_PA=cdf('binom',Expect,PA,&nDeals);
Put "Probability of less than expected hands with ace: " Prob_LE_PA;
Prob_GE_PA=1-Prob_LE_PA;
Put "Probability of greater than expected hands with ace: " Prob_GE_PA;
run;
/* Wicklin code for creating Black Jack Deals */
proc surveyselect data=HonestBlackJackDeck seed=123 NOPRINT
method=SRS /* sample without replacement */
outrandom /* randomize the order of the cards */
N=%eval(&nCards * &nPlayers) /* num cards per deal */
reps=&nDeals /* total number of deals */
out=AllCards_HonestDeck;
run;
/* assign the cards to players */
data AllDeals_HonestDeck;
set AllCards_HonestDeck;
by Replicate;
if first.Replicate then do;
Cnt = 0;
end;
Player = 1 + floor(Cnt/&nCards);
Cnt + 1;
drop Cnt;
run;
/* OPTIONAL: Convert from long form to wide form */
proc transpose data=AllDeals_HonestDeck
out=HonestDeals(rename=(col1-col&nCards=C1-C&nCards) drop=_NAME_);
var Card;
by Replicate Player;
run;
/* Check for an honest deck */
Proc freq data=HonestBlackJackDeck;
Title "Honest Black Jack Deck";
tables value;
run;
/* Find number of deals that contain aces */
Proc freq data=AllDeals_HonestDeck;
Title1 "Honest Black Jack Deck:";
Title2 "Number of deals that contain at least one ace";
where value contains 'A';
tables value /outexpect;
/* ALTERED BLACK JACK DECK */
/*(1 extra Ace of Clubs replacing a 2 of Clubs) */
/* Standard deviation of expected frequency of drawing at least one ace
in an altered Black Jack Deck */
data _null_;
Title1 "Binomial Distribution Calculations: Altered Black Jack Deck";
Title2 "After Substituting an Ace of Clubs for a Deuce of Clubs";
File Print;
Ctot=(312*311)/(2*1);
Put "Number of possible hands: " Ctot;
/*Hands with no aces after substituting and ace for a deuce for a total of 25 aces */
CnoA=(312-25)*(312-25-1)/(2*1);
Put "Number of hands with no aces: " CnoA;
/*Probability of no aces */
PnoA=CnoA/Ctot;
Put "Probability of no aces: " PnoA;
/*Probability of at least one ace */
PA=1-PnoA;
Put "Probability of at least 1 ace: " PA;
/* Expected number of hands with at least 1 ace */
Ndeals=&ndeals;
Put "Number of Deals: " Ndeals;
Expect=&nDeals*PA;
Put "Expected number of hands with at least 1 ace: " Expect;
/* Standard Deviation of a Binomial Distribution */
sigma=sqrt(&nDeals*PA*PnoA);
Put "Standard deviation of hands with of at least 1 ace: " sigma;
/* 90% Confidence Interval */
CI90=1.645*(sigma/sqrt(ndeals));
Put "90% Confidence Interval: " CI90;
run;
proc surveyselect data=AlteredBlackJackDeck seed=123 NOPRINT
method=SRS /* sample without replacement */
outrandom /* randomize the order of the cards */
N=%eval(&nCards * &nPlayers) /* num cards per deal */
reps=&nDeals /* total number of deals */
out=AllCards_AlteredDeck;
run;
/* assign the cards to players */
data AllDeals_AlteredDeck;
set AllCards_AlteredDeck;
by Replicate;
if first.Replicate then do;
Cnt = 0;
end;
Player = 1 + floor(Cnt/&nCards);
Cnt + 1;
drop Cnt;
run;
/* OPTIONAL: Convert from long form to wide form */
proc transpose data=AllDeals_AlteredDeck
out=AlteredDeals(rename=(col1-col&nCards=C1-C&nCards) drop=_NAME_);
var Card;
by Replicate Player;
run;
/* Check for an honest deck */
Proc freq data=AlteredBlackJackDeck;
Title "Altered Black Jack Deck (1 extra Ace of Clubs replacing a 2 of Clubs)";
tables value;
run;
/* Find number of deals that contain aces */
Proc freq data=AllDeals_AlteredDeck;
Title "Altered Black Jack Deck";
Title2 "Number of deals that contain at least one ace";
where value contains 'A';
tables value /outexpect;
In practice, the subterfuge would be recognized the first time that a hand appears that shows two Ace of clubs. This will happen frequently, at which point you are 100% sure that the deck is altered.
In terms of the simulation, your situation is equivalent to using a deck of 52 numbers that look like this:
{1,1,2,3,4,6,7,8,...,52}, where '1'=AC and '5'=2C.
If you want to stick with your original problem, which estimates frequencies, I suggest you start with a smaller deck for which the simulation will run faster and for which the probabilities are larger. For example, start with a deck of 8 cards (Aces and Twos) that look like
{1,1,2,3,4,6,7,8}.
Figure out the answer to your problem with this smaller deck. When you can solve the problem with a deck that has 8 cards, test your knowledge by moving to a deck that has 12 cards. Then try 16. Then you will be ready for 52.
It sounds like your problem is related to using simulation to estimate "power and sample size." See these articles:
Well, dang...I intended to select Rick Wicklin's solution as "Accepted" but clicked the wrong one. The link to Rick's blog post on sample size for a binomial test of proportions was most helpful. As he found in the example he used there to determine how many students would be needed for a meaningful test, the number of blackjack hands that would have to be dealt is much larger than one might intuitively think.
I'll also take this opportunity to thank Rick Wicklin for his DO Loop blog. I've lost count of the number of times I've Googled a question about a SAS statistical approach or a SAS Procedure and been directed to one of his always helpful posts. This is but one more example of the value of the DO Loop.
April 27 – 30 | Gaylord Texan | Grapevine, Texas
Walk in ready to learn. Walk out ready to deliver. This is the data and AI conference you can't afford to miss.
Register now and lock in 2025 pricing—just $495!
ANOVA, or Analysis Of Variance, is used to compare the averages or means of two or more populations to better understand how they differ. Watch this tutorial for more.
Find more tutorials on the SAS Users YouTube channel.