2

I need to be able to click on a button, then have a few different names come out in a random order without any name being repeated. Displaying random names is simple enough, but I cannot avoid repeats. Here's what I have and I don't understand why it doesn't work.

<script>

var players = []
players[0] = "Billy";
players[1] = "Alex";
players[2] = "Kevin";
players[3] = "Fred";

function tournament(amount) {
    var a = 0, i = 0, place = 1;
    randomlyselect:
    while (a<amount) {
        var randomplayer = Math.floor(Math.random()*(players.length));
        if (players[randomplayer] === document.getElementById('player1').innerHTML || document.getElementById('player2').innerHTML || document.getElementById('player3').innerHTML) {
            continue randomlyselect;
            } 
        else {
            document.getElementById('player'+place).innerHTML = players[randomplayer];
            place++;
            a++;
        }
    }

}

</script>

<button onClick="tournament(4)">Tournament Results</button>

<p id="player1"></p>
<p id="player2"></p>
<p id="player3"></p>
<p id="player4"></p>

I know the problem is the if statement, but I don't know how else I would check if a name was already being displayed. If you know what's wrong with my method of checking if something was already picked or a better way of avoiding repeats please let me know.

HalfEmptyJar
  • 41
  • 1
  • 4

4 Answers4

5

var players = []
players[0] = "Billy";
players[1] = "Alex";
players[2] = "Kevin";
players[3] = "Fred";


function tournament(amount) {
  var randomOrder = shuffle(players)
  var count = Math.min(amount, randomOrder.length)
  for (var i = 0; i < count; ++i) {
    document.getElementById("player" + (i + 1)).textContent = randomOrder[i]
  }
}

// http://stackoverflow.com/a/2450976/4339170
function shuffle(array) {
  var currentIndex = array.length,
    temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}
<button onClick="tournament(4)">Tournament Results</button>

<p id="player1"></p>
<p id="player2"></p>
<p id="player3"></p>
<p id="player4"></p>
CoderPi
  • 12,985
  • 4
  • 34
  • 62
  • 1
    This is the best way of doing this, you get very good randomness because of the little algorithm (which is proven to work well). You also get to keep your array intact so you can use it more than once on the same pageload, while ensuring there won't be duplicate names – Glubus Dec 24 '15 at 09:46
  • @HalfEmptyJar if you need any help or explanation about the code please ask here in the comments – CoderPi Dec 24 '15 at 09:51
  • Why did you use "Math.min(amount, randomOrder.length)" instead of just using amount. And why did you use textContent instead of innerHTML? – HalfEmptyJar Dec 31 '15 at 09:33
  • @HalfEmptyJar Math.min(amount, randomOrder.length) just in case the array would be smaller then the amount. TextContet, well you can also use innerHTML – CoderPi Jan 01 '16 at 21:08
1

You can clone your original array and then just splice items from it one by one. This way you will guarantied get unique results each time.

var players = ["Billy", "Alex", "Kevin", "Fred"];

function tournament(amount) {
  
    var clone = players.slice(), i, player;

    for (var i = 0; i < amount; i++) {
        player = clone.splice(Math.floor(Math.random() * clone.length), 1);
        document.getElementById('player' + (i + 1)).innerHTML = player;
    }
}
<button onClick="tournament(4)">Tournament Results</button>

<p id="player1"></p>
<p id="player2"></p>
<p id="player3"></p>
<p id="player4"></p>

But be aware that since it creates a copy of the array, this approach might be not ideal in case of really big players arrays.

dfsq
  • 191,768
  • 25
  • 236
  • 258
1

Here's a generic functional method to create a new array with values of the original array in random order without duplicates:

function randomizeArrayValues(arr) {
    return String(Array(arr.length))
           .split(',')
           .map(
              function () {
                return this
                       .splice(Math.floor((Math.random()*this.length)), 1)
                       .pop();
              }, 
              arr.slice()
    );
}

// example
// -------
var players = ["Billy", "Alex", "Kevin", "Fred", "Mary", "Beth"];
var trial = 10;

while (trial--) {
 document.querySelector('#result').textContent += 
      randomizeArrayValues(players).join(', ') + '\n';
}
<pre id="result"></pre>
KooiInc
  • 119,216
  • 31
  • 141
  • 177
0

I'd slice each selection out of the array so it's not able to be picked again and then write it in the loop.

var randomplayer = Math.floor(Math.random()*(players.length));
players = players.slice(randomplayer, 1);

EDIT: let me write the entire function just in case there's confusion.

function tournament(){
    var place = 1;
    while(players.length > 0){
        var randomplayer = Math.floor(Math.random()*(players.length));
        document.getElementById('player'+place).innerHTML = players[randomplayer];
        players = players.slice(randomplayer, 1);
        place++;
    }
}
Donnie D'Amato
  • 3,832
  • 1
  • 15
  • 40
  • You could do this, though if OP wants to use the array again he'll have to copy the array first or do all kinds of ugly stuff. – Glubus Dec 24 '15 at 09:47
  • Since copying the array is as simple as `players.slice(0)`, I can't imagine that being an issue. – Donnie D'Amato Dec 24 '15 at 09:49
  • It's just a nerdy opinion to have on it to be honest, copying your data while your feature does not suggest it is nasty. It implies performance issues on larger scale projects though I bet for OPs problem this might even be less work. – Glubus Dec 24 '15 at 09:52
  • I guess it would depend on if the OP needs to keep the array or not, right? – Donnie D'Amato Dec 24 '15 at 09:54
  • Yes, and with the idea of that being possible, currently or in the future of OPs project, it is better to write code that does not bring side effects with it, rather than code that does. – Glubus Dec 24 '15 at 10:05