Home > front end >  New class instance until condition is met in JS
New class instance until condition is met in JS

Time:11-07

My knowledge about JS classes is quite limited, so I don't know if this is possible.

My goal is to generate two random and balanced (the crux of the matter) teams from a list of players.

Explanation of my code:

const players: it is an array of objects. Each one is a player, with a name and a tier.

function diff(a, b): utility function. It returns the difference between to integers.

function shuffle(array): utility function. It shuffles the content of an array.

class Team: a class to generate team objects. It has a property "players", passed as an argument, and a propery "tier" which is the summatory of all players tiers.

function checkTeamsLevel(team1, team2): this function checks if two teams are well balanced. It returns true only if the difference between both teams tier is equal or less than 1.

function generateTeams(): this is the main function of the app. It first shuffle the array of players and then splices them in two array of players. Then it generates two teams. In this point, everything works great, but we are not sure if the teams ara balanced. So my idea is to run a while loop to generate new teams until the function checkTeamsLevel() returns true. This code is not working because when this function returns false, the loop doesn't stop. It turns out to be an infinite loop.

How could I instantiate Team classes until they pass the filter of my checkTeamsLevel() function? Is this really possible?

Here is my code:

// Array of player objects
const players = [
  {name: 'John', tier: 1},
  {name: 'James', tier: 3},
  {name: 'Louis', tier: 2},
  {name: 'Rebeca', tier: 2},
  {name: 'Peter', tier: 4},
  {name: 'Oscar', tier: 3},
  {name: 'Laura', tier: 1},
  {name: 'Rebeca', tier: 2},
  {name: 'Paula', tier: 2},
  {name: 'Michael', tier: 4},
];


// Function to check difference between integers.
function diff(a, b) {
 return (a > b) ? (a - b) : (b - a);
}

// Function to shuffle array contents.
function shuffle(array) {
  var currentIndex = array.length;
  var temporaryValue, randomIndex;while (0 !== currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }
  return array;
}

// Team Class
class Team {
  constructor(players) {
    this.players = players;
    this.tier = this.getTeamTier();
  }
  getTeamTier() {
    return this.players.reduce((total, player) => total   player.tier, 0);
  }
}


// Function to check if two teams are balanced.
function checkTeamsLevel(team1, team2) {
  let tierThreshold = 1;
  return ((team1 && team2) && diff(team1.tier, team2.tier) <= tierThreshold);
}


// Function to generate 2 balanced teams
function generateTeams(players) {

  // Shuffle players
  shuffle(players);
  
  // Divide players in 2 groups
  let middleIndex = Math.ceil(players.length / 2);
  let playersForTeam1 = players.splice(0, middleIndex);
  let playersForTeam2 = players.splice(-middleIndex);

  let team1 = new Team(playersForTeam1);
  let team2 = new Team(playersForTeam2);

  // This loop is not working.
  // I have to do something to generate two teams with a tier difference bellow 2.
  while (!checkTeamsLevel(team1, team2)) {
    team1 = new Team('yellow', playersForTeam1);
    team2 = new Team('black', playersForTeam2);
  }

  // Debug
  console.log(team1);
  console.log(team2);
  console.log(checkTeamsLevel(team1, team2));

  return [team1, team2];
}


// Run generateTeams
generateTeams(players);

CodePudding user response:

Look at the code below. It works as you (probably) expect. See comments in the code.

// Array of player objects
const players = [
  {  name: 'John', tier: 1 },
  { name: 'James', tier: 3 },
  { name: 'Louis', tier: 2 },
  { name: 'Rebeca', tier: 2 },
  { name: 'Peter', tier: 4 },
  { name: 'Oscar', tier: 3 },
  { name: 'Laura', tier: 1 },
  { name: 'Rebeca II', tier: 2 }, //duplicate name in OP
  { name: 'Paula', tier: 2 },
  { name: 'Michael', tier: 4 },
  {name: 'Chris', tier: 6}//added to test odd number
];

//No need to code diff. Use Math.abs instead

// Function to shuffle array contents.
//No need. Easy to inline

// Team Class
class Team {
  constructor(players) {
    this.players = players;
    this.teamTier = this.getTeamTier();
  }
  getTeamTier() {
    return this.players.reduce((total, player) => total   player.tier, 0);
  }
}


// Function to check if two teams are balanced.
function checkTeamsLevel(team1, team2) {
  let tierThreshold = 1;
  return team1 && team2 && Math.abs(team1.teamTier - team2.teamTier) <= tierThreshold;
}


// Function to generate 2 balanced teams
function generateTeams(players) {
  let cnt = 0;
  do {
    // Shuffle players
    // .sort acts on the array
    players.sort(() => Math.random() < 0.5 ? -1 : 1);
    // Divide players in 2 groups
    // use .floor instead of .ceil
    let middleIndex = Math.floor(players.length / 2); //if the number of players is odd then then someone go out of game
    //use slice; splice removes elements
    let playersForTeam1 = players.slice(0, middleIndex);
    let playersForTeam2 = players.slice(-middleIndex);

    var team1 = new Team(playersForTeam1);
    var team2 = new Team(playersForTeam2);

    // I have to do something to generate two teams with a tier difference bellow 2.
    cnt  ;
    console.log(cnt);
  } while (!checkTeamsLevel(team1, team2) && /*limit the number of runs to avoid infinite loop */ cnt < 15);

  // Debug
  //console.log(team1);
  //console.log(team2);

  return [team1, team2];
}

// Run generateTeams
let [team1, team2] = generateTeams(players.slice());//slice to keep const players array immutable
console.log('team1', team1, '\nteam2', team2);
//check original players array
console.log('const players',players);

  • Related