Howdy, Stranger!

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

math.Random(4) runs out

edited March 2014 in General Posts: 316

Hi,

So I have a variable which is obstacles. There are 4 obstacles that are generated at random using

obstacle=math.random(4)

It works and so generates randomly any combination of 1-4 but it also runs out.

In other words it creates say obstacles in the order of 3,4,1,2 and then stops working.

Is it because that is what the (4) is doing and I need another number in there, or is it because it actually creates a 0 as well and I haven't defined that?

If so how do I define that the math to do as random is between 1 and 4?

Thanks,
Major

Comments

  • IgnatzIgnatz Mod
    Posts: 5,396

    @Majormorgan - try this

    obstacle=math.random(1,4)
    
  • Posts: 316

    Thanks @Ignatz. I think it wasn't what I thought after all, but what I know now is I need to reset the position of the objects once they pass the screen so that when they are called again by the math they appear from where they are.

    I've still implemented the (1,4) so it means there is only objects 1-4 anyway. I just have to work out how to remove the object once its passed the screen and reset the xpostion.

    Thanks,
    Major

  • Posts: 316

    Ok so that's all working now.

    the interesting challange it to randomize without using the same object again, so if the current object is 1, then 1 should be left off the list somehow. Hmm.... Takes a bit of thinking...

  • IgnatzIgnatz Mod
    edited March 2014 Posts: 5,396

    @Majormorgan - why not use a table, eg

    objects={{1,math.random()},{2,math.random()},{3,math.random()},{4,math.random()}}
    table.sort(objects,function(a,b) return a[2]<b[2] end)
    

    so you have 4 mini-tables, the second item is just a fractional random number. We sort the mini tables based on these random numbers, which jumbles the numbers 1-4. Then your first object number is objects[1][1], your second one is objects[2][1], etc

    or you can delete them when you've used them, like this

    --get next object
    O = objects[1][1] --take first object number in list
    table.remove(objects,1) --remove first object from list
    --repeat the same code to get the next object
    
  • Posts: 2,161

    @Majormorgan You need the Fisher-Yates algorithm (see this write-up).

    function KnuthShuffle(n,odd)
        local l
        local o = 0
        local p = {}
        for k = 1,n do
            p[k] = k
        end
        for k = 1,n-1 do
            l = math.random(k,n)
            if l ~= k then
                p[k],p[l] = p[l],p[k]
                o = 1 - o
            end
        end
        if not odd and o == 1 then
            p[1],p[2] = p[2],p[1]
        end
        return p
    end
    

    This produces a random permutation of the numbers 1 to n. The odd parameter is to allow all permutations rather than just even permutations so you probably want to set that to true.

  • IgnatzIgnatz Mod
    Posts: 5,396

    @Andrew_Stacey - what's wrong with mine? It's way shorter!

  • Posts: 2,161

    @Ignatz In terms of lines of code, perhaps, but not in terms of what actually happens. Doing the table.sort involves some sort of sort (I think we established once that it was a quicksort) which is more expensive than is needed for this.

  • IgnatzIgnatz Mod
    Posts: 5,396

    @Andrew_Stacey - if you had 10,000 items, yes, but 4?

    I think there is value in keeping the solution as easy as possible in situations like this. But I'm quibbling. All help is good help. :)

  • Posts: 2,161

    @Ignatz Yeah, but the problem is that people don't read the label and do use these little hacks on data sets of 10,000.

  • Posts: 316

    Thank you @Ignatz and @Andrew_Stacey

    I think I actually do need to create a table version as per Ignatz' example just because my code currently is using one math formula and switches the object on stage as opposed to generates one and attach it to the stage then removes later when it's off screen.

    Saying that tables like this do give me a headache but when I understand it I'm sure it will be cool.

    I'll let you know how I get on. Wish me luck!

  • Posts: 136

    I may be misunderstanding, but I have made some simple games like comet dodgers, and when I set the x position to change I will do something like setting, in your case obstacle, in an if then statement (If obstacle == nil then obstacle = math.random(1,4) ) Then when the asteroid is off the screen I set obstacle to nil again, so it will then give it another random x position.

  • Posts: 316

    Hi, so what I have are currently 4 obstacles. I'll add up to four more later.

    The screen travels at a constant speed and you avoid the obstacles. Currently I do a math.random(1,4) to pick one of the four obstacles and then it has to wait for them to come off the screen before I generate a new obstacle.

    What I need to be able to do is let an obstacle get halfway across and then generate the next one.

    Then once the obstacle is off of the screen then it can be deleted or put back into the obstacle pool to be called upon.

  • Posts: 136

    have you considered just having 4-8 different math.random for the 4-8 different obstacles? Sometimes the simplest way is the best way. If you need to generate more obstacles this wouldn't work, but it should be easy for just 4. I would try copying and pasting then replacing data to save time.

  • dave1707dave1707 Mod
    edited March 2014 Posts: 8,064

    @Majormorgan Is this something like what you're after. Set up for 8 sprites.


    displayMode(FULLSCREEN) function setup() img1=readImage("Planet Cute:Character Boy") img2=readImage("Planet Cute:Character Cat Girl") img3=readImage("Planet Cute:Character Horn Girl") img4=readImage("Planet Cute:Character Pink Girl") img5=readImage("Planet Cute:Character Princess Girl") img6=readImage("Planet Cute:Enemy Bug") img7=readImage("Planet Cute:Gem Blue") img8=readImage("Planet Cute:Gem Green") img={img1,img2,img3,img4,img5,img6,img7,img8} -- table of sprites -- screen objects x,y,z z=0 off screen 1=left side 2=right side obj={vec3(0,0,0),vec3(0,0,0),vec3(0,0,0),vec3(0,0,0), vec3(0,0,0),vec3(0,0,0),vec3(0,0,0),vec3(0,0,0)} next() end function draw() background(40, 40, 50) for a,b in pairs(obj) do if b.z>0 then -- draw sprite on screen sprite(img[a],b.x,b.y) -- draw sprite b.x=b.x-5 -- move sprite to the left end if b.x<=WIDTH/2 and b.z==2 then -- on right side of screen b.z=1 -- 1 = now on left half of screen next() -- get next sprite not on screen end if b.x<-40 then -- off left side of screen b.x=0 -- reset everything to 0 b.y=0 b.z=0 end end end function next() local t={} -- create table for z=1,#obj do -- loop for number of objects (8) if obj[z].z==0 then -- object not currently on screen table.insert(t,z) -- put number in table end end local r=t[math.random(1,#t)] -- random number from table obj[r].x=WIDTH+20 -- starting x position obj[r].y=math.random(50,HEIGHT-50) -- starting y position obj[r].z=2 -- 2 = on right half of screen end
  • Posts: 2,161

    @dave1707 That's pretty inefficient. It can potentially loop for a long time.

  • Posts: 316

    Hi all. Thanks for the ideas and code examples. The first iteration of the game has gone off now for approval. In the next update I'll address the frequency of the obstacles I generate with some of these ideas.

    Thanks for the insights !

  • Posts: 316

    @Dave1707 thank you for your coding ideas too. I've got to rethink how I'm going to do it as there are classes for each object (there's six now) and I will add more and more. Thanks all for your help

  • dave1707dave1707 Mod
    Posts: 8,064

    @Andrew_Stacey What do you consider a long time. There are only 2 sprites on the screen at any one time. That means there are 6 sprites waiting to choose from. In landscape mode, a new sprite is picked about every 2 seconds at the speed they're going. So depending on the randomness of math.random, there's only 2 numbers out of 8 that will come up as being in use and it will have to try to pick another number. I don't consider milliseconds or less a long time every 2 seconds. From what I think the game will be doing, it isn't a time critical program that needs every CPU cycle it can get.

  • Posts: 2,161

    @dave1707 Let me rephrase my objection then: that solution doesn't scale well. As I said to Ignatz above, there's a tendency (which I share myself) to simply cut-and-paste code without looking at how applicable it is to the new circumstances. Your code is fine in the situation you describe, but wouldn't work in other similar situations.

  • dave1707dave1707 Mod
    edited March 2014 Posts: 8,064

    @Andrew_Stacey I think that's where you, I, and @Ignatz differ in the code we show. You seem to write code that can be used in any type of situation. You try to code so it covers every type of condition because you want your code to be useful to everyone no matter how complex or simple the code is they write. In other words, you want to be thorough. My code is meant to be simple and used in the situation that it's written for. @Majormorgan said he wanted to expand it to 8 sprites, so that's what I coded it for. I'm not expecting someone to take this code an use it for 100 or 1000 sprites. But if they did, then as long as the number of sprites on the screen compared to the total number of sprites is low, then this will still work OK. I'm retired, so my days of writing complex code to cover every condition is behind me. I now just code simple, use this in this situation type of code.

  • IgnatzIgnatz Mod
    Posts: 5,396

    @Andrew_Stacey - you also have to bear in mind that @dave1707 has to keep a 300 foot drive clear of snow, which doesn't leave a lot of time for optimising code :D

  • dave1707dave1707 Mod
    Posts: 8,064

    I'll give you one guess what I was doing this morning. 1 week till Spring and we had a blizzard yesterday. 30+ mph wind with snow going sideways creating drifts.

  • IgnatzIgnatz Mod
    Posts: 5,396

    @dave1707 - we had our first rain for 55 days today, 0.2mm. And our first day under 30C for as long as I can remember!

  • dave1707dave1707 Mod
    Posts: 8,064

    @Majormorgan I updated my above code. I changed the next() function to not use a while loop. I now put the number corresponding to a sprite not on the screen into a table. I then pick a number at random from that table. @Ignatz Right now I would settle for some hot days. We're you out dancing in the rain. 0.2mm amounts to what, about 3 drops in the rain guage.

  • Posts: 316

    @Dave1707 , that's a nice way to approach it, place the objects not on screen into a table to pick from. That idea is cool. I'll have a play and change my randomising engine to use that idea. Great!

    The reason I can't use the whole of your code is my engine is created in a different way. As its a constant scrolling game screen and these objects are separate classes, I'm passing data out to the classes through Init and I'm tied to quite a lot of different hit tests and game rules.

    I think for my next game I'll be building a simpler engine but for now I have to modify what I have.

    I'll work on that randomising idea for v1.1 which will have some tweaks, new obstacles and also this new randomiser which will make obstacles appear more frequently and make it more challenging.

    We've had terrible rain these past 3 weeks in England. Time for the sun to come out ;)

    Thanks
    Major

  • dave1707dave1707 Mod
    edited March 2014 Posts: 8,064

    @Majormorgan Glad to hear that you can use something from my code and good luck on your code. If you have any questions, there are a lot of people here to help.

Sign In or Register to comment.