最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Best way to generate random number between x and y but not between a and b - Stack Overflow

programmeradmin1浏览0评论

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.

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.

Share asked Dec 14, 2012 at 14:02 SamSam 3135 silver badges17 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 4

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.

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

Instead of having a set of forbidden rectangles, you could calculate a set of allowed rectangles. To get a random position inside any allowed rectangle, you first choose a random rectangle and then a random position inside that chosen rectangle.

When the retangles don't have an equal size, you need to weight them by area, otherwise smaller rectangles will have a higher density than larger ones (a 200x100 rectangle needs to be 100 times as likely as a 10x20 rectangle).

Just generate those numbers between (0,0) and (1,1) and then use some linear function to do the mapping.

Otherwise, divide the area where you want the random coordinates to fall in rectangles. Let's say you obtain N such rectangles. Each of those rectangles may be populated through mapping the output of a random generator betweeen (0,0) and (1,1) to that rectangle (this is a linear mapping).

发布评论

评论列表(0)

  1. 暂无评论