I have seen that this method you are using to "shuffle" the array, is not very indicated, see this post from the English OS:
link
[community edit: This answer is incorrect; see comments. It is being left here for future reference because the idea is not that rare.]
[1,2,3,4,5,6].sort(function() {
return .5 - Math.random();
});
So I took another answer to the same question in English OS:
How to randomize (shuffle) a JavaScript array?
link
To mount this function:
function shuffle(array) {
var currentIndex = array.length;
var newArray = array.slice();
var 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 = newArray[currentIndex];
newArray[currentIndex] = newArray[randomIndex];
newArray[randomIndex] = temporaryValue;
}
return newArray;
}
I also created this other function:
function getPessoaSorteada(pessoas, pessoasSorteadas) {
if (pessoasSorteadas.length == 0)
pessoasSorteadas = shuffle(pessoas);
return pessoasSorteadas.pop();
}
And I modified that part of your code in which the Result is mounted, thus:
var pessoasSorteadas = [];
var pessoa1, pessoa2;
datas.forEach(data => {
pessoa1 = getPessoaSorteada(Pessoa, pessoasSorteadas);
pessoa2 = getPessoaSorteada(Pessoa, pessoasSorteadas);
if (pessoa2==pessoa1)
pessoa2 = getPessoaSorteada(Pessoa, pessoasSorteadas);
Resultado.push({
data: data.format('L'),
diaSemana: semana[data.day()],
escala: [pessoa1, pessoa2]
})
});
Explaining:
I create a copy of the array of people and the pack, to make the lottery. Every day I want to use two people from this list and remove them from there, when the array is out of people, I create a scrambled copy of the list of people again. Just Czech so that the last person on the previous list does not happen to be the first one on the current list.
That way I think the result was the way you wanted it. Was that right?
EDIT:
I realized there was a hole in my first suggestion: if, by coincidence, the last person drawn from one round was equal to the first person on the next round list, I simply ignored that person and used the next one on the list, there would be repetition, but then that person would not be escalated in that next round, ie it would be a round of 6 people only, instead of 7.
I thought of a new scheme, so that in the case of repetition, instead of jumping the person, I recreate the list of drawn, as many times as necessary, until the last person does not repeat itself. So, I will always have a complete list, with 7 people, and no one "double".
For this, I changed this function:
function getPessoaSorteada(pessoas, pessoasSorteadas, ultimaPessoaSorteada) {
if (pessoasSorteadas.length == 0) {
pessoasSorteadas = shuffle(pessoas);
while (ultimaPessoaSorteada == pessoasSorteadas[pessoasSorteadas.length - 1])
pessoasSorteadas = shuffle(pessoas);
}
return pessoasSorteadas.pop();
}
And I also changed the section that mounts the result:
var pessoasSorteadas = [];
var pessoa1, pessoa2;
datas.forEach(data => {
pessoa1 = getPessoaSorteada(Pessoa, pessoasSorteadas, pessoa2);
pessoa2 = getPessoaSorteada(Pessoa, pessoasSorteadas, pessoa1);
Resultado.push({
data: data.format('L'),
diaSemana: semana[data.day()],
escala: [pessoa1, pessoa2]
})
});
EDIT 2:
There was another problem in the code I proposed: The getPessoaSorteada()
function recreated the pessoasSorteadas
array when it was empty, but in Javascript there is apparently no way to pass a argument by reference by ref ), then when I recreated the array inside the function, it was not returned to the code that called the function, so the array was being recreated all the time, causing several repetitions in the people drawn: / p>
function getPessoaSorteada(pessoas, pessoasSorteadas, ultimaPessoaSorteada) {
// ...
// Essa linha criava um novo array, que não era
// devolvido através do argumento da função.
pessoasSorteadas = shuffle(pessoas);
// ...
}
I had found it strange because when I tested the code it worked, but then I discovered it also because before it worked: I had written the function parameter name wrong, I typed pesoasSorteadas
(with a 's' only), but in the function body I was using the correct name, pessoasSorteadas
. Since the code variable that called the function also had the same name, pessoasSorteadas
, and was in a "global" scope, I think it was using inside the function the variable that was defined outside of it.
The solution I found was to fill the array passed as an argument to the function with the values of the new array, so the array is returned by the argument, since it is not recreated, and therefore remains the same object. For this I used this response in the SO en , then the excerpt that used to be this:
function getPessoaSorteada(pessoas, pessoasSorteadas, ultimaPessoaSorteada) {
// ...
// Essa linha criava um novo array, que não era
// devolvido através do argumento da função.
pessoasSorteadas = shuffle(pessoas);
// ...
}
Now it looks like this:
function getPessoaSorteada(pessoas, pessoasSorteadas, ultimaPessoaSorteada) {
// ...
// Agora ao invés de criar um novo array em cima do argumento
// 'pessoasSorteadas', o mesmo objeto (array) passado para a
// função é populado com os elementos do novo array, com as
// pessoas sorteadas, criado pela função shuffle(pessoas).
pessoasSorteadas.push.apply(sorteadas, shuffle(pessoas));
// ...
}
The whole function looks like this, then:
function getPessoaSorteada(pessoas, pessoasSorteadas, ultimaPessoaSorteada) {
if (pessoasSorteadas.length == 0) {
pessoasSorteadas.push.apply(pessoasSorteadas, shuffle(pessoas));
while (ultimaPessoaSorteada == pessoasSorteadas[pessoasSorteadas.length - 1])
pessoasSorteadas.push.apply(pessoasSorteadas, shuffle(pessoas));
}
return pessoasSorteadas.pop();
}