Raised This Month: $ Target: $400
 0% 

[HOW TO] Retrieve random values from an array without retreiving the same twice


  
 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
Author Message
Exolent[jNr]
Veteran Member
Join Date: Feb 2007
Location: Tennessee
Old 07-22-2008 , 18:30   [HOW TO] Retrieve random values from an array without retreiving the same twice
Reply With Quote #1

So, the main purpose of this tutorial is to show how to retrieve values from an array from random slots, without ever getting the same slot twice.

Note: This is intended for AMX Mod X scripters who are fluent in scripting plugins. (No learners, please.)

Code:
// Overview of the tutorial: // players[] = all players in the server // total = amount of players in the players[] array // retreive = amount of players to retrieve from the players[] array // selected[] = random players taken from players[] array // count = amount of players saved in the selected[] array // rand = random loop number to retrieve random players // I will just use the players array, // since this is what most people want this for new players[32], total; get_players(players, total); // this will be how many random we want new retrieve = 5; // check if it is larger than total // because you cannot get more players than the ones that exist if( retrieve > total ) retrieve = total; // this will be the counter of how many random we have gotten new count; // this will hold all the random players // note: if this isn't for players, //       make sure that this array size is the same as the array you are getting values from new selected[32]; // lets start a loop // we get a random number each time to randomize the selected // then, we delete the random index from the original players list new rand; do {     rand = random(total);         // save the player id in the selected array,     // and increase the amount we saved     selected[count++] = players[rand];         // this replaces the random one we used with the last one in the array     // also, it decreases the total since we got rid of the random one     players[rand] = players[--total]; } while( count < retrieve ); // you now have an array (selected[]) that holds "count" number of players // they are all random players that are currently in the server // Note: this is only an example, and can be used for any random array retrieving.

Now, for all you people that want to know how to use this with the dynamic array system.

Code:
// Overview of the tutorial: // players = all players in the server // total = amount of players in the players array // retreive = amount of players to retrieve from the players array // selected = random players taken from players array // count = amount of players saved in the selected array // rand = random loop number to retrieve random players // player = random player selected from players array new Array:players = ArrayCreate(1, 32); new total; // this code will fill the players array will all players in the server // if you aren't using this tutorial for players, skip this part, assuming your array is filled new max_players = get_maxplayers(); for( new id = 1; id <= max_players; id++ ) {     if( is_user_connected(id) )     {         ArrayPushCell(players, id);         total++;     } } // this will be how many random we want new retrieve = 5; // check if it is larger than total // because you cannot get more players than the ones that exist if( retrieve > total ) retreive = total; // this will be the counter of how many random we have gotten new count; // this will hold all the random players new Array:selected = ArrayCreate(1, retrieve); new player; // lets start a loop // we get a random number each time to randomize the selected // then, we delete the random index from the original players list new rand; do {     rand = random(total);         player = ArrayGetCell(players, rand);         // save the player id in the selected array,     // and increase the amount we saved     ArrayPushCell(selected, player);     count++;         // now we need to remove the index from the list     // so, we will shift all slots above the player id slot down 1     ArrayDeleteItem(players, rand);         // decrease total player ids since we removed one     total--; } while( count < retrieve ); // you now have an array (selected) that holds "count" number of players // they are all random players that are currently in the server // Note: this is only an example, and can be used for any random array retrieving.

This is a more advanced way which uses the Sort*() functions from AMXX.
I'm not experienced in this area. This was shown by P34nut and arkshine (a few posts after this one).
Code:
YourFunction() {     new players[32], pnum;     get_players(players, pnum); // you can use any flags you wish         SortCustom1D(players, pnum, "HandleRandomSort"); } HandleRandomSort(elem1, elem2, const array[], const data[], const dataSize) {     switch( random(61) )     {         case 0 .. 29: return -1;         case 30: return 0;     }         return 1; }

Here is an example for a function that retrieves a random player.
Code:
YourFunction() {     new player = GetRandomPlayer("a"); } GetRandomPlayer(const flags[]="", const teamORname[]="") {     new players[32], pnum;     get_players(players, pnum, flags, teamORname);         return (pnum > 0) ? players[random(pnum)] : 0; }

Here is an example for a function that retrieves an array of random players.
Code:
YourFunction() {     new players[32], pnum;     GetRandomPlayers(players, pnum, "a"); } GetRandomPlayers(players[32], &pnum, const flags[]="", const teamORname[]="") {     new original[32], total;     get_players(original, total, flags, teamORname);         pnum = 0;         new rand, i;     do     {         rand = random(total);                 players[pnum++] = original[rand];                 original[rand] = original[--total];     }     while( total > 0 ); }

EDIT:

Here are some useful functions that I wrote up.
It allows you to just copy these functions and implement anything you needed from the first post.

Code:
GetRandomNumberRange( const minn, const maxx );
GetRandomNumbersRange( numbers[ ], const size, const minn, const maxx );
any:GetRandomNumberCArray( const Array:array );
GetRandomNumbersCArray( any:numbers[ ], const size, const Array:array, bool:dont_modify );
any:GetRandomNumberArray( const any:array[ ], const array_size = sizeof( array ) );
GetRandomNumbersArray( any:numbers[ ], const size, const any:array[ ], const array_size = sizeof( array ) );
Code:
// Returns a random number from 'minn' to 'maxx' // Note: Only works for integers #define GetRandomNumberRange random_num //#define GetRandomNumberRange(%1,%2) random_num(%1, %2) /*stock GetRandomNumberRange( const minn, const maxx ) {     return random_num( minn, maxx ); }*/ // Gives an array of random numbers ranging from 'minn' to 'maxx' // Note: Only works for a integers // Note2: If the size of the array is larger than the range, the array will not be completely filled, since numbers are not duplicated. // Note3: If the size of the array is smaller than the range, not all of the numbers in the range will be given. // Note4: Requires  GetRandomNumbersCArray() to work. stock GetRandomNumbersRange( numbers[ ], const size, const minn, const maxx ) {     new Array:array = ArrayCreate( 1 );     for( new i = minn; i <= maxx; i++ )     {         ArrayPushCell( array, i );     }         new count = GetRandomNumbersCArray( numbers, size, array, .dont_modify = false );         ArrayDestroy( array );         return count; } // Returns the value from a random index in a cell array #define GetRandomNumberCArray(%1) ArrayGetCell( %1, random( ArraySize( %1 ) ) ) /*stock any:GetRandomNumberCArray( const Array:array ) {     return any:ArrayGetCell( array, random( ArraySize( array ) ) ); }*/ // Gives an array of values from random indexes in a cell array // Note: dont_modify - true: don't delete items from the array that were used, false: delete items that were used // Note2: If the size of the array is larger than the size of the cell array, the array will not be completely filled, since indexes are not duplicated. // Note3: If the size of the array is smaller than the size of the cell array, not all of the indexes will be given. stock GetRandomNumbersCArray( any:numbers[ ], const size, const Array:array, bool:dont_modify ) {     new Array:temp;     new array_size = ArraySize( array );         if( dont_modify )     {         temp = ArrayCreate( 1 );             for( new i = 0; i < array_size; i++ )         {             ArrayPushCell( temp, any:ArrayGetCell( array, i ) );         }     }     else     {         temp = array;     }         new count;     new rrandom;         while( count < size && array_size > 0 )     {         rrandom = random( array_size );         numbers[ count++ ] = any:ArrayGetCell( temp, rrandom );         ArrayDeleteItem( temp, rrandom );         array_size--;     }         if( dont_modify )     {         ArrayDestroy( temp );     }         return count; } // Returns a random number from an array of numbers // Note: If your given array size is undefined (like from a function), then don't pass the 'array_size' argument and it will be auto-determined. //#define GetRandomNumberArray(%1) %1[ random( sizeof( %1 ) ) ] stock any:GetRandomNumberArray( const any:array[ ], const array_size = sizeof( array ) ) {     // this is not a #define because using a function can always find the array size     // but in a #define, it replaces the function with it's defined action     // if it is used on an array that is passed to a function with no size, it will give a compiler error     // this will prevent that     return any:array[ random( array_size ) ]; } // Gives an array of values from random indexes in a given array // Note: If your given array size is undefined (like from a function), then don't pass the 'array_size' argument and it will be auto-determined. // Note2: If the size of the array is larger than the size of the given array, the array will not be completely filled, since indexes are not duplicated. // Note3: If the size of the array is smaller than the size of the given array, not all of the indexes will be given. // Note4: Requires  GetRandomNumbersCArray() to work. stock GetRandomNumbersArray( any:numbers[ ], const size, const any:array[ ], const array_size = sizeof( array ) ) {     new Array:CArray = ArrayCreate( 1 );     for( new i = 0; i < array_size; i++ )     {         ArrayPushCell( CArray, array[ i ] );     }         new count = GetRandomNumbersCArray( numbers, size, CArray, .dont_modify = false );         ArrayDestroy( CArray );         return count; }

Here is an example for those people who want random players.

Code:
// only used for readability const MAX_PLAYERS = 32; new iPlayers[ MAX_PLAYERS ], iNum; // get your players how you want them // example for all: get_players( iPlayers, iNum ); // example for all alive: get_players( iPlayers, iNum, "a" ); // look here for more possibilities //http://www.amxmodx.org/funcwiki.php?go=func&id=174 new iRandomPlayers[ MAX_PLAYERS ]; GetRandomNumbersFromArray( iRandomPlayers, MAX_PLAYERS, iPlayers, iNum ); for( new i = 0; i < iNum; i++ ) {     log_amx( "iPlayers[%i] = %i, iRandomPlayers[%i] = %i", i, iPlayers[ i ], i, iRandomPlayers[ i ] ); }

That is all!

Feel free to point out any suggestions/errors.
__________________
No private work or selling mods.
Quote:
Originally Posted by xPaw View Post
I love you exolent!

Last edited by Exolent[jNr]; 11-27-2010 at 15:42.
Exolent[jNr] is offline
 



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 21:31.


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