Shuffling array based on seed to get always the same result?

你离开我真会死。 提交于 2019-12-06 02:07:13

If you need it on any pc, you need a random number generator that works the same across computers. I looked up one pseudo-random-number generator that might be suitable for you from the Random Number Generation Wikipedia page and put it into a class so you can seed it.

I don't know for what you need it, but this just might suit your needs. It's independent to system configuration:

function shuffleIt($array, $seed)
{
    $mwc = new mwc($seed);
    $order = array();
    $count = count($array);
    while($count--)
        $order[] = $mwc->random()
    ;

    array_multisort($order, $array);
    return $array;
}

/**
 * Multiply-with-carry RNG
 * 
 * method invented by George Marsaglia
 */
class mwc
{
    private static $def_m_w = 1712; /* must not be zero */
    private static $def_m_z = 23;   /* must not be zero */
    private $m_w, $m_z;
    public function __construct($seed = NULL)
    {
        $this->m_w = self::$def_m_w;
        $this->m_z = self::$def_m_z;
        if (NULL !== $seed)
            $this->seed($seed);
    }
    public function seed($seed)
    {
        $seed = (int) $seed;
        if (!$seed) throw new InvalidArgumentException('Must not be zero.');
        $this->m_z = $seed;
        $this->random();
    }
    public function random()
    {
        $this->m_z = 36969 * ($this->m_z & 65535) + ($this->m_z >> 16);
        $this->m_w = 18000 * ($this->m_w & 65535) + ($this->m_w >> 16);
        return ($this->m_z << 16) + $this->m_w;  /* 32-bit result */
    }
}

Note: This might behave differently between 32/64 bit systems, especially as PHP differs here for integers and overflows between windows and unix. You might want offset at the signed minimum for 32 bit integers in PHP instead of 0 as it is now, to switch the implementation to gmp or just reduce the size by one bit.


Usage Example 32 bit reported to work by ekke from netherlands

$shuffle = new GeorgeShuffle();
$seed    = $shuffle->seed();
$a       = array('A', 'B', 'C', 'D', 'E', 'F', 'G');
$shuffle->reOrder($a);
var_dump($a);
$shuffle->seed($seed);
$shuffle->reOrder($a);
var_dump($a);

/**
 * Array shuffle class using
 * the multiply-with-carry method
 * invented by George Marsaglia
 */
class GeorgeShuffle
{

    private static $def_m_w = 1959; /* must not be zero */
    private static $def_m_z = 2006; /* must not be zero */
    private $m_w, $m_z;
    const maxint = 2147483647;

    public function __construct($seed = null)
    {
        $this->m_w = self::$def_m_w;
        $this->m_z = self::$def_m_z;
        if ($seed) $this->seed($seed);
    }

    public function reOrder(&$array, $seed = null)
    {
        if (!empty($seed)) $this->seed($seed);
        $a = array();
        for ($i = 0, $j = count($array); $i < $j; $i++) {
            $a[$i] = $this->random();
        }
        array_multisort($a, $array);
        //- to return a copy, remove the &
        return $array;
    }

    public function seed($seed = false)
    {
        if (is_string($seed)) $seed = hexdec($seed);
        if (empty($seed)) $seed = round(mt_rand(1, self::maxint));
        $this->m_z = $seed;
        $this->random();
        //- return the seed used in hex (8 chars) for reproducing
        return str_pad(dechex($seed), 8, '0', STR_PAD_LEFT);
    }

    public function random()
    {
        $this->m_z = 36969 * (($this->m_z And 65535) + ($this->m_z >> 16));
        $this->m_w = 18000 * (($this->m_w And 65535) + ($this->m_w >> 16));
        return ($this->m_z << 16) + $this->m_w; /* 32-bit signed result */
    }
}

Does you host run by chance the Suhosin security extension? Apparently, it has a couple of directives that prevent scripts from setting a seed:

suhosin.srand.ignore = On
suhosin.mt_srand.ignore = On

Further reading:

Here's a quick way to test whether this is the problem:

<?php

mt_srand(33);
var_dump(mt_rand(1, 10000));

mt_srand(33);
var_dump(mt_rand(1, 10000));

mt_srand(33);
var_dump(mt_rand(1, 10000));
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!