Last active
September 16, 2016 06:20
-
-
Save guillaumewuip/4d60bef331128578f7a3c85ea07a15a5 to your computer and use it in GitHub Desktop.
Google Sheet Script to distribute projects to groups
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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