Search code examples
pythonmathrandompygamecube

What cubic function can I use to get a random distribution biased towards the middle


I want a circle with more circles inside it (doesn't strictly need to be inside it). The position of inner circles are determined randomly in a way that there should be most circles at the centre and less and less and it goes out towards the edge of the circle.

From this question, I gathered that numbers can be biased using f(x) instead of just x, x being the random number, of course. Here is the code:

def distBiasedMiddle(_min, _max):
    r = lambda : random.uniform(0, 1)
    r1, r2 = r(), r()
    bias = lambda _r:  _r**3 * (1 + _max - _min) + _min
    return (bias(r1), bias(r2))

testBias = distBiasedMiddle

rps = []
for i in range(100):
    rps.append(testBias(-50, 50))

while True:

    for p in rps:
         pygame.draw.circle(window, (255, 0, 0), (p[0] + 300, p[1] + 300), 2)
    pygame.draw.circle(window, (0,255,0), (300, 300), 50, 1)

For people not familiar with pygame, green circle is of radius 50 and is drawn at (300, 300) and the red circles are drawn at (p[0] + 300, p[1] + 300)

Here I used x ** 3 but It did not work. I need help picking the correct function. Here's what I got.

enter image description here

I know that the rest of the code is correct because I used another function mentioned in that answer (f(X)=2X/(1+X)) and it gives the right distribution, biased towards the higher values:

def distBiasedUpper(_min, _max):
    r = lambda : random.uniform(0, 1)
    r1, r2 = r(), r()
    bias = lambda _r: (2 * _r / (1 + _r)) * (1 + _max - _min) + _min
    return (bias(r1), bias(r2))

Solution

  • Actually you are generating random numbers in the range [0.0, 1.0] and assigning them to the range [_min, _max]. Therfore 0 is mapped to _min. As a result, there are more points near _min.
    You have to generate random numbers in range [-1.0, 1.0] and map them to the range [_min, _max]. So 0 is in the middle of the range and most of the points are near (_min + _max) / 2:

    def distBiasedMiddle(_min, _max):
        r = lambda : random.uniform(-1, 1)
        r1, r2 = r(), r()
        bias = lambda _r:  _r**3 * (_max - _min) / 2 + (_min + _max) / 2
        return (bias(r1), bias(r2))