<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Sinterklaas</title>
</head>
<body>
<label for="jaar">Jaar:</label>
<select id="jaar">
<option>2017</option>
<option selected>2018</option>
</select>
<label for="naam">Ik ben:</label>
<select id="naam">
<option value="">Kies hier je naam</option>
</select>
<button id="go">Wie heb ik?</button>
<div id="result"></div>
</body>
</html>
const jaren = {
2017: {
klazen: [
'a',
'b',
'c',
'd',
'e',
'f',
'g'
],
taken: ['surprise (en een gedicht)', 'gedicht', 'gedicht']
},
2018: {
klazen: [
'b',
'c',
'd',
'e',
'g',
'h'
],
taken: ['surprise (en een gedicht)', 'gedicht', 'gedicht']
}
};
const jaarSelect = document.getElementById('jaar');
const naamSelect = document.getElementById('naam');
const goButton = document.getElementById('go');
let seed;
window.onload = redraw;
goButton.onclick = redraw;
jaarSelect.onchange = veranderJaar;
function veranderJaar() {
clearNaamOptions();
redraw();
}
function redraw() {
const {naam, jaar} = readDom();
const {klazen, taken} = jaren[jaar];
updateNaamOptions(klazen);
if (!jaar || !naam) {
display("Kies een jaar en een naam.");
} else {
const lootjes = trekLootjes(klazen, taken, jaar);
display(formatResults(lootjes, taken, naam));
}
}
function updateNaamOptions(namen) {
const selectedIndex = naamSelect.options.selectedIndex;
clearNaamOptions();
setNaamOptions(namen);
naamSelect.options.selectedIndex = selectedIndex;
}
function setNaamOptions(namen) {
namen.forEach(naam => {
const option = document.createElement('option');
option.text = naam;
naamSelect.options.add(option);
});
}
function clearNaamOptions() {
while (naamSelect.options.length > 1) {
naamSelect.options.remove(naamSelect.options.length - 1);
}
}
function readDom() {
let jaar = jaarSelect.value;
let naam = naamSelect.value;
return {naam: naam, jaar: jaar};
}
function trekLootjes(klazen, taken, jaar) {
seed = jaar * 10000;
const trekkingen = getLootjes(klazen, taken.length),
results = distribute(trekkingen, klazen);
return results;
}
function display(text) {
document.getElementById('result').innerText = text;
}
function formatResults(lootjes, taken, naam) {
const mijnLootjes = lootjes[naam];
if (!mijnLootjes) {
return `Dag ${naam}... je doet dit jaar niet mee, kan dat?`;
}
return `Lieve ${naam},
Je opdrachten voor dit jaar zijn:
${formatLootjes(mijnLootjes, taken)}
Veel plezier,
Sinterklaas`
}
function formatLootjes(lootjes, taken) {
return lootjes.map(formatLootje.bind(null, taken)).join('\n')
}
function formatLootje(taken, lootje, index) {
return `Maak een ${taken[index]} voor ${lootje}`;
}
function distribute(trekkingen, klazen) {
return klazen.reduce(
(acc, naam, index) => {return {acc, [naam]: trekkingen.map(trekking => trekking[index])}}
, {})
}
function getLootjes(klazen, num) {
let trekkingen = [];
while (trekkingen.length < num) {
trekkingen.push(getAcceptabeleLootjes(klazen, trekkingen));
}
return trekkingen;
}
function getAcceptabeleLootjes(klazen, eerdereTrekkingen) {
let lootjes;
do {
lootjes = shuffleArray(klazen);
} while (!isAcceptabel(lootjes, [klazen, eerdereTrekkingen]));
return lootjes;
}
function isAcceptabel(lootjes, eerdereTrekkingen) {
return eerdereTrekkingen.every(heeftAllemaalAndereLootjes.bind(null, lootjes));
}
function heeftAllemaalAndereLootjes(lootjes, eerdereTrekking) {
return eerdereTrekking.every(
(lootje, index) => lootjes[index] !== lootje
);
}
function shuffleArray(inArray) {
let array = [inArray];
for (let i = array.length - 1; i > 0; i--) {
const j = randomNumberUpTo(i + 1);
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
function randomNumberUpTo(n) {
const x = Math.sin(seed++) * 10000,
fractional = x - Math.floor(x);
return Math.floor(fractional * n);
}
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |