AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Scripting Help (https://forums.alliedmods.net/forumdisplay.php?f=11)
-   -   Random numbers without repeating (https://forums.alliedmods.net/showthread.php?t=282244)

KiLLeR. 05-02-2016 11:32

Random numbers without repeating
 
PHP Code:

for(new i=0i<5i++)
{
    
num[i] = random_num(110);


So, how to retrieve 4 random numbers between 1 and 10, but without repeating.

I can use something like:
PHP Code:

if((num[0] == (num[1] | num[2] | num[3] | num[4] | num[5])) || (num[1]  == (....)))
{
    
// retrieve a new random number


But I think, that this isn't the most efficient way (even if it works).

Black Rose 05-02-2016 12:20

Re: Random numbers without repeating
 
Don't worry too much about efficiency here.
I ran this code 1 000 000 times with the result of 1.795s. (That's an average of .001795milliseconds per time you randomize 5 numbers... trivial.)

Code:
    for ( new i ; i < sizeof num ; i++ ) {         do num[i] = random_num(1, 10);         while ( AlreadyExists(num[i], num, i) )     } // ... AlreadyExists(num, array[], size) {     for ( new i ; i < size ; i++ )         if ( array[i] == num )             return 1;     return 0; }

siriusmd99 05-02-2016 12:27

Re: Random numbers without repeating
 
PHP Code:

for(new i=0i<5i++)
{
   
num[i] = random_num(110);
   while(
num_exists(num[i], num) )
   
num[i] = random_num(110);

}  

bool:num_exists(numbercountsource[]){

 for(new 
jcountj++)
 if(
source[j]==number)
 return 
true;
 
 return 
false;



KiLLeR. 05-02-2016 13:54

Re: Random numbers without repeating
 
Thanks you! I already made something that seems is working, but I will use your method, because looks better.

PHP Code:

new num[11], temprnum;
            
    for(new 
i=1i<sizeof(num); i++)
    {
        
num[i] = i;
    }
    
    for(new 
i=1i<sizeof(num); i++)
    {
        
temp num[i];
        
rnum random_num(110);
        
        
num[i] = num[rnum];
        
num[rnum] = temp;
    }
    
    new 
randomnum[5];
    
    for(new 
i=0i<5i++)
    {
        
randomnum[i] = num[i+1];
    }
    
    
server_print("%i %i %i %i %i"randomnum[0], randomnum[1],randomnum[2],randomnum[3],randomnum[4]); 


siriusmd99 05-02-2016 14:32

Re: Random numbers without repeating
 
Quote:

Originally Posted by Black Rose (Post 2416009)
Don't worry too much about efficiency here.
I ran this code 1 000 000 times with the result of 1.795s. (That's an average of .001795milliseconds per time you randomize 5 numbers... trivial.)

Code:
    for ( new i ; i < sizeof num ; i++ ) {         do num[i] = random_num(1, 10);         while ( AlreadyExists(num[i], num, i) )     } // ... AlreadyExists(num, array[], size) {     for ( new i ; i < size ; i++ )         if ( array[i] == num )             return 1;     return 0; }

Loooool, we have the same thoughts...., gj..


Also @KiLLeR., you can avoid this thing:

Quote:

server_print("%i %i %i %i %i", randomnum[0], randomnum[1],randomnum[2],randomnum[3],randomnum[4]);
by using this :

PHP Code:

new tmpmsg[16]

for(new 
i5i++)
  
add(tmpmsg15,"%i "randomnum[i])

server_print(tmpmsg); 


Black Rose 05-02-2016 14:33

Re: Random numbers without repeating
 
It depends on implementation.
If it actually is 5 values between 1 and 10 it doesn't matter.
But your method of scrambling an array will be more consistent as the previous 2 versions of pure randomizing values will be dependent on the availability of the numbers. As you fill the array and the available numbers become rare, time increases because of retries.

Here's a small example comparing the two functions.
Code:
#include <amxmodx> #include <rose> #define SIZE 5 #define MIN 1 #define MAX 10 #define RANDOMIZER 10 public plugin_init() {     register_plugin("Test Plugin 5", "", "[ --{-@ ]");     server_print("MIN: %d, MAX: %d, SIZE: %d, RANDOMIZER: %d", MIN, MAX, SIZE, RANDOMIZER);         new hTimer = TimerStart();     for ( new l ; l < 1000000 ; l++ )         Randomize_1()     TimerStop(hTimer);     new output[32];     TimerFormat(hTimer, output, charsmax(output), 2)     server_print("Method one, 1 000 000 runs, time: %s", output);     hTimer = TimerStart();     for ( new l ; l < 1000000 ; l++ )         Randomize_2()     TimerStop(hTimer);     TimerFormat(hTimer, output, charsmax(output), 2)     server_print("Method two, 1 000 000 runs, time: %s", output); } Randomize_1() {     static num[SIZE];     for ( new i ; i < sizeof num ; i++ ) {         do num[i] = random_num(MIN, MAX);         while ( AlreadyExists(num[i], num, i) )     } } AlreadyExists(num, array[], size) {     for ( new i ; i < size ; i++ )         if ( array[i] == num )             return 1;     return 0; } Randomize_2() {     static num[SIZE];     static values[MAX];     new temp, r;     for ( new i ; i < sizeof values ; i++ )         values[i] = i + 1;     for ( new i ; i < RANDOMIZER ; i++ ) {         r = random(sizeof values);         temp = values[i % sizeof values];         values[i % sizeof values] = values[r];         values[r] = temp;     }     for ( new i ; i < sizeof num ; i++ )         num[i] = values[i]; }

Here are some examples I ran:
Code:

MIN 1, MAX 10, SIZE 5, RANDOMIZER 10:
Method one, 1 000 000 runs, time: 1s 853ms
Method two, 1 000 000 runs, time: 2s 681ms

Code:

MIN: 1, MAX: 10, SIZE: 5, RANDOMIZER: 30
Method one, 1 000 000 runs, time: 1s 882ms
Method two, 1 000 000 runs, time: 5s 930ms

Code:

MIN: 1, MAX: 5, SIZE: 5, RANDOMIZER: 10
Method one, 1 000 000 runs, time: 2s 960ms
Method two, 1 000 000 runs, time: 2s 428ms

Code:

MIN: 1, MAX: 20, SIZE: 15, RANDOMIZER: 10
Method one, 1 000 000 runs, time: 12s 618ms
Method two, 1 000 000 runs, time: 3s 685ms

Code:

MIN: 1, MAX: 20, SIZE: 20, RANDOMIZER: 50
Method one, 1 000 000 runs, time: 41s 402ms
Method two, 1 000 000 runs, time: 10s 470ms

As you can see, as the size increases and the possible values become more similar to the number of slots to fill the first method gets really slow.
Again, this is 1 000 000 runs. So even 41s equals to an average of .041 milliseconds per run. Again, trivial.

Bugsy 05-08-2016 13:55

Re: Random numbers without repeating
 
I know this is already answered but I was bored and put this together.

You must first call PrepRandom() for any min/max combo prior to calling GetRandom() for that min/max combo. Once you call PrepRandom(), you can repeatedly call GetRandom() and you will always get a unique random until all numbers have been used. Once all are used, you will then begin getting the numbers again, and they will be unique until you again use up all the numbers.

Like this. But you cannot cannot call GetRandom on a particular min/max until you first call PrepRandom for that min/max set.
PHP Code:

PrepRandom10 );
GetRandom10 );
GetRandom10 );
GetRandom10 );
GetRandom10 );

PrepRandom500 );
GetRandom500 );
GetRandom500 );
GetRandom500 );
GetRandom500 ); 

PHP Code:


#include <amxmodx>

new const Version[] = "0.1";

//Set this to the absolute max random number that you will attempt to generate.
const MaxRandom 20;

new 
AllNumbers[ ( MaxRandom >> ) + ];

public 
plugin_init()
{
    
register_plugin"Random Number No Dupes" Version "bugsy" );
    
    
PrepRandom20 );
    
    for ( new 
<= 100 i++ )
        
server_print"[%d] Random=%d" GetRandom20 ) );
}

PrepRandomiRanMin iRanMax )
{
    for ( new 
iRanMin <= iRanMax i++ )
        
AllNumbers>> ] |= ( << );
}

public 
GetRandomiRanMin iRanMax )
{    
    static 
UsedNumbers[ ( MaxRandom >> ) + ];
    new 
iRandom bool:bAllUsed=true;
    
    if ( 
iRanMax MaxRandom )
        
set_fail_state"Must increase MaxRandom value: %d > %d" iRanMax MaxRandom );
    
    
//Check if all numbers have already bee nused, if so this will reset the 'used' variable.
    
for ( new sizeofUsedNumbers ) ; i++ )
    {
        if ( 
AllNumbers] && ( AllNumbers] != UsedNumbers] ) )
        {
            
bAllUsed false;
            break;
        }
    }

    
//If all random numbers have already been used, reset variable so they can be re-used.
    
if ( bAllUsed )
        
arraysetUsedNumbers sizeofUsedNumbers ) );
    
    
//Find random number
    
do
    {
        
iRandom random_numiRanMin iRanMax );
    }
    while ( ( 
UsedNumbersiRandom >> ] & ( << iRandom ) ) )  
    
    
//Set current random number as used
    
UsedNumbersiRandom >> ] |= ( << iRandom );
    
    
//Return random number
    
return iRandom;




All times are GMT -4. The time now is 18:43.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.