8

I am trying to create a "random" string based on a fixed string. I'd like to be able, if at all possible, create the same random string (i know its an oxymoron) provided I use the same seed. like so:

    $base = '0123456789abcdef';
    $seed = 'qwe123';

    function get_seeded_random_string($base, $seed){
        ???
    }

The expected behavior would be that as long as I give the same $base and $seed I always get the same random string.

cwd
  • 53,018
  • 53
  • 161
  • 198
Angel S. Moreno
  • 3,469
  • 3
  • 29
  • 40
  • 2
    Make sure you use a [Fisher–Yates shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) so your not-really-random string is really random (or as random as the generator :)). – Matthew Flaschen Jul 03 '10 at 00:31
  • @Matthew Flaschen - how would you do a Fischer-Yates shuffle in PHP? – cwd Jul 01 '11 at 13:31
  • @cwd, I think both [shuffle](http://php.net/manual/en/function.shuffle.php) (for arrays) and [str_shuffle](http://php.net/manual/en/function.str-shuffle.php) (for strings) are. `str_shuffle` is explicitly [based](http://lxr.php.net/opengrok/xref/PHP_TRUNK/ext/standard/string.c#5086) on shuffle. The [shuffle code](http://lxr.php.net/opengrok/xref/PHP_TRUNK/ext/standard/array.c#1764) has some internal details. But if you look at the [main part](http://lxr.php.net/opengrok/xref/PHP_TRUNK/ext/standard/array.c#1778) it looks like Fisher-Yates to me. – Matthew Flaschen Jul 01 '11 at 18:28
  • @CWD: [Fischer-Yates Shuffle in PHP](http://stackoverflow.com/questions/6557805/randomize-a-php-array-with-a-seed/6557863#6557863) – hakre Jul 02 '11 at 16:27
  • @hakre - yes, thanks. That's my question :) – cwd Jul 04 '11 at 02:36

2 Answers2

12

Sorry, but accordingly to the documentation the shuffle function is seeded automatically.

Normally, you shouldn't try to come up with your own algorithms to randomize things since they are very likely to be biased. The Fisher-Yates algorithm is known to be both efficient and unbiased though:

function fisherYatesShuffle(&$items, $seed)
{
    @mt_srand($seed);
    $items = array_values($items);
    for ($i = count($items) - 1; $i > 0; $i--)
    {
        $j = @mt_rand(0, $i);
        $tmp = $items[$i];
        $items[$i] = $items[$j];
        $items[$j] = $tmp;
    }
}

Same function for a string in php7

function fisherYatesShuffle(string &$items, int $seed)
{
    @mt_srand($seed);
    for ($i = strlen($items) - 1; $i > 0; $i--)
    {
        $j = @mt_rand(0, $i);
        $tmp = $items[$i];
        $items[$i] = $items[$j];
        $items[$j] = $tmp;
    }
}
superhero
  • 6,281
  • 11
  • 59
  • 91
André Laszlo
  • 15,169
  • 3
  • 63
  • 81
  • You need to `return $items;`. –  Apr 06 '13 at 19:02
  • Nope, since it's [passed by reference](http://php.net/manual/en/language.references.pass.php). I wanted it to behave like the native [shuffle](http://www.php.net/manual/en/function.shuffle.php) function. Thanks for reviewing the code though! – André Laszlo Apr 08 '13 at 14:39
  • 1
    The code did not work for me, but I guess I applied it wrong. I deleted the seeding line (line 3), and the `, $seed` from the backets in the first line, because I already had a seed from a previous mt_rand() in the same script, then did `fisherYatesShuffle($items)`, but nothing was returned. When I added `return $items;`, it worked. So how do I use that code? –  Apr 08 '13 at 15:09
  • 1
    @what, Here's a very small usage example that works for me: http://pastebin.com/V1PBCHB8 – André Laszlo Apr 08 '13 at 19:13
  • 1
    You should add `$items = array_values($items);` as the first line in this function. Without it the function won't work correctly if the indexes are not 0, 1, 2... The native PHP shuffle() function doesn't preserve indexes, so it's fine if fisherYatesShuffle() ignores them too. – Rafał G. Jul 02 '14 at 08:54
  • The function works just fine. Use it just like shuffle(). Refer to the php docs on shuffle() to use this function. The function is intended to be used with a numeric array (not an associative array) which is passed by reference. – MeatFlavourDev Mar 16 '17 at 09:20
2

Yes, with mt_srand you can specify the seed for the "better" random number generator mt_rand.

Artefacto
  • 96,375
  • 17
  • 202
  • 225