Skip to content

Instantly share code, notes, and snippets.

@guillaumewuip
Last active September 16, 2016 06:20
Show Gist options
  • Save guillaumewuip/4d60bef331128578f7a3c85ea07a15a5 to your computer and use it in GitHub Desktop.
Save guillaumewuip/4d60bef331128578f7a3c85ea07a15a5 to your computer and use it in GitHub Desktop.
Google Sheet Script to distribute projects to groups
var CHOICES_SHEETS = 'Choix',
PROJECTS_SHEETS = 'Sujets',
RESULTS_SHEETS = 'Résultat';
/**
* randomInt
* @return {Number} An int in [0; max[
*/
var randomInt = function (max) {
var max = Math.floor(max);
return Math.floor(Math.random() * (max));
};
var _d = (function () {
var data = {
_groups: {},
_projects: {},
init: function (projects, groups, choices) {
data._projects = projects;
data._groups = groups;
},
assign: function (group, project) {
data._groups[group] = project;
data._projects[project].taken = group;
Logger.log('Assign '+ group + ' to ' + project);
},
isGroupDone: function (group) {
return !!data._groups[group];
},
isProjectTaken: function (project) {
return !!data._projects[project].taken;
},
getFreeProjects: function () {
var arr = []; //we return an array it's better here
for (var k in data._projects) {
var p = data._projects[k];
if (!p.taken) {
arr.push({
name: k,
choices: p.choices,
});
}
}
return arr;
},
getFreeGroups: function () {
var arr = []; //we return an array it's better here
for (var k in data._groups) {
if (!data.isGroupDone(k)) {
arr.push(k);
}
}
return arr;
},
};
/**
* getRowProjects
* Get projects from the sheet
*/
var getRowProjects = function (spreadsheet) {
var projectsSheet = spreadsheet.getSheetByName(PROJECTS_SHEETS);
var maxRow = projectsSheet.getLastRow();
var projects = projectsSheet.getRange(2, 1, maxRow, 1);
var o = {};
projects.getValues()
.map(function (e) {
return e[0]
})
.forEach(function (p) {
o[p] = {
choices: [[], [], [], [], []],
taken: false,
};
});
return o;
};
/**
* getChoices
* Get choices from the sheet
*/
var getChoices = function (spreadsheet) {
var choiceSheet = spreadsheet.getSheetByName(CHOICES_SHEETS);
var maxRow = choiceSheet.getLastRow();
var choices = choiceSheet.getRange(2, 1, maxRow, 6);
return choices.getValues()
.filter(function (e) {
return e[0] !== '';
});
};
/**
* getGroups
* Get groups from the sheet
*/
var getGroups = function (spreadsheet) {
var choiceSheet = spreadsheet.getSheetByName(CHOICES_SHEETS);
var maxRow = choiceSheet.getLastRow();
var groups = choiceSheet.getRange(2, 1, maxRow, 1);
var o = {};
groups.getValues()
.filter(function (e) {
return e[0] !== '';
})
.forEach(function (g) {
o[g] = null;
});
return o;
};
/**
* buildProjects
*
* Build the projects object
* @example
* {
* 'my-project': {
* choices: [ // array length is 5 (because 5 choices)
* ['Group X', 'Group M'], // first choice groups
* ['Group A'], // second choice groups
* ],
* },
* ...
* }
*
* @return {Object} All the projects with their choices
*/
var buildProjects = function (projects, choices) {
choices.forEach(function (row) {
var group = row.shift();
row.forEach(function (project, i) {
Logger.log('Register ' + group + ' to '
+ project + ' for choice ' + i);
projects[project].choices[i].push(group);
});
});
return projects;
};
/**
* assignByPref
*
* Assign projects according to choice number `pref`
*/
var assignByPref = function (data, pref) {
data.getFreeProjects()
.forEach(function (project) {
// groups that want this project and aren't already done
var groups = project.choices[pref].filter(function (group) {
return !data.isGroupDone(group);
});
if (groups.length === 0) { // no group for this project
return;
}
if (groups.length === 1) {
// just one group, perfect !
data.assign(groups[0], project.name);
} else {
// more than one group for this project
// we compute a random number to decide wich group will get the
// project
var r = randomInt(groups.length);
data.assign(groups[r], project.name);
}
});
};
/**
* assignLastProjectsAndGroups
*
* Assign untaken projects with untaken groups
* Must be run at the end of the distribution
*/
var assignLastProjectsAndGroups = function (data) {
var freeProjects = data.getFreeProjects();
var freeGroups = data.getFreeGroups();
freeProjects.forEach(function (p, i) {
if (freeGroups[i]) { //if only their is a free group
data.assign(freeGroups[i], p.name);
}
});
};
/**
* writeResultToSheet
*/
var writeResultToSheet = function (spreadsheet, data) {
var confirm = Browser.msgBox(
'Erase all previous results ?',
Browser.Buttons.OK_CANCEL
);
Logger.log('Ask confirmation. Got ' + confirm);
if (confirm !== 'ok') { // stop here
return;
}
var resultSheet = spreadsheet.getSheetByName(RESULTS_SHEETS);
var maxRow = resultSheet.getLastRow();
resultSheet.deleteRows(2, maxRow);
for (var k in data._groups) {
Logger.log('Group ' + k + ' - Project ' + data._groups[k]);
resultSheet.appendRow([k, data._groups[k]]);
}
data.getFreeProjects()
.forEach(function (p) {
Logger.log('Free Project ' + p.name);
resultSheet.appendRow(['', p.name]);
});
};
var init = function () {
var spreadsheet = SpreadsheetApp.getActive();
// INIT
var projects = getRowProjects(spreadsheet),
groups = getGroups(spreadsheet),
choices = getChoices(spreadsheet);
var builtProjects = buildProjects(projects, choices);
data.init(builtProjects, groups, choices);
// Distributing projects
for (var i=0; i < 5; i++) {
assignByPref(data, i);
};
assignLastProjectsAndGroups(data);
// Done, logging results
writeResultToSheet(spreadsheet, data);
};
return init;
}());
function distribute() {
_d();
}
/**
* A special function that runs when the spreadsheet is open, used to add a
* custom menu to the spreadsheet.
*/
function onOpen() {
var spreadsheet = SpreadsheetApp.getActive();
var menuItems = [
{name: 'Distribute projets', functionName: 'distribute'}
];
spreadsheet.addMenu('Distribution', menuItems);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment