@@ -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 |