Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

php shuffle a pack of cards

I would like to use php to create a collection of random bridge hands. I thought that I could encode an ordered pack of cards as the string $deal below (I like it that there are 52 letters when considering both upper and lower case). I discovered the php function str_shuffle. So I thought that I could do the following:

$pack = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$shuffledPack = str_shuffle($pack);

This gives me the desired output.

My question is: does str_shuffle give output that follows a uniform distribution for each and every possible permutation?

like image 707
Geoff Avatar asked Oct 01 '22 10:10

Geoff


1 Answers

Internally, str_shuffle() uses rand() which doesn't produce good quality random numbers as you can see in this answer; if you want a better distribution, you may wish to implement Fisher-Yates yourself and pick a random source of your choice, e.g. mt_rand():

function my_str_shuffle($str)
{
    if ($str == '') {
        return $str;
    }

    $n_left = strlen($str);

    while (--$n_left) {
        $rnd_idx = mt_rand(0, $n_left);
        if ($rnd_idx != $n_left) {
            $tmp = $str[$n_left];
            $str[$n_left] = $str[$rnd_idx];
            $str[$rnd_idx] = $tmp;
        }
    }

    return $str;
}

See also my earlier answer on finding a suitable 0/1 randomiser.

Update

Using openssl_random_pseudo_bytes() as your random source:

assert($n_left <= 255);
$random = openssl_random_pseudo_bytes($n_left);

while (--$n_left) {
    $rnd_index = round($random[$n_left] / 255 * $n_left);
    // ...
}
like image 136
Ja͢ck Avatar answered Oct 11 '22 11:10

Ja͢ck