Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Make random (short range) more randomized
Started by stalxerhd Jan 14 2020 12:33 AM

- - - - -
10 replies to this topic
[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

stalxerhd

[GLOBAL: userInfoPane.html]
stalxerhd
  • Observer

  • 23 posts
  • Corona SDK

I have levels where the math.random works between numbers 1-3, 1-5, and periodically (not always but in 25-30 % cases) the math.random creates a series of the same repeating numbers, five or even seven in a row at a time.

 

For me, this is a problem. Is there a way to somehow improve the randomizing mechanics?

 

For example, I don't request idle 1, 2, 3, 1, 2, 3 random generating but I also don't need 1, 1, 1, 1, 2, 1, 1 random, which periodically quite often happens.



[TOPIC: post.html]
#2

nick_sherman

[GLOBAL: userInfoPane.html]
nick_sherman
  • Corona Geek

  • 1,913 posts
  • Corona SDK

I've been doing some C64 programming lately and this problem with random numbers is even more pronounced on that machine, can often get 'stuck' on a particular value for 10, 11, 12 iterations.

 

I did a couple of things to get round this:

 

Have a variable that increases every frame, as it's 8-bit it loops round when it reaches 256. I add this to the 'generated' random number. This can work quite well as long as there's no particular pattern to when you request numbers.

 

I also change this number based on user input - i.e. every time they move the joystick right, it increases by x, every time they press fire it decreases by y. 

 

Another option is to have a lookup table which repeats 1, 2, 3 say 32 times. Generate a random number between 1-96 and use this to get the value in the table. 



[TOPIC: post.html]
#3

nick_sherman

[GLOBAL: userInfoPane.html]
nick_sherman
  • Corona Geek

  • 1,913 posts
  • Corona SDK

I have also used this random number generator when I needed seeded values that would be the same whether running on iOS, Android or Desktop. No idea whether it gives a better distribution than math.random but might be worth a go?

 
-- "GameRand.lua"
--
-- This is an implementation of a md5 based
-- pseudo random number generator which creates the same
-- sequence of values for implementations on different
-- platforms (Hans Raaf)
 
-- copy what we need as local
local floor = math.floor
local byte = string.byte
local sub = string.sub
local random = math.random
local tostring = tostring
local assert = assert
 
local crypto = require('crypto')
 
local digest = crypto.digest
local md5 = crypto.md5
 
-- make it into a module
module(...)
 
-- All functions are local and used only inside the objects I create
 
local randInt = function(self, min, max)
    assert(self.pos > 0) -- is 0 if neither seed nor randomize was called
    assert(max - min < 256 and max - min > 0) -- only possible values
    if self.pos > 16 then
        self.digest = digest(md5, self.digest, true)
        self.pos = 1
    end
    local x = floor(byte(sub(self.digest, self.pos, self.pos))
            * (max - min + 1) / 256) + min
    self.pos = self.pos + 1
    self.my_step = self.my_step + 1
    return x
end
 
local seed = function(self, s)
    self.my_step = 0
    self.my_seed = s
    self.digest = digest(md5, self.my_seed, true)
    self.pos = 1
end
 
local randomize = function(self)
    self:seed(tostring(random()))
end
 
local step = function(self, step)
    assert(self.pos > 0) -- is 0 if neither seed nor randomize was called
    -- fast forward to a position
    local i
    -- shortcut for full 16 steps
    for i = 1, floor(step / 16) do
        self.digest = digest(md5, self.digest, true)
        self.pos = 1
        self.my_step = self.my_step + 16
    end
    -- set the offsets to the right position
    self.pos = self.pos + step % 16
    self.my_step = self.my_step + step % 16
end
 
 
return function()
-- create a new Object :)
    return {
        my_step = 0,
        my_seed = nil,
        digest = nil,
        pos = 0,
        randInt = randInt,
        seed = seed,
        randomize = randomize,
        step = step
    }
end
 
 


[TOPIC: post.html]
#4

ldurniat

[GLOBAL: userInfoPane.html]
ldurniat
  • Contributor

  • 400 posts
  • Corona SDK

Hi @stalxerhd,

 

Try

math.randomseed( os.time() )

local prev_rand_index = 0
for i=1, 10 do
  repeat
    rand_index = math.random(3) 
  until rand_index ~= prev_rand_index 
  prev_rand_index = rand_index
  print( rand_index )
end 

Have a nice day:)

ldurniat

 



[TOPIC: post.html]
#5

pixec

[GLOBAL: userInfoPane.html]
pixec
  • Contributor

  • 102 posts
  • Corona SDK

if you force that two numbers next to each other cant be the same, then the outcome is much less random. In @idurniat’s code, if you had 3 numbers long sequence, then only the first number has 1/3 chance of being 1, 1/3 of being 2 and 1/3 of being 3. Afterwards the chances are only 1/2 and 1/2, so randomness clearly suffers.


For better random, get better seed. All computer random numbers are pseudo random, ie not random. But if you restrict them, then it gets much worse.

[TOPIC: post.html]
#6

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,613 posts
  • Corona SDK

You can also use a shuffle bag.

 

https://roaminggamer.github.io/RGDocs/pages/SSK2/libraries/shufflebag/

local bag = ssk.shuffleBag.new( 1,2,3,4,5 )

print( bag:get() ) -- guaranteed 1..5
print( bag:get() ) -- guaranteed 1..5; non-repeating
print( bag:get() ) -- guaranteed 1..5; non-repeating
print( bag:get() ) -- guaranteed 1..5; non-repeating
print( bag:get() ) -- guaranteed 1..5; non-repeating
print( bag:get() ) -- guaranteed 1..5; may repeat last




[TOPIC: post.html]
#7

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Corona Geek

  • 1,103 posts
  • Corona SDK

@Idurniat's suggestion is good if all you want is to avoid having the same number twice in a row. However, as the original question was "how to make a sequence of numbers more randomised", this function makes the sequence deterministic instead of random.

 

The equation for possible outcomes these simple sequences would be N^M, where N is the possible outcomes for each number and M is the amount of numbers in a given sequence. For instance, if you have five numbers in a sequence between the values of 1 and 3, then N = 3 and M = 5, for 3^5 = 243.

 

If you insist that two consecutive numbers can't be the same, then the equation changes to N x (N-1)^(M-1). For the same five numbers in a sequence between the values of 1 and 3, the result becomes 3 x (3-1)^(5-1) = 48.

 

So, if you wish to prevent the same number from occurring twice in a row, then in the above example you can only have 48 unique sequences instead to 243 unique sequences, i.e. significantly less random.


  • Michael Flad and pixec like this

[TOPIC: post.html]
#8

pixec

[GLOBAL: userInfoPane.html]
pixec
  • Contributor

  • 102 posts
  • Corona SDK

Exactly! Thanks for the real maths!

[TOPIC: post.html]
#9

stalxerhd

[GLOBAL: userInfoPane.html]
stalxerhd
  • Observer

  • 23 posts
  • Corona SDK

Guys, thank you all for the advice. This was an interesting discussion, but I did not speak of literally two or three identical values ​​in a row.
 
The problem for me is 4-5 or more identical values ​​in a row, which happens quite often on random short ranges.
 
 
XeduR @Spyric this example is not correct, because it does not describe the probability. In your example, there are 243 search options, three of which will always have five identical numbers in a row. You can also count four identical numbers in a row from a five-element string; three and two identical numbers; but it's all combinatorics.
 
This does not mean at all that if we in lua generate 243 times a five-element array, then there will always be 3 arrays, all contain the same values. I have checked, random will give out from 0 to 8 arrays with the same values ​​(any). So this 0 to 8 is our probability. We can, of course, repeat the procedure 5,000 times, then yes, average will be 3 arrays with the same values, but this is already the law of large numbers.
 
I'm working with random () on-demand, and if I record, for example, an array of 1000 random values, there I could found 8-12 rows of five identical values ​​(any). And four is around 20-25. If unpack() and watch on it, you could found sections with a good random (when the values ​​regularly change or are repeated no more than 2 times) and bad (values ​​go one after another 4-8 times).
 
Realization of probability could be various, it is another question. Most programming languages ​​use a uniform probability distribution, which means that the generated random number can reach any point in the range with equal probability. However, in lua all this works well only on wide ranges (0-100) and large samples (more than 1000).
 
My task is exactly the opposite - a short-range and a permanent stream of random (), so I don't have a sample. I generate 1-2 objects per second, and on the screen another 6-8 objects from previous generations. And from time to time it is clearly visible that the probability is either uniform or fixated on one value.
 
Just as an example, let's say I'm playing poker and receive cards from an endless deck, open them, and all are jokers. From the point of view of probability/LLN theory, everything is correct, since the deck is infinite, then an infinite number of standard 54-card decks are shuffled in it and jokers percentage in the entire deck strictly 0.037%.
 
But the very quality of this shuffle is very, very bad since the player regularly encounters only jokers, aces or jacks, several aces or jacks of the same suit, and so on.
 
 
And I asked for some simple way to improve the operation of the random mechanism in the sense of its “shuffling”. But the discussion showed that I need to create some kind of partially randomized, partially determined algorithm.


[TOPIC: post.html]
#10

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Corona Geek

  • 1,103 posts
  • Corona SDK

@stalxerhd, the example is still correct, you are talking about a different matter.

 

Shuffling, as already talked about, can be a valid approach. Shuffling a predetermined table is a good means for controlling probabilities. Many games that I know of use this method to control drop rates.

 

For instance, if you had a game where the player has 1% chance to get a legendary item, 5% for epic, 10% for rare, 20% for uncommon and 64% for common items. If a designer wants to ensure that a player will get exactly 1% chance for a said legendary item, then they'd create an array with 100 entries and they'd shuffle it. Every time the game reaches the end of said array, it is simply reshuffled once more. This would ensure that the developer intended probabilities would remain constant and there would be no "lucky breaks" or "dice hell".


  • pixec likes this

[TOPIC: post.html]
#11

SGS

[GLOBAL: userInfoPane.html]
SGS
  • Corona Geek

  • 2,131 posts
  • Corona SDK

if math.random(1, 10) is too repetitive then try math.floor(math.random(10, 100) / 10) or even math.floor(math.random(100, 1000) / 100)




[topic_controls]
[/topic_controls]