#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# Am I doing something completely wrong or is there a bug in GS loops?

Posts: 453Member
edited July 2015

first I was trying to create something that this question asked for
I guess you could use tables or other things to do this but I'd thought I'd try to use strings of 0's and 1's to indicate which numbers were selected already.
So I made a timer, inside of which is a rule that checks to see if spawned actors < 26 to perform work.
Inside of that I have a loop that keeps selecting an actor_id to be random(1,26) until it finds the string in the flags (flags starts out as a string of 26 zeros) that is not "1" at that actor_id.
Then i know i have a good actor_id that hasn't been spawned, so i increment my spawned_actor counter and put a "1" into that actor_id position in the flag using textSubStr.
But what i am observing is that it seems to work sometimes, and other times, not.
So GS masters, please have a look and tell me what I am doing wrong.

PS: Before this, I was trying to use flags as a number (as a sum of powers of 2's to indicate which actor has been spawned).
And I would add the number pow(2,actor_id) to flags to indicate that it has been spawned.
Then I would check to see if that flag was used by doing a numerical expression of
mod(flags,pow(2,actor_id+1)) >= pow(2,actor_id) to see if that bit is a 1 or not and that didn't seem to work either that's why i have changed it to a flags of text now see if there's something wrong in my logics.

• Posts: 4,761Member, PRO

Without looking at the exact logic, I suspect you'll find running a loop inside an every timer, especially a "run to completion" timer, is going to end badly.

• Posts: 453Member

@Armelline said:
Without looking at the exact logic, I suspect you'll find running a loop inside an every timer, especially a "run to completion" timer, is going to end badly.

really? is there a reason why?
I can see it being a problem if whatever is in the timer takes longer than the interval because than another process would start...but my timer doesn't run that often, almost once every second that should be plenty of time for the previous timer run actions to finish.

• Posts: 4,761Member, PRO
edited July 2015

Okay, I've taken a look at the logic now. For what you're trying to achieve, the loop is entirely redundant. But what seems to be happening is this:

When there are 26 free "slots" to pick from, finding one set to 0 is fast and easy. As the number of free slots is reduced, finding one set to 0 becomes increasingly difficult. By the time you're picking the last one, you have a 1 in 26 chance of the spot you pick being a 0, and a 25 in 26 chance of it being a 1. So what's happening is that the loop is working at first, but by the time you get to the later slots, it's having to loop over and over and over and over and over to find a free one - which is taking longer than the time allotted (approximately 0.7s). Each iteration is taking approximately 0.03s and the time allotted is 0.77s. So sometimes it's managing, sometimes it's not.

You can avoid this limit by scrapping the loop.

In my testing, the 25th and 26th slot regularly take several seconds to be found. Theoretically, it could take forever.

• Posts: 453Member

thanks ... for you mentioning of timers and loops..
I moved the logic outside of timer and only have the timer set and spawn, moved the loop outside of timer and it seems to work all the time now.

• Posts: 4,761Member, PRO

Something like this I assume?

Probably the quickest way to do it while using default behaviours.

Do remember though that the speed this will run is entirely down to probability.

• Posts: 453Member

@Armelline said:
Something like this I assume?

Probably the quickest way to do it while using default behaviours.

Do remember though that the speed this will run is entirely down to probability.

Nope i moved the loop logic just outside of timer on its own, then moved the set flag and counter and spawned logic inside the timer.

• Posts: 453Member

although based on stats, the worse case should be running the loop 26 times since if 25 slots are picked the chance of it hitting the free spot is 1/26 so 26 times shouldn't take too long.

• Posts: 4,761Member, PRO

You definitely don't need both a loop and a timer. Using one or the other is more than sufficient.

I'd also recommend something like this:

The biggest thing slowing this method down is the 25th and 26th items needing multiple attempts to randomly pick a 0.

You can completely avoid this for the 26th item - as there's only 1 place it can be, there's no point looking for it by randomly spawning.

You can also reduce this a little for the remainder. Randomly pick from only the lowest 0 - so if the first 10 are all set to 1 already, pick from 11 upwards.

Something like this:

• Posts: 453Member

it still bugs me that you can't make it function with loop inside a timer though... I even tried to up the timer to run once every 2 seconds...and it still doesn't work properly.

• Posts: 4,761Member, PRO

@tintran said:
it still bugs me that you can't make it function with loop inside a timer though... I even tried to up the timer to run once every 2 seconds...and it still doesn't work properly.

Why would you want to?

• Posts: 453Member

never used textFind before, i'll give it some thoughts. thanks.

• Posts: 4,761Member, PRO
edited July 2015

Here's the result of using just the loop and skipping the 26th one using random:

• Posts: 453Member
edited July 2015

TextFind is pretty clever.
I used a random_find = random(1,26)
then I used
(TextFind(flags,"0",random_find) > -1) and TextFind(flags,"0",random_find) or TextFind(flags,"0",1)
so it would always find a zero at a random start index, but if it can't find one, find from index 1.
It's awesome because it's no longer dependent on probability but always constant time to seek and i can set the timer to spawn to something really short interval..
Thanks again.
TextFind skill acquired

• Posts: 453Member

hey how did you save the screenshot as a .gif file? I'd like to know

• Posts: 4,761Member, PRO
edited July 2015

I use a simple little app called LICEcap. http://www.cockos.com/licecap/

There are lots of alternatives, but that one's both Mac and PC and really quick and easy to use.

It used to be that you could upload a gif to the forums and display it, but the last few times I tried that way didn't work. So now I upload the gif to http://gfycat.com/ and then link to that.

Also I'd really recommend using the loop rather than the timer - in my testing it turned out faster (which is quite unusual!). You'll probably need to test both though and see which is faster with your current logic.

• Posts: 478Key Master, Head Chef, Member, PRO

This type of question, picking a random item from a set of items with no repeating, seems to come up fairly often.

The way you would normally do it in a programming language is to put all the items you want to choose from in a container, shuffle the container, then just pick them in order as needed. Once you get to the end of the container you could reshuffle or switch to a different set of items or whatever. A common use for this would be dealing cards from a deck.

It seems like it might be nice to make that more convenient rather than you guys reinventing the wheel every time. I do like seeing the different solutions though.

I didn't study the initial algorithm too deeply, but for the case where you're choosing the last item from a set of 26 it's true the chance is 1/26 of directly choosing it, but if you're trying to find it randomly the chance is 1/26 every time you pick, so it's not guaranteed that 26 tries will result in finding the item, it may take many more tries.

• Posts: 453Member
edited July 2015

@Armelline said:
I use a simple little app called LICEcap. http://www.cockos.com/licecap/

There are lots of alternatives, but that one's both Mac and PC and really quick and easy to use.

It used to be that you could upload a gif to the forums and display it, but the last few times I tried that way didn't work. So now I upload the gif to http://gfycat.com/ and then link to that.

Also I'd really recommend using the loop rather than the timer - in my testing it turned out faster (which is quite unusual!). You'll probably need to test both though and see which is faster with your current logic.

with (TextFind(flags,"0",random_find)>-1) and TextFind(flags,"0",random_find) or (TextFind(flags,"0",1)
I don't need a timer or loop.
I just put it in a rule that checks to see if the current actor_id points to a 1, then i execute it to find a 0 starting at a random index. It finds the random "0" in constant time number of steps.

Then I only need a timer to spawn my actors because I want it to appear over time.
The original question only required to spawn 26 actors over 20 seconds so that's plenty of time.

• Posts: 9,913Member

@GeorgeGS said:
This type of question, picking a random item from a set of items with no repeating, seems to come up fairly often.

The way you would normally do it in a programming language is to put all the items you want to choose from in a container, shuffle the container, then just pick them in order as needed. Once you get to the end of the container you could reshuffle or switch to a different set of items or whatever. A common use for this would be dealing cards from a deck.

It seems like it might be nice to make that more convenient rather than you guys reinventing the wheel every time. I do like seeing the different solutions though.

I didn't study the initial algorithm too deeply, but for the case where you're choosing the last item from a set of 26 it's true the chance is 1/26 of directly choosing it, but if you're trying to find it randomly the chance is 1/26 every time you pick, so it's not guaranteed that 26 tries will result in finding the item, it may take many more tries.

Yes @tatiang built something similar using tables. I use that method often.

i like the old method also of storing the last number selected an forcing another shuffle when the last two selections match. Pretty easy to do and efficent.

• Posts: 2,782Member, PRO

It seems like it might be nice to make that more convenient rather than you guys reinventing the wheel every time. I do like seeing the different solutions though.

Yep, would be so fantastic to extend the table functions by adding:

TableShuffle( table )
TableSort( table , colnumber )

It would almost be too fantastic, depriving keen fledgling developers of the need to learn some of the most fundamental coding skills.

• Posts: 9,913Member
edited July 2015

@Hopscotch said:

Hey I sound like George..lmao

• Posts: 4,761Member, PRO

@Hopscotch said:
It would almost be too fantastic, depriving keen fledgling developers of the need to learn some of the most fundamental coding skills.

While we're adding table functions, tableReset too!

• Posts: 478Key Master, Head Chef, Member, PRO

Yeah, I can see sort having some use as well. I think there was a question about how to figure out the rankings in a racing game, and sort would make it so simple.

What would reset do? Reset to the original contents? I'm not familiar enough with how the tables work to know if we actually have the original data in all cases.

• Posts: 4,761Member, PRO
edited July 2015

@GeorgeGS said:
What would reset do? Reset to the original contents? I'm not familiar enough with how the tables work to know if we actually have the original data in all cases.

Yes, reset to the "default" contents. It would be helpful for any situation where we currently have to make a duplicate table and copy it over to the "working" table in order to reset the table's state.

If we're talking about new functions, I'd also love to see:

textUpper
textLower

Also, being able to do things like find the digits in a string would be great, so more of this: http://www.lua.org/pil/20.2.html