Temple of The Roguelike Forums

Development => Programming => Topic started by: Gr3yling on April 12, 2014, 03:46:32 AM

Title: Generating a list of unique random numbers
Post by: Gr3yling on April 12, 2014, 03:46:32 AM
So, I've been trying to understand random dungeon generation, and have really gotten sidetracked on a tangent related to generating lists of random numbers.  It's driving me crazy, and I can't go forward with working on making an actual roguelike until I can resolve the questions I have.  Sorry if this question isn't as directly related to programming a roguelike as some of the others on this board, but I know you guys/girls and I think you are my best chance for getting an answer that I can understand.

I want to generate a list of unique random numbers in the following way:

1. generate a random number
2. check to see if it is already in the list
3. if not, append it
4. if so, chunk it and go back to step 2

I *don't* want to do something like this code that I wrote:

from random import randint

random_list = []

random_source_list = [i for i in range(10)]

print random_list

print random_source_list

while len(random_list) <= 9:
    random_index = randint(0, len(random_source_list) - 1)
    random_list.append(random_source_list[random_index])
    random_source_list.remove(random_source_list[random_index])

print random_list

print random_source_list

It works, but I want to be able to accomplish my goal in the way that I stated previously.  Nor do I want to append a random number to the list, check for repeats, and then delete repeating numbers until I get a list of all uniques.  I already came up with a way to do it like that, but it just seems sloppy to me to use trial and error.  And I don't want to use classes either.

I realize these criteria must seem arbitrary, but this is something that I'm trying to figure out as a personal challenge, and it's about to drive me nuts.
Title: Re: Generating a list of unique random numbers
Post by: sokol815 on April 12, 2014, 04:01:37 AM
ah, the experiences of lists of random numbers. Javascript makes something like this super easy:

Code: [Select]
var numArr = Array(20);
for(var i = 0; i < numArr.length;i++){
   numArr[i] = i;
}
numArr.sort(function(){return Math.random()-.5;});
console.log(numArr);
some outputs from the above code:
Code: [Select]
[15, 18, 10, 1, 7, 6, 9, 8, 4, 19, 11, 5, 12, 13, 14, 2, 3, 16, 17, 0]
[10, 17, 5, 15, 4, 9, 13, 1, 19, 11, 0, 12, 6, 2, 18, 14, 7, 3, 16, 8]
[19, 2, 3, 4, 5, 6, 8, 7, 13, 11, 0, 9, 1, 14, 15, 16, 17, 12, 10, 18]

the magic here is in the built-in javascript sort function. you can pass it random values and it will randomly sort all the elements.

another option that may be simpler for you (if you don't have an easy way to make sort be random) is to first initialize a new ordered array then create another array and pull from the first randomly and append to the second.
Code: [Select]
var arr = [0,1,2,3,4,5,6,7,8,9];
var endArr = [];
while(arr.length > 0){
     var loc = (Math.random() * arr.length) >> 0; //bitwise operator >> 0 does a shift 0 and gives an int. Math.random() returns a value between 0 and 1.
     endArr.push(arr[loc]); //add the picked element to the destination array.
     arr.splice(loc,1); //remove the just added element from the source array; arr.length is now 1 less.
}

the 2nd way is probably one of the easiest ways to do what you are proposing. Have fun!
Title: Re: Generating a list of unique random numbers
Post by: Trystan on April 12, 2014, 04:08:04 AM
If you don't want to remove duplicates or check if something is a duplicate then you can use a set instead of a list (sets usually ignore any duplicates you try to add) or, if you have a small enough set of acceptable values, actually remove things from the random_source_list when you add to your random_list.

Code: [Select]
while len(random_list)< 10:
  random_list.add(random_source_list.pop(randint(0, len(random_source_list))))

I haven't done python in a long while so the syntax may be off.
Title: Re: Generating a list of unique random numbers
Post by: Gr3yling on April 12, 2014, 04:35:41 AM
the 2nd way is probably one of the easiest ways to do what you are proposing. Have fun!

Thanks for the suggestion, but I *don't* want to pull from one list to add to another.  I already found a way to do that (although it was probably much clumsier than the one you suggested).   And I forgot about using pop like Trystan suggested, that would have simplified the code that I posted.

It just seems "un-pythonic" that there is no way to go through precisely these steps: generate a random number, compare it to all the entries in a list, and then either append it or generate a new one.

Oh well, I guess it can't be done though.  It makes me feel better to know that there wasn't some obvious solution that I missed.  I appreciate the input from both of you.
Title: Re: Generating a list of unique random numbers
Post by: requerent on April 12, 2014, 04:54:23 AM
Code: [Select]
random.sample(range(x), y)
https://docs.python.org/3.5/library/random.html#random.sample

Pythonic enough?





Edit: Pythonic algorithms leverage the standard lib as much as possible. You shouldn't implement algorithms in python, just instructions.

If you want an algorithm, consider something more dynamic than generate->check->append, which has a potentially sun-burning-out run-time (esp in python). If bit-wise/mask solutions frighten you, try generating the numbers in increasing order. Just add a random delta to the previous value. If you need them shuffled also, you can run a shuffling algo in tandem with the number generation without ever needing to the traverse the currently generated list more than once.
Title: Re: Generating a list of unique random numbers
Post by: Trystan on April 12, 2014, 07:16:48 AM
It just seems "un-pythonic" that there is no way to go through precisely these steps: generate a random number, compare it to all the entries in a list, and then either append it or generate a new one.

Oh well, I guess it can't be done though.  It makes me feel better to know that there wasn't some obvious solution that I missed.  I appreciate the input from both of you.

Code: [Select]
while len(random_list) < 10:
  value = get_some_random_value()
  if value not in random_list:
    random_list.add(value)

Your 3 step algorithm is, I believe, just a few lines of python. If I remember correctly, "X not in XS" is valid python but you may have to use a contains method or whatever python lists have.
Title: Re: Generating a list of unique random numbers
Post by: chooseusername on April 12, 2014, 09:36:50 AM
It just seems "un-pythonic" that there is no way to go through precisely these steps: generate a random number, compare it to all the entries in a list, and then either append it or generate a new one.

Oh well, I guess it can't be done though.  It makes me feel better to know that there wasn't some obvious solution that I missed.  I appreciate the input from both of you.

Code: [Select]
while len(random_list) < 10:
  value = get_some_random_value()
  if value not in random_list:
    random_list.add(value)

Your 3 step algorithm is, I believe, just a few lines of python. If I remember correctly, "X not in XS" is valid python but you may have to use a contains method or whatever python lists have.
Or if you use sets:
Code: [Select]
MY_SET = set()
while len(MY_SET) < 10:
   MY_SET.add(get_some_random_value())
Title: Re: Generating a list of unique random numbers
Post by: requerent on April 12, 2014, 11:55:17 AM
OMG PEOPLE STOP!

https://docs.python.org/3.5/library/random.html#random.sample

THERE IS A FUNCTION IN THE PYTHON STD FOR THIS EXACTLY.
Title: Re: Generating a list of unique random numbers
Post by: mushroom patch on April 12, 2014, 01:55:32 PM
Obviously, you should just use the standard library functions that perform sampling (random.sample) without replacement from a collection or random permutation of a list (random.shuffle, although the implementation of this method sounds like it would not be suitable for purposes that require even moderately high performance).

If it bugs you that you don't know a good way to do it by hand, it sounds like for what you want to do, you could just make a list of the values you want to draw from, say there are n of them, select a random number k between 1 and n and take the kth element of the list, removing that element when you do so and putting into your result list. Decrement n and repeat until you've populated your list. In other words, what you're asking for is sampling without replacement. Since it takes time check if something is already in your list, this method will be asymptotically better than what you suggest in the OP.
Title: Re: Generating a list of unique random numbers
Post by: Jaxian on April 12, 2014, 04:30:53 PM
Even though there is a built-in function, we might still want to understand how this can be implemented.  Learning this algorithm will help us apply apply a similar technique to solve other problems.

I unfortunately don't know Python, but I will attempt to write Python code here using a reference, so forgive the almost-certainly-incorrect syntax.  To write your algorithm as you described it in the original post, it might look like this:

Code: [Select]
value_list = list()

for x in range(0, 100):
    val = random()
   
    while val in value_list:
        val = random()

    value_list.append(val)

However, the line "val in value_list" requires the code to compare "val" to every single value in the list.  As the list grows in size, this could take a longer time.  For this reason, it is better to use a Set instead of a List.  A Set uses hashing so that the same operation can be completed much more quickly:

Code: [Select]
used_values = set()

for x in range(0, 100):
    val = random()

    while val in used_values:
        val = random()

    used_values.add(val)

    // Do something with val, maybe append to a result list or call a function to build part of your map

In the code from your original post, you started with a known list of possible values (random_source_list).  If you have such a list, you could write an algorithm that randomly picks a value from that list, then swaps the value at the end into the spot you picked.  Then the next time you pick a number, you consider the list one position shorter.  This would be fast, but will modify the source list, meaning you might have to copy it if you need it somewhere else.  That might look like this:

Code: [Select]
len = len(source_list)

for x in range(0, 100):
    val_index = _int(random() * len)
    val = source_list[val_index];
    source_list[val_index] = source_list[len - 1]
    len--

    // Do something with val, maybe append to a result list or call a function to build part of your map

As requerent wrote, it makes the most sense to use the built-in version random.sample method to solve this problem, but hopefully these examples were useful in some way.
Title: Re: Generating a list of unique random numbers
Post by: Gr3yling on April 12, 2014, 05:11:38 PM
Even though there is a built-in function, we might still want to understand how this can be implemented.  Learning this algorithm will help us apply apply a similar technique to solve other problems.

Thanks Jaxian.  Yep, that's exactly where I was going with this.  Although I do appreciate your input, requerent.

I think for the most part I understand what you guys are saying, and I'll try some of your suggestions. 

EDIT: Oh, and maybe in about a decade I'll have a working prototype to share with you all.
Title: Re: Generating a list of unique random numbers
Post by: requerent on April 12, 2014, 05:37:25 PM
Even though there is a built-in function, we might still want to understand how this can be implemented.  Learning this algorithm will help us apply apply a similar technique to solve other problems.

Thanks Jaxian.  Yep, that's exactly where I was going with this.  Although I do appreciate your input, requerent.

I think for the most part I understand what you guys are saying, and I'll try some of your suggestions. 

EDIT: Oh, and maybe in about a decade I'll have a working prototype to share with you all.

sorry. All I was trying to say is that if the algorithm isn't O(N), it's no good.
Title: Re: Generating a list of unique random numbers
Post by: Xecutor on April 13, 2014, 04:17:55 AM
The question is in what range you want your random numbers?
Answer for 'n random numbers in range 0..n-1' would be classic algorithm by Knuth:
Code: [Select]
  arr=Array(n)
  for i in 0..n-1
   k=random_in_range(0..i)
   arr[i]=arr[k]
   arr[k]=i
  end

if you want n random numbers in arbitrary range, then variant with set above is probably the best option.
if you want content of an array in random order, generate array of random indeces with algo above and
use them to access array of items.
Title: Re: Generating a list of unique random numbers
Post by: chooseusername on April 13, 2014, 05:51:46 AM
However, the line "val in value_list" requires the code to compare "val" to every single value in the list.  As the list grows in size, this could take a longer time.  For this reason, it is better to use a Set instead of a List.  A Set uses hashing so that the same operation can be completed much more quickly:

Code: [Select]
used_values = set()

for x in range(0, 100):
    val = random()

    while val in used_values:
        val = random()

    used_values.add(val)

    // Do something with val, maybe append to a result list or call a function to build part of your map
Note that for every number generated, val is looked up in used_values twice.  Once to check if it is in there already, and once when it gets added (because that's how sets work).  If you take this into account, you can reduce this example to what I wrote earlier.  Of course, you are not talking about Python's random.random() here, that would be bad.

It is not premature optimisation, it is understanding exactly how things work, and writing code so as to not do unnecessary work.  These things do matter, I've often profiled slow Python code in commercial Python games, and these things make a significant difference.

random.sample() is a limited function, and it smacks to me of something someone put in to handle their own special case.  The Python standard library has many of these sorts of things.  There are arbitrary modules in there that almost do what I want, but are just unusable because whomever wrote them wanted them to work in a way that was unusable for me.  Back to sample(), I've never had a sequence I needed to pick out a unique list of entries from.  If I had to do this, it would be clearer IMO to write the code yourself than to call this function.  Most of my random number usage was picking from weighted lists, and repicking was desirable.  After all, you want 2x50 arrows sometimes, 1x50 arrows some other times, and so forth.
Title: Re: Generating a list of unique random numbers
Post by: mushroom patch on April 13, 2014, 01:46:26 PM
random.sample() is a limited function, and it smacks to me of something someone put in to handle their own special case.  The Python standard library has many of these sorts of things.  There are arbitrary modules in there that almost do what I want, but are just unusable because whomever wrote them wanted them to work in a way that was unusable for me.  Back to sample(), I've never had a sequence I needed to pick out a unique list of entries from.  If I had to do this, it would be clearer IMO to write the code yourself than to call this function.  Most of my random number usage was picking from weighted lists, and repicking was desirable.  After all, you want 2x50 arrows sometimes, 1x50 arrows some other times, and so forth.

Sampling without replacement is an extremely standard thing to do. It appears in any book on basic probability. If you want to draw a hand of cards from a deck in a card game, your deck may be represented by a list and the hand can be "drawn" via random.sample(). One can imagine plenty of similar applications. I've never felt this way about the standard library in python myself, but I suppose everyone has an opinion. I can hardly believe you think this is an instance of implementing something no one else is likely to use/need though.

Edit: Perhaps a more topical example: Suppose you want to generate treasures to populate a vault, but you don't want a lot of repeated treasures or treasure types and you want to do it in a flexible, data-oriented way (e.g. you want it to depend on dungeon levels, maybe some kind of theming for different vault types, etc.). You can write a routine that puts together a large list of item types (or better item builder objects), then use random.sample to draw from it.
Title: Re: Generating a list of unique random numbers
Post by: Z on April 13, 2014, 02:47:48 PM
ah, the experiences of lists of random numbers. Javascript makes something like this super easy:

Code: [Select]
var numArr = Array(20);
for(var i = 0; i < numArr.length;i++){
   numArr[i] = i;
}
numArr.sort(function(){return Math.random()-.5;});
console.log(numArr);

It is impossible to randomly shuffle three values in a bounded number of coin tosses. Thus, this method either makes some permutations more probable than others or it uses an unbonded number of comparisons, depending on how "sort" works. For example, on my browser,
Code: [Select]
ile = Array(); for(t=0; t<1000000; t++) { arr = Array(1,2,3); arr.sort(function(){return Math.random()-.5;}); s=arr[0]+","+arr[1]+","+arr[2]; if(ile[s]) ile[s]++; else ile[s] = 1; } ilereturns 1,2,3 and 2,1,3 twice as frequently as other permutations.

EDIT: With 4 elements some permutations turn out to appear 180 times more frequently than others. Even if you look just at the first element: 1 and 2 appear with probability 28%, 3 with 18% and 4 with 25%. The probabilities of choosing each element seem out to be more and more different when the number of elements increased (with 17 elements, 1..17, they range from 3.5% for 6 to 15.8% for 1). If you wrote a game using this, it could be completely different on a different browser.

Title: Re: Generating a list of unique random numbers
Post by: Jaxian on April 13, 2014, 03:59:32 PM
However, the line "val in value_list" requires the code to compare "val" to every single value in the list.  As the list grows in size, this could take a longer time.  For this reason, it is better to use a Set instead of a List.  A Set uses hashing so that the same operation can be completed much more quickly:

Code: [Select]
used_values = set()

for x in range(0, 100):
    val = random()

    while val in used_values:
        val = random()

    used_values.add(val)

    // Do something with val, maybe append to a result list or call a function to build part of your map
Note that for every number generated, val is looked up in used_values twice.  Once to check if it is in there already, and once when it gets added (because that's how sets work).  If you take this into account, you can reduce this example to what I wrote earlier.  Of course, you are not talking about Python's random.random() here, that would be bad.

A good point.  It did not occur to me to me to use the length of the set to determine whether or not a value was added uniquely, and I do think that avoiding a second hash is worthwhile.  As for which version of random() I am referring to, I don't know Python, so I can't say.  If there is a certain version of random() that should be avoided, then hopefully someone can explain that here.
Title: Re: Generating a list of unique random numbers
Post by: chooseusername on April 13, 2014, 08:29:01 PM
If there is a certain version of random() that should be avoided, then hopefully someone can explain that here.
random() is the name of the standard library function which returns a float between 0.0-1.0.  There would of course be no point in putting that as the key in a dictionary or set.
Title: Re: Generating a list of unique random numbers
Post by: chooseusername on April 13, 2014, 08:51:47 PM
Edit: Perhaps a more topical example: Suppose you want to generate treasures to populate a vault, but you don't want a lot of repeated treasures or treasure types and you want to do it in a flexible, data-oriented way (e.g. you want it to depend on dungeon levels, maybe some kind of theming for different vault types, etc.). You can write a routine that puts together a large list of item types (or better item builder objects), then use random.sample to draw from it.
Do you really believe this is a realistic example?  Or is it one contrived to employ random.sample()?  To me, it seems like the latter.  Is there anyone out there other than me that's written loot dropping code, who would write it this way or use random.sample()?
Title: Re: Generating a list of unique random numbers
Post by: requerent on April 13, 2014, 09:08:53 PM

random.sample() is a limited function, and it smacks to me of something someone put in to handle their own special case.  The Python standard library has many of these sorts of things.  There are arbitrary modules in there that almost do what I want, but are just unusable because whomever wrote them wanted them to work in a way that was unusable for me.  Back to sample(), I've never had a sequence I needed to pick out a unique list of entries from.  If I had to do this, it would be clearer IMO to write the code yourself than to call this function.  Most of my random number usage was picking from weighted lists, and repicking was desirable.  After all, you want 2x50 arrows sometimes, 1x50 arrows some other times, and so forth.

This is ludicrous. Python standard libraries are written in C- many of which have undergone pretty severe optimizations. I don't even like python for games, but if you're going to use it, you want to leverage the standard libraries as much as possible. Period. Even if a python library doesn't have exactly what you need, it's going to give you better performance to modify the results afterwards than to try and implement it entirely in python. Or you can go shopping for other modules that fit your purpose more precisely. At all costs, avoid coding in actual python as much as possible. That is the more pythonic approach.

Quote
Do you really believe this is a realistic example?  Or is it one contrived to employ random.sample()?  To me, it seems like the latter.  Is there anyone out there other than me that's written loot dropping code, who would write it this way or use random.sample()?

If the OP is asking how to do it, that is sufficiently good enough reason to implement it in that matter or discuss such an implementation. The problem domain is unique to each individual's design goals, it doesn't matter if nobody has done it yet. There are a LOT of ways to utilize sampling for loot. Arguing against its use while ignorant of the problem domain is just silly. The OP isn't asking for advice on how to generate loot, he's asking for a specific algorithm which may be perfect for the game he's working on.
Title: Re: Generating a list of unique random numbers
Post by: mushroom patch on April 13, 2014, 09:29:46 PM
Edit: Perhaps a more topical example: Suppose you want to generate treasures to populate a vault, but you don't want a lot of repeated treasures or treasure types and you want to do it in a flexible, data-oriented way (e.g. you want it to depend on dungeon levels, maybe some kind of theming for different vault types, etc.). You can write a routine that puts together a large list of item types (or better item builder objects), then use random.sample to draw from it.
Do you really believe this is a realistic example?  Or is it one contrived to employ random.sample()?  To me, it seems like the latter.  Is there anyone out there other than me that's written loot dropping code, who would write it this way or use random.sample()?

Absolutely. It's a lot cleaner than the ridiculous hacks you see in major roguelikes for tasks like monster and item generation, e.g. run through a list, add up a bunch of weights assigned to each possible item, make a list of threshold values, generate a random number, etc.

I mean, if your argument is that many roguelike developers don't use/know what sampling without replacement and/or random permutations are, I'll totally grant you that. I don't think that really means anything though, except perhaps that there's a lot of scope for improvement on the state of the art.

Also:

If there is a certain version of random() that should be avoided, then hopefully someone can explain that here.
random() is the name of the standard library function which returns a float between 0.0-1.0.  There would of course be no point in putting that as the key in a dictionary or set.

Actually, a reasonable way to do what the OP asks (if you don't know about random.sample) would something like sort(l, key=lambda x: random.random()) -- you risk key value collisions (which just results in slightly less random behavior than desired), but the odds of that are low enough that they have almost no effect statistically. Python only evaluates the key function once per item and stores the result, so there's no problem doing it this way.
Title: Re: Generating a list of unique random numbers
Post by: chooseusername on April 13, 2014, 10:19:20 PM
This is ludicrous. Python standard libraries are written in C- many of which have undergone pretty severe optimizations. I don't even like python for games, but if you're going to use it, you want to leverage the standard libraries as much as possible. Period. Even if a python library doesn't have exactly what you need, it's going to give you better performance to modify the results afterwards than to try and implement it entirely in python. Or you can go shopping for other modules that fit your purpose more precisely. At all costs, avoid coding in actual python as much as possible. That is the more pythonic approach.
Have you ever looked at the standard library?  Very little of it is written in C.  And have you ever subscribed to the python-dev list for a reasonable period of time?  The actual process of getting something into the standard library comes mainly from attrition, or it has for most of the lifetime of Python development.  All you have to do is have something you want in there, and the staying power to argue away all detractors, and to offer to maintain it once it is in there.  So what happens is that what gets into the standard library, is not the best or most useful, it's just the most pushed by those who can be bothered.

You seem to ascribe some magical quality to the standard library.  Or to the mystical quality of being Pythonic.  It is not uncommon to have arguments where people where each argues different perspectives of how what they want to push on the other is more Pythonic.  It's just a worthless appeal to authority, an empty point foisted on those who do not know better.

Avoid coding in Python if possible?  Wow, we really do have different approaches.  How can you be confident that your code works right, and is easy to maintain, if you do not know how it works and are not afraid to rewrite it as needed?  Too many people just use libraries and frameworks and treat them like a magical black box that just work the way they want.

If the OP is asking how to do it, that is sufficiently good enough reason to implement it in that matter or discuss such an implementation. The problem domain is unique to each individual's design goals, it doesn't matter if nobody has done it yet. There are a LOT of ways to utilize sampling for loot. Arguing against its use while ignorant of the problem domain is just silly. The OP isn't asking for advice on how to generate loot, he's asking for a specific algorithm which may be perfect for the game he's working on.
*sigh* You're talking in circles trying to justify it's usefulness.  I never said I only used random numbers in loot dropping.  I just used it as an example, for how things are generally more complicated and how random.sample() is only useful in theory, rather than in practice.

I can't argue with overly emotional irrational arguments made solely to push something unjustified on someone else, so I'm going to choose to opt out of responding to your posts from now on.  Good luck with your personal opinions.
Title: Re: Generating a list of unique random numbers
Post by: chooseusername on April 13, 2014, 10:26:31 PM
Absolutely. It's a lot cleaner than the ridiculous hacks you see in major roguelikes for tasks like monster and item generation, e.g. run through a list, add up a bunch of weights assigned to each possible item, make a list of threshold values, generate a random number, etc.

I mean, if your argument is that many roguelike developers don't use/know what sampling without replacement and/or random permutations are, I'll totally grant you that. I don't think that really means anything though, except perhaps that there's a lot of scope for improvement on the state of the art.
We're going to have to disagree.  Unless you care to link to any of these ridiculous hacks and describe how you would do it better (without simplifying things to the point where value is removed).
Title: Re: Generating a list of unique random numbers
Post by: sokol815 on April 14, 2014, 12:20:08 AM
ah, the experiences of lists of random numbers. Javascript makes something like this super easy:

Code: [Select]
var numArr = Array(20);
for(var i = 0; i < numArr.length;i++){
   numArr[i] = i;
}
numArr.sort(function(){return Math.random()-.5;});
console.log(numArr);

It is impossible to randomly shuffle three values in a bounded number of coin tosses. Thus, this method either makes some permutations more probable than others or it uses an unbonded number of comparisons, depending on how "sort" works. For example, on my browser,
Code: [Select]
ile = Array(); for(t=0; t<1000000; t++) { arr = Array(1,2,3); arr.sort(function(){return Math.random()-.5;}); s=arr[0]+","+arr[1]+","+arr[2]; if(ile[s]) ile[s]++; else ile[s] = 1; } ilereturns 1,2,3 and 2,1,3 twice as frequently as other permutations.

EDIT: With 4 elements some permutations turn out to appear 180 times more frequently than others. Even if you look just at the first element: 1 and 2 appear with probability 28%, 3 with 18% and 4 with 25%. The probabilities of choosing each element seem out to be more and more different when the number of elements increased (with 17 elements, 1..17, they range from 3.5% for 6 to 15.8% for 1). If you wrote a game using this, it could be completely different on a different browser.

Yeah, that first code block is really not useful. maybe for prototyping something... If I needed to randomize an array, I would use the second method that I mentioned. Here is a test harnessed up to that 2nd method:
Code: [Select]
var ile = {};
for(var t = 0; t < 1000000; t++){
var arr = [1,2,3];
var arr2 = [];
var s;
while(arr.length > 0){
var index = (Math.random() * arr.length) >> 0;
arr2.push(arr[index]);
if(arr2.length == 1){
s = arr2[0];
} else {
s = s + "," + arr2[arr2.length-1];
}
arr.splice(index,1);
}
if(!ile[s]){
ile[s] = 1;
} else {
ile[s]++;
}
}
ile;

this method returns all 6 orders in similar proportions.
Code: [Select]
1,2,3: 166352
1,3,2: 166225
2,1,3: 166572
2,3,1: 166947
3,1,2: 166894
3,2,1: 167010

I use an implementation of a RC4 psuedo-random algorithm (http://en.wikipedia.org/wiki/RC4#RC4-based_random_number_generators) in my javascript games. it is called "Seedrandom.js" (https://github.com/davidbau/seedrandom). Seed random provides a seedable RNG. V8's built-in RNG is not seedable, so I use this instead.
Title: Re: Generating a list of unique random numbers
Post by: mushroom patch on April 14, 2014, 02:17:33 AM
Quote
Have you ever looked at the standard library?  Very little of it is written in C.

True fact. The standard library method in question is implemented here (in python):

http://svn.python.org/projects/python/branches/py3k/Lib/random.py

Absolutely. It's a lot cleaner than the ridiculous hacks you see in major roguelikes for tasks like monster and item generation, e.g. run through a list, add up a bunch of weights assigned to each possible item, make a list of threshold values, generate a random number, etc.

I mean, if your argument is that many roguelike developers don't use/know what sampling without replacement and/or random permutations are, I'll totally grant you that. I don't think that really means anything though, except perhaps that there's a lot of scope for improvement on the state of the art.
We're going to have to disagree.  Unless you care to link to any of these ridiculous hacks and describe how you would do it better (without simplifying things to the point where value is removed).

I checked out the angband source, which is the last place I looked for this kind of thing. I decided I'm willing to settle with disagreement because it's too much of a pain in the ass locating exactly which if-else ladder/switch statement I propose to replace. Moreover, angband doesn't even have the kind of finesse to consider the issue of whether or not you really want to select different item types independently -- it just does it.
Title: Re: Generating a list of unique random numbers
Post by: requerent on April 14, 2014, 02:40:27 AM
Whoops. Python is disappoint.
Title: Re: Generating a list of unique random numbers
Post by: Jaxian on April 14, 2014, 03:18:12 AM
random() is the name of the standard library function which returns a float between 0.0-1.0.  There would of course be no point in putting that as the key in a dictionary or set.

Why do you say that?  Do I not know something about the interaction between floats and sets?
Title: Re: Generating a list of unique random numbers
Post by: Trystan on April 14, 2014, 05:16:06 AM
random() is the name of the standard library function which returns a float between 0.0-1.0.  There would of course be no point in putting that as the key in a dictionary or set.

Why do you say that?  Do I not know something about the interaction between floats and sets?


Because you could end up with something like 0.000000001, 0.000000002, 0.000000003, 0.000000004, 0.000000005. All unique numbers but all very close. It's pretty much impossible to call random a few times and get duplicate numbers. You have to be careful when comparing or doing math with floats.
Title: Re: Generating a list of unique random numbers
Post by: Numeron on April 14, 2014, 06:25:38 AM
I don't know much python, but if you want to create a really large set of unique randoms ints, it might be faster to use a hashset rather than a list so you don't have to O(n) your way through the list on every number generated. Putting duplicate values into a set will automatically check if the number already exists in the set.

In java, primitive ints are auto-boxed into Integer objects for the standard library HashSets (which makes the above awful memorywise), so if this is the same with python you would probably want to go look for some library that has hashsets specifically catered to primitives (like Trove in java)

Title: Re: Generating a list of unique random numbers
Post by: Jaxian on April 14, 2014, 03:44:50 PM
Because you could end up with something like 0.000000001, 0.000000002, 0.000000003, 0.000000004, 0.000000005. All unique numbers but all very close. It's pretty much impossible to call random a few times and get duplicate numbers. You have to be careful when comparing or doing math with floats.

Sure, the numbers may be very close, but they are still unique.  Why would their closeness be a concern?  Perhaps in reality the goal is not a list of unique floats but a list of unique integers within a range, say 0 - 5000.  In this case we would of course need to convert the random value to an integer first.  But is that all that was being said?  It sounded more like "a float between 0 and 1 should never be used as a key in a set or dictionary."

As a side-note, I do think it should be possible to get duplicate values.  If we think of an integer as 32 bits, a random positive integer should have its sign bit set to 0, and the remaining 31 bits should be randomized.  Conversely, a random float between 0 and 1 should have its sign bit set to 0, as well as its exponent's sign bit set to 1, and the remaining 30 bits randomized.  This means that a random float should be more likely to contain a duplicate than a random integer (having 2^30 possible values instead of 2^31).  It's true that one must be careful comparing floats when crossing architectures or after performing math.  However, two floats with the same bits will compare as equal.
Title: Re: Generating a list of unique random numbers
Post by: Gr3yling on April 18, 2014, 02:20:17 AM
This is what I was trying to do (I think), in pretty much the way I was trying to do it:


from random import randint


random_list = []

while len(random_list) <= 20:
    random_no = randint(0,20)
    Unique = True
    for entry in random_list:
        if random_no == entry:
            Unique = False
   
    if Unique == True:
        random_list.append(random_no)

print random_list

raw_input()


Yes, there are better ways to do it which have already been mentioned, but this one fits my weird criteria.  Sorry if someone already posted something essentially the same as this and I missed it.
Title: Re: Generating a list of unique random numbers
Post by: Xecutor on April 18, 2014, 04:00:52 AM
Code: [Select]
import random
random_list = [0]*20
for i in range(0,20):
  k = random.randint(0,i)
  random_list[i]=random_list[k]
  random_list[k]=i
print random_list