Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to generate random number between x and y but not between a and b

I have a canvas that is 1000x600px. I want to spawn sprites outside the canvas (but evenly distributed). What is the best way to retrieve random values between (-500, -500) and (1500, 1100) but not between (0, 0) and (1000, 600)? I understand a while loop could be used to generate numbers until they are in range but that seems superfluous. Thanks.

like image 883
Sam Avatar asked Dec 03 '25 17:12

Sam


2 Answers

If you want to generate a number between -500 and 1500, excluding 0 to 1000, you can just generate a number between 0 and 1000 ( 0 - -500 + 1500 - 1000).

If the number is less than 500, you subtract 500; if the number is greater or equal to 500, add 500.

Or, more generically:

function randomInt(outerMin, outerMax, innerMin, innerMax)
{
    var usableRange = innerMin - outerMin + outerMax - innerMax,
    threshold = innerMin - outerMin,
    num = Math.floor(Math.random() * (usableRange + 1));

    if (num < threshold) {
        return num - threshold;
    } else {
        return num - threshold + innerMax;
    }
}

randomInt(-500, 1500, 0, 1000);

For two-dimensional points you have to get more creative. First, you generate two points that ARE inside the forbidden area and then spread those values to the good areas:

function randomVector(outer, inner)
{
    var innerWidth = inner.right - inner.left,
    innerHeight = inner.bottom - inner.top,
    x = Math.floor(Math.random() * (innerWidth + 1)),
    y = Math.floor(Math.random() * (innerHeight + 1)),
    midx = Math.floor(innerWidth / 2),
    midy = Math.floor(innerHeight / 2);

    if (x < midx) { // left side of forbidden area, spread left
        x = x / midx * (inner.left - outer.left) - inner.left;
    } else { // right side of forbidden area, spread right
        x = (x - midx) / midx * (outer.right - inner.right) + inner.right;
    }

    if (y < midy) { // top side of forbidden area, spread top
        y = y / midy * (inner.top - outer.top) - inner.top;
    } else { // bottom side of forbidden area, spread bottom
        y = (y - midy) / midy * (outer.bottom - inner.bottom) + inner.bottom;
    }

    // at this point I'm not sure how to round them
    // but it probably should have happened one step above :)
    return {
        x: Math.floor(x),
        y: Math.floor(y)
    }
}

randomVector({
    left: -500,
    top: -500,
    right: 1500,
    bottom: 1100
 }, {
    left: 0,
    top: 0,
    right: 1000,
    bottom: 600
 });

Important

This works because the areas outside of your "forbidden" area are equal in their respective dimension, i.e. padding-top == padding-bottom && padding-left == padding-right.

If this will be different, the distribution is no longer uniform.

like image 200
Ja͢ck Avatar answered Dec 06 '25 06:12

Ja͢ck


Generate a random number between 0 and 1000, if its over 500 add 500 (or 600 respectivly) if not negate it.

like image 31
odinthenerd Avatar answered Dec 06 '25 08:12

odinthenerd



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!