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: 318

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

Tagged:

• Mod
Posts: 5,396

@Majormorgan - try this

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

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: 318

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

• 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`.

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

• 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: 318

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: 318

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.

• Mod
edited March 2014 Posts: 9,725

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

``````displayMode(FULLSCREEN)

function setup()
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: 318

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: 318

@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

• Mod
Posts: 9,725

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

• Mod
edited March 2014 Posts: 9,725

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

• 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

• Mod
Posts: 9,725

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.

• 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!

• Mod
Posts: 9,725

@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: 318

@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

• Mod
edited March 2014 Posts: 9,725

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