JSFiddle - React, Tailwind, and code Playground
by rgthree
HTML
<fieldset>
<legend>Test Data</legend>
<form id="test-form" name="test-form">
<label>Num of Prompts:</label>
<input name="prompts" value="17" type="text" required pattern="\d+"><br>
<label>Num of Choices (per prompt):</label>
<input name="choices" value="4" type="text" required pattern="\d+"><br>
<label>Num of Entries:</label>
<input name="entries" value="2" type="text" required pattern="\d+"><br>
<label>Automate Number of Tests:</label>
<input name="tests" value="1000" type="text" required pattern="\d+"><br>
<input type="submit" value="Run Test" />
</form>
</fieldset>
<br><br><br>
<fieldset>
<legend>Results</legend>
<pre id="results"></pre>
<div id="graph"></div>
<div id="curve"></div>
</fieldset>
CSS
html {
font-size: 10px;
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
body {
background: #fff;
font-family: Arial, sans-serif;
}
fieldset {
border: 1px solid #ccc;
}
legend {
background: #ccc;
font-size: 1.1rem;
padding: 0.5rem 1rem;
}
label {
display: inline-block;
width: 200px;
font-size: 1.3rem;
}
label + input[type="text"] {
display: inline-block;
width: 75px;
font-size: 1.3rem;
}
label + input[readonly] {
width: 175px;
}
pre#results {
white-space: pre-line;
font-size: 1.4rem;
}
#graph,
#curve {
font-size: 0;
display: block;
width: 100%;
margin: 1rem auto;
border: 1px solid #ccc;
padding: 1rem;
}
#graph .keys,
#graph .bars {
width: 100%;
display: flex;
flex-direction: row;
align-items: flex-end;
}
#graph .bars {
height: 100px;
border-bottom: 1px solid #aaa;
}
#graph .bar-container,
#graph .key {
display: inline-block;
width: 33px;
overflow: hidden;
vertical-align: bottom;
border: 1px solid #fff;
text-align: center;
}
#graph .bar-container {
height: 100%;
display: inline-flex;
flex-direction: column;
justify-content: flex-end;
opacity: 0.75;
transition: all 0.25s ease-in-out;
flex-grow: 1;
flex-shrink: 1;
}
#graph .bar-container:hover {
opacity: 1;
}
#graph .bar-container > * {
flex-grow: 0;
flex-shrink: 0;
}
#graph .bar {
max-height: 0%;
background: rgba(145, 0, 0, 0.55);
color: #fff;
}
#graph .bar-container label {
display: block;
font-size: 1rem;
background: #fff;
color: #000;
width: 100%;
}
#graph .-highest .bar {
background: rgba(145, 0, 0, 1);
}
#graph .-zero .bar {
background: #aaa;
}
#graph .-zero label {
opacity: 0.75;
}
#graph .key {
font-size: 1rem;
flex-grow: 1;
flex-shrink: 1;
}
#graph.-on .bar {
transition: max-height 0.5s ease-in-out;
max-height: 100%;
}
#graph .bar-container label {
color: #fff;
}
#graph.-on .bar-container label {
transition: color 0.5s ease-in-out;
color:...
JavaScript
'use strict';
let alphabet = 'abcdefghijklmnopqrstuvwxyz'.toUpperCase().split('');
class Util {
static $(id) {
return document.getElementById(id);
}
static random(min = 0, max = 100) {
return Math.random() * (max - min) + min;
}
static arrayMean(arr) {
var sum = arr.reduce((a, b) => a + b);
return sum / arr.length;
}
static arrayMedian(arr) {
var medianIndex = (arr.length - 1) / 2;
var median;
if (medianIndex === Math.floor(medianIndex)) {
median = arr[medianIndex];
} else {
median = (arr[Math.floor(medianIndex)] + arr[Math.ceil(medianIndex)]) / 2;
}
return median;
}
static arrayVariance(arr) {
let mean = Util.arrayMean(arr);
let squared = arr.reduce((a, b) => a + Math.pow(b - mean, 2));
return squared / (arr.length - 1); // Divide by n-1, instead of n
}
static roundDecimal(n) {
return Math.round(n * 1000) / 1000;
}
static percentage(num, total) {
return Util.roundDecimal((num / total) * 100);
}
static chooseRandom(choices) {
var distribution = 100;
return choices[Math.floor(Util.random(0, distribution - 1) / (distribution / choices.length))];
}
}
/**
* A entry of answers.
*/
class Entry {
constructor(choices) {
this.choices = choices.slice(0);
this.chosen = new Map();
this.choices.forEach(c => this.chosen.set(c, 0));
}
choose() {
let choice = Util.chooseRandom(this.choices);
this.chosen.set(choice, this.chosen.get(choice) + 1);
return choice;
}
}
/**
* A full test run.
* @class
*/
class Test {
constructor(numOfPrompts, numOfEntries, numOfChoices) {
this.numOfPrompts = numOfPrompts;
this.numOfEntries = numOfEntries;
let choices = alphabet.slice(0, numOfChoices);
let entries = [];
do {
entries.push(new Entry(choices))
} while (--numOfEntries);
this.promptsAnsweredTheSame = 0;
do {
let promptAnswers = [];
entries.forEach(e =>...