Pseudo-randomly Generate Unique Indices

From Second Life Wiki
Revision as of 16:09, 16 December 2015 by Haravikk Mistral (talk | contribs)
Jump to navigation Jump to search

Pseudo-randomly Generate Unique Indices

Ordinarily when a collection of data needs to be retrieved in a random order, it can simply be reshuffled by randomly swapping elements and then iterating through the resulting, shuffled, collection. However there are cases where this is infeasible, especially in LSL, and as such the following functions can be used to generate indices in a pseudo-random way that should be "good enough" for many purposes.

integer _prui_counter = 1;
integer _prui_limit = 0;

integer _prui_start = 0;
integer _prui_stride = 0;
integer _prui_next = 0;

prui_init(integer limit) {
    _prui_limit = limit;
    _prui_start = (integer)llFrand((float)limit);
    _prui_stride = (integer)llFrand((float)limit - 1.0) + 1;
    _prui_next = _prui_start;
}

integer prui_next() {
    if (!_prui_counter) prui_init(_prui_limit);

    integer result = _prui_next;
    _prui_next = (_prui_next + _prui_stride) % _prui_limit;
    if (_prui_next == _prui_start) {
        _prui_start = (_prui_start + 1) % _prui_limit;
        _prui_next = _prui_start;
    }
    return result;
}

Examples

List

The following script will spit out a random entry from a list when touched. In this example the list contains letters of the alphabet and as such the first 26 touches will produce a unique letter, the following 26 touches will likewise produce no duplicates and so-on.

// Add the above prui variables and functions here

list myList = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
integer myListLength;

default {
    state_entry() {
        prui_init(myListLength = llGetListLength(myList));
        llSetText("Touch me for a complimentary letter of the alphabet!", <1.0, 1.0, 1.0>, 1.0);
    }
    
    touch_start(integer x) { llRegionSayTo(llDetectedKey(0), PUBLIC_CHANNEL, llList2String(myList, prui_next())); }
}

String

This is the same example rewritten to more efficiently use a string for storing the letters of the alphabet:

// Add the above prui variables and functions here

string myString = "abcdefghijklmnopqrstuvwxyz";
integer myStringLength;

default {
    state_entry() {
        prui_init(myStringLength = llStringLength(myString));
        llSetText("Touch me for a complimentary letter of the alphabet!", <1.0, 1.0, 1.0>, 1.0);
    }
    
    touch_start(integer x) { llRegionSayTo(llDetectedKey(0), PUBLIC_CHANNEL, llGetSubString(myString, x = prui_next(), x)); }
}

Notecard

Finally, this example performs the same incredible feat using lines in a notecard (one for each letter of the alphabet):

// Add the above prui variables and functions here

key myNotecard = "a62213ba-381d-2347-7f7b-818f15f12d83";
integer myNotecardLength = -1;
key talkTo = NULL_KEY;

default {
    state_entry() { llGetNumberOfNotecardLines(myNotecard); }
    dataserver(key id, string data) {
        if (myNotecardLength > 0) llRegionSayTo(talkTo, PUBLIC_CHANNEL, data);
        else prui_init(myNotecardLength = (integer)data);
    }
    
    touch_start(integer x) {
        talkTo = llDetectedKey(0);
        llGetNotecardLine(myNotecard, prui_next());
    }
}