HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptMinor

JavaScript function to create 2 soccer teams as even as possible, from a list of players

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
soccerteamscreatejavascriptfunctionplayerslistpossibleevenfrom

Problem

? Given a list of players with their respective scores (how well does a player play soccer, from 1 to 5 points), return two teams that are as even as possible.

I've created this code, which is a first version, but I really would like to hear about ideas of how can I improve it.

exports.TeamCreator = (function () {

    this.players = [];

    function setPlayers(players){
        this.players = Object.assign([], players);
    }

    function createTeams() {

        var input = this.players;

        var teams = [],
            i = 0,
            scores = [],
            max = input.length;

        scores["A"]=0; scores["B"]=0;
        teams["A"]=[]; teams["B"]=[];

        input.sort(function(a, b){ return b.score - a.score;});

        var nextPlayer;
        var teamForNextPlayer;

        for (i = 0; i  counterB) { //B has less players than A
                teamForNextPlayer = "B";

                if(scoreB >= scoreA){
                    getWorst();
                }else{
                    getBest();
                }
            }
            else if(counterA = scoreB){
                    getWorst();
                }else{
                    getBest();
                }
            }
            else //Same amount of players
            {
                getBest();
                teamForNextPlayer = (scoreA >= scoreB) ? "B" : "A";
            }
        }

        return {
            teamA: teams["A"],
            teamB: teams["B"],
            diff: Math.abs(scores["A"] - scores["B"]),
            scoreA: scores["A"],
            scoreB: scores["B"]
        };

    }
    return {
        setPlayers : setPlayers,
        createTeams: createTeams
    }
}());


If it's easier, you can pull the code from here.

Solution

First I would make each team an object with a score and players rather than an object for scores and one for players:

var teams = [ { name:'A'; score: 0, players:[] },
              { name:'B', score: 0, players:[] };


Once you have sorted the players by score it might be simpler to pick them off the list two at a time and assign the one with the higher score to the lower scoring team:

// Note: slice is probably better than Object.assign 
let input = this.players.slice();
assert(input.length % 2 == 0, 'Need an equal number of players');

while (input.length > 0) {
  let [strongerTeam,   weakerTeam]   = teams;
  let [strongerPlayer, weakerPlayer] = input.slice(0,2);
  addPlayer(strongerTeam, weakerPlayer);
  addPlayer(weakerTeam,   strongerPlayer);
  sortTeams(teams); 
}

function addPlayer(team, player) {
  team.players.push(player);
  team.score += player.score;
}

// Sort highest scoring team first
function sortTeams(teams) {
  teams.sort(function(a, b) { return b.score - a.score;});      
}

return teams;


One advantage is this always returns the more powerful team first.

This algorithm is not ideal in that it doesn't always choose the most balanced team, for example given players with scores of 8, 4, 3, 3, 1 and 1, Team A will have players 8, 3 and 1 (score of 12) while team b will have players with scores of 4, 3 and 1 (totaling 8). It might be more reasonable to balance them as Team A: 8, 1, 1 and Team B 4, 3, 3 so that both teams have a score of 10. The logic for that might be:

while (input.length > 0) {
  let [strongerTeam,   weakerTeam]   = teams;
  let nextPlayer = input.slice(0,1)[0];
  addPlayer(weakerTeam,   nextPlayer);
  if (strongerTeam.length - weakerTeam.length == input.length) {
    addPlayers(strongerTeam, input);
    input = [];
  }

  sortTeams(teams); 
}

function addPlayers(team, players) {
  for (let player of players) {
    addPlayer(team, player);
  }
}

Code Snippets

var teams = [ { name:'A'; score: 0, players:[] },
              { name:'B', score: 0, players:[] };
// Note: slice is probably better than Object.assign 
let input = this.players.slice();
assert(input.length % 2 == 0, 'Need an equal number of players');

while (input.length > 0) {
  let [strongerTeam,   weakerTeam]   = teams;
  let [strongerPlayer, weakerPlayer] = input.slice(0,2);
  addPlayer(strongerTeam, weakerPlayer);
  addPlayer(weakerTeam,   strongerPlayer);
  sortTeams(teams); 
}

function addPlayer(team, player) {
  team.players.push(player);
  team.score += player.score;
}

// Sort highest scoring team first
function sortTeams(teams) {
  teams.sort(function(a, b) { return b.score - a.score;});      
}

return teams;
while (input.length > 0) {
  let [strongerTeam,   weakerTeam]   = teams;
  let nextPlayer = input.slice(0,1)[0];
  addPlayer(weakerTeam,   nextPlayer);
  if (strongerTeam.length - weakerTeam.length == input.length) {
    addPlayers(strongerTeam, input);
    input = [];
  }

  sortTeams(teams); 
}

function addPlayers(team, players) {
  for (let player of players) {
    addPlayer(team, player);
  }
}

Context

StackExchange Code Review Q#155943, answer score: 2

Revisions (0)

No revisions yet.