Как генерировать два разных случайных числа?

мне нужно сгенерировать два разных случайных числа, они не могут быть равны друг другу или третьему числу. Я пытался использовать много if, чтобы охватить все возможности, но, похоже, мои навыки алгоритма не так хороши.

может кто-нибудь помочь мне в этом?

var numberOne = Math.floor(Math.random() * 4);
var numberTwo = Math.floor(Math.random() * 4);
var numberThree = 3; // This number will not always be 3

if((numberOne == numberThree) && (numberOne + 1 < 3)) {
    numberOne++;
} else if ((numberOne == numberThree) && (numberOne + 1 == 3)) {
    numberOne = 0;
}

if ((numberOne == numberTwo) && (numberOne+1 < 3)) {
    if (numberOne+1 < 3) {
        numberOne++;
    } else if(numberThree != 0) {
        numberOne = 0;
    }
}

это то, что у меня есть до сих пор, следующим шагом будет:

if (numberTwo == numberThree) {
    (...)
}

правильно ли я мыслю? Примечание: генерируемые числа должны находиться между 0 и 3. Спасибо заранее.

8 ответов


Вы можете запустить while цикл, пока все числа не будут разными.

// All numbers are equal
var numberOne = 3; 
var numberTwo = 3; 
var numberThree = 3; 

// run this loop until numberOne is different than numberThree
do {
    numberOne = Math.floor(Math.random() * 4);
} while(numberOne === numberThree);

// run this loop until numberTwo is different than numberThree and numberOne
do {
    numberTwo = Math.floor(Math.random() * 4);
} while(numberTwo === numberThree || numberTwo === numberOne);

вот jsfiddle с вышеуказанным кодом, основанным на предложении @jfriend00 http://jsfiddle.net/x4g4kkwc/1.

вот оригинальная рабочая демонстрация:http://jsfiddle.net/x4g4kkwc/


вы можете создать массив случайных возможностей, а затем удалить элементы из этого массива по мере их использования, выбрав будущие случайные числа из оставшихся значений в массиве. Это позволяет избежать цикла, пытаясь найти значение, которое не соответствует предыдущим элементам.

function makeRandoms(notThis) {
    var randoms = [0,1,2,3];

    // faster way to remove an array item when you don't care about array order
    function removeArrayItem(i) {
        var val = randoms.pop();
        if (i < randoms.length) {
            randoms[i] = val;
        }
    }

    function makeRandom() {
        var rand = randoms[Math.floor(Math.random() * randoms.length)];
        removeArrayItem(rand);
        return rand;
    }

    // remove the notThis item from the array
    if (notThis < randoms.length) {
        removeArrayItem(notThis);
    }

    return {r1: makeRandom(), r2: makeRandom()};
}

рабочая демонстрация:http://jsfiddle.net/jfriend00/vhy6jxja/

FYI, этот метод обычно более эффективен, чем цикл, пока вы не получите что - то новое, когда вы просите случайным образом выберите большинство чисел в диапазоне, потому что это просто устраняет ранее использованные числа из случайного набора, поэтому ему не нужно снова и снова гадать, пока он не получит неиспользуемое значение.


эта версия минимизирует количество вызовов случайных, как вы сделали, но немного проще и не предвзято. В вашей версии есть шанс 2/4, что numberOne перейдет к 0, и шанс 1/4, если перейдет к 1 и 2. В моей версии есть равные шансы numberOne в конечном итоге как 0, 1 или 2).

i0 = Math.floor(Math.random() * 4); //one of the 4 numbers in [0, 4), namely 3
i1 = Math.floor(Math.random() * 3); //only 3 possibilities left now
i2 = Math.floor(Math.random() * 2); //only two possibilities left now

x0 = i0;
x1 = i1 + (i1 >= i0 ? 1 : 0);
x2 = i2 + (i2 >= i0 ? 1 : 0) + (i2 >= i1 : 1 : 0);

это особый случай упомянутой версии deceze для перетасовки массива, но когда у вас есть только два числа


Я не уверен, что вы пытаетесь сделать (или на самом деле, почему ваш код настолько сложен, что я понял). Возможно, это не самый оптимизированный код, но вот моя попытка:

var n3 = 3;
var n2 = Math.floor(Math.random() * 4);
var n1 = Math.floor(Math.random() * 4);

while(n1 == n3)
{
    n1 = Math.floor(Math.random() * 4);
}
while (n2 == n1 || n2 == n3)
{
    n2 = Math.floor(Math.random() * 4);
}

EDIT: черт, слишком поздно ^^


var rangeTo = 4;
var uniqueID = (function () {
    var id, cache = [];
    return function () {
        id = Math.floor((Math.random() * (new Date).getTime()) % rangeTo);
        var cacheLength = cache.length;
        if (cacheLength === rangeTo) {
            throw new Error("max random error");
        };
        var i = 0
        while (i < cacheLength) {
            if (cache[i] === id) {
                i = 0;
                id = Math.floor((Math.random() * (new Date).getTime()) % rangeTo);
            }
            else {
                i++;
            }
        }
        cache.push(id);
        return id;
    };
})();

var n = 4; //to get two random numbers between 0 and 3
var n3 = 2; //for example
var n1 = Math.floor(Math.random(n-1));
var n2 = Math.floor(Math.random(n-2));
if(n1 >= n3) {
    n1++;
    if(n2 >= n3)
        n2++;
    if(n2 >= n1)
        n2++;
} else {
    if(n2 >= n1)
        n2++;
    if(n2 >= n3)
        n2++;
}

вам нужно сравнить n2 минимум n1 и n3 во-первых, чтобы убедиться, что у вас нет равенства:

предположим n1=1 и n3=2. Если вы получите n2=1 и сравните его сначала с n3, вы не увеличите n2 на первом шаге. На втором этапе вы бы увеличили его с n2 >= n1. В конце концов, n2 = 2 = n3.

этот алгоритм гарантирует равномерное распределение, и вы звоните только дважды Math.random().


имейте в виду, что спина к спине вызывает Math.random() вызывает ошибка в chrome как указано здесь, поэтому измените любой из других ответов, позвонив safeRand() ниже.:

function safeRand() {
  Math.random();
  return Math.random();
}

Это все еще не идеально, но значительно уменьшает корреляции, так как каждый дополнительный, отброшенный вызов Math.random() будет.


Как правило, в псевдо-коде я делаю:

var nbr1 = random()
var nbr2 = random()
while (nbr1 == nbr2) {
    nbr2 = random();
}

таким образом, вы получите два разных случайных чисел. С дополнительным условием вы можете сделать их отличными от другого (3-го) числа.