@@ -0,0 +1,177 @@ | |||||
const TESTS_LIST = ['Charles', 'Baruch','Frédéric', 'John', 'Dan', | |||||
'Linus', 'Nina', 'Mikhaïl', 'Russel', 'Françoise', | |||||
'Albert', 'Beth', 'Erykah', 'Aretha', 'Lucio', | |||||
'Bartleby','Zach','Patti','Aesop','Vernon'] | |||||
var participants; | |||||
function loadParticipantsFileChooser(){ | |||||
document.getElementById('filechooser').click() | |||||
} | |||||
function loadTest(){ | |||||
addParticipants(TESTS_LIST) | |||||
} | |||||
function loadParticipantsFromFile(file){ | |||||
let reader = new FileReader(); | |||||
let contents = reader.readAsText(file); | |||||
reader.onload = function(event) { | |||||
let contents = reader.result; | |||||
let lines = contents.split('\n'); | |||||
addParticipants(lines) | |||||
}; | |||||
} | |||||
function addParticipants(list){ | |||||
list.forEach(function(item) { | |||||
if(item.trim() !== '') | |||||
addParticipant(item) | |||||
}); | |||||
} | |||||
function addParticipant(name){ | |||||
var newInput = document.createElement('input'); | |||||
newInput.setAttribute('class','participant'); | |||||
newInput.setAttribute('placeholder','participant'); | |||||
if(name) | |||||
newInput.value = name; | |||||
document.getElementById('participants').appendChild(newInput) | |||||
} | |||||
function russellize(){ | |||||
let availablesPerParticipants = new Map() | |||||
participants.forEach(function (p) { | |||||
availablesPerParticipants.set(p,participants.slice().filter(el => el !== p)) | |||||
}); | |||||
let k = document.getElementById('nbPerGroup').value | |||||
let nbRounds = document.getElementById('nbRounds').value | |||||
let nbGroups = Math.ceil(participants.length / k) | |||||
let rounds = new Array() | |||||
for(let i = 1; i <= nbRounds; i++){ | |||||
let round = new Array() | |||||
let availables = participants.slice() | |||||
for(let j = 0; j < nbGroups ; j++){ | |||||
let currentGroup = new Array() | |||||
let toTest = availables.slice() | |||||
while(currentGroup.length < k){ | |||||
let random = Math.floor(Math.random()*toTest.length) | |||||
let randomParticipant = toTest[random] | |||||
let ok = true | |||||
toTest.splice(random, 1); | |||||
// console.log(randomParticipant + '/' + random) | |||||
currentGroup.forEach(function (p) { | |||||
if(availablesPerParticipants.get(p).indexOf(randomParticipant)<0){ | |||||
ok = false | |||||
return | |||||
} | |||||
}) | |||||
if(!ok && toTest.length === 0){ | |||||
return false | |||||
} | |||||
if(ok){ | |||||
let randomEq = availables.indexOf(randomParticipant) | |||||
availables.splice(randomEq, 1); | |||||
// console.log(availables) | |||||
currentGroup.forEach(function (p) { | |||||
let l = availablesPerParticipants.get(p) | |||||
let index = l.indexOf(randomParticipant) | |||||
l.splice(index,1) | |||||
}) | |||||
currentGroup.push(randomParticipant) | |||||
} | |||||
} | |||||
round.push(currentGroup) | |||||
} | |||||
rounds.push(round) | |||||
} | |||||
return rounds | |||||
} | |||||
function run(){ | |||||
doIt() | |||||
} | |||||
function doIt(){ | |||||
participants = new Array() | |||||
var inputs = document.getElementsByClassName('participant') | |||||
for(var i = 0; i < inputs.length; i++){ | |||||
participants.push(inputs[i].value) | |||||
} | |||||
let rounds = false | |||||
let attempts = 0 | |||||
while(!rounds){ | |||||
attempts ++ | |||||
rounds = russellize() | |||||
} | |||||
console.log(rounds) | |||||
console.log("Attempts = " + attempts) | |||||
let stats = new Map() | |||||
participants.forEach(function (p) { | |||||
let l = new Array() | |||||
stats.set(p,l) | |||||
rounds.forEach(function (round) { | |||||
round.forEach(function (group) { | |||||
if(group.indexOf(p)>=0){ | |||||
group.forEach(function (p2) { | |||||
if(p !== p2){ | |||||
l.push(p2) | |||||
} | |||||
}) | |||||
} | |||||
}) | |||||
}) | |||||
}) | |||||
document.getElementById('rounds').innerHTML='' | |||||
let view = renderRounds(rounds) | |||||
document.getElementById('rounds').appendChild(view) | |||||
} | |||||
function renderRounds(rounds){ | |||||
let x = 1 | |||||
let roundsBlock = document.createElement('div') | |||||
rounds.forEach(function (round) { | |||||
let roundBlockWrap = document.createElement('div') | |||||
let roundBlock = document.createElement('div') | |||||
let roundTitle = document.createElement('h2') | |||||
let roundTitleText = document.createTextNode('Round ' + x) | |||||
roundTitle.appendChild(roundTitleText) | |||||
roundBlockWrap.appendChild(roundTitle) | |||||
roundBlock.classList.add('round') | |||||
let y = 1 | |||||
round.forEach(function (group) { | |||||
let groupBlock = document.createElement('div') | |||||
let groupTitle = document.createElement('h4') | |||||
let groupTitleText = document.createTextNode('Group ' + y) | |||||
groupTitle.append(groupTitleText) | |||||
groupBlock.append(groupTitle) | |||||
roundBlock.append(groupBlock) | |||||
let list = document.createElement('ul') | |||||
groupBlock.appendChild(list) | |||||
groupBlock.classList.add('group') | |||||
group.forEach(function (p) { | |||||
let item = document.createElement('li') | |||||
item.appendChild(document.createTextNode(p)) | |||||
list.appendChild(item) | |||||
}) | |||||
y ++ | |||||
}) | |||||
x++ | |||||
roundBlockWrap.append(roundBlock) | |||||
roundsBlock.appendChild(roundBlockWrap) | |||||
}) | |||||
return roundsBlock | |||||
} |
@@ -0,0 +1,79 @@ | |||||
@font-face { | |||||
font-family: 'Roboto'; | |||||
src: url('../fonts/Roboto-Light.ttf'); | |||||
} | |||||
html, body{ | |||||
margin:0px; | |||||
padding:0px; | |||||
font-family: 'Roboto'; | |||||
} | |||||
#rounds, #participants{ | |||||
padding:10px; | |||||
} | |||||
.round{ | |||||
display:flex; | |||||
flex-wrap: wrap; | |||||
} | |||||
.group{ | |||||
margin:5px; | |||||
border: 1px solid #aaa; | |||||
border-radius:3px; | |||||
padding:5px; | |||||
width: 15%; | |||||
} | |||||
h4{ | |||||
margin:5px; | |||||
} | |||||
.group ul { | |||||
list-style-type: square; | |||||
} | |||||
label{ | |||||
display:inline-block; | |||||
} | |||||
.participant{ | |||||
margin:2px; | |||||
} | |||||
#participants{ | |||||
border-bottom: 2px solid black; | |||||
padding-bottom:10px; | |||||
margin-top:20px; | |||||
} | |||||
nav{ | |||||
display: flex; | |||||
justify-content: space-between; | |||||
padding:10px; | |||||
} | |||||
button{ | |||||
background-color: white; | |||||
border: 1px solid #333; | |||||
border-radius: 2px; | |||||
cursor:pointer; | |||||
} | |||||
button img{ | |||||
vertical-align: middle; | |||||
} | |||||
button:hover{ | |||||
background-color: #ddd; | |||||
} | |||||
#settings > div{ | |||||
height:32px; | |||||
} | |||||
#settings input{ | |||||
width:80px; | |||||
} | |||||
#settings img{ | |||||
vertical-align: bottom; | |||||
margin-right:10px; | |||||
} | |||||
#filechooser{ | |||||
display:none; | |||||
} |
@@ -0,0 +1 @@ | |||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/><path d="M0 0h24v24H0z" fill="none"/></svg> |
@@ -0,0 +1 @@ | |||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg> |
@@ -0,0 +1 @@ | |||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/><path d="M0 0h24v24H0z" fill="none"/></svg> |
@@ -0,0 +1 @@ | |||||
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 512 512" height="512px" id="Layer_1" version="1.1" viewBox="0 0 512 512" width="512px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="_x23_231f20ff"><path d="M409.434,82.96c30.04,25.7,60.08,51.42,89.971,77.29c-29.49,26.511-60.15,51.851-90.101,77.9 c0.07-17.43-0.11-34.851,0.061-52.271c-19,0.03-38-0.109-56.99,0.061c-9.13,0.02-17.72,4.58-23.87,11.16 c-54.55,56.779-109.21,113.46-163.74,170.26c-6.06,6.29-14.51,10.4-23.34,10.32c-34.689,0.22-69.39-0.17-104.069,0.229 c-12.891-0.38-23.95-12.06-23.94-24.89c-0.64-13.91,11.62-25.9,25.28-26.311c27.55-0.26,55.13,0.15,82.68-0.189 c10.05-0.061,18.9-5.92,25.24-13.32c53.72-55.939,107.5-111.83,161.25-167.75c6.04-6.59,14.72-10.65,23.68-10.85 c25.939-0.11,51.89,0.1,77.82-0.101C409.313,117.32,409.174,100.141,409.434,82.96z"/><path d="M32.764,134.48c37.5-0.311,75.131,0.03,112.69-0.08c9.68-0.43,19.54,3.2,26.12,10.43 c15.609,16.061,31.05,32.311,46.57,48.46c6.359,6.5,9.85,15.96,7.64,24.98c-2.41,11.04-12.98,19.819-24.36,19.71 c-7.729,0.35-14.85-3.59-20.54-8.48c-10.64-11.34-20.84-23.12-31.649-34.31c-6.19-6.3-15.09-9.41-23.83-9.29 c-27.99-0.12-55.98,0.08-83.971-0.09c-11.14-0.34-23.02-5.601-27.13-16.66C7.974,155.07,17.654,137.19,32.764,134.48z"/><path d="M261.554,278.17c9.67-7.729,24.83-6.609,33.36,2.32c11.689,11.98,23.13,24.21,34.83,36.18 c6.08,6.41,14.84,10.07,23.67,9.98c18.66-0.07,37.319,0.08,55.99-0.09c-0.19-17.11-0.07-34.221-0.04-51.33 c30.27,25.64,60.31,51.55,90.3,77.52c-29.95,25.95-60.061,51.71-90.221,77.41c-0.38-17.5,0.04-35.01-0.189-52.51 c-25.97-0.24-51.94-0.021-77.91-0.11c-8.95-0.08-17.57-4.35-23.56-10.91c-16.73-17.27-33.73-34.27-50.29-51.689 C247.904,304.471,250.034,286.36,261.554,278.17z"/></g></svg> |
@@ -0,0 +1 @@ | |||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM8 17.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5zM9.5 8c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5S9.5 9.38 9.5 8zm6.5 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></svg> |
@@ -0,0 +1 @@ | |||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h4v-2H5V8h14v10h-4v2h4c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm-7 6l-4 4h3v6h2v-6h3l-4-4z"/></svg> |
@@ -0,0 +1,40 @@ | |||||
<?xml version="1.0" encoding="UTF-8" ?> | |||||
<!DOCTYPE html> | |||||
<html xmlns="http://www.w3.org/1999/xhtml"> | |||||
<head> | |||||
<meta charset="utf-8" /> | |||||
<title>Round table groups generator</title> | |||||
<link href="css/app.css" rel="stylesheet"> | |||||
<script src="app.js"></script> | |||||
</head> | |||||
<body> | |||||
<nav> | |||||
<div> | |||||
<button title="load participants from file" onclick="loadParticipantsFileChooser()"> | |||||
<img src='images/upload.svg' /> | |||||
</button> | |||||
<button title="load test participants" onclick="loadTest()"> | |||||
<img src='images/random.svg'width="24px"/> | |||||
</button> | |||||
<button title="add participant" onclick="addParticipant()"> | |||||
<img src='images/add.svg' /> | |||||
</button> | |||||
<button id="btn-do-it" title="run" onclick="run()"> | |||||
<img src="images/play.svg"/> | |||||
</button> | |||||
<input id="filechooser" type="file" onchange="loadParticipantsFromFile(this.files[0])"/> | |||||
</div> | |||||
<div id="settings"> | |||||
<div><label><img title="Table/Group size" src="images/group.svg"></label><input title="Table/Group size" type="number" value="4" id="nbPerGroup"/></div> | |||||
<div> | |||||
<label><img title="Number of rounds" src="images/round.svg"></label><input type="number" title="Number of rounds" value="6" id="nbRounds"/> | |||||
</div> | |||||
</div> | |||||
</nav> | |||||
<div id="participants"></div> | |||||
<div id="rounds"></div> | |||||
</body> | |||||
</html> |
@@ -0,0 +1,20 @@ | |||||
Janeth | |||||
Versie | |||||
Mayola | |||||
Toni | |||||
Geoffrey | |||||
Suanne | |||||
Chang | |||||
Genaro | |||||
Shona | |||||
Arletta | |||||
Tiesha | |||||
Jo | |||||
Madge | |||||
Roselyn | |||||
Delmar | |||||
Staci | |||||
Christoper | |||||
Bernice | |||||
Alvera | |||||
Charlesetta |