<?PHP

/*
   THIS IS A SIMPLE PROGRAM TO DEAL A SEQUENCE OF CARDS
   FOR NO OR ANY PARTICULAR PURPOSE FROM A STANDARD
   52-CARD DECK WITHOUT REPLACEMENT.

   AUTHOR   : Jay Tanner
   LANGUAGE : PHP 5.2.4 - Revised with PHP 8.2.12
   REVISED  : 2025-Sep-12-Fri

   THIS PROGRAM EXPECTS THE CARD IMAGE FILES TO BE IN
   THE SAME FOLDER AS THIS PROGRAM.
*/


// *********************************************
// *********************************************

   
$ProgramVersion "4.1";

// ------------------------------------------
// Read current year value from system clock.
   
$year date("Y");

// ----------------
// Get script name.

   
$_ACTION_FILE_NAME_ $_SERVER['SCRIPT_NAME'];

// ------------------------------------
// Define internal HTML web page title.

   
$_INTERNAL_HTML_PAGE_TITLE_ "Random N-Cards Dealer";




// -----------------------------
// Read number of cards to draw.

   
$N IntVal(trim(@$_POST['N']))+0;

   if (
$N <  0)  {$N =  1;}
   if (
$N == 0)  {$N =  5;}
   if (
$N 52)  {$N 52;}

   
$s = ($N 1)? "s" "";

   
$WOR = ($N <> and $N <> 52)? " Without Replacement " "";
   
$ALL = ($N == 52)? 'All ':'';

   
$decimals 2;

   
$CombNum bcComb_N_R ('52'$N);
   
$CombNumName 'About ' BC_Big_Int_Name ($CombNum$decimals) . ' to 1';
   
$CombinationOdds Number_Format($CombNum);
   if (
$CombNum 1000000) {$CombNumName '';}

   
$PermNum bcPerm_N_R ('52'$N);
   
$PermNumName 'About ' BC_Big_Int_Name ($PermNum$decimals) . ' to 1';
   
$PermutationOdds Number_Format($PermNum);
   if (
$PermNum 1000000) {$PermNumName '';}

// ------------------------------------
// Define page heading text to display.

   
$_PAGE_HEADER_ "<B style='font-size:125%;'>Random Cards Dealer</B><br><span style='font-size:12pt;'>From Standard 52-Card American Deck</span>";

   
$RandomColor '';

/* ------------------------------------------
   Deal a random sequence of cards from a
   standard 52-card deck without replacement.
   The cards are returned as an HTML encoded
   card image file names string.
*/
   
$CardsDrawn "\n" Draw_N_Cards($N);


/*
   #################################################
   This function draws a sequence of N random cards
   from a standard 52-card deck without replacement.
   #################################################
*/
   
function Draw_N_Cards($ArgN)
{

// Read the N argument.
   
$N trim($ArgN)+0;

// If N <= 0 then return empty string.
   
if ($N <= 0) {return '';}

// Initialize array for card deck.
   
$cards = Array();

// Initialize HTML image code string.
   
$DrawnCards '';

// Create an array and fill it with the 52-cards.
   
for ($i=0;   $i 52;   $i++)  {$cards[$i] = $i+1;}

// Shuffle the deck three times.
   
shuffle($cards);
   
shuffle($cards);
   
shuffle($cards);

// Draw the requested number of cards
// from the top of the shuffled deck.
   
for ($i=0;   $i $N;   $i++)
  {

// Get current card ID (1 to 52)
// from card deck array.
   
$CardID $cards[$i];

// Compute suit code number (1 to 4)
   
$CardSuitCode floor(($CardID-1) / 13) + 1;

// Encode card rank number (1 to 13)
   
$CardRank = ($CardID 13) + 1;

// Compute hex code equivalent to decimal card
// rank and force to upper case letters.
   
$CardRankHex StrToUpper(DecHex($CardRank));

// Construct numerical card code.  This will
// always be two hexadecimal digits that
// uniquely identify each card by suit
// and rank.
   
$CardCode "$CardSuitCode$CardRankHex";



// Create image ALT text (full card name) from card ID code.

   
$CardName CardCode_to_CardName($CardCode);

// print "*** CardCode = $CardCode = $CardName ***";




// Construct card image file name.
   
$CardImageFileName "$CardCode.png";

// Construct HTML encoded image file tag for the current
// card and attach to string of accumulated cards.
   
$DrawnCards .= "<IMG SRC=\"$CardImageFileName\" ALT=\" $CardName \" BORDER=\"1\">\n";

  }

// Done
   
return $DrawnCards;

// End of  Draw_N_Cards()










/*

This function generates the card deck in sequential order
by suit and rank, or the direct opposite of shuffling into
a random order.

NOT DONE YET

*/

  
function Standard_Card_Deck()
{
  
$w =  Draw_N_Cards(52);

  return 
$w;
}














/*
   ##############################################
   This function returns the full-text name of
   a card.  For example 212 as an input argument
   would return the string "Queen of Clubs" as
   the card name.
   ##############################################
*/

   
function CardCode_to_CardName ($CardCodeArg)

{

   
$CardSuitCode preg_split("[ ]""Diamonds Clubs Hearts Spades");

   
$SuitCode substr($CardCodeArg01)+0;
   
$SuitName $CardSuitCode[$SuitCode-1];
   
$RankCode HexDec(substr($CardCodeArg1strlen($CardCodeArg)));
   
$RankName $RankCode;

   if (
$RankCode ==  1)  {$RankName "Ace";}
   if (
$RankCode == 11)  {$RankName "Jack";}
   if (
$RankCode == 12)  {$RankName "Queen";}
   if (
$RankCode == 13)  {$RankName "King";}

   return 
"$RankName of $SuitName";

}


// PHP BLOCK ENDS HERE
// *********************************************
// *********************************************
// THE HTML BLOCK BEGINS HERE.



print <<< _HTML

<!DOCTYPE HTML>

<HTML>

<HEAD>

<TITLE>Random Playing Cards Dealer</TITLE>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<meta http-equiv='content-type' content='text/html; charset=UTF-8'>
<meta name='description' content='This PHP program simply deals a given number of playing cards without replacement from a standard American deck of 52 cards.'>
<meta name='keywords' content='card dealer,random cards,random card dealer,PHPScienceLabs.com'>
<meta name='author' content='Jay Tanner - NeoProgrammics.com / PHPScienceLabs.com'>
<meta http-equiv='pragma'  content='no-cache'>
<meta http-equiv='expires' content='-1'>
<meta name='robots'    content='index,follow'>
<meta name='googlebot' content='index,follow'>

<style type='text/css'>

BODY {color:white; background-color:black;  font-family:Verdana; font-size:14px}

TABLE {font-family:Verdana; font-size:14px;}

TD {color:black; background-color:white;  line-height:150%; font-size:14px; padding:6px; text-align:center;}

LI {text-align:justify;}

DIV, P {color:black; background-color:white; font-family:Verdana; text-align:left; padding:6px; font-size:14px;}

PRE {color:black; background-color:white; font-family:monospace; font-size:16px; font-weight:bold; text-align:left; border:1px solid black; border-radius:8px; box-shadow:4px 4px 3px #999999; padding:4px;}

CODE {font-family:monospace; font-size:16px; font-weight:bold;}

TEXTAREA {color:black; background-color:white; font-family:monospace; font-size:18px; font-weight:bold; box-shadow:4px 4px 3px #999999; border-radius: 8px; border:1px solid black; padding:4px; white-space:pre;}

IMG {border:1px solid black; box-shadow:3px 4px 5px #444444; border-radius:4px;}

INPUT[type='text']::-ms-clear {width:0; height:0;}
INPUT[type='text']{color:black; background-color:white; border-radius:4px; font-family:monospace; font-size:18px; font-weight:bold; text-align:center; box-shadow:2px 2px 3px #999999; border:2px solid black;}
INPUT[type='text']:focus {color:black; background-color:white; border-radius:4px; font-family:monospace; font-size:18px; font-weight:bold; text-align:center; box-shadow:2px 2px 3px #666666; border:2px solid blue;}

INPUT[type='submit']{font-size:100%; font-weight:bold; border:1px solid black; border-radius:4px;}
INPUT[type='submit']:hover {font-size:100%; box-shadow:2px 3px 4px #222222; background:cyan; font-weight:bold; border:1px solid black; border-radius:4px;}

INPUT[type='checkbox']:checked {box-shadow:2px 2px 3px #222222;}

INPUT[type='radio']:checked {box-shadow:2px 2px 3px #222222;}

HR {background-color:black; height:2px; border:0px;}

A:link    {background-color:transparent; color:blue; font-family:Verdana; font-size:14px; font-weight:bold; text-decoration:none; line-height:150%; padding:2px;}
A:visited {background-color:transparent; color:DarkCyan;}
A:hover   {background-color:transparent; color:red;}
A:active  {background-color:transparent; color:red;}

::selection      {background:yellow; color:black;}  /* IE9+ and Safari     */
::-moz-selection {background:yellow; color:black;}  /* FireFox and Mozilla */

</style>

</HEAD>

<BODY style='background:black;'>

<TABLE width='1150' BGCOLOR="black" ALIGN="top" BORDER="0" CELLSPACING="1">

<tr><td style='color:white; background:#000066; border:2px solid white; border-radius:8px 8px 0px 0px;'>
<H3 ALIGN="center"><B style='font-size:20pt; font-weight:normal;'>Random Playing Cards Dealer</B><br><span style='font-size:10pt;'>Using a Standard 52-Card American Deck</span><br><span style='font-size:8pt;'>PHP Program by Jay Tanner</span></H3>
<a href='View-Source-Code.php' target='_blank'
   style='font-family:Verdana; color:black; background:yellow;
         text-decoration:none; border:1px solid black; padding:4px;
         border-radius:4px;'>
         &nbsp;<span style='font-weight:normal;'>View/Copy PHP Source Code</span>&nbsp;</a>
</td></tr>

<TR>
<TD style="background:GreenYellow;">
$CardsDrawn</TD>
</TR>

<tr><td style='color:black; background:LightYellow;'>
<b style='font-size:11pt; line-height:300%;'>For 
$ALL$N Card$s Randomly Drawn$WOR From a Standard 52-Card Deck:</b>
<br>
The odds of drawing ALL of the cards contained in the combination shown above,<br>REGARDLESS OF THE SEQUENCE in which which they were drawn, are:<br><code>
$CombinationOdds &colon; 1</code><br>
$CombNumName
<hr>
The odds of the making any draw are the same as the odds of predicting the draw.
<hr>
The odds of drawing ALL of the cards shown above, in the<br>SAME EXACT SEQUENCE as shown, are :<br><code>
$PermutationOdds &colon; 1</code><br>
$PermNumName
<br>
</td></tr>

<tr><td style="background-color:LightCyan; border-radius:0px 0px 8px 8px;">
<FORM ACTION="
$_ACTION_FILE_NAME_" METHOD="post">

<!--
<TABLE WIDTH="1150" BGCOLOR="black" CELLPADDING="2" BORDER="0" CELLSPACING="1">
-->

<B>Number of Cards to Draw</B> (<B>1</B> to <B>52</B>)<B>&nbsp;&#63;&nbsp;&nbsp;</B>
<INPUT NAME="N" TYPE="text" SIZE="3" MAXLENGTH="2" VALUE="
$N">
&nbsp;&nbsp;&nbsp;
<INPUT TYPE="submit" NAME="Deal_Cards_Button" VALUE="Deal the Card
$s">
<BR>
<BR>
</FORM>
Each card sequence drawn is fresh and totally independent of any previous drawings.<br>
</td></tr>

</TABLE>


<!--
<A HREF="display_all_cards.php">&nbsp;Display Whole Deck</A> &nbsp;
-->



<br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br>

</BODY>

</HTML>

_HTML;

// THE HTML BLOCK ENDS HERE.
// *********************************************
// *********************************************
// PHP BLOCK BEGINS HERE.





/*
   These functions are used to compute the basic probabilities of each
   drawing.
*/

/*
  ==========================================================================
  This function returns the EXACT number all possible random combinations
  of (R) items selected from a total set of (N) unique items available.

  NOTE:  In combinations, only which items are in the selected group matters.
  The sequential order in which the items are selected or arranged does not
  matter.

  Regardless of order, no two groups contain exactly the same set of items.

  RULE: (N, R) are non-negative integers where 0 <= R <= N

  This function uses arbitrary-precision Binary Calculator (BC) arithmetic
  which can return exact values up to several thousands of digits long.
  ==========================================================================
*/

  
function bcComb_N_R ($N$R)
{
  
$C 1;  $j $N $R;

  for (
$i=0;   $i $j;   $i++)
      {
$C bcDiv(bcMul($C$N-$i), $i+1);}  return $C;
}



/*
  ===========================================================================
  This function returns the EXACT count of unique permutations of (N) items
  that are possible when selected in random groups of (R) at a time.

  NOTE:  In permutations, the sequential line order of items in each group
         IS important.  No two selected sequences are in the same order.

  Permutations refers to the physical count of the number of unique sequences
  into which we can arrange the items within a row, line or column.

  RULE: (N, R) are non-negative integers where 0 <= R <= N

  This function uses arbitrary-precision BC (Binary Calculator) arithmetic
  which can return exact values up to several thousands of digits long.
  ===========================================================================
*/

  
function bcPerm_N_R ($N$R)
{
  
$P=1; for ($i=0;  $i $R;  $i++) {$P bcMul($P$N-$i);}  return $P;
}




/*
  ----------------------------------------------------------------------------
  This function returns the formal names of very large
  integers up to a limit of 99 digits length.

  The American system of numerical nomenclature is used.

  Arguments:
  $BigIntStr = Large integer as a string (1 million and above).
  $LabelStr  = Optional lable string suffix to attach to output.
  ----------------------------------------------------------------------------
*/

   
function BC_Big_Int_Name ($BigIntStr$Decimals=2)
{
   
$BigInt Str_Replace(',' ,''Str_Replace(' ' ,''trim($BigIntStr)));
   
$DigitsCount StrLen($BigInt);

   
$decimals trim($Decimals);

// ------------------------------------------------
// Break up big integer into spaced 3-digit groups
// and count the number of groups.

   
$DigitGroupsStr '';

   
$BigInt StrRev($BigInt);


// ***************
// ***************

   
$groups[1]  = '';
   
$groups[2]  = 'thousand';
   
$groups[3]  = 'million';
   
$groups[4]  = 'billion';
   
$groups[5]  = 'trillion';
   
$groups[6]  = 'quadrillion';
   
$groups[7]  = 'quintillion';
   
$groups[8]  = 'sextillion';
   
$groups[9]  = 'septillion';
   
$groups[10] = 'octillion';
   
$groups[11] = 'nonillion';
   
$groups[12] = 'decillion';
   
$groups[13] = 'undecillion';
   
$groups[14] = 'duodecillion';
   
$groups[15] = 'tredecillion';
   
$groups[16] = 'quattuordecillion';
   
$groups[17] = 'quindecillion';
   
$groups[18] = 'sexdecillion';
   
$groups[19] = 'septendecillion';
   
$groups[20] = 'octodecillion';
   
$groups[21] = 'novemdecillion';
   
$groups[22] = 'vigintillion';
   
$groups[23] = 'unvigintillion';
   
$groups[24] = 'duovigintillion';
   
$groups[25] = 'trevigintillion';
   
$groups[26] = 'quattuorvigintillion';
   
$groups[27] = 'quinvigintillion';
   
$groups[28] = 'sexvigintillion';
   
$groups[29] = 'septenvigintillion';
   
$groups[30] = 'octovigintillion';
   
$groups[31] = 'novemvigintillion';
   
$groups[32] = 'trigintillion';
   
$groups[33] = 'untrigintillion';
   
$groups[34] = 'duotrigintillion';

// ***************
// ***************

   
for($i=0;   $i $DigitsCount;   $i++)
  {
   
$DigitGroupsStr .= substr($BigInt,$i,1);

   if ((
$i+1) % == 0) {$DigitGroupsStr .= ' ';}
  }
   
$DigitGroupsStr trim(StrRev($DigitGroupsStr));

   
$DigitGroupsCount Substr_Count($DigitGroupsStr' ');

// Get top name.
   
$TopNameStr $groups[$DigitGroupsCount];

// Make number into decimal value (x).
   
$w StrRev($DigitGroupsStr);
   
$n StrRev(StrRChr($w' '));
   
$L StrLen($n);
   
$w StrRev($w);
   
$w trim($n).'.'.substr(Str_Replace(' ','',$w), $L-1StrLen($w));
   
$w SPrintF("%1.$decimals"f"$w);

   unset(
$groups);

   return 
"$w $TopNameStr";

}






?>