Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make lottery less random #79

Open
Namaskar-1F64F opened this issue Mar 18, 2022 · 1 comment
Open

Make lottery less random #79

Namaskar-1F64F opened this issue Mar 18, 2022 · 1 comment

Comments

@Namaskar-1F64F
Copy link
Member

A request for a less random picker was brought up after some people out of a group of 15 participants have yet to be picked in the past two months.

Describe the solution you'd like
Have a new list of weights per participant. the weights can start proportionally and when a person is chosen, their weight is cut by 3/4 and their weight is evenly distributed to the other participants. When a new participant joins, weights are adjusted to allow the newcomer a starting proportional weight.

Describe alternatives you've considered
to start - make sure a person isn't chosen twice in a row by filtering out the previous winners.

await unsetWinners();

Additional context
Maybe something like this? https://www.npmjs.com/package/random-weighted-choice where everyone but the winner's weight is increased by 1? and newcomer weight is the average of all weights?

@Geczy
Copy link
Member

Geczy commented Apr 18, 2023

Your proposed solution to use weighted random selection with weights adjusted based on previous selections seems reasonable. It would allow for more even distribution of selections among participants over time and prevent certain participants from being picked too frequently or too infrequently.

As for the implementation, you could create an object to store the current weights for each participant and initialize them with proportional weights based on the number of participants. For example, if you have 15 participants, each would have an initial weight of 1/15. Then, when a participant is chosen, their weight would be cut by 3/4 and their weight would be evenly distributed to the other participants, meaning each of the remaining participants would receive an additional weight of 3/(4*(n-1)), where n is the number of participants remaining after removing the selected participant. When a new participant joins, you would adjust the weights again to allow the newcomer a starting proportional weight.

Here's some sample code that implements this approach:

const participants = ['Alice', 'Bob', 'Charlie', 'Dave', 'Eve', 'Frank', 'Grace', 'Heidi', 'Ivan', 'Judy', 'Kathy', 'Larry', 'Mallory', 'Nancy', 'Oscar'];
const weights = {};
let remainingParticipants = [...participants];

// Initialize weights with proportional values
remainingParticipants.forEach(p => {
  weights[p] = 1 / participants.length;
});

// Function to select a participant
function selectParticipant() {
  if (remainingParticipants.length === 0) {
    console.log('No participants remaining!');
    return null;
  }

  // Calculate cumulative weights
  const cumWeights = {};
  let cumWeight = 0;
  remainingParticipants.forEach(p => {
    cumWeight += weights[p];
    cumWeights[p] = cumWeight;
  });

  // Generate random number in range [0,1)
  const rand = Math.random();

  // Select participant with corresponding cumulative weight
  const selectedParticipant = remainingParticipants.find(p => cumWeights[p] > rand * cumWeight);

  // Update weights
  remainingParticipants = remainingParticipants.filter(p => p !== selectedParticipant);
  const remainingWeight = 3 / (4 * remainingParticipants.length);
  remainingParticipants.forEach(p => {
    weights[p] += remainingWeight;
  });
  weights[selectedParticipant] *= 1 / 4;

  return selectedParticipant;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants