Reformat and modernise code

This commit is contained in:
Florine W. Dekker 2019-06-08 03:57:10 +02:00
parent e013d67d1d
commit e7fe9a9254
Signed by: FWDekker
GPG Key ID: B1B567AF58D6EE0F
1 changed files with 227 additions and 232 deletions

View File

@ -3,297 +3,292 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="Felix W. Dekker" /> <meta name="author" content="Felix W. Dekker"/>
<meta name="application-name" content="Dice probabilities" /> <meta name="application-name" content="Dice probabilities"/>
<meta name="description" content="Calculates the probability of throwing a value given a combination of dice." /> <meta name="description" content="Calculates the probability of throwing a value given a combination of dice."/>
<meta name="theme-color" content="#0033cc" /> <meta name="theme-color" content="#0033cc"/>
<title>Dice probabilities | FWDekker</title> <title>Dice probabilities | FWDekker</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" integrity="sha256-l85OmPOjvil/SOvVt3HnSSjzF1TUMyT9eV0c2BzEGzU=" crossorigin="anonymous" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.3.0/milligram.min.css" integrity="sha256-Ro/wP8uUi8LR71kwIdilf78atpu8bTEwrK5ZotZo+Zc=" crossorigin="anonymous" /> integrity="sha256-l85OmPOjvil/SOvVt3HnSSjzF1TUMyT9eV0c2BzEGzU=" crossorigin="anonymous"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.3.0/milligram.min.css"
integrity="sha256-Ro/wP8uUi8LR71kwIdilf78atpu8bTEwrK5ZotZo+Zc=" crossorigin="anonymous"/>
<style> <style>
body { body {
margin-top: 50px; margin-top: 50px;
margin-bottom: 50px; margin-bottom: 50px;
} }
</style> </style>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h1>Dice probabilities</h1> <h1>Dice probabilities</h1>
<blockquote> <blockquote>
<p><em>Calculates the probability of throwing a value given a combination of dice.</em></p> <p><em>Calculates the probability of throwing a value given a combination of dice.</em></p>
</blockquote> </blockquote>
<!-- Input --> <!-- Input -->
<div class="row"> <div class="row">
<div class="column"> <div class="column">
<form> <form>
<fieldset> <fieldset>
<table id="dieSettings"> <table id="dieSettings">
<thead> <thead>
<tr> <tr>
<th>Sides per die</th> <th>Sides per die</th>
<th>Number of throws</th> <th>Number of throws</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><button id="addDieRowButton" class="button-outline" type="button">Add dice</button></td> <td>
</tr> <button id="addDieRowButton" class="button-outline" type="button">Add dice</button>
</tbody> </td>
</table> </tr>
</tbody>
</table>
<button id="submit" type="button">Submit</button> <button id="submit" type="button">Submit</button>
</fieldset> </fieldset>
</form> </form>
</div> </div>
</div> </div>
<!-- Output --> <!-- Output -->
<h2>Probabilities</h2> <h2>Probabilities</h2>
<div class="row" height="400px"> <div class="row">
<div class="column"> <div class="column">
<canvas id="probChart"></canvas> <canvas id="probChart"></canvas>
</div> </div>
</div> </div>
</div> </div>
<!-- Scripts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"
integrity="sha256-oSgtFCCmHWRPQ/JmR4OoZ3Xke1Pw4v50uh6pLcu+fIc=" crossorigin="anonymous"></script>
<script>
//////
///
/// Helper functions
///
//////
<!-- Scripts --> const doAfterLoad = fun => {
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js" integrity="sha256-oSgtFCCmHWRPQ/JmR4OoZ3Xke1Pw4v50uh6pLcu+fIc=" crossorigin="anonymous"></script> const oldOnLoad = window.onload || (() => {
<script> });
////// window.onload = (() => {
/// oldOnLoad();
/// Helper functions fun();
/// });
////// };
function addOnLoad(fun) { const repeat = (value, length) => {
var oldOnLoad = window.onload || (() => {}); const zeroArray = [];
window.onload = (() => { for (let i = 0; i < length; i++)
oldOnLoad(); zeroArray.push(value);
fun(); return zeroArray;
}); };
}
function repeat(value, length) { const rangeExclusive = (from, to) => {
var zeroArray = []; const rangeArray = [];
for (var i = 0; i < length; i++) { for (let i = from; i < to; i++)
zeroArray.push(value); rangeArray.push(i);
} return rangeArray;
return zeroArray; };
}
function rangeExclusive(from, to) { const rangeInclusive = (from, to) => {
var rangeArray = []; const rangeArray = rangeExclusive(from, to);
for (var i = from; i < to; i++) { rangeArray.push(to);
rangeArray.push(i); return rangeArray;
} };
return rangeArray;
}
function rangeInclusive(from, to) { const iterateNodeList = (nodeList, fun) => {
var rangeArray = rangeExclusive(from, to); for (let i = 0; i < nodeList.length; i++) {
rangeArray.push(to); const node = nodeList.item(i);
return rangeArray; fun(node);
} }
};
function iterateNodeList(nodeList, fun) {
for (var i = 0; i < nodeList.length; i++) {
var node = nodeList.item(i);
fun(node);
}
}
//////
///
/// Input
///
//////
////// const inputTable = {};
///
/// Input
///
//////
var inputTable = {};
// Functions // Functions
inputTable.getTable = function() { inputTable.getTable = () => document.querySelector("#dieSettings tbody");
return document.querySelector("#dieSettings tbody");
};
inputTable.highestDieRowIndex = function() { inputTable.highestDieRowIndex = () => {
var table = inputTable.getTable(); const table = inputTable.getTable();
var highestDieRowIndex = -1; let highestDieRowIndex = -1;
iterateNodeList(table.getElementsByTagName("tr"), (node) => { iterateNodeList(table.getElementsByTagName("tr"), (node) => {
if (!isNaN(node.dataset.index)) { if (!isNaN(node.dataset.index))
highestDieRowIndex = Math.max(highestDieRowIndex, node.dataset.index); highestDieRowIndex = Math.max(highestDieRowIndex, node.dataset.index);
} });
});
return highestDieRowIndex; return highestDieRowIndex;
}; };
inputTable.addDieRow = function() { inputTable.addDieRow = () => {
function createNumberInput(index, className, value) { const createNumberInput = (index, className, value) => {
var input = document.createElement("input"); const input = document.createElement("input");
input.id = className + index; input.id = className + index;
input.className = className; input.className = className;
input.type = "number"; input.type = "number";
input.min = 1; input.min = 1;
input.step = 1; input.step = 1;
input.value = value; input.value = value;
input.addEventListener("keypress", (e) => { input.addEventListener("keypress", (e) => {
if (e.key == "Enter") { if (e.key === "Enter")
updateProbGraph(); outputChart.updateProbGraph();
} });
}); input.focus();
input.focus(); return input;
return input; };
}
function createRemoveLink(index, className) { const createRemoveLink = (index, className) => {
var link = document.createElement("button"); const link = document.createElement("button");
link.id = className + index; link.id = className + index;
link.className = className + " button-clear"; link.className = className + " button-clear";
link.type = "button"; link.type = "button";
link.innerHTML = "Remove"; link.innerHTML = "Remove";
link.onclick = (() => inputTable.removeDieRow(index)); link.onclick = (() => inputTable.removeDieRow(index));
return link; return link;
} };
var table = inputTable.getTable(); const table = inputTable.getTable();
var newIndex = inputTable.highestDieRowIndex() + 1; const newIndex = inputTable.highestDieRowIndex() + 1;
var row = table.insertRow(newIndex); const row = table.insertRow(newIndex);
row.dataset.index = newIndex; row.dataset.index = newIndex;
row.insertCell().appendChild(createNumberInput(newIndex, "dieEyes", 6)); row.insertCell().appendChild(createNumberInput(newIndex, "dieEyes", 6));
row.insertCell().appendChild(createNumberInput(newIndex, "dieCount", 2)); row.insertCell().appendChild(createNumberInput(newIndex, "dieCount", 2));
row.insertCell().appendChild(createRemoveLink(newIndex, "dieRemove")); row.insertCell().appendChild(createRemoveLink(newIndex, "dieRemove"));
}; };
inputTable.removeDieRow = function(index) { inputTable.removeDieRow = index => {
if (inputTable.highestDieRowIndex() > 0) { if (inputTable.highestDieRowIndex() > 0) {
var table = inputTable.getTable(); const table = inputTable.getTable();
var row = table.querySelector("tr[data-index=\"" + index + "\"]"); const row = table.querySelector("tr[data-index=\"" + index + "\"]");
row.parentElement.removeChild(row); row.parentElement.removeChild(row);
} }
}; };
inputTable.getDice = function() { inputTable.getDice = () => {
var dice = []; const dice = [];
var eyesInputs = document.getElementsByClassName("dieEyes"); const eyesInputs = document.getElementsByClassName("dieEyes");
var countInputs = document.getElementsByClassName("dieCount"); const countInputs = document.getElementsByClassName("dieCount");
for (var i = 0; i < eyesInputs.length; i++) { for (let i = 0; i < eyesInputs.length; i++) {
var count = parseInt(countInputs.item(i).value); const count = parseInt(countInputs.item(i).value);
for (var j = 0; j < count; j++) { for (let j = 0; j < count; j++)
dice.push(parseInt(eyesInputs.item(i).value)); dice.push(parseInt(eyesInputs.item(i).value));
} }
}
return dice; return dice;
}; };
// Handlers // Handlers
document.getElementById("addDieRowButton").onclick = inputTable.addDieRow; document.getElementById("addDieRowButton").onclick = inputTable.addDieRow;
// Init // Init
addOnLoad(() => document.getElementById("addDieRowButton").click()); doAfterLoad(() => document.getElementById("addDieRowButton").click());
//////
///
/// Output
///
//////
////// const outputChart = {};
///
/// Output
///
//////
var outputChart = {};
// Functions // Functions
outputChart.calculateDiceFrequencies = function(dice) { outputChart.calculateDiceFrequencies = dice => {
if (dice.length == 0) { if (dice.length === 0)
return []; return [];
}
// Roll dice // Roll dice
var rollFreqs = [0].concat(repeat(1, dice[0])); let rollFreqs = [0].concat(repeat(1, dice[0]));
dice.slice(1).forEach(die => { dice.slice(1).forEach(die => {
var dieRollFreqs = rollFreqs.concat(repeat(0, die)); const dieRollFreqs = rollFreqs.concat(repeat(0, die));
rollFreqs = repeat(0, dieRollFreqs.length); rollFreqs = repeat(0, dieRollFreqs.length);
rangeInclusive(1, die).forEach(throwValue => { rangeInclusive(1, die).forEach(throwValue => {
rangeExclusive(1, dieRollFreqs.length - die).forEach(i => { rangeExclusive(1, dieRollFreqs.length - die).forEach(i => {
rollFreqs[throwValue + i] += dieRollFreqs[i]; rollFreqs[throwValue + i] += dieRollFreqs[i];
}); });
}); });
}); });
rollFreqs.shift(); rollFreqs.shift();
// Calculate frequencies // Calculate frequencies
var totalRolls = rollFreqs.reduce((a, b) => a + b, 0); const totalRolls = rollFreqs.reduce((a, b) => a + b, 0);
rangeExclusive(0, rollFreqs.length).forEach(roll => { rangeExclusive(0, rollFreqs.length).forEach(roll => {
rollFreqs[roll] = rollFreqs[roll] / totalRolls; rollFreqs[roll] = rollFreqs[roll] / totalRolls;
}); });
return rollFreqs; return rollFreqs;
}; };
outputChart.updateProbGraph = function() { outputChart.updateProbGraph = () => {
var dice = inputTable.getDice(); const dice = inputTable.getDice();
var rollFreqs = outputChart.calculateDiceFrequencies(dice); const rollFreqs = outputChart.calculateDiceFrequencies(dice);
probChart.data.labels = rangeInclusive(1, rollFreqs.length); probChart.data.labels = rangeInclusive(1, rollFreqs.length);
probChart.data.datasets = [{ probChart.data.datasets = [{
data: rollFreqs, data: rollFreqs,
backgroundColor: "rgb(155, 77, 202, 0.4)" backgroundColor: "rgb(155, 77, 202, 0.4)"
}]; }];
probChart.update(); probChart.update();
}; };
// Handlers // Handlers
document.getElementById("submit").onclick = outputChart.updateProbGraph; document.getElementById("submit").onclick = outputChart.updateProbGraph;
// Init // Init
var ctx = document.getElementById("probChart").getContext("2d"); const ctx = document.getElementById("probChart").getContext("2d");
var probChart = new Chart(ctx, { const probChart = new Chart(ctx, {
type: "line", type: "line",
data: {}, data: {},
options: { options: {
legend: { legend: {
display: false display: false
}, },
scales: { scales: {
yAxes: [{ yAxes: [{
display: true, display: true,
ticks: { ticks: {
suggestedMin: 0 suggestedMin: 0
} }
}] }]
} }
} }
}); });
addOnLoad(() => document.getElementById("submit").click()); doAfterLoad(() => document.getElementById("submit").click());
</script> </script>
</body> </body>
</html> </html>