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