I have a SHA512 hex string consisting of my random input and that of the user.
Since rand.Seed only accepts a int64 I can never generate enough possibilities to shuffle an array with numbers 1-75: 75! = 2.480914e+109.
So my plan was to loop over the hex string 11 times, each time converting 10 hex characters to decimal and keep on shuffling the numbers.
func Shuffle(t []int, hex string) {
for j := 0; j < 11; j++ {
shuffleSeed, _ := strconv.ParseInt(hex[j*10:(j+1)*10], 16, 64)
rand.Seed(shuffleSeed)
for i := 1; i < len(t); i++ {
r := rand.Intn(i + 1)
if i != r {
t[r], t[i] = t[i], t[r]
}
}
}
}
items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75}
hex := "099b5721eaa9b5bcd87a07366aa175a1fb5b6fa6e5671b93ef443df927474198ec2ae959928f95c46f9fe9621575aa4e1e6f70780b059044da17737fcc99a322"
Shuffle(items, hex)
What do you think about this? I'm not a cryptography expert, not a math expert and certainly not a Go expert (I started yesterday).
Taken from another post I shuffled an array with [1,2,3] and here are the occurrences of each after 1 million times:
167136 166403 166877 166520 166925 166145
1 Answer 1
Initialization
A simple loop would be easier to maintain than hard-coding an array of 75 values.
items := make([]int, 75, 75)
for i := range items {
items[i] = i + 1
}
Seeding
The PRNG should be seeded just once.
You are correct that an Int64 seed is "only" capable of producing 264 ≈ 1019 distinct sequences, which is well under 75! ≈ 10109.
However, you should also consider the magnitude of the numbers involved. The age of the Universe is well under 1018 seconds. There is therefore no way you could remotely come close to producing a small fraction of the 75! possible permutations, just due to lack of time. A 64-bit seed is more than enough to generate as many unreproducible sequences as you could ever want.
So, calling rand.Seed(time.Now().UnixNano()) just once in func init() will be sufficient.
-
\$\begingroup\$ Thank you for taking time to answer! Due to the nature of my "game" I will need to reproduce the results and prove it to the user. So I think I'll keep going with the first 10 hex characters converted to
int64as the seed. Every time theShufflefunction is called the hex will be different. So I'll guess that's fine. \$\endgroup\$Martijn Buurman– Martijn Buurman2014年08月06日 20:36:11 +00:00Commented Aug 6, 2014 at 20:36
hexpart in my sample code will be different every time. Is that what you mean? \$\endgroup\$hexstring come from? You've asked about the randomness properties of the shuffle, but haven't told us much about the source of that randomness, except that it derives from the SHA512 hash of some other data, and it's hard-coded in your shuffling program. \$\endgroup\$