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

335
06 февраля 2018, 11:03

Есть 10 иконок. При загрузке страницы выбираю рандомную из них и показываю

   const id =  pictures[Math.floor(Math.random() * pictures.length)];

Далее при нажатии на кнопку "показать еще" нужно чтобы функция random уже искал рандомную среди оcтавшихся pictures и так далее, пока картинки не закончатся. Когда они закончатся, все повторяется снова. Ищем рандом из 10 картинок, из 9 и т.д. Нужно сделать, чтобы картинки при рандоме не повторялись. после того как выбрали все 10 иконок (рандомно), следующая картинка (одиннадцатая) не может совпасть с последней, выбранной из первой десятки

Answer 1

Решение в лоб:

  1. Завести другой массив, из которого будем брать случайный элемент.
  2. Когда он опустеет (или если он ещё пустой), то переносить все элементы из изначального массива картинок в него.
  3. После нахождения случайного элемента, удалять элемент из этого массива.

Как-то так:

const picturesNotUsed = [];
function getRandomPicture() {
    if (picturesNotUsed.length === 0) {
        for (let i = 0; i < pictures.length; ++i) {
            picturesNotUsed.push(pictures[i]);
        }
    }
    const index = Math.floor(Math.random() * picturesNotUsed.length);
    const id =  picturesNotUsed[index];
    picturesNotUsed.splice(index, 1);
    return id;
}
Answer 2

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

function swap (list){
    let x = Math.floor(Math.random() * list.length);
    let y = Math.floor(Math.random() * list.length);
    let b = list[y];
    list[y] = list[x];
    list[x] = b;
}
const arr = [1, 2, 3, 4, 5];
for (let i = 0; i < 100; i++) // сколько раз перемешать
    swap(arr);

UPD Из комментария под предыдущим ответом: лучше использовать данную реализацию генератора случайных чисел

function randomInteger(min, max) {
    let rand = min - 0.5 + Math.random() * (max - min + 1)
    rand = Math.round(rand);
    return rand;
  }
Answer 3
//  исходный массив с айдишниками картинок
var pictures_ids = [10, 12, 15];
var id;
//  "вредный код"
Array.prototype.nextElem = function() {
    if (typeof this.current === 'undefined') {
        this.current = 0;
        return this[this.current];
    }
    this.current++;
    if (typeof this[this.current] === 'undefined') {
        this.current = 0;
    }
    return this[this.current];
};
//  получаем массив айдишников в случайном порядке
var pictures_rand = pictures_ids;
pictures_rand.sort(function(a, b){return 0.5 - Math.random()});
//  теперь где-то при нажатии на кнопку "показать еще" достаточно вызвать код
id = pictures_rand.nextElem();
alert(id);

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

Answer 4

Вариант, где не выпадают последние пять иконок и приоритет отдается иконкам, которые давно не выпадали.

const size = 10; 
let weights = Array(size).fill(10); // Вероятности выпадения иконок, изначально равны. 
 
// Возвращает индекс массива w с вероятностью, заданной значением элементов. 
function randDistr(w) { 
  let sum = w.reduce((a, b) => a + b, 0); 
  let rand = Math.floor(Math.random() * sum); 
  let i = 0; 
  for (let s = w[0]; s <= rand; s += w[i]) { 
    i++; 
  } 
  return i; 
} 
 
function getRndInx() { 
  let w = weights.map(x => x >= 5 ? x : 0); // Копируем вероятности выпадения, исключая те, у которых вероятность меньше пяти. 
  let i = randDistr(w); 
  weights = weights.map(a => ++a); // Увеличиваем на единицу вероятности для всех иконок. 
  weights[i] = 0; // Для выпавшей иконки обнуляем вероятность (не будет выпадать, пока не вырастет до пяти). 
  return i; 
} 
 
for (let i = 0; i < 30; ++i) { 
  console.log(getRndInx()); 
}

Answer 5

Upd.Пример:

<div class="a1 hidden"></div>
<div class="a2 hidden"></div>
<div class="a3 hidden"></div>
<div class="a4 hidden"></div>
<div class="a5 hidden"></div>
<button id="btn">Нажмите меня</button>
<style>
div {
    width: 50px;
    height: 50px;
}
.a1 {
    background: #FF0000;
}
.a2 {
    background: #8000FF;
}
.a3 {
    background: #1997FF;
}
.a4 {
    background: #00FF59;
}
.a5 {
    background: #EEFF00;
}
.hidden {
  display: none;
}
button {
  position: absolute;
  top: 25px;
  left: 70px;
}
</style>
<script>
let imgs = document.querySelectorAll('div');
btn.addEventListener('click', function(){
    showImg(imgs);
});
function showImg(cll){
    if(showImg.count == cll.length) {
        showImg.count = 0;
    }
    if(showImg.count == 0) {
        showImg.arr = Array.prototype.slice.call(cll);
    }
    let currentImg = generateId(showImg.arr).next().value;
    if(showImg.hidden) showImg.hidden.classList.add('hidden');
    currentImg.classList.remove('hidden');
    showImg.count++;
    showImg.hidden = currentImg;
    console.log(currentImg);
}    
showImg.count = 0;
showImg.hidden = 0;
function* generateId(arr) {
        yield arr.splice(getRandomNumber(0, arr.length-1), 1)[0];
    }
function getRandomNumber(min, max) {
    if(max == 0) return 0;
    return Math.floor(min + Math.random() * (max + 1 - min));
    }
</script>
READ ALSO
Отключения JS-скрипта

Отключения JS-скрипта

Некая CMS отрисовует теги со старыми неактуальными srcВ самой CMS найти тот самый участок кода, который "пакостит" не удается

294
Как спарсить данные загруженные с iframe?

Как спарсить данные загруженные с iframe?

Есть некая форма в iframe с результатом, который загружается после загрузки некоего сайта при помощи ajax запроса

175
При загрузке страницы и нажатой ЛКМ прикрепить элемент sortable.

При загрузке страницы и нажатой ЛКМ прикрепить элемент sortable.

Суть проблемы: Нужно при загрузке страницы c Sortable Widget и нажатой ЛКМ автоматически "прикрепить" элемент к мыши, как будто это сделал пользователь...

173