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

tintrantintran Member Posts: 453
edited July 2015 in Working with GS (Mac)

first I was trying to create something that this question asked for
http://forums.gamesalad.com/discussion/88101/how-do-i-choose-a-random-number-without-choosing-the-same-one-again#latest
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.

Comments

  • ArmellineArmelline Member, PRO Posts: 5,327

    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.

  • tintrantintran Member Posts: 453

    @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.

  • ArmellineArmelline Member, PRO Posts: 5,327
    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.

  • tintrantintran Member Posts: 453

    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.

  • ArmellineArmelline Member, PRO Posts: 5,327

    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.

  • tintrantintran Member Posts: 453

    @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.

  • tintrantintran Member Posts: 453

    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.

  • ArmellineArmelline Member, PRO Posts: 5,327

    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:

  • tintrantintran Member Posts: 453

    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.

  • ArmellineArmelline Member, PRO Posts: 5,327

    @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?

  • tintrantintran Member Posts: 453

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

  • ArmellineArmelline Member, PRO Posts: 5,327
    edited July 2015

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

  • tintrantintran Member Posts: 453
    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 :D

  • tintrantintran Member Posts: 453

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

  • ArmellineArmelline Member, PRO Posts: 5,327
    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.

  • GeorgeGSGeorgeGS Member, PRO Posts: 478

    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.

  • tintrantintran Member Posts: 453
    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.

  • The_Gamesalad_GuruThe_Gamesalad_Guru Member Posts: 9,922

    @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.

  • HopscotchHopscotch Member, PRO Posts: 2,782

    @The_Gamesalad_Guru said:
    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. :o

  • The_Gamesalad_GuruThe_Gamesalad_Guru Member Posts: 9,922
    edited July 2015
  • ArmellineArmelline Member, PRO Posts: 5,327

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

    While we're adding table functions, tableReset too!

  • GeorgeGSGeorgeGS Member, PRO Posts: 478

    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.

  • ArmellineArmelline Member, PRO Posts: 5,327
    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

Sign In or Register to comment.