0

I'm currently working on a script that randomly generates loadouts for Mordhau.

I'm not worried about it calculating point values at the moment, but I would like to make it so it doesn't repeat any selected perks.

I have the perks in an array:

let perks = ["Smith","Wrecker","Scavenger","Cat","Friendly","Tenacious"]; //etc etc

And, admittedly my way of selecting them is pretty clunky but it gets the job mostly done.

let p1 = perks[Math.floor(Math.random()*(perks.length))]; //perk 1
let p2 = perks[Math.floor(Math.random()*(perks.length))]; //perk 2
let p3 = perks[Math.floor(Math.random()*(perks.length))]; //perk 3

Is there a way to assign these variables (p1, p2, p3) without any repeats from the items in the array "perks"?

Thanks in advance!

anonfoxer
  • 25
  • 6
  • You could make a copy of the array, shuffle it, then `.pop()` items until it's empty. Then make another copy, shuffle it, repeat. That way you'd always go through the array before repeating - with the only chance for a repeat being if the last item of the previous array and the first item of the next array are the same - in the case of which you could just remove it or re-shuffle. – cbr Apr 11 '21 at 17:34
  • 1
    [how to shuffle](https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array/2450976#2450976) – James Apr 11 '21 at 17:36

2 Answers2

0

One approach could be to use generate random indexes until you get n distinct index from array:

function getRandomIndexes(arr, indexesCount) {
  if (indexesCount > arr.length) {
    return [];//Cant extract more items than we have in array.
  }
  const indexesSet = new Set();
  while (indexesSet.size < indexesCount) {
    indexesSet.add(Math.floor(Math.random() * arr.length));
  }
  const op = [];
  for (let index of indexesSet) {
    op.push(arr[index]);
  }
  return op;
}


let perks = ["Smith", "Wrecker", "Scavenger", "Cat", "Friendly", "Tenacious"];

let [p1, p2, p3] = getRandomIndexes(perks, 3);
console.log({p1,p2,p3})

NOTE: This approach could be terrible if arr.length is close to indexesCount, in that case cloning and shuffling might be a better approach or rather than getting n random values you can get arr.length-n random values and filter them off.

Shub
  • 2,686
  • 17
  • 26
0

Using a function would the way I would to do it without modifying the original array. Passing the number of items you want back from the array, then destructuring it on return

let perks = ["Smith", "Wrecker", "Scavenger", "Cat", "Friendly", "Tenacious"];

function dup(len) {
  const a = [];
  const arr = [...perks];
  
  for (let i = 0; i < len; i++) {
    let i = Math.floor(Math.random() * arr.length); 
    a.push(arr.splice(i, 1)[0]);
  }
  
  return a;
}

let [p1, p2, p3] = dup(3);
console.log(p1, p2, p3);

Or you could change the random number and splice it out of the array for every item you need.

let perks = ["Smith", "Wrecker", "Scavenger", "Cat", "Friendly", "Tenacious"];

const arr = [...perks];
let i = Math.floor(Math.random() * arr.length);
let p1 = arr.splice(i, 1)[0];

i = Math.floor(Math.random() * arr.length);
let p2 = arr.splice(i, 1)[0];

i = Math.floor(Math.random() * arr.length);
let p3 = arr.splice(i, 1)[0];

console.log(p1, p2, p3);
a.mola
  • 3,883
  • 7
  • 23
  • 1
    Hi, you mentioned _without modifying the original array_ however you are passing on the array `perks` to dup function and inside you are doing `splice` which affects original array, you might wanna clone array before passing it on. – Shub Apr 11 '21 at 17:53