0

Hi everyone
Can't figure out how can I take element from array in a random way and without repeating. Here is my code:

var letters = [ "A", "A", "B", "B", "C", "C", "D", "D", "E", "E",
           "F", "F", "G", "G", "H", "H", "I", "I", "J", "J" ],
cards = document.getElementsByClassName( "cards" ),
cardBoxes = document.getElementsByClassName( "card-boxes" );


//generate random number
function randomNum( nums ) {
 return Math.floor( Math.random() * nums.length );
}


//hide letter behind card in random way
function hideLetter() {
 for ( var i = cards.length - 1; i >= 0; i-- ) { 
   var randomLetter = letters[ randomNum(letters) ];
   cards[i].textContent = randomLetter;
 };
}
hideLetter();

I take element in a random way, but Math.random repeating themselves. I think I have to write some sort of if statment, which will be detect if element was taken two times, but cant figure how to do it. Looking for advice. Thanks.

Here Codepen of problem http://codepen.io/Kuzyo/pen/vdlai

kuzyoy
  • 99
  • 10

4 Answers4

2

The sure way is to remove element from the array after it was used. This way it will never be repeated

Yuriy Galanter
  • 38,833
  • 15
  • 69
  • 136
2

randomise your array, then walk through the randomised array. This has the benefit of the usual "remove elements while using random indices", while keeping the sequence around in case you need a repeat operation that relies on the same random sorting:

function randomize(array) {
  var copy = array.slice(),
      random = [],
      element, pos;
  while(copy.length>0) {
    pos = (Math.random()*copy.length) | 0; // bit operation forces 32-bit int
    subarray = copy.splice(pos, 1);
    random.push(subarray[0]);
  }
  return random;
}

var letters = [ "A", "A", "B", "B", "C", "C", "D", "D", "E", "E",
       "F", "F", "G", "G", "H", "H", "I", "I", "J", "J" ],
    randomLetters = randomize(letters);

randomLetters.forEach(function(letter) {
  // create a card for this letter
});

// do we need it again, in a new random fashion?
// then we can simply call this:
randomLetters = randomize(letters);
Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
1

Here is my version, with a generator. The function returned by makeRandomGenerator will return random, non-repeating members of inputArray. Once all elements have been used, it will return undefined.

function shuffle(array) {
  return array.sort(function() {
    return Math.random() > 0.5 ? 1 : -1;
  });
}

function makeRandomGenerator(inputArr) {
  var arr = inputArr.slice(0);
  shuffle(arr);

  return function() {
    return arr.pop();
  }
}

to use:

var letterGenerator = makeRandomGenerator(letters);

function hideLetter() {
 for ( var i = cards.length - 1; i >= 0; i-- ) { 
   var randomLetter = letterGenerator();
   if (randomLetter === undefined) {
     return;
   }
   cards[i].textContent = randomLetter;
 };
}
hideLetter();
sabof
  • 8,062
  • 4
  • 28
  • 52
0

Randomize the array and shift off values from the array :

var letters   = [ "A", "A", "B", "B", "C", "C", "D", "D", "E", "E", "F", "F", "G", "G", "H", "H", "I", "I", "J", "J" ],
    cards     = document.getElementsByClassName( "cards" ),
    i         = letters.length, j, temp;

while ( --i ) {
    j = Math.floor( Math.random() * (i - 1) );
    temp = letters[i];
    letters[i] = letters[j];
    letters[j] = temp;
}

for ( var i = cards.length; i--; ) { 
     cards[i].innerHTML = letters.shift();
}

FIDDLE

adeneo
  • 312,895
  • 29
  • 395
  • 388
  • Thanks @Adeneo for the help. Works like a charm. Sad that I don't properly understand how it works :( – kuzyoy Jul 27 '13 at 16:59
  • The while loop randomizes the array just once, then shift() will always get the first value in the array, but it also removes that value from the array, so next time it gets the next value etc. that way it will never select the same value twice, and it's always random. – adeneo Jul 27 '13 at 17:04