Shoutbox

Random numbers, prevent from being used more than once - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4)
+---- Forum: Scripting (/forumdisplay.php?fid=39)
+----- Thread: Random numbers, prevent from being used more than once (/showthread.php?tid=75840)

Random numbers, prevent from being used more than once by stu on 07-03-2007 at 10:14 PM

Ok, so I got bored today and was thinking what else I could add to a script that I have been working on that displays a random lyric. What I want to do, is make it so that the random number that is generated is not repeated within a certain amount of number generations. So for example, the numer 7 is generated, and then that number cant be used again until 10 different numbers have been used. Something like that.

What I am looking for are ideas to do that.. I looked online, and all I could find was ways to prevent using the same number twice in a row.. But I am looking for a way to prevent the same lyric being used until, lets say 10, different lyrics have been used. I dont like using the same lyric every other or every 4 times or something, and that has happened.

Anyways, does anyone have any ideas how to go about doing this? I was thinking of storing the random number into an array and then comparing the new random number against the array to make sure they are different.. but I couldnt find any way to make that work. Any new ideas or help would be great, thanks


RE: Random numbers, prevent from being used more than once by pollolibredegrasa on 07-03-2007 at 10:33 PM

Hmm, there are probably better ways to do this, but you could possibly do this using a multidimensional array...

I'm not sure how to explain but in my head it makes sense. Basically create an array for all the used lyrics, in which each item is also an array containing the 1) lyric number and 2) number of times a lyric has been generated since that one.

So say you generate lyric number 8, the used lyrics array would contain [8,0]

Then every time you generate another lyric, add it to the usedlyrics array and increment the second array item for all the previously generated ones until they are 10, at which point you can remove the item from the usedlyrics array.

Thus if you generate another lyric (say, number 3), your usedlyrics array would contain [8,1],[3,0].

Then another lyric (say number 9): [8,2],[3,1],[0,9] etc.

Obviously you have to make sure the lyric generated is not already in the usedlyrics array before adding it though =p

Sorry if I'm not making myself clear,  I'm tired and not feeling great but it sounded good in my head :P


RE: Random numbers, prevent from being used more than once by foaly on 07-03-2007 at 10:34 PM

the easiest thing to do would be an array and a function like:

function a{
int i is random;
for(int j=0,j<array.length;j++){
  if(i==array[j]){
    return a();
  }
}
array[count]=i;
count++;
count=count%9;
return i;
}

something like that...


RE: Random numbers, prevent from being used more than once by roflmao456 on 07-04-2007 at 03:15 AM

Create this at the top of your script:

code:
var Array = new Array();


Then put this code to where the random thing is:
code:
var random = Math.floor(Math.random()*10 /* 10 lyrics.. */);
for(i=0;i<Array.length;i++){

if(Array[random] != i){
Array[random] = i;
return;
}

}

i'm not sure if that will work..
RE: Random numbers, prevent from being used more than once by Volv on 07-04-2007 at 06:01 AM

I think foaly's is the simplest working code.

Although I think instead of:
count=count%9
You should replace it with:
count= (count==9 ? 0:count);

Because you don't want to have unnecessarily large integers being stored in memory.
EDIT: actually ignore this, foaly's does exactly the same :p My mistake.


RE: Random numbers, prevent from being used more than once by markee on 07-04-2007 at 02:17 PM

why use count at all when j will give you the same result?
your code should just be this:

code:
var lyricsArray = new Array("Come fly with me, lets fly, lets fly away","Can't buy me love","Yesterday, all my troubles seemed so far away");
var selectedArray = new Array();

function chooseRandomLyric(){
    var i = Math.round(Math.random()*(lyricsArray.length-1));
    var j;
    Inner:
    for(j=0;j<selectedArray.length;j++){
        if(i==selectedArray[j]){
            i=Math.round(Math.random()*lyricsArray.length);
            continue Inner;
        }
    }
    if(selectedArray.length === 10){
        selectedArray.pop;
    }
    selectedArray.concat(i,selectedArray);
    return i;
}

I did label a function which a lot of people are probably unfamiliar with, but it makes it a little more resource friendly as you can be calling the same function hundreds of times (there is a chance that it will never give you an answer and freeze your computer too.... but this is very limited, but more probable when you have a lot of lyrics and have gone through most of them).  And I also added an if statement at the end to make sure that there is no case where there are no lyrics left... which would leave you with an infinite loop too.

Furthermore, dynamic functions are a very wise idea and that is why I have made the random number based upon the array of lyrics rather than you having to do that manually when you update it.  I hope you enjoy.

EDIT: updated code due to Volv's post below
RE: Random numbers, prevent from being used more than once by Volv on 07-04-2007 at 02:31 PM

markee, that code isn't very elegant and could be more optimised, but it also doesn't solve the initial problem =/

quote:
Originally posted by markee
why use count at all when j will give you the same result?
'count' provides a means of allowing the lyric to be re-used after 10 different lyrics have been used as was requested:
quote:
Originally posted by stu
But I am looking for a way to prevent the same lyric being used until, lets say 10, different lyrics have been used. ...
So for example, the numer 7 is generated, and then that number cant be used again until 10 different numbers have been used. Something like that.


RE: Random numbers, prevent from being used more than once by markee on 07-04-2007 at 02:35 PM

quote:
Originally posted by Volv
'count' provides a means of allowing the lyric to be re-used after 10 different lyrics have been used as was requested:

    quote:Originally posted by stu
    But I am looking for a way to prevent the same lyric being used until, lets say 10, different lyrics have been used. I dont like using the same lyric every other or every 4 times or something, and that has happened.


well in that case then I just need to use a .pop on my selectedArray if the length is 10 and add the new one on.... not overly difficult.  I'll edit my code above :P
RE: Random numbers, prevent from being used more than once by foaly on 07-04-2007 at 04:00 PM

quote:
Originally posted by markee
   
code:
var lyricsArray = new Array("Come fly with me, lets fly, lets fly away","Can't buy me love","Yesterday, all my troubles seemed so far away");
    var selectedArray = new Array();

    function chooseRandomLyric(){
    var i = Math.round(Math.random()*(lyricsArray.length-1));
    var j;
    Inner:
    for(j=0;j<selectedArray.length;j++){
    if(i==selectedArray[j]){
    i=Math.round(Math.random()*lyricsArray.length);
    continue Inner;
    }
    }
    if(selectedArray.length === 10){
    selectedArray.pop;
    }
    selectedArray.concat(i,selectedArray);
    return i;
    }


this option maybe nicer...
but it might be easier to use a function you understand...
and I doubt the thread starter understands how exactly your function works... :P
RE: Random numbers, prevent from being used more than once by stu on 07-04-2007 at 04:50 PM

Wow, thanks for the responses guys, didnt expect so many.. I'll give your suggestions all a try today and see what I come up with. A lot of it, I dont even understand though, like markee's code, lol. But I will give it a try anyways.

foaly, in your code, what does "count=count%9;" that line mean? Never seen that before..

Also, Im going to attach a copy of my script on here as it is right now if you want to take a look at it to better understand what I am doing. I took out the lyrics to cut down on filesize, but if anyone is interested in seeing them as well, just let me know.

Probably later on tonight I'll get back to you about what my results were, thanks again for the suggestions

Edit: Replaced file with current working version, with this implemented in it, and all lyrics I currently have for anyone who is interested.


RE: Random numbers, prevent from being used more than once by roflmao456 on 07-04-2007 at 05:22 PM

another suggestion:

instead of putting the lyrics on the script (big filesize)
you can put it on a webserver then call a 'httpwebrequest' object?


RE: Random numbers, prevent from being used more than once by Volv on 07-04-2007 at 05:47 PM

quote:
Originally posted by stu
foaly, in your code, what does "count=count%9;" that line mean? Never seen that before..
The % operator is the modulo, it gives you the remainder when dividing by the number ie. the remainder when dividing count by 9. Because of the way that the function is coded, you should replace 9 with the number of lyrics you want to be displayed before you want repetition minus one (so if you want 20 lyrics you would do count%19).
RE: Random numbers, prevent from being used more than once by CookieRevised on 07-05-2007 at 12:34 AM

What is being requested can be done in essentially just 3 steps/lines of code!!

(if you don't count in 1 line for generating the initial random number and 1 line to return the new lyric, which each method would have...)

And if it wasn't for the 'undefined' problem, it would be just 2 steps/lines of code!!!!



----------------------------------------------------------------------



quote:
Originally posted by Volv
I think foaly's is the simplest working code.
Actualy foaly's method is not going to work, it is fatfreechicken's method which would be working.

The method used by fatfreechicken (although a bit overcomplicated than it needs to be) is actually a very widely used method to generate a random set of numbers in such a way that no number will be drawn twice (or trice, quar...blah, whatever. :D)...

foaly's method doesn't return anything if the randomly generated lyric already exists in the past 10 lines! His function would simply stop. And even if it was fixed to regenerate a new random number when the current one already exists instead of simply quiting (which I assume is what he wanted to do ;)), his method will be dead slow because in the worst case scenario his routine would take a very long time because it constantly draws a number/lyric which was already used before and thus it needs to regenerate a new one again. The bigger the ratio of uniqueness vs the number of lyrics is, the slower such a routine will become (eg: use his routine to generate lyrics out of 100 possible lyric lines where 99 continues lines can't have the same lyric... it would take a very long time).

roflmao456's method simply fills some random items of an array (not even all items for that matter).

markee's method is a variation on what I had done (though I didn't posted this yet because I was at work all day). But it is again overcomplicated and containes the big and slow 'regenerate until you have a valid number' kind of infinite loop like foaly....



----------------------------------------------------------------------



quote:
Originally posted by Volv
Although I think instead of:
count=count%9
You should replace it with:
count= (count==9 ? 0:count);

Because you don't want to have unnecessarily large integers being stored in memory.
it wouldn't make a difference.




----------------------------------------------------------------------



Here is my method:

(it might be possible that this is what fatfreechicken wanted to do in the first place though):

You have an array full of all the possible lyric lines (to choose from).
You have (currently an empty) array of used lyrics.

STEP 1:

Each time you draw a new random lyric line you remove that lyric line from your original array and add it to the array of used lyrics.

Now your original array wont contain that lyric line anymore.  And thus there is no need to check anything at all, you wont be able to choose it again anyways (= no unneeded and long loops like with foaly's method).

STEP 2:

Move the 10th element of the used lyrics array back to the original big array of lyrics (because you must be able to choose it again).

DONE!

Do this for as long as you want... The function would be instant, no loops at all! And it always makes sure you would have 10 different lines... thus no infinite loops, not even a slow 'check against all array elements' check...

useable directly out of the box:
code:
var arrLyrics = new Array();
var arrPrevious = new Array();
var nUniqueness = 10; // positive number, should always be lower than the total number of possible lyric lines!

function GetAllLyrics() {
        // normally you read in all the possible lyrics from a file here
        return Array("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")
}

function GetRandomLyric() {
        // get a random lyric line from the 'possible lyrics' array
        var rndLyric = Math.floor(Math.random() * arrLyrics.length);
        // step 1: add new line to 'used lyrics' array and remove it from the 'possible lyrics' array
        arrPrevious[nUniqueness-1] = arrLyrics.splice(rndLyric, 1);
        // step 2: add last lyric line from the 'used lyrics' array back to the 'possible lyrics' array
        if (arrPrevious[0] !== undefined) arrLyrics.push(arrPrevious[0]);
        // step 3: remove last lyric line from the 'used lyrics' array
        arrPrevious.shift();
        // you're done: return the new lyric line
        return arrPrevious[nUniqueness-2]
}

// EXAMPLE START (get 20 lyrics)
        arrLyrics = GetAllLyrics();
        for (var i=0; i<20; i++) {
                Debug.Trace('New lyric: ' + GetRandomLyric());
        }
// EXAMPLE END


;)


EDIT: PS: stu, don't forget to use the var statement if you use/initialize a new variable inside a function. Not doing so will make that variable a global variable instead of a local variable.
RE: Random numbers, prevent from being used more than once by stu on 07-05-2007 at 12:51 AM

Ok, so like CookieRevised said, the suggestions made did not work.. so I guess its not just me not being able to get them to work, lol. Cookie, I will give yours a try now, it looks like I will need to make a few adjustments to it to make it work with my script though, so I'll let you know how that turns out, thanks :)


RE: Random numbers, prevent from being used more than once by CookieRevised on 07-05-2007 at 12:55 AM

quote:
Originally posted by stu
Cookie, I will give yours a try now, it looks like I will need to make a few adjustments to it to make it work with my script though
I don't see what you need to adjust...

The function GetRandomLyric() can be used without any modification, as long as your lyrics array is named 'arrLyrics'.

The build-in lyrics array you have in your script (named Text[]) can simply be overwritten with the array read from the file (named Lines[]). You don't need two different arrays for that. Name them both arrLyrics[], stick in the routine I showed and you're done...

PS: and make your 'FileToArray' code as a seperate function and let it simply return an array so you can do:
if (which === 0) arrLyrics  = FileToArray('C:\\quotes.txt'));
or, to preserve the contents of the existing array also:
if (which === 0) arrLyrics.concat(FileToArray('C:\\quotes.txt'))

;)



code:
function FileToArray(sFileName) {
        var arrTemp = new Array();
        var oFSO = new ActiveXObject("Scripting.FileSystemObject")
        if (oFSO.FileExists(sFileName)) {
                var oFile = oFSO.OpenTextFile(sFileName, 1);       
                while(!oFile.AtEndOfStream) {
                        var sLine = oFile.ReadLine().replace(/^\s+|\s+$/g,'');
                        if (sLine !== '') arrTemp.push(sLine);
                }
                oFile.Close();
        }
        return arrTemp;
}


quote:
Originally posted by stu
Ok, so like CookieRevised said, the suggestions made did not work..
they work, but it can be done in a much shorter and faster way.

RE: Random numbers, prevent from being used more than once by stu on 07-05-2007 at 01:03 AM

my array is called Text, so i renamed your code appropriately, as well as your random number variable, to Number, as it is in my code (I attached my code in one of my previous posts, if you havent seen it).  So right now other then that, its just copied straight in, and it doesnt seem to be working, or returning any lyric for that matter, just undefined. Going to further look into it now..


RE: Random numbers, prevent from being used more than once by CookieRevised on 07-05-2007 at 01:32 AM

Seeing your code you need to do more than that...

What you've been requesting in this thread is for an array which doesn't change.

Your code shows that you also change the array completely (the which variable and use).

But in doing so, you actually make it yourself very hard...

The use of the random variable which is wrong. You check upon it inside the personalMessage() function each time you want to change the PSM. Way easier and way more efficient is that you check on it outside of the personalMessage().

And according to what which is, you create your arrLyrics[] array.

So, instead, just make an array of only the lyrics (the old case where which is 1) or make an array of only all the external files (the old case where which is 0), or make an array of everything (not currently implemented in your existing script, but extremely easy to do if you follow my advise ;)).... You don't need to have different arrays for everything, it is all the same array which you simply (re)create according to what you want... This is done in the GetAllLyrics() function in my example code.

That is why it is there; it initializes the array you're going to use. And you call that function (GetAllLyrics()) each time the user changes the script preferences (which I assume is what which eventually will reflect).

So, since the array is created outside the personalMessage() function, you don't need to bother to see from which array you draw a random line from. AND(!) the stuff you want (don't draw the same line for x times) will work.

Hence why I suggested to just rename your stuff instead. Because if you're going to change your code over time and make your code more efficient as you go, you would end up renaming your arrays and variables the same anyways...


RE: Random numbers, prevent from being used more than once by stu on 07-05-2007 at 01:55 AM

Ok, so if I was to do it as you suggest, outside my personalMessage function I would check to see what which is.. But thats not how I want the script to work though. The reason the which statement is there, is for when the script calls the personalMessage function to get a new personal message, the function can choose, by using which, if its going to be a lyric, or using my example in the script, a joke. so instead of creating 3 functions, i just have the one. the 3 functions being one that gets called on when a new personal message is displayed that chooses either joke or lyric(which would be the which statement), and one for each, the lyric and joke.  I want it to choose between a lyric and a joke each time that the script requests a new psm, and doing it outside of my function would not allow me to do so..

Anyways, I am only using the lyric method for now, I only have the which variable included for the future, if I decide to use that as well.

You keep on updating your post, lol..   

quote:
And you call that function (GetAllLyrics()) each time the user changes the script preferences (which I assume is what which eventually will reflect).

No, I didnt plan on having the which variable user defined.. thats why it is set up like it is..

Anyways, I had a question. Where you have
quote:
// EXAMPLE START (get 20 lyrics)
        arrLyrics = GetAllLyrics();
        for (var i=0; i<20; i++) {
                Debug.Trace('New lyric: ' + GetRandomLyric());
        }
// EXAMPLE END
Does that go inside my personalMessage function, or outside it like everything else?

This is what the script debugging shows
code:
New lyric: A
New lyric: B
New lyric: E
New lyric: J
New lyric: D
New lyric: K
New lyric: Q
New lyric: R
New lyric: N
New lyric: O
New lyric: G
New lyric: I
New lyric: M
New lyric: S
New lyric: P
New lyric: H
New lyric: U
New lyric: X
New lyric: W
New lyric: C
arrLyrics - F,L,T,V,Y,Z,A,B,E,J,D,K,Q,R,N,O,G
arrPrevios: I,M,S,P,H,U,X,W,C
I added two more trace routines to show the arrays also.
RE: Random numbers, prevent from being used more than once by CookieRevised on 07-05-2007 at 02:00 AM

quote:
Originally posted by stu
Ok, so if I was to do it as you suggest, outside my personalMessage function I would check to see what which is.. But thats not how I want the script to work though. The reason the which statement is there, is for when the script calls the personalMessage function to get a new personal message, the function can choose, by using which, if its going to be a lyric, or using my example in the script, a joke. so instead of creating 3 functions, i just have the one.
No, what I suggest is exactly how you want your script to work...

What you do now is exactly the same as using 3 functions, only you grouped them together into a 'parent' function. So, that isn't putting 3 functions into 1, that is just grouping 3 functions...

You're really making it difficult for yourself in the way you do it now ;)

quote:
Originally posted by stu
I want it to choose between a lyric and a joke each time that the script requests a new psm, and doing it outside of my function would not allow me to do so..
in that case you do not need the which checking, seperate arrays, and all that other stuff at all. Just concat the lyrics array with your quotes array and be done with it. In other words, you're REALLY making it WAY hard on yourself :P...

(and hence my initial suggestion to not alter my example routine at all but instead optimizing your code!).



-------------------

In a nutshell you would have:
code:
var Text = new Array(); // build in array or whatever... though I would indeed never ever build in a big array like that!
Text[0] = "blah1";
Text[1] = "blah2";

var arrLyrics = new Array(); // Working array
var arrPrevious = new Array(); // working array
var nUniqueness = 10; // magic


function GetAllLyrics(nWhich) {
        arrPrevious = new Array();
        switch (nWhich) {
                // use the external file quotes
                case 0: return FileToArray("C:\\quotes.txt")
                // use the internal lyrics
                case 1: return Text
                // use both
                case 2: return FileToArray("C:\\quotes.txt").concat(Text)
       
        }
}


function personalMessage() {
        Debug.Trace ("Started Personal Message");
        if (randomlyric==1) {
                var rndLyric = GetRandomLyric();
                Messenger.MyPersonalMessage = "( 8)" + rndLyric;       
                MsgPlus.DisplayToast("New Random Lyric", "( 8)" + rndLyric, null, 'OnToastClick', null);
                MsgPlus.AddTimer('randomtext', timer);
                Debug.Trace ("Printed personal message - " + rndLyric);
       }
}

function GetRandomLyric() {
etc...
etc...

Which is extremely shorter than what you have now....

GetAllLyrics() is called wherever you have your routine when the user changes the option from "quotes" to "lyrics" or to "both"....

And if you never want to implement a feature where the user can choose from which arrays the random line should be taken, you could simply only use case 2 from GetAllLyrics(). Aka: concatenate all the arrays you're going to use FIRST. Once that is done you don't need to be bothered about stuff like if (which = x) or whatever else...

----------------------------------

quote:
Originally posted by stu
Anyways, I had a question. Where you have
quote:
// EXAMPLE START (get 20 lyrics)
        arrLyrics = GetAllLyrics();
        for (var i=0; i<20; i++) {
                Debug.Trace('New lyric: ' + GetRandomLyric());
        }
// EXAMPLE END
Does that go inside my personalMessage function, or outside it like everything else?
That is example code. Code to show how you would use the above functions...
RE: Random numbers, prevent from being used more than once by stu on 07-05-2007 at 02:18 AM

Ok, Im not too worried about the which statement right now, its just redundant code in my script for right now, and I have actually just taken it out, I probably wont use it, but I was playing around with it earlier. But anyways, I still cant seem to get this to work.. all I am still getting is "undefined" for my lyric.. I have ttried putting your code straight in, and playing around with it, cant seem to get it. Havent tried anyeverything, but maybe you've got an idea to speed up the process?

quote:
in that case you do not need the which checking, seperate arrays, and all that other stuff at all. Just concat the lyrics array with your quotes array and be done with it. In other words, you're REALLY making it WAY hard on yourself ...

(and hence my initial suggestion to not alter my example routine at all but instead optimizing your code!).
Yes, I could very well do that, and the reason I did not was that if, going by my example again, I used lyrics, and jokes, they would be displayed different, by adding (8) in front of the lyric, and probably not adding anything to the joke. If i just had them all together, the jokes would also have (8) in front of them.. that is why they are seperate...

Also, I did try to change my initial code to match yours, but as far as I got it didnt work, and then you said something about using my code that I had already, so I changed it all back, lol. I think I am running around in circles.

quote:
That is example code. Code to show how you would use the above functions...
Yes, I realize that is just example code, I was just trying to clarify if that would go inside my function or not, because it did not seem so when you originally posted it.

RE: Random numbers, prevent from being used more than once by CookieRevised on 07-05-2007 at 02:32 AM

I think the problem you have is that you're thinking too much about seperate arrays and making it so that your code switches between arrays, checks stuff, etc.... You're focussing too much on that. Forget about all that. You only need 1 array to work with, nothing more. And that array should only be (re)created when the user enables the "change PSM to random line" feature of your script.

What you need to do in the main code is getting a random line out of 1 array. What that array contains is of no concearn anymore as that array was created and filled at the beginning of your script (aka: when the user changed options). As such it could contain quotes, lyrics, the lines from 5 external files, only the lines from 1 external file, or whatever else you (or the user) wants, combinations of stuff, it doesn't matter.

1) script initializes (or user enabled the feature of the script or whatever): create the array.
2) When timer triggers and PSM must change: read random line from the array. No need to check anything, you already have your array...
;)


quote:
Originally posted by stu
quote:
in that case you do not need the which checking, seperate arrays, and all that other stuff at all. Just concat the lyrics array with your quotes array and be done with it. In other words, you're REALLY making it WAY hard on yourself ...

(and hence my initial suggestion to not alter my example routine at all but instead optimizing your code!).
Yes, I could very well do that, and the reason I did not was that if, going by my example again, I used lyrics, and jokes, they would be displayed different, by adding (8) in front of the lyric, and probably not adding anything to the joke. If i just had them all together, the jokes would also have (8) in front of them.. that is why they are seperate...
No it wouldn't.

That's what I mean with "you're thinking to much about seperate arrays"...

If you want to show "(8)" in front of lyrics, then add "(8)" to each lyric line when you create the array, not when you are showing stuff...

So the array would contain:
"quote one"
"quote two"
"(8) lyric one"
"(8) lyric two"
":) joke one"
":) joke two"

You don't need seperate arrays....

In that same matter you can instead add 1 character as an identifiers to each line you add to the array to indicate 'special stuff' to be done when you actually show a line (eg: "Q" for a quote, "L" for a lyric, etc). The point is: you're doing stuff inside the "show it" routine which should actually be done before you show it, not during it...

;)
RE: Random numbers, prevent from being used more than once by Volv on 07-05-2007 at 02:45 AM

quote:
Originally posted by CookieRevised
Actualy foaly's method is not going to work
It works perfectly fine for generating the random number without repetition until 10 others have been selected.
quote:
Originally posted by CookieRevised
foaly's method doesn't return anything if the randomly generated lyric already exists in the past 10 lines! His function would simply stop.
Yes it does, it's a recursive function if you look closely. If the line exists it simply calls itself again until it returns a new number.
quote:
Originally posted by CookieRevised
quote:
Although I think instead of:
count=count%9
You should replace it with:
count= (count==9 ? 0:count);

Because you don't want to have unnecessarily large integers being stored in memory.
it wouldn't make a difference.
I already said this in the edit about 8 hours ago =/


Granted, the theory behind your idea is much more intelligent and efficient you shouldn't be dissing people's suggestions without first understanding them :(
RE: Random numbers, prevent from being used more than once by stu on 07-05-2007 at 02:51 AM

Ok, true enough, if I want to take the extra time to change that now, and each future one as I add it. I am just going to leave that for now though. As I said, I have now cut out the which statement alltogether, and am using just the Text array so its not a huge deal right now, to me..

I still cant get this to work though, when it calls the GetRandomLyric function,nothing seems to happen, and it just returns "undefined"..

Edit: Looks like I was missing a line of code, my bad.. testing it out now..

quote:
quote:
--------------------------------------------------------------------------------
Originally posted by CookieRevised
Actualy foaly's method is not going to work
--------------------------------------------------------------------------------


It works perfectly fine for generating the random number without repetition until 10 others have been selected.

I tried his method as well, but could not get that to work. If you think it can, that would be great if you could think of a way for me to figure it out, always better to know more than one method..
___________________________________________________________

Ok, so I got it to display a lyric. when the lyric is chosen, it is removed from the array, and added into arrPrevious (but it only seems to stay there for one lyric, see debuging). After 10 lyrics though, they dont get added back into the original array. Here is what the script debugger shows.. As you can see, my Text array consists of 12 Tests..
quote:
Started Personal Message
Printed personal message - Test 10
ArrPrevious - ,,,,,,,,Test 10
ArrLyrics - Test 1,Test 2,Test 3,Test 4,Test 5,Test 6,Test 7,Test 8,Test 9,Test 11,Test 12
Started Personal Message
Printed personal message - Test 8
ArrPrevious - ,,,,,,,,Test 8
ArrLyrics - Test 1,Test 2,Test 3,Test 4,Test 5,Test 6,Test 7,Test 9,Test 11,Test 12
Timer = 15000
Started Personal Message
Printed personal message - Test 9
ArrPrevious - ,,,,,,,,Test 9
ArrLyrics - Test 1,Test 2,Test 3,Test 4,Test 5,Test 6,Test 7,Test 11,Test 12
Timer = 15000
Started Personal Message
Printed personal message - Test 5
ArrPrevious - ,,,,,,,,Test 5
ArrLyrics - Test 1,Test 2,Test 3,Test 4,Test 6,Test 7,Test 11,Test 12
Timer = 15000
Started Personal Message
Printed personal message - Test 11
ArrPrevious - ,,,,,,,,Test 11
ArrLyrics - Test 1,Test 2,Test 3,Test 4,Test 6,Test 7,Test 12
Timer = 15000
Started Personal Message
Printed personal message - Test 2
ArrPrevious - ,,,,,,,,Test 2
ArrLyrics - Test 1,Test 3,Test 4,Test 6,Test 7,Test 12
Timer = 15000
Started Personal Message
Printed personal message - Test 1
ArrPrevious - ,,,,,,,,Test 1
ArrLyrics - Test 3,Test 4,Test 6,Test 7,Test 12
Timer = 15000
Started Personal Message
Printed personal message - Test 4
ArrPrevious - ,,,,,,,,Test 4
ArrLyrics - Test 3,Test 6,Test 7,Test 12
Timer = 15000
Started Personal Message
Printed personal message - Test 7
ArrPrevious - ,,,,,,,,Test 7
ArrLyrics - Test 3,Test 6,Test 12
Timer = 15000
Started Personal Message
Printed personal message - Test 3
ArrPrevious - ,,,,,,,,Test 3
ArrLyrics - Test 6,Test 12
Timer = 15000
Started Personal Message
Printed personal message - Test 12
ArrPrevious - ,,,,,,,,Test 12
ArrLyrics - Test 6
Timer = 15000
Started Personal Message
Printed personal message - Test 6
ArrPrevious - ,,,,,,,,Test 6
ArrLyrics -
Timer = 15000
Started Personal Message
Printed personal message -
ArrPrevious - ,,,,,,,,
ArrLyrics -
Timer = 15000

RE: Random numbers, prevent from being used more than once by CookieRevised on 07-05-2007 at 03:07 AM

quote:
Originally posted by Volv
quote:
Originally posted by CookieRevised
Actualy foaly's method is not going to work
It works perfectly fine for generating the random number without repetition until 10 others have been selected.
sorry for missing the recursive bit.
quote:
Originally posted by Volv
I already said this in the edit about 8 hours ago =/
quote:
(though I didn't posted this yet because I was at work all day)

quote:
Originally posted by Volv
you shouldn't be dissing people's suggestions without first understanding them :(
ermm.... first of all I'm not dissing anything, I'm trying to explain things. Big difference... Second, yes, I missed the recursive bit of foaly's method, but that is still not dissing or not understanding stuff. Seeing all the stuff I wrote in this thread I think it is clear I understand how the suggested stuff works. In fact, in that same first post of mine you quoted from, I also explained foaly's method and what disadvantage it has. The reason I missed the recursive bit was not because I don't understand what he wrote, it was because it I saw what "method" he used, not what exact "code" he wrote (hard to explain though).

If I would be dissing stuff I wouldn't take the hours of time I already put into this to explain stuff... I would simply say it is crap or something (and thus wouldn't say anything at all)...

:/



quote:
Originally posted by stu
Ok, true enough, if I want to take the extra time to change that now, and each future one as I add it.
You don't need to change all your saved files, you can do it inside the code when you create the array... If you read lines from a "jokes" file, add the smilie, if it is from a "lyrics" file, add the note, etc...

quote:
Originally posted by stu
Ok, so I got it to display a lyric. when the lyric is chosen, it is removed from the array, and added into arrPrevious (but it only seems to stay there for one lyric, see debuging). After 10 lyrics though, they dont get added back into the original array. Here is what the script debugger shows.. As you can see, my Text array consists of 12 Tests..
You've not copied the code exactly as I put it (or you changed stuff too much or in the wrong way)...
RE: Random numbers, prevent from being used more than once by Volv on 07-05-2007 at 03:11 AM

quote:
Originally posted by stu
I tried his method as well, but could not get that to work. If you think it can, that would be great if you could think of a way for me to figure it out, always better to know more than one method..
code:
var arrLyrics = Array('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');

var count = 0;
var arrUsedLyrics = new Array();
function GetIndex(arrArray, intRepeatAfter) {
    var i = Math.round(Math.random()*arrArray.length);
   
    for(var j=0;j<arrUsedLyrics.length;j++){
          if(i==arrUsedLyrics[j]){
            return GetIndex(arrArray,intRepeatAfter);
          }
    }
   
    arrUsedLyrics[count]=i;
    count++;
    count=count%(intRepeatAfter-1);
    return i;
}
I don't take credit for this code - foaly's idea.
and whenever you want to pick a random element from an array you just do:
var myRandomLyrics = arrLyrics[GetIndex(arrLyrics,10)];
Where 10 is the number of lyrics after one has been chose which must be chosen before that lyric can be repeated.

NOTE: You must still only ever have 1 array (as Cookie has pointed out) otherwise you will bump into problems.
RE: Random numbers, prevent from being used more than once by stu on 07-05-2007 at 03:22 AM

Thanks Volv for the (foaly's) code, I'll try that out as well once I get Cookie's code working
___________________________________

quote:
You've not copied the code exactly as I put it (or you changed stuff too much or in the wrong way)...
Perhaps so, take a look.

This is the code as I have it.. well, the main functions...
code:
var Text=new Array();

var num=0;

Text[num++] = "Test 1";

Text[num++] = "Test 2";

Text[num++] = "Test 3";

Text[num++] = "Test 4";

Text[num++] = "Test 5";

Text[num++] = "Test 6";

Text[num++] = "Test 7";

Text[num++] = "Test 8";

Text[num++] = "Test 9";

Text[num++] = "Test 10";

Text[num++] = "Test 11";

Text[num++] = "Test 12";


///////////////////////////////////////////////////////////
//                    Script Starts here
//////////////////////////////////////////////////////////

var arrLyrics = new Array();
var arrPrevious = new Array();
var nUniqueness = 10;


function GetAllLyrics() {
arrPrevious = new Array();
return Text
}

function GetRandomLyric() {
// get a random lyric line from the 'possible lyrics' array
var rndLyric = Math.floor(Math.random() * arrLyrics.length);
// step 1: add new line to 'used lyrics' array and remove it from the 'possible lyrics' array
arrPrevious[nUniqueness-1] = arrLyrics.splice(rndLyric, 1);
// step 2: add last lyric line from the 'used lyrics' array back to the 'possible lyrics' array
if (arrPrevious[0] !== undefined) arrLyrics.push(arrPrevious[0]);
// step 3: remove last lyric line from the 'used lyrics' array
arrPrevious.shift();
// you're done: return the new lyric line
return arrPrevious[nUniqueness-2]
Debug.Trace(arrPrevious);
}


function personalMessage()
{
Debug.Trace ("Started Personal Message");
    //reading the timer value from the registry
    try{
        timer = WShell.RegRead(MsgPlus.ScriptRegPath+Messenger.MyUserId+"\\JeremysRandomSongLyricTimer");
    }
    catch(e){}

    try{
        randomlyric = WshShell.RegRead(MsgPlus.ScriptRegPath+Messenger.MyUserId+"\\JeremysRandomSongLyric");
    }
    catch(e){}
    if (randomlyric==1)
    {

       
        arrLyrics = GetAllLyrics();

        var rndLyric = GetRandomLyric();
        //Messenger.MyPersonalMessage = "( 8)" + rndLyric;
        MsgPlus.DisplayToast("New Random Lyric", "( 8)" + rndLyric, null, 'OnToastClick', null);
        MsgPlus.AddTimer('randomtext', timer);
        Debug.Trace ("Printed personal message - " + rndLyric);
        Debug.Trace ("ArrPrevious - " + arrPrevious);
        Debug.Trace ("ArrLyrics - " + arrLyrics);
       
}

RE: Random numbers, prevent from being used more than once by CookieRevised on 07-05-2007 at 03:36 AM

remove

quote:
Originally posted by stu
arrLyrics = GetAllLyrics();
Do not (re)create/(re)read the array each time you wanna change the PSM. The array should be created only once, outside of personalMessage()...

That's the major point I'm trying to make in all my posts...

Instead put that line in the initializing code of your script or in the part where the user activates the PSM changing for the first time (if that is still in the code).

;)


PS:
code:
// you're done: return the new lyric line
return arrPrevious[nUniqueness-2]
Debug.Trace(arrPrevious);
That debug line will never be executed since the function is ended before that line because of the statement 'return'.

RE: Random numbers, prevent from being used more than once by stu on 07-05-2007 at 03:45 AM

Removing that line prevents a lyric from being displayed though, even when changing the array Text to ArrLyrics.. all I get then is undefined.
I realize that debug line will not be executed, but the debug lines that I have added inside the personalMessage function now display nothing for arrPrevious, and still show the array entries for arrLyrics


RE: Random numbers, prevent from being used more than once by CookieRevised on 07-05-2007 at 03:47 AM

quote:
Originally posted by stu
Removing that line prevents a lyric from being displayed though, even when changing the array Text to ArrLyrics..
Because you need to create the array first.

Put that line in the initializing code of your script or in the part where the user activates the PSM changing for the first time (if that is still in the code). Thus outside of personalMessage()...

again (no offense though!):

You're constantly doing:
1) timer triggerd
        I) make new PSM
                a) create different arrays
                b) get random line from array

You need to do:
1) create 1 array
2) timer triggerd
        I) make new PSM
                a) get random line from array

RE: Random numbers, prevent from being used more than once by stu on 07-05-2007 at 03:55 AM

lol, ok, so lets see if I get this right.. I should remove

code:
arrLyrics = GetAllLyrics();
from my personalMessage function, but add it in where the script is first initialized from.. So that should be put in OnEvent_Signin(Email), and OnEvent_Initialize(MessengerStart). (Little bit off topic: I have copied most of this stuff from Toast Message, as it had a menu similiar to what I wanted, and then I tweaked it for myself. It has both of those functions doing the same thing, what exactly is the difference of them both, and do I really need both of them?)

Edit: I think I would need to add it to the toggle function, that switches between on and off, as well *-)

Is my thinking now correct? I think this is all beginning to make sense to me now, lol. I really must thank you for all this help :)

Edit2: So it does seem to work now, I added it to the three places mentioned above. It does make more sense having it that way, it just took a while to get it through my head, lol. Sorry for the difficulties, I blame it on myself currently being sick and not functioning properly, lol.
RE: RE: Random numbers, prevent from being used more than once by CookieRevised on 07-05-2007 at 04:23 AM

quote:
Originally posted by stu
lol, ok, so lets see if I get this right.. I should remove
code:
arrLyrics = GetAllLyrics();
from my personalMessage function, but add it in where the script is first initialized from..
yes

quote:
Originally posted by stu
So that should be put in OnEvent_Signin(Email), and OnEvent_Initialize(MessengerStart).

Edit: I think I would need to add it to the toggle function, that switches between on and off, as well *-)
Actually, you only need to add it once. Best to do this in the 'toggle' function.

The OnEvent_Signin() and OnEvent_Initialize() just need to point to the toggle function also. Because I suspect you currently have the same code in those functions also....

This is again optimizing code in a logic way, splitting things up, instead of putting many same code all over the place.

eg:
code:
function OnEvent_Initialize() {
        if (Messenger.MyStatus > 0) OnEvent_Signin();
}

function OnEvent_Signin() {
        GetUserSettings()
}

function OnEvent_SignOut() {
        SaveUserSettings();
        Toggle(false);
}

function GetUserSettings() {
        <read the user settings from the registry here, eg: should the stuff be enabled or not (= boolean value bEnabled below)>
        Toggle(bEnable);
}

function SaveUserSettings() {
        <write the user settings to the registry here>
}

function Toggle(bEnable) {
        if (bEnable) {
            arrLyrics = GetAllLyrics();
            <do some other stuff here, like starting timers or whatever>
        } else {
            <disable timers, etc>
        }
}

function personalMessage() {
        <...>
}
something like that...

In that way you only need to change stuff in one place.



quote:
Originally posted by stu
(Little bit off topic: I have copied most of this stuff from Toast Message, as it had a menu similiar to what I wanted, and then I tweaked it for myself. It has both of those functions doing the same thing, what exactly is the difference of them both, and do I really need both of them?)
You only need one of the two. The difference is only in what window it uses to get to the contactlist.

RE: Random numbers, prevent from being used more than once by stu on 07-05-2007 at 04:30 AM

Ok, thanks a lot for the help :) Glad to finally get this working. I will work on optimizing my code further.. probably would explain why I couldnt get this working trying it myself, my array kept on getting erased, now I see why.

As for only having that line of code in one place, I believe I need to keep it in the 3 places, unless I cut out one of the two functions that do the same thing. Those two are setup totally different then the toggle function by reading the registry at the start to check if the script is turned on, and toggle switches between on and off.

Again, thanks for the help


RE: Random numbers, prevent from being used more than once by foaly on 07-05-2007 at 10:57 AM

Glad you got it to work...
If you're still going to try using "my" code (still can't believe I've got my own code :P.)
Be careful that you don't try to random a number lower then the repeating value.
This will cause an infinite loop and will crash your messenger...
(You're right cookie that the loop thingy is a big disadvantage...)
The best thing to do is sticking to cookies code :) 


RE: Random numbers, prevent from being used more than once by stu on 07-05-2007 at 04:59 PM

foaly, I just finished trying your code, it did seem to be working at first, but then it gave me an error in the script debugger

quote:
Error: Out of stack space (code: -2146828260)
       File: test.js. Line: 68.
which is this line
code:
return GetIndex(Text,intRepeatAfter);
 
Also, it returned one undefined result, but I think that just has to do with the random number rounding up to a nonexistant number, as its using math.round in the code Volv provided, so thats no biggy to fix. But I think I am going to take your advice and just stick to Cookies code, so thanks a lot for the suggestion anyways :)
RE: Random numbers, prevent from being used more than once by CookieRevised on 07-05-2007 at 11:39 PM

quote:
Originally posted by stu
foaly, I just finished trying your code, it did seem to be working at first, but then it gave me an error in the script debugger
code:
Error: Out of stack space (code: -2146828260)
       File: test.js. Line: 68.

Foaly used a recursive function.

Recursive functions are functions which will call themselfs. eg:
code:
// when you call the next funcion with its parameter set to True, it will constantly call itself and never end.
// And after a very short while you will run out of stack space.
function DoSomething(bEnable) {
        var myString = "Hello World";
        if (bEnabled === true) {
                DoSomething(true) // let's call ourself again
        }
        Debug.Trace('the end');
}
With such functions you can create very short code and/or do very fancy stuff. eg:
- many highly optimized sorting routines like QuickSort routines are recursive.
- It is also used in many arithmetic functions, eg: calculating the factorial of a number
- And of course it is used a hell of a lot for creating Fractals.

However, there is one massive disadvantage with recursive functions: they eat memory... That is: each time the function calls itself again, the operating system needs to preserve everything and initialize the function again. This preserving is done by temporarly placing everything from that function in memory, the so call 'stack space'. Only when an iteration of a function is ended, the temporary used stack space for that individual iteration is freed. And the problem is that stack space is very limited...

So, if a function calls itself a bit too much, the operating system will run out of stack space, and you'll recieve that error...

And because Foaly's method uses such a recursive function, it has the potential danger of running out of stack space, as you just experienced.
This because it calls itself again each time it produces a random line which already exists in one of the x previous lines. I think I talked about this in one of my previous posts: This is mostly noticeable when the ratio between the number of unique lines and the total number of possible lines is very high. eg: you have 100 different lines to choose from and you don't want the same line to occur in a continues row of 99 lines. Foaly's function would in that case constantly call itself because the chance it picks an already existing line is extremely high (99/100). And the more the function calls itself, the more stack space it needs...

Thus when you use recursive functions you need to test and use them with great care.

PS: you can compare recursive functions with a 'todo list': After 5 minutes of being busy with a certain task, you start to work on another task and thus you put all the stuff from the first task in the 'busy' box. Then again after some time you start a third task, thus you put everything from task 2 in the 'busy' box on top of the stuff from the first task. Then after some times you start a 4th task, etc... Eventually the box will be full and you wont be able to put anything more in it...


quote:
Originally posted by stu
Also, it returned one undefined result, but I think that just has to do with the random number rounding up to a nonexistant number, as its using math.round in the code Volv provided, so thats no biggy to fix.
indeed, it should be math.floor... math.round should never be used to generate a random number.


;)